aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml')
-rw-r--r--src/qml/CMakeLists.txt2
-rw-r--r--src/qml/Qt6AndroidQmlMacros.cmake8
-rw-r--r--src/qml/Qt6QmlBuildInternals.cmake1
-rw-r--r--src/qml/Qt6QmlDeploySupport.cmake11
-rw-r--r--src/qml/Qt6QmlMacros.cmake390
-rw-r--r--src/qml/Qt6qt.conf.in5
-rw-r--r--src/qml/common/qv4alloca_p.h36
-rw-r--r--src/qml/common/qv4compileddata_p.h6
-rw-r--r--src/qml/common/qv4staticvalue_p.h4
-rw-r--r--src/qml/compiler/qqmlirbuilder.cpp13
-rw-r--r--src/qml/compiler/qqmlirbuilder_p.h1
-rw-r--r--src/qml/configure.cmake2
-rw-r--r--src/qml/doc/src/cmake/cmake-properties.qdoc21
-rw-r--r--src/qml/doc/src/cmake/policy/qtp0005.qdoc42
-rw-r--r--src/qml/doc/src/cmake/qt_add_qml_module.qdoc3
-rw-r--r--src/qml/doc/src/external-resources.qdoc9
-rw-r--r--src/qml/doc/src/javascript/qmlglobalobject.qdoc4
-rw-r--r--src/qml/doc/src/qmllanguageref/documents/structure.qdoc25
-rw-r--r--src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc2
-rw-r--r--src/qml/doc/src/qmlsingletons.qdoc2
-rw-r--r--src/qml/doc/src/tools/qtqml-tooling-svgtoqml.qdoc85
-rw-r--r--src/qml/jsapi/qjsprimitivevalue.h20
-rw-r--r--src/qml/jsruntime/qv4arraybuffer.cpp8
-rw-r--r--src/qml/jsruntime/qv4arraybuffer_p.h4
-rw-r--r--src/qml/jsruntime/qv4arrayobject.cpp4
-rw-r--r--src/qml/jsruntime/qv4arrayobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4booleanobject.cpp4
-rw-r--r--src/qml/jsruntime/qv4booleanobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4context.cpp4
-rw-r--r--src/qml/jsruntime/qv4context_p.h2
-rw-r--r--src/qml/jsruntime/qv4dataview.cpp4
-rw-r--r--src/qml/jsruntime/qv4dataview_p.h2
-rw-r--r--src/qml/jsruntime/qv4dateobject.cpp4
-rw-r--r--src/qml/jsruntime/qv4dateobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4engine.cpp85
-rw-r--r--src/qml/jsruntime/qv4engine_p.h2
-rw-r--r--src/qml/jsruntime/qv4errorobject.cpp32
-rw-r--r--src/qml/jsruntime/qv4errorobject_p.h16
-rw-r--r--src/qml/jsruntime/qv4executablecompilationunit_p.h1
-rw-r--r--src/qml/jsruntime/qv4function.cpp20
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp246
-rw-r--r--src/qml/jsruntime/qv4functionobject_p.h210
-rw-r--r--src/qml/jsruntime/qv4generatorobject.cpp4
-rw-r--r--src/qml/jsruntime/qv4generatorobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4global_p.h1
-rw-r--r--src/qml/jsruntime/qv4globalobject.cpp6
-rw-r--r--src/qml/jsruntime/qv4globalobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4jscall_p.h7
-rw-r--r--src/qml/jsruntime/qv4managed_p.h2
-rw-r--r--src/qml/jsruntime/qv4mapobject.cpp8
-rw-r--r--src/qml/jsruntime/qv4mapobject_p.h4
-rw-r--r--src/qml/jsruntime/qv4numberobject.cpp4
-rw-r--r--src/qml/jsruntime/qv4numberobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4objectproto.cpp4
-rw-r--r--src/qml/jsruntime/qv4objectproto_p.h2
-rw-r--r--src/qml/jsruntime/qv4promiseobject.cpp4
-rw-r--r--src/qml/jsruntime/qv4promiseobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4proxy.cpp39
-rw-r--r--src/qml/jsruntime/qv4proxy_p.h17
-rw-r--r--src/qml/jsruntime/qv4qmetaobjectwrapper.cpp71
-rw-r--r--src/qml/jsruntime/qv4qmetaobjectwrapper_p.h72
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp111
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper_p.h9
-rw-r--r--src/qml/jsruntime/qv4regexpobject.cpp4
-rw-r--r--src/qml/jsruntime/qv4regexpobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp60
-rw-r--r--src/qml/jsruntime/qv4sequenceobject.cpp60
-rw-r--r--src/qml/jsruntime/qv4sequenceobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4setobject.cpp8
-rw-r--r--src/qml/jsruntime/qv4setobject_p.h4
-rw-r--r--src/qml/jsruntime/qv4stringobject.cpp4
-rw-r--r--src/qml/jsruntime/qv4stringobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4symbol.cpp4
-rw-r--r--src/qml/jsruntime/qv4symbol_p.h2
-rw-r--r--src/qml/jsruntime/qv4typedarray.cpp14
-rw-r--r--src/qml/jsruntime/qv4typedarray_p.h4
-rw-r--r--src/qml/jsruntime/qv4urlobject.cpp8
-rw-r--r--src/qml/jsruntime/qv4urlobject_p.h4
-rw-r--r--src/qml/jsruntime/qv4value_p.h5
-rw-r--r--src/qml/jsruntime/qv4vtable_p.h77
-rw-r--r--src/qml/parser/qqmljs.g8
-rw-r--r--src/qml/parser/qqmljsast_p.h1
-rw-r--r--src/qml/parser/qqmljslexer.cpp53
-rw-r--r--src/qml/qml/ftw/qqmlnullablevalue_p.h2
-rw-r--r--src/qml/qml/qqmlbinding.cpp3
-rw-r--r--src/qml/qml/qqmlboundsignal.cpp5
-rw-r--r--src/qml/qml/qqmlbuiltinfunctions.cpp69
-rw-r--r--src/qml/qml/qqmlbuiltinfunctions_p.h15
-rw-r--r--src/qml/qml/qqmlcontextdata_p.h4
-rw-r--r--src/qml/qml/qqmldelayedcallqueue.cpp5
-rw-r--r--src/qml/qml/qqmlengine.cpp63
-rw-r--r--src/qml/qml/qqmlimport.cpp5
-rw-r--r--src/qml/qml/qqmlirloader.cpp2
-rw-r--r--src/qml/qml/qqmlplatform.cpp7
-rw-r--r--src/qml/qml/qqmlpropertycache.cpp20
-rw-r--r--src/qml/qml/qqmlpropertydata_p.h13
-rw-r--r--src/qml/qml/qqmltypewrapper.cpp225
-rw-r--r--src/qml/qml/qqmltypewrapper_p.h86
-rw-r--r--src/qml/qml/qqmlvaluetype_p.h6
-rw-r--r--src/qml/qml/qqmlvaluetypewrapper.cpp39
-rw-r--r--src/qml/qml/qqmlvaluetypewrapper_p.h8
-rw-r--r--src/qml/qml/qqmlvmemetaobject.cpp2
-rw-r--r--src/qml/qml/qqmlxmlhttprequest.cpp2
-rw-r--r--src/qml/qqmlbuiltins_p.h35
-rw-r--r--src/qml/types/qqmlconnections.cpp5
105 files changed, 1848 insertions, 818 deletions
diff --git a/src/qml/CMakeLists.txt b/src/qml/CMakeLists.txt
index cbcdc2f8f9..d52b4c4325 100644
--- a/src/qml/CMakeLists.txt
+++ b/src/qml/CMakeLists.txt
@@ -492,6 +492,7 @@ qt_internal_add_qml_module(Qml
Qt::QmlBuiltinsPrivate
EXTRA_CMAKE_FILES
"${CMAKE_CURRENT_LIST_DIR}/${INSTALL_CMAKE_NAMESPACE}qmldirTemplate.cmake.in"
+ "${CMAKE_CURRENT_LIST_DIR}/${INSTALL_CMAKE_NAMESPACE}qt.conf.in"
"${CMAKE_CURRENT_LIST_DIR}/${INSTALL_CMAKE_NAMESPACE}QmlPluginTemplate.cpp.in"
"${CMAKE_CURRENT_LIST_DIR}/${INSTALL_CMAKE_NAMESPACE}QmlFindQmlscInternal.cmake"
"${CMAKE_CURRENT_LIST_DIR}/${INSTALL_CMAKE_NAMESPACE}QmlDeploySupport.cmake"
@@ -505,6 +506,7 @@ qt_internal_add_qml_module(Qml
POLICIES
QTP0001
QTP0004
+ QTP0005
)
_qt_internal_add_qml_deploy_info_finalizer(Qml)
diff --git a/src/qml/Qt6AndroidQmlMacros.cmake b/src/qml/Qt6AndroidQmlMacros.cmake
index 5f6f01fd76..0a17665d5b 100644
--- a/src/qml/Qt6AndroidQmlMacros.cmake
+++ b/src/qml/Qt6AndroidQmlMacros.cmake
@@ -135,5 +135,13 @@ function(_qt_internal_generate_android_qml_deployment_settings out_var target)
_qt_internal_add_tool_to_android_deployment_settings(${out_var} qmlimportscanner
"qml-importscanner-binary" ${target})
+ # Add qml-dom-binary binary path
+ _qt_internal_add_tool_to_android_deployment_settings(${out_var} qmldom "qml-dom-binary"
+ "${target}")
+
+
+ _qt_internal_add_android_deployment_list_property(${out_var} "qml-files-for-code-generator"
+ ${target} "_qt_qml_files_for_java_generator")
+
set(${out_var} "${${out_var}}" PARENT_SCOPE)
endfunction()
diff --git a/src/qml/Qt6QmlBuildInternals.cmake b/src/qml/Qt6QmlBuildInternals.cmake
index 418b552692..7b181fabde 100644
--- a/src/qml/Qt6QmlBuildInternals.cmake
+++ b/src/qml/Qt6QmlBuildInternals.cmake
@@ -94,7 +94,6 @@ function(qt_internal_add_qml_module target)
)
# TODO: Remove these once all repos have been updated to not use them
set(ignore_option_args
- SKIP_TYPE_REGISTRATION # Now always done
PLUGIN_OPTIONAL # Now the default
GENERATE_QMLTYPES # Now the default
INSTALL_QMLTYPES # Now the default
diff --git a/src/qml/Qt6QmlDeploySupport.cmake b/src/qml/Qt6QmlDeploySupport.cmake
index a230e71409..1b43059cc2 100644
--- a/src/qml/Qt6QmlDeploySupport.cmake
+++ b/src/qml/Qt6QmlDeploySupport.cmake
@@ -159,6 +159,11 @@ function(_qt_internal_deploy_qml_imports_for_target)
# file names, so account for those. There should never be plugin
# libraries for more than one QML module in the directory, so we
# shouldn't need to worry about matching plugins we don't want.
+ #
+ # install_qmldir and install_plugin do not contain $ENV{DESTDIR},
+ # whereas dest_qmldir and dest_plugin do.
+ # The install_ variants are used in file(INSTALL) to avoid double DESTDIR in paths.
+ # Other code should reference the dest_ variants instead.
set(relative_qmldir "${arg_QML_DIR}/${entry_RELATIVEPATH}")
if("${CMAKE_INSTALL_PREFIX}" STREQUAL "")
set(install_qmldir "./${relative_qmldir}")
@@ -180,6 +185,12 @@ function(_qt_internal_deploy_qml_imports_for_target)
file(INSTALL "${entry_PATH}/qmldir" DESTINATION "${install_qmldir}")
+ if(DEFINED __QT_DEPLOY_TARGET_${entry_LINKTARGET}_FILE AND
+ __QT_DEPLOY_TARGET_${entry_LINKTARGET}_TYPE STREQUAL "STATIC_LIBRARY")
+ # If the QML plugin is built statically, skip further deployment.
+ continue()
+ endif()
+
if(__QT_DEPLOY_POST_BUILD)
# We are being invoked as a post-build step. The plugin might
# not exist yet, so we can't even glob for it, let alone copy
diff --git a/src/qml/Qt6QmlMacros.cmake b/src/qml/Qt6QmlMacros.cmake
index 5352f896f6..07848342c8 100644
--- a/src/qml/Qt6QmlMacros.cmake
+++ b/src/qml/Qt6QmlMacros.cmake
@@ -13,6 +13,129 @@ set(__qt_qml_macros_module_base_dir "${CMAKE_CURRENT_LIST_DIR}" CACHE INTERNAL "
include(GNUInstallDirs)
_qt_internal_add_deploy_support("${CMAKE_CURRENT_LIST_DIR}/Qt6QmlDeploySupport.cmake")
+# This function is used to parse DEPENDENCY and IMPORT entries passed to qt_add_qml_module
+# It takes the entry as a mandatory argument, and then sets the following
+# user provided properties in the callers scope
+# OUTPUT_URI <property>: the URI of the module; mandatory argument
+# OUTPUT_VERSION <property>: the requested version of the module; will potentially be empty; mandatory
+# OUTPUT_MODULE_LOCATION <property>: the folder in which the module is located; optional; can be used to extract potential import path
+# OUTPUT_MODULE_TARGET <property>: the target corresponding to the module
+
+function(_qt_internal_parse_qml_module_dependency dependency was_marked_as_target)
+ set(args_option "")
+ set(args_single OUTPUT_URI OUTPUT_VERSION OUTPUT_MODULE_LOCATION OUTPUT_MODULE_TARGET)
+ set(args_multi QML_FILES IMPORT_PATHS)
+
+ cmake_parse_arguments(PARSE_ARGV 2 arg
+ "${args_option}" "${args_single}" "${args_multi}"
+ )
+ if(arg_UNPARSED_ARGUMENTS)
+ message(FATAL_ERROR "Unknown/unexpected arguments: ${arg_UNPARSED_ARGUMENTS}")
+ endif()
+
+ if(NOT arg_OUTPUT_URI)
+ message(FATAL_ERROR "Missing output URI variable")
+ endif()
+ if(NOT arg_OUTPUT_VERSION)
+ message(FATAL_ERROR "Missing output version variable")
+ endif()
+
+ set(dep_version "")
+ set(dep_target_or_uri "")
+ string(FIND "${dependency}" "/" slash_position REVERSE)
+ if(slash_position EQUAL -1)
+ set(dep_target_or_uri "${dependency}")
+ else()
+ string(SUBSTRING "${dependency}" 0 ${slash_position} dep_module)
+ math(EXPR slash_position "${slash_position} + 1")
+ string(SUBSTRING "${dependency}" ${slash_position} -1 dep_version)
+ if(NOT dep_version MATCHES "^([0-9]+(\\.[0-9]+)?|auto)$")
+ message(FATAL_ERROR
+ "Invalid module dependency version number. "
+ "Expected 'VersionMajor', 'VersionMajor.VersionMinor' or 'auto'."
+ )
+ endif()
+ set(dep_target_or_uri "${dep_module}")
+ endif()
+ if("${was_marked_as_target}" AND NOT TARGET ${dep_target_or_uri})
+ message(FATAL_ERROR "Argument ${dep_target_or_uri} is not a target!")
+ endif()
+ if("${was_marked_as_target}")
+ qt6_query_qml_module(${dep_target_or_uri}
+ URI dependency_uri
+ QMLDIR qmldir_location
+ )
+ set(dep_module ${dependency_uri})
+ else()
+ set(dep_module "${dep_target_or_uri}")
+ endif()
+ set(${arg_OUTPUT_URI} ${dep_module} PARENT_SCOPE)
+ set(${arg_OUTPUT_VERSION} ${dep_version} PARENT_SCOPE)
+ if(arg_OUTPUT_MODULE_LOCATION)
+ if(was_marked_as_target)
+ if(NOT qmldir_location)
+ message(FATAL_ERROR "module has no qmldir! Given target was ${dep_target_or_uri}")
+ endif()
+ set(module_location "${qmldir_location}")
+ string(REGEX MATCHALL "\\." matches "${dependency_uri}")
+ list(LENGTH matches go_up_count)
+ # inclusive, which is what we want here: go up once for the qmldir,
+ # and then once per separated component
+ foreach(i RANGE ${go_up_count})
+ get_filename_component(module_location "${module_location}" DIRECTORY)
+ endforeach()
+ set(${arg_OUTPUT_MODULE_LOCATION} "${module_location}" PARENT_SCOPE)
+ else()
+ set(${arg_OUTPUT_MODULE_LOCATION} "NOTFOUND" PARENT_SCOPE)
+ endif()
+ endif()
+ if (arg_OUTPUT_MODULE_TARGET AND was_marked_as_target)
+ set(${arg_OUTPUT_MODULE_TARGET} "${dep_target_or_uri}" PARENT_SCOPE)
+ else()
+ set(${arg_OUTPUT_MODULE_TARGET} "" PARENT_SCOPE)
+ endif()
+endfunction()
+
+function(_qt_internal_write_deferred_builddir_qtconf folder)
+ set(qt_all_qml_output_dirs "")
+ get_directory_property(targets
+ DIRECTORY "${folder}"
+ QT_QML_TARGETS_FOR_DEFERRED_QTCONF_WRITEOUT
+ )
+ set(qtconf_file "${folder}/qt.conf")
+ foreach(target IN LISTS ${targets})
+ get_target_property(dependency_targets "${target}" QT_QML_DEPENDENT_QML_MODULE_TARGETS)
+ if(NOT dependency_targets)
+ continue()
+ endif()
+ foreach(dep_target ${dependency_targets})
+ qt6_query_qml_module(${dep_target}
+ QMLDIR qmldir_location
+ )
+ get_filename_component(module_location "${qmldir_location}" DIRECTORY)
+ get_filename_component(module_import_path "${module_location}" DIRECTORY)
+ list(APPEND qt_all_qml_output_dirs ${module_import_path})
+ endforeach()
+ endforeach()
+ if (NOT qt_all_qml_output_dirs)
+ return()
+ endif()
+
+ list(REMOVE_DUPLICATES qt_all_qml_output_dirs)
+ # lists are just strings containing semicolons;
+ # we replace them with "," to get the right format for qtconf.
+ # However, we need to add quotes to deal with whitespace
+ list(TRANSFORM qt_all_qml_output_dirs APPEND "\"")
+ list(TRANSFORM qt_all_qml_output_dirs PREPEND "\"")
+ list(JOIN qt_all_qml_output_dirs "," qt_all_qml_output_dirs)
+
+ configure_file(
+ ${__qt_qml_macros_module_base_dir}/Qt6qtconf.in ${qtconf_file}
+ @ONLY
+ )
+endfunction()
+
+
function(qt6_add_qml_module target)
set(args_option
STATIC
@@ -30,8 +153,6 @@ function(qt6_add_qml_module target)
NO_CACHEGEN
NO_RESOURCE_TARGET_PATH
NO_IMPORT_SCAN
- # TODO: Remove once all usages have also been removed
- SKIP_TYPE_REGISTRATION
ENABLE_TYPE_COMPILER
# Used to mark modules as having static side effects (i.e. if they install an image provider)
@@ -112,12 +233,6 @@ function(qt6_add_qml_module target)
)
endif()
- if(arg_SKIP_TYPE_REGISTRATION)
- message(AUTHOR_WARNING
- "SKIP_TYPE_REGISTRATION is no longer used and will be ignored."
- )
- endif()
-
# Mandatory arguments
if (NOT arg_URI)
message(FATAL_ERROR
@@ -399,53 +514,93 @@ function(qt6_add_qml_module target)
set(arg_TYPEINFO ${target}.qmltypes)
endif()
+ set(all_qml_import_paths "${arg_IMPORT_PATH}")
+ set(all_dependency_targets)
+
+ set(original_no_show_policy_value "${QT_NO_SHOW_OLD_POLICY_WARNINGS}")
+ # silent by default, we only warn if someone uses TARGET as a URI
+ set(QT_NO_SHOW_OLD_POLICY_WARNINGS TRUE)
+ __qt_internal_setup_policy(QTP0005 "6.8.0"
+ "" # intentionally empty as we silence the warning anyway
+ )
+ qt6_policy(GET QTP0005 allow_targets_for_dependencies_policy)
+ set(QT_NO_SHOW_OLD_POLICY_WARNINGS "${original_no_show_policy_value}")
+ string(COMPARE EQUAL "${allow_targets_for_dependencies_policy}" "NEW" target_is_keyword)
+
+
+ set(target_keyword_was_set FALSE)
foreach(import_set IN ITEMS IMPORTS OPTIONAL_IMPORTS DEFAULT_IMPORTS)
foreach(import IN LISTS arg_${import_set})
- string(FIND ${import} "/" slash_position REVERSE)
- if (slash_position EQUAL -1)
+ if (import STREQUAL "TARGET")
+ if (target_is_keyword)
+ set(target_keyword_was_set TRUE)
+ continue()
+ else()
+ message(AUTHOR_WARNING "TARGET is treated as a URI because QTP0005 is set to OLD. This is deprecated behavior. Check https://doc.qt.io/qt-6/qt-cmake-policy-qtp0005.html for policy details.")
+ set(target_keyword_was_set FALSE)
+ endif()
+ endif()
+ _qt_internal_parse_qml_module_dependency(${import} ${target_keyword_was_set}
+ OUTPUT_URI import_uri
+ OUTPUT_VERSION import_version
+ OUTPUT_MODULE_LOCATION module_location
+ OUTPUT_MODULE_TARGET dependency_target
+ )
+ get_filename_component(module_import_path "${module_location}" DIRECTORY)
+ list(APPEND all_qml_import_paths "${module_import_path}")
+
+ if (NOT "${import_version}" STREQUAL "")
set_property(TARGET ${target} APPEND PROPERTY
- QT_QML_MODULE_${import_set} "${import}"
+ QT_QML_MODULE_${import_set} "${import_uri} ${import_version}"
)
else()
- string(SUBSTRING ${import} 0 ${slash_position} import_module)
- math(EXPR slash_position "${slash_position} + 1")
- string(SUBSTRING ${import} ${slash_position} -1 import_version)
- if (import_version MATCHES "^([0-9]+(\\.[0-9]+)?|auto)$")
- set_property(TARGET ${target} APPEND PROPERTY
- QT_QML_MODULE_${import_set} "${import_module} ${import_version}"
- )
- else()
- message(FATAL_ERROR
- "Invalid module ${import} version number. "
- "Expected 'VersionMajor', 'VersionMajor.VersionMinor' or 'auto'."
- )
- endif()
+ set_property(TARGET ${target} APPEND PROPERTY
+ QT_QML_MODULE_${import_set} "${import_uri}"
+ )
+ endif()
+ if(TARGET "${dependency_target}")
+ list(APPEND all_dependency_targets "${dependency_target}")
endif()
+ set(target_keyword_was_set FALSE)
endforeach()
endforeach()
foreach(dependency IN LISTS arg_DEPENDENCIES)
- string(FIND ${dependency} "/" slash_position REVERSE)
- if (slash_position EQUAL -1)
+
+ if (dependency STREQUAL "TARGET")
+ if (target_is_keyword)
+ set(target_keyword_was_set TRUE)
+ continue()
+ else()
+ message(AUTHOR_WARNING "TARGET is treated as a URI because QTP0005 is set to OLD. This is deprecated behavior. Check https://doc.qt.io/qt-6/qt-cmake-policy-qtp0005.html for policy details.")
+ set(target_keyword_was_set FALSE)
+ endif()
+ endif()
+ _qt_internal_parse_qml_module_dependency(${dependency} "${target_keyword_was_set}"
+ OUTPUT_URI dep_uri
+ OUTPUT_VERSION dep_version
+ OUTPUT_MODULE_LOCATION module_location
+ OUTPUT_MODULE_TARGET dependency_target
+ )
+ get_filename_component(module_import_path "${module_location}" DIRECTORY)
+ list(APPEND all_qml_import_paths "${module_import_path}")
+ if (NOT "${dep_version}" STREQUAL "")
set_property(TARGET ${target} APPEND PROPERTY
- QT_QML_MODULE_DEPENDENCIES "${dependency}"
+ QT_QML_MODULE_DEPENDENCIES "${dep_uri} ${dep_version}"
)
else()
- string(SUBSTRING ${dependency} 0 ${slash_position} dep_module_uri)
- math(EXPR slash_position "${slash_position} + 1")
- string(SUBSTRING ${dependency} ${slash_position} -1 dep_version)
- if (dep_version MATCHES "^([0-9]+(\\.[0-9]+)?|auto)$")
- set_property(TARGET ${target} APPEND PROPERTY
- QT_QML_MODULE_DEPENDENCIES "${dep_module_uri} ${dep_version}"
- )
- else()
- message(FATAL_ERROR
- "Invalid module dependency version number. "
- "Expected 'VersionMajor', 'VersionMajor.VersionMinor' or 'auto'."
- )
- endif()
+ set_property(TARGET ${target} APPEND PROPERTY
+ QT_QML_MODULE_DEPENDENCIES "${dep_uri}"
+ )
+ endif()
+ set(target_keyword_was_set FALSE)
+ if(TARGET "${dependency_target}")
+ list(APPEND all_dependency_targets "${dependency_target}")
endif()
endforeach()
+ ### TODO: add support for transitive dependencies, too
+ list(REMOVE_DUPLICATES all_dependency_targets)
+ set_property(TARGET ${target} PROPERTY QT_QML_DEPENDENT_QML_MODULE_TARGETS "${all_dependency_targets}")
_qt_internal_collect_qml_module_dependencies(${target})
if(arg_AUTO_RESOURCE_PREFIX)
@@ -491,6 +646,8 @@ Check https://doc.qt.io/qt-6/qt-cmake-policy-qtp0001.html for policy details."
endif()
endif()
+ list(REMOVE_DUPLICATES all_qml_import_paths)
+
set_target_properties(${target} PROPERTIES
QT_QML_MODULE_NO_LINT "${arg_NO_LINT}"
QT_QML_MODULE_NO_CACHEGEN "${arg_NO_CACHEGEN}"
@@ -520,7 +677,7 @@ Check https://doc.qt.io/qt-6/qt-cmake-policy-qtp0001.html for policy details."
QT_QML_MODULE_PAST_MAJOR_VERSIONS "${arg_PAST_MAJOR_VERSIONS}"
# TODO: Check how this is used by qt6_android_generate_deployment_settings()
- QT_QML_IMPORT_PATH "${arg_IMPORT_PATH}"
+ QT_QML_IMPORT_PATH "${all_qml_import_paths}"
)
if(arg_TYPEINFO)
@@ -767,6 +924,88 @@ Check https://doc.qt.io/qt-6/qt-cmake-policy-qtp0001.html for policy details."
endif()
endif()
endif()
+
+ if((backing_target_type STREQUAL "EXECUTABLE") AND (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.19.0"))
+ set_property(
+ DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ APPEND
+ PROPERTY QT_QML_TARGETS_FOR_DEFERRED_QTCONF_WRITEOUT
+ ${target}
+ )
+ get_directory_property(is_qtconf_writeout_scheduled DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} QT_QML_BUILDDIR_QTCONF_DEFERRED)
+ if (NOT is_qtconf_writeout_scheduled)
+ set_property(
+ DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ PROPERTY QT_QML_BUILDDIR_QTCONF_DEFERRED TRUE
+ )
+
+ cmake_language(EVAL CODE "
+ cmake_language(DEFER DIRECTORY [[${PROJECT_SOURCE_DIR}]]
+ CALL _qt_internal_write_deferred_builddir_qtconf [[${CMAKE_CURRENT_BINARY_DIR}]])
+ ")
+ endif()
+ endif()
+
+ if("${CMAKE_VERSION}" VERSION_GREATER_EQUAL "3.19.0" AND NOT CMAKE_GENERATOR STREQUAL "Xcode")
+ set(id qmlaotstats_aggregation)
+ cmake_language(DEFER DIRECTORY ${PROJECT_BINARY_DIR} GET_CALL ${id} call)
+
+ if("${call}" STREQUAL "")
+ cmake_language(EVAL CODE "cmake_language(DEFER DIRECTORY ${PROJECT_BINARY_DIR} "
+ "ID ${id} CALL _qt_internal_deferred_aggregate_aotstats_files ${target})")
+ endif()
+ else()
+ if(NOT TARGET all_aotstats)
+ if(CMAKE_GENERATOR STREQUAL "Xcode") #TODO: QTBUG-125995
+ add_custom_target(
+ all_aotstats
+ ${CMAKE_COMMAND} -E echo "aotstats is not supported on Xcode"
+ )
+ else()
+ add_custom_target(
+ all_aotstats
+ ${CMAKE_COMMAND} -E echo "aotstats is not supported on CMake versions < 3.19"
+ )
+ endif()
+ endif()
+ endif()
+endfunction()
+
+function(_qt_internal_deferred_aggregate_aotstats_files target)
+ get_property(module_aotstats_files GLOBAL PROPERTY "module_aotstats_files")
+ list(JOIN module_aotstats_files "\n" lines)
+ set(aotstats_list_file "${PROJECT_BINARY_DIR}/.rcc/qmlcache/all_aotstats.aotstatslist")
+ file(WRITE ${aotstats_list_file} ${lines})
+
+ set(all_aotstats_file ${PROJECT_BINARY_DIR}/.rcc/qmlcache/all_aotstats.aotstats)
+ set(formatted_stats_file ${PROJECT_BINARY_DIR}/.rcc/qmlcache/all_aotstats.txt)
+
+ _qt_internal_get_tool_wrapper_script_path(tool_wrapper)
+ add_custom_command(
+ OUTPUT
+ ${all_aotstats_file}
+ ${formatted_stats_file}
+ DEPENDS ${module_aotstats_files}
+ COMMAND
+ ${tool_wrapper}
+ $<TARGET_FILE:Qt6::qmlaotstats>
+ aggregate
+ ${aotstats_list_file}
+ ${all_aotstats_file}
+ COMMAND
+ ${tool_wrapper}
+ $<TARGET_FILE:Qt6::qmlaotstats>
+ format
+ ${all_aotstats_file}
+ ${formatted_stats_file}
+ )
+
+ if(NOT TARGET all_aotstats)
+ add_custom_target(all_aotstats
+ DEPENDS ${formatted_stats_file}
+ COMMAND ${CMAKE_COMMAND} -E cat ${formatted_stats_file}
+ )
+ endif()
endfunction()
function(_qt_internal_write_deferred_qmlls_ini_file)
@@ -2403,6 +2642,8 @@ function(qt6_target_qml_sources target)
"$<${have_direct_calls}:--direct-calls>"
"$<${have_arguments}:${arguments}>"
${qrc_resource_args}
+ "--dump-aot-stats"
+ "--module-id=${arg_URI}(${target})"
)
# For direct evaluation in if() below
@@ -2613,6 +2854,17 @@ function(qt6_target_qml_sources target)
set_property(TARGET ${target} APPEND_STRING PROPERTY
_qt_internal_qmldir_content "${qmldir_file_contents}"
)
+
+ if(ANDROID AND QT_ANDROID_GENERATE_JAVA_QML_COMPONENTS)
+ get_source_file_property(qml_file_generate_java_classes ${qml_file_src}
+ QT_QML_GENERATE_JAVA_CLASS
+ )
+ if(qml_file_generate_java_classes)
+ get_target_property(qml_module_uri ${target} QT_QML_MODULE_URI)
+ set_property(TARGET ${target} APPEND PROPERTY
+ _qt_qml_files_for_java_generator "${qml_module_uri}.${qml_file_typename}")
+ endif()
+ endif()
endif()
endif()
@@ -2649,9 +2901,17 @@ function(qt6_target_qml_sources target)
set(qmlcachegen_cmd "${qmlcachegen}")
endif()
+ set(aotstats_file "")
+ if("${qml_file_src}" MATCHES ".+\\.qml")
+ set(aotstats_file "${compiled_file}.aotstats")
+ list(APPEND aotstats_files ${aotstats_file})
+ endif()
+
_qt_internal_get_tool_wrapper_script_path(tool_wrapper)
add_custom_command(
- OUTPUT ${compiled_file}
+ OUTPUT
+ ${compiled_file}
+ ${aotstats_file}
COMMAND ${CMAKE_COMMAND} -E make_directory ${out_dir}
COMMAND
${tool_wrapper}
@@ -2695,6 +2955,29 @@ function(qt6_target_qml_sources target)
endif()
endforeach()
+ if(NOT "${arg_URI}" STREQUAL "")
+ list(JOIN aotstats_files "\n" aotstats_files_lines)
+ set(module_aotstats_list_file "${CMAKE_CURRENT_BINARY_DIR}/.rcc/qmlcache/module_${arg_URI}.aotstatslist")
+ file(WRITE ${module_aotstats_list_file} ${aotstats_files_lines})
+
+ # Aggregate qml file aotstats into module-level aotstats
+ _qt_internal_get_tool_wrapper_script_path(tool_wrapper)
+ set(output "${CMAKE_CURRENT_BINARY_DIR}/.rcc/qmlcache/module_${arg_URI}.aotstats")
+ add_custom_command(
+ OUTPUT ${output}
+ DEPENDS ${aotstats_files}
+ COMMAND
+ ${tool_wrapper}
+ $<TARGET_FILE:Qt6::qmlaotstats>
+ aggregate
+ ${module_aotstats_list_file}
+ ${output}
+ )
+
+ # Collect module-level aotstats files for later aggregation at the project level
+ set_property(GLOBAL APPEND PROPERTY "module_aotstats_files" ${output})
+ endif()
+
if(ANDROID)
_qt_internal_collect_qml_root_paths("${target}" ${arg_QML_FILES})
endif()
@@ -3825,9 +4108,30 @@ endif()")
# imports deployed to the bundle anyway, the build RPATHs will allow
# the regular libraries, frameworks and non-QML plugins to still be
# found, even if they are outside the app bundle.
+
+ # Support Xcode, which places the application build dir into a configuration specific
+ # subdirectory. Override both the deploy prefix and install prefix, because we
+ # differentiate them in the qml installation implementation due to ENV{DESTDIR}
+ # handling.
+ set(deploy_path_suffix "")
+ get_cmake_property(is_multi_config GENERATOR_IS_MULTI_CONFIG)
+ if(is_multi_config)
+ set(deploy_path_suffix "/$<CONFIG>")
+ endif()
+
+ set(target_binary_dir_with_config_prefix
+ "$<TARGET_PROPERTY:${arg_TARGET},BINARY_DIR>${deploy_path_suffix}")
+
+ set(post_build_install_prefix
+ "CMAKE_INSTALL_PREFIX=${target_binary_dir_with_config_prefix}")
+
+ set(post_build_deploy_prefix
+ "QT_DEPLOY_PREFIX=${target_binary_dir_with_config_prefix}")
+
add_custom_command(TARGET ${arg_TARGET} POST_BUILD
COMMAND ${CMAKE_COMMAND}
- -D "QT_DEPLOY_PREFIX=$<TARGET_PROPERTY:${arg_TARGET},BINARY_DIR>"
+ -D "${post_build_install_prefix}"
+ -D "${post_build_deploy_prefix}"
-D "__QT_DEPLOY_IMPL_DIR=${deploy_impl_dir}"
-D "__QT_DEPLOY_POST_BUILD=TRUE"
-P "${post_build_deploy_script}"
diff --git a/src/qml/Qt6qt.conf.in b/src/qml/Qt6qt.conf.in
new file mode 100644
index 0000000000..10a7dcab50
--- /dev/null
+++ b/src/qml/Qt6qt.conf.in
@@ -0,0 +1,5 @@
+[Paths]
+QmlImports = @qt_all_qml_output_dirs@
+
+[Config]
+MergeQtConf = true
diff --git a/src/qml/common/qv4alloca_p.h b/src/qml/common/qv4alloca_p.h
index c1d1e6e87d..51c99192d3 100644
--- a/src/qml/common/qv4alloca_p.h
+++ b/src/qml/common/qv4alloca_p.h
@@ -17,16 +17,17 @@
#include <QtCore/private/qglobal_p.h>
-#if QT_CONFIG(alloca_h)
+#include <stdlib.h>
+#if __has_include(<alloca.h>)
# include <alloca.h>
-#elif QT_CONFIG(alloca_malloc_h)
+#endif
+#if __has_include(<malloc.h>)
# include <malloc.h>
+#endif
+
+#ifdef Q_CC_MSVC
// This does not matter unless compiling in strict standard mode.
-# ifdef Q_CC_MSVC
-# define alloca _alloca
-# endif
-#else
-# include <stdlib.h>
+# define alloca _alloca
#endif
// Define Q_ALLOCA_VAR macro to be used instead of #ifdeffing
@@ -37,7 +38,7 @@
Q_ALLOCA_DECLARE(type, name); \
Q_ALLOCA_ASSIGN(type, name, size)
-#if QT_CONFIG(alloca)
+#ifdef alloca
#define Q_ALLOCA_DECLARE(type, name) \
type *name = 0
@@ -46,27 +47,16 @@
name = static_cast<type*>(alloca(size))
#else
-QT_BEGIN_NAMESPACE
-class Qt_AllocaWrapper
-{
-public:
- Qt_AllocaWrapper() { m_data = 0; }
- ~Qt_AllocaWrapper() { free(m_data); }
- void *data() { return m_data; }
- void allocate(int size) { m_data = malloc(size); memset(m_data, 0, size); }
-private:
- void *m_data;
-};
-QT_END_NAMESPACE
+# include <memory>
#define Q_ALLOCA_DECLARE(type, name) \
- Qt_AllocaWrapper _qt_alloca_##name; \
+ std::unique_ptr<char[]> _qt_alloca_##name; \
type *name = nullptr
#define Q_ALLOCA_ASSIGN(type, name, size) \
do { \
- _qt_alloca_##name.allocate(size); \
- name = static_cast<type*>(_qt_alloca_##name.data()); \
+ _qt_alloca_##name.reset(new char[size]); \
+ name = reinterpret_cast<type*>(_qt_alloca_##name.get()); \
} while (false)
#endif
diff --git a/src/qml/common/qv4compileddata_p.h b/src/qml/common/qv4compileddata_p.h
index 79df230872..c21fc19fa9 100644
--- a/src/qml/common/qv4compileddata_p.h
+++ b/src/qml/common/qv4compileddata_p.h
@@ -1227,6 +1227,7 @@ struct Unit
NativeMethodsAcceptThisObject = 0x800,
ValueTypesCopied = 0x1000,
ValueTypesAddressable = 0x2000,
+ ValueTypesAssertable = 0x4000,
};
quint32_le flags;
quint32_le stringTableSize;
@@ -1706,6 +1707,11 @@ public:
return unitData()->flags & CompiledData::Unit::ValueTypesAddressable;
}
+ bool valueTypesAreAssertable() const
+ {
+ return unitData()->flags & CompiledData::Unit::ValueTypesAssertable;
+ }
+
bool componentsAreBound() const
{
return unitData()->flags & CompiledData::Unit::ComponentsBound;
diff --git a/src/qml/common/qv4staticvalue_p.h b/src/qml/common/qv4staticvalue_p.h
index e887cdc674..9b4f582c00 100644
--- a/src/qml/common/qv4staticvalue_p.h
+++ b/src/qml/common/qv4staticvalue_p.h
@@ -366,10 +366,10 @@ struct StaticValue
QV4_NEARLY_ALWAYS_INLINE void setDouble(double d) {
if (qt_is_nan(d)) {
// We cannot store just any NaN. It has to be a NaN with only the quiet bit
- // set in the upper bits of the mantissa and the sign bit off.
+ // set in the upper bits of the mantissa and the sign bit either on or off.
// qt_qnan() happens to produce such a thing via std::numeric_limits,
// but this is actually not guaranteed. Therefore, we make our own.
- _val = (quint64(QuickType::NaN) << Tag_Shift);
+ _val = (quint64(std::signbit(d) ? QuickType::MinusNaN : QuickType::NaN) << Tag_Shift);
Q_ASSERT(isNaN());
} else {
memcpy(&_val, &d, 8);
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp
index a81f8fb1d8..72111b3138 100644
--- a/src/qml/compiler/qqmlirbuilder.cpp
+++ b/src/qml/compiler/qqmlirbuilder.cpp
@@ -861,6 +861,15 @@ private:
return true;
}
+ if (value == "Inassertable"_L1) {
+ setFlag(Pragma::Assertable, false);
+ return true;
+ }
+ if (value == "Assertable"_L1) {
+ setFlag(Pragma::Assertable, true);
+ return true;
+ }
+
return false;
});
}
@@ -1718,6 +1727,10 @@ void QmlUnitGenerator::generate(Document &output, const QV4::CompiledData::Depen
.testFlag(Pragma::Addressable)) {
createdUnit->flags |= Unit::ValueTypesAddressable;
}
+ if (Pragma::ValueTypeBehaviorValues(p->valueTypeBehavior)
+ .testFlag(Pragma::Assertable)) {
+ createdUnit->flags |= Unit::ValueTypesAssertable;
+ }
break;
case Pragma::Translator:
if (createdUnit->translationTableSize)
diff --git a/src/qml/compiler/qqmlirbuilder_p.h b/src/qml/compiler/qqmlirbuilder_p.h
index 546d1fac58..ffd3ad72f7 100644
--- a/src/qml/compiler/qqmlirbuilder_p.h
+++ b/src/qml/compiler/qqmlirbuilder_p.h
@@ -443,6 +443,7 @@ struct Q_QML_COMPILER_EXPORT Pragma
{
Copy = 0x1,
Addressable = 0x2,
+ Assertable = 0x4,
};
Q_DECLARE_FLAGS(ValueTypeBehaviorValues, ValueTypeBehaviorValue);
diff --git a/src/qml/configure.cmake b/src/qml/configure.cmake
index d1ff90bd54..1bc647ff29 100644
--- a/src/qml/configure.cmake
+++ b/src/qml/configure.cmake
@@ -14,7 +14,7 @@ qt_find_package(LTTngUST PROVIDED_TARGETS LTTng::UST MODULE_NAME qml QMAKE_LIB l
qt_find_package(Python REQUIRED)
if(Python_Interpreter_FOUND)
# Need to make it globally available to the project
- set(QT_INTERNAL_DECLARATIVE_PYTHON "${Python_EXECUTABLE}" CACHE STRING "")
+ set(QT_INTERNAL_DECLARATIVE_PYTHON "${Python_EXECUTABLE}" CACHE STRING "" FORCE)
endif()
#### Tests
diff --git a/src/qml/doc/src/cmake/cmake-properties.qdoc b/src/qml/doc/src/cmake/cmake-properties.qdoc
index 297a094582..a2ca59efc8 100644
--- a/src/qml/doc/src/cmake/cmake-properties.qdoc
+++ b/src/qml/doc/src/cmake/cmake-properties.qdoc
@@ -206,3 +206,24 @@ C++ during qmltc compilation.
\sa{qmltc-cmake}
*/
+
+/*!
+\page cmake-source-file-property-qt-qml-generate-java-class.html
+\ingroup cmake-source-file-properties-qtqml
+\ingroup cmake-android-build-properties
+
+\title QT_QML_GENERATE_JAVA_CLASS
+
+\summary {Marks a QML file for Java code generation.}
+
+\cmakepropertysince 6.8
+When using QML as a \l {Android: View} in Android via \l QtQuickView, you can choose
+the QML components to make available as generated Java classes usable from Android code.
+To mark a \c {.qml} file for code generation, set its \c QT_QML_GENERATE_JAVA_CLASS
+source property to \c TRUE. The source property must be set before
+\l {qt_add_qml_module}{creating} the module. The file should start with an uppercase
+letter and define a QML component. This property is valid only if
+\l QT_ANDROID_GENERATE_JAVA_QML_COMPONENTS is defined.
+
+\sa {Naming Custom QML Object Types}
+*/
diff --git a/src/qml/doc/src/cmake/policy/qtp0005.qdoc b/src/qml/doc/src/cmake/policy/qtp0005.qdoc
new file mode 100644
index 0000000000..25d5175789
--- /dev/null
+++ b/src/qml/doc/src/cmake/policy/qtp0005.qdoc
@@ -0,0 +1,42 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qt-cmake-policy-qtp0005.html
+\ingroup qt-cmake-policies
+
+\title QTP0005
+\keyword qt_cmake_policy_qtp0005
+
+\summary {qt_add_qml_module's DEPENDENCIES argument accepts targets}
+
+This policy was introduced in Qt 6.8. It allows passing targets to
+\l{qt_add_qml_module}{qt_add_qml_module()} \c DEPENDENCIES, \c IMPORTS, \c
+OPTIONAL_IMPORTS and \c DEFAULT_IMPORTS.
+
+Enabling this policy means that the arguments which are passed to the key words
+can be prefixed with TARGET, and are then treated as a target name.
+
+The \c OLD behavior of this policy is that the "TARGET name" is treated as two
+URIs, "TARGET" and "name".
+
+The \c NEW behavior of this policy is that \c TARGET is considered a keyword,
+and the URI is extracted from the target which follows next. It is a hard error
+if the name following \c TARGET does not name a target, or if that target does
+not correspond to a QML module.
+
+In both the \c NEW and the \c OLD behavior it is possible to specify a module
+version by appending a slash and the version. See
+\l{Declaring module dependencies} for more details.
+
+Qt 6.8 issues warnings if you pass a URI to \c DEPENDENCIES which coincides
+with a target name.
+Use the \l qt_policy command to suppress the warning by explicitly setting
+the policy to \c OLD or \c NEW.
+
+\qtpolicydeprecatedbehavior
+
+\sa qt_policy, {qt6_standard_project_setup}{qt_standard_project_setup()},
+ qt_cmake_policies, qt_add_qml_module
+
+*/
diff --git a/src/qml/doc/src/cmake/qt_add_qml_module.qdoc b/src/qml/doc/src/cmake/qt_add_qml_module.qdoc
index 4ca7635b9c..63f9707d4d 100644
--- a/src/qml/doc/src/cmake/qt_add_qml_module.qdoc
+++ b/src/qml/doc/src/cmake/qt_add_qml_module.qdoc
@@ -578,6 +578,9 @@ These additional targets are generated internally by \c{qt_add_qml_module()}
and are referenced by the backing target's linking requirements as part of
ensuring that resources are set up and loaded correctly.
+\note Since Qt 6.8, it is possible to pass a target name to IMPORTS and
+DEPENDENCIES. See \l{QTP0005} for more details.
+
\target PLUGIN_TARGET
\section2 Targets and plugin targets
diff --git a/src/qml/doc/src/external-resources.qdoc b/src/qml/doc/src/external-resources.qdoc
index 091df193a5..6ea7e4a005 100644
--- a/src/qml/doc/src/external-resources.qdoc
+++ b/src/qml/doc/src/external-resources.qdoc
@@ -69,3 +69,12 @@
\externalpage https://developer.android.com/reference/java/lang/ClassCastException
\title Android: ClassCastException
*/
+/*!
+ \externalpage https://developer.android.com/topic/libraries/view-binding
+ \title Android: View binding
+*/
+/*!
+ \externalpage https://developer.android.com/reference/android/Manifest.permission#SYSTEM_ALERT_WINDOW
+ \title Android: SYSTEM_ALERT_WINDOW
+*/
+
diff --git a/src/qml/doc/src/javascript/qmlglobalobject.qdoc b/src/qml/doc/src/javascript/qmlglobalobject.qdoc
index 15b9996ff3..1bd03fad54 100644
--- a/src/qml/doc/src/javascript/qmlglobalobject.qdoc
+++ b/src/qml/doc/src/javascript/qmlglobalobject.qdoc
@@ -13,8 +13,8 @@ additional imports:
\list
\li The \l{QmlGlobalQtObject}{Qt object}: A QML object that offers helper methods
and properties specific to the QML environment.
-\li \l {Qt::}{qsTr()}, \l {Qt::}{qsTranslate()}, \l {Qt::}{qsTrId()}, \l {Qt::}{qsTrNoOp()},
- \l {Qt::}{qsTranslateNoOp()}, \l {Qt::}{qsTrIdNoOp()} functions:
+\li \l {Qt::}{qsTr()}, \l {Qt::}{qsTranslate()}, \l {Qt::}{qsTrId()}, \l {Qt::}{QT_TR_NOOP()()},
+ \l {Qt::}{QT_TRANSLATE_NOOP()}, \l {Qt::}{QT_TRID_NOOP()} functions:
QML functions that let you translate \l{Mark Strings for Translation}
{strings} and \l{Mark Translatable Data Text Strings}{string literals} in the
QML environment.
diff --git a/src/qml/doc/src/qmllanguageref/documents/structure.qdoc b/src/qml/doc/src/qmllanguageref/documents/structure.qdoc
index 5a43ae2028..72a6e08407 100644
--- a/src/qml/doc/src/qmllanguageref/documents/structure.qdoc
+++ b/src/qml/doc/src/qmllanguageref/documents/structure.qdoc
@@ -215,12 +215,6 @@ QtObject {
}
\endqml
-If the type does not match, casting returns \c undefined. \c instanceof
-only checks for inheritance, not for all possible type coercions. So, for
-example, a \l{QRect} is not a \c rect value type since \c rect is \l{QRectF}
-in C++, and therefore not related by inheritance. With \c as you can cast
-to any type compatible via coercion.
-
Since \c rect in the above example is now a type name, it will shadow any
properties called \c{rect}.
@@ -231,6 +225,25 @@ able to. You can use \l{qmllint Reference}{qmllint} to find such occurrences.
There is also a \c{Inaddressable} value you can use to explicitly specify the
default behavior.
+Another attribute to the \c{ValueTypeBehavior} pragma is \c{Assertable},
+introduced in Qt 6.8. Due to a mistake in Qt 6.6 and 6.7 the \c{a as rect} above
+not only checks whether \c{a} is a \c{rect} but also constructs a \c{rect} if
+\c{a} is of a compatible type. This is obviously not what a type assertion
+should do. Specifying \c{Assertable} prevents this behavior and restricts type
+assertions for value types to only check for the type. You should always specify
+it if you are going to use value types with \c{as}. In any case, if the
+type assertion for a value type fails, the result is \c{undefined}.
+
+\c{instanceof} does not have this problem since it only checks for inheritance,
+not for all possible type coercions.
+
+\note Using \c{as} with the \c{int} and \c{double} types is not advisable since by
+JavaScript rules, the result of any calculation is a floating point number, even
+if it happens to hold the same value as its integer equivalent. Conversely, any
+integer constant you declare in JavaScript is not a double by QML's type mapping
+rules. Furthermore, \c{int} and \c{double} are reserved words. You can only
+address these types via type namespaces.
+
Value types and sequences are generally treated as references. This means, if
you retrieve a value type instance from a property into a local value, and then
change the local value, the original property is also changed. Furthermore,
diff --git a/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc b/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc
index 0fb7d5f039..2b1803042e 100644
--- a/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc
+++ b/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc
@@ -868,7 +868,7 @@ provided by the client:
SquareButton {
onDeactivated: console.log("Deactivated!")
onActivated: (xPosition, yPosition) => {
- console.log(`Activated at {xPosition}, ${yPosition}`)
+ console.log(`Activated at ${xPosition}, ${yPosition}`)
}
}
\endqml
diff --git a/src/qml/doc/src/qmlsingletons.qdoc b/src/qml/doc/src/qmlsingletons.qdoc
index ad441eca85..e5c95d4178 100644
--- a/src/qml/doc/src/qmlsingletons.qdoc
+++ b/src/qml/doc/src/qmlsingletons.qdoc
@@ -20,7 +20,7 @@ the singleton in a QML file, or register it from C++.
\section2 Defining singletons in QML
To define a singleton in QML, you first have to add
\code
-pragma singleton
+pragma Singleton
\endcode
to the top of your file.
There's one more step: You will need to add an entry to the QML module's
diff --git a/src/qml/doc/src/tools/qtqml-tooling-svgtoqml.qdoc b/src/qml/doc/src/tools/qtqml-tooling-svgtoqml.qdoc
index 28d2683ff9..836acc3f6a 100644
--- a/src/qml/doc/src/tools/qtqml-tooling-svgtoqml.qdoc
+++ b/src/qml/doc/src/tools/qtqml-tooling-svgtoqml.qdoc
@@ -1,4 +1,4 @@
-// Copyright (C) 2023 The Qt Company Ltd.
+// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
@@ -7,11 +7,86 @@
\brief The SVG to QML converter tool
\ingroup qtqml-tooling
-svgtoqml is a command line tool shipped with Qt that converts an SVG document
+\c svgtoqml is a command line tool shipped with Qt that converts an SVG document
to a QML file. This QML file can then be used as a component in Qt Quick
-applications.
+applications. The \l{Weather Forecast Example} includes multiple QML files that have been generated
+using this tool.
-\note svgtoqml is currently in a Tech Preview stage. It only supports
-a limited subset of what the QtSvg module supports.
+\section1 Overview
+The \c svgtoqml will convert an SVG file to a QML file which uses Qt Quick primitives. Since
+Qt Quick supports scalable vector graphics, the resulting item will be smoothly transformable as far
+as this is possible. As a baseline, the tool supports most of the static features of the SVG Tiny 1.2
+profile. Certain additional features are supported, determined on a case-by-case basis. Interactive
+features and animations are not supported.
+
+\section1 Usage
+The basic usage of \c svgtoqml is to provide an input file and an output file:
+\c{svgtoqml input.svg output.qml}. This will read the \c{input.svg} file and convert it into the
+corresponding Qt Quick scene in \c{output.qml}, which can then be used as part of a Qt Quick
+application.
+
+In addition, it supports the following options:
+
+\table
+\header
+ \li Option
+ \li Description
+\row
+ \li --copyright-statement <string>
+ \li Adds <string> as a comment at the beginning of the generated file.
+\row
+ \li --curve-renderer
+ \li Enables the curve renderer backend for \l{Qt Quick Shapes}. This enables smooth, antialiased
+ shapes in the scene without multi-sampling, but at some extra cost.
+\row
+ \li --optimize-paths
+ \li Enables optimization of paths before committing them to the QML file, potentially making
+ them faster to load and render later.
+\row
+ \li --outline-stroke-mode
+ \li Stroke the outline (contour) of the filled shape instead of the original path.
+\row
+ \li -t, --type-name <string>
+ \li In place of \l{Shape}, the output will use the type name <string> instead. This is
+ enables using a custom item to override the default behavior of \l{Shape} items.
+\row
+ \li -v, --view
+ \li Display a preview of the Qt Quick item as it will be generated.
+\endtable
+
+\section1 Comparison to other options
+There are multiple options for including SVG content in Qt Quick. The following will give an
+overview of where \c svgtoqml fits into the story.
+
+\section2 Comparison to Qt Svg
+\l{Qt Svg} is a module which provides a parser and software renderer for SVG files. In addition, it
+includes an image loader plugin, so that SVG files can be loaded directly by the \l{Image} element
+in Qt Quick. The SVG will then be rasterized and cached at a specified size and redrawing it will
+be quite cheap. But zooming into the image without pixelation will involve reloading it at a
+different size, which in turn can be expensive.
+
+\c svgtoqml (and the \l{VectorImage} component) are alternative ways of rendering the same content.
+Once loaded into Qt Quick, transforms can be changed while retaining the geometry data needed to
+render the scene in GPU memory. Thus, the vector image can be redrawn at different scales with very
+little overhead.
+
+If the image size will not change during the life time of the application, however, loading the
+SVG as an \l{Image} will be more efficient. In this case, if the SVG is always rendered at a
+small subset of possible sizes, consider pre-rasterizing it to an image format which is more
+efficient to load, such as \c PNG.
+
+\section2 Comparison to VectorImage
+The \l{VectorImage} component provides the same basic functionality as \c svgtoqml, but instead of
+pregenerating the Qt Quick scene as a QML file, it creates the scene at runtime. This allows loading
+SVG files that are not provided at build time and thus allows for more flexibility. Pregenerating
+the scenes with \c svgtoqml allows optimizing the scene before it is loaded. Thus, for files that
+are available at build time, \c svgtoqml is the preferred option.
+
+\section2 Comparison to PathSvg
+The \l{PathSvg} component is part of the \l{Qt Quick Shapes} module. It provides a way to define
+paths with the syntax used by SVG, where the control points of a path are specified as a string. It
+does not support loading SVG files, so it is not a direct alternative to \c svgtoqml. If a complex
+SVG contains a specific shape needed by the application, then copying this path description into
+\l{PathSvg} may be more convenient than generating the full file.
*/
diff --git a/src/qml/jsapi/qjsprimitivevalue.h b/src/qml/jsapi/qjsprimitivevalue.h
index 4ba3fd7dc3..3551eca358 100644
--- a/src/qml/jsapi/qjsprimitivevalue.h
+++ b/src/qml/jsapi/qjsprimitivevalue.h
@@ -355,11 +355,16 @@ public:
return leftInt % rightInt;
Q_FALLTHROUGH();
}
- default:
+ case Undefined:
+ case Null:
+ case Double:
+ case String:
break;
}
Q_FALLTHROUGH();
- default:
+ case Undefined:
+ case Double:
+ case String:
break;
}
@@ -706,9 +711,18 @@ private:
{
switch (type()) {
case Undefined: return true;
+ case Null: return false;
+ case Boolean: return false;
+ case Integer: return false;
case Double: return std::isnan(asDouble());
- default: return false;
+ case String: return false;
}
+ // GCC 8.x does not treat __builtin_unreachable() as constexpr
+ #if !defined(Q_CC_GNU_ONLY) || (Q_CC_GNU >= 900)
+ Q_UNREACHABLE_RETURN(false);
+ #else
+ return false;
+ #endif
}
struct QJSPrimitiveValuePrivate
diff --git a/src/qml/jsruntime/qv4arraybuffer.cpp b/src/qml/jsruntime/qv4arraybuffer.cpp
index f2be552cf8..a49bd32d66 100644
--- a/src/qml/jsruntime/qv4arraybuffer.cpp
+++ b/src/qml/jsruntime/qv4arraybuffer.cpp
@@ -12,14 +12,14 @@ DEFINE_OBJECT_VTABLE(ArrayBufferCtor);
DEFINE_OBJECT_VTABLE(SharedArrayBuffer);
DEFINE_OBJECT_VTABLE(ArrayBuffer);
-void Heap::SharedArrayBufferCtor::init(QV4::ExecutionContext *scope)
+void Heap::SharedArrayBufferCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("SharedArrayBuffer"));
+ Heap::FunctionObject::init(engine, QStringLiteral("SharedArrayBuffer"));
}
-void Heap::ArrayBufferCtor::init(QV4::ExecutionContext *scope)
+void Heap::ArrayBufferCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("ArrayBuffer"));
+ Heap::FunctionObject::init(engine, QStringLiteral("ArrayBuffer"));
}
ReturnedValue SharedArrayBufferCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
diff --git a/src/qml/jsruntime/qv4arraybuffer_p.h b/src/qml/jsruntime/qv4arraybuffer_p.h
index aafa3c6335..af1195a947 100644
--- a/src/qml/jsruntime/qv4arraybuffer_p.h
+++ b/src/qml/jsruntime/qv4arraybuffer_p.h
@@ -25,11 +25,11 @@ namespace QV4 {
namespace Heap {
struct SharedArrayBufferCtor : FunctionObject {
- void init(QV4::ExecutionContext *scope);
+ void init(QV4::ExecutionEngine *engine);
};
struct ArrayBufferCtor : SharedArrayBufferCtor {
- void init(QV4::ExecutionContext *scope);
+ void init(QV4::ExecutionEngine *engine);
};
struct Q_QML_EXPORT SharedArrayBuffer : Object {
diff --git a/src/qml/jsruntime/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp
index a32017210a..7c9e7034d8 100644
--- a/src/qml/jsruntime/qv4arrayobject.cpp
+++ b/src/qml/jsruntime/qv4arrayobject.cpp
@@ -14,9 +14,9 @@ using namespace QV4;
DEFINE_OBJECT_VTABLE(ArrayCtor);
-void Heap::ArrayCtor::init(QV4::ExecutionContext *scope)
+void Heap::ArrayCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("Array"));
+ Heap::FunctionObject::init(engine, QStringLiteral("Array"));
}
ReturnedValue ArrayCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
diff --git a/src/qml/jsruntime/qv4arrayobject_p.h b/src/qml/jsruntime/qv4arrayobject_p.h
index b07e27b24f..a68068937f 100644
--- a/src/qml/jsruntime/qv4arrayobject_p.h
+++ b/src/qml/jsruntime/qv4arrayobject_p.h
@@ -50,7 +50,7 @@ namespace QV4 {
namespace Heap {
struct ArrayCtor : FunctionObject {
- void init(QV4::ExecutionContext *scope);
+ void init(QV4::ExecutionEngine *engine);
};
}
diff --git a/src/qml/jsruntime/qv4booleanobject.cpp b/src/qml/jsruntime/qv4booleanobject.cpp
index 3110ec7992..5c1d50e753 100644
--- a/src/qml/jsruntime/qv4booleanobject.cpp
+++ b/src/qml/jsruntime/qv4booleanobject.cpp
@@ -8,9 +8,9 @@ using namespace QV4;
DEFINE_OBJECT_VTABLE(BooleanCtor);
DEFINE_OBJECT_VTABLE(BooleanObject);
-void Heap::BooleanCtor::init(QV4::ExecutionContext *scope)
+void Heap::BooleanCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("Boolean"));
+ Heap::FunctionObject::init(engine, QStringLiteral("Boolean"));
}
ReturnedValue BooleanCtor::virtualCallAsConstructor(const FunctionObject *that, const Value *argv, int argc, const Value *newTarget)
diff --git a/src/qml/jsruntime/qv4booleanobject_p.h b/src/qml/jsruntime/qv4booleanobject_p.h
index e009b0413a..1b2d3914ac 100644
--- a/src/qml/jsruntime/qv4booleanobject_p.h
+++ b/src/qml/jsruntime/qv4booleanobject_p.h
@@ -25,7 +25,7 @@ namespace QV4 {
namespace Heap {
struct BooleanCtor : FunctionObject {
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
};
}
diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp
index 3ae3e5d24c..01f9b4adf3 100644
--- a/src/qml/jsruntime/qv4context.cpp
+++ b/src/qml/jsruntime/qv4context.cpp
@@ -32,7 +32,7 @@ Heap::CallContext *ExecutionContext::newBlockContext(CppStackFrame *frame, int b
Heap::ExecutionContext *outer = static_cast<Heap::ExecutionContext *>(frame->context()->m());
c->outer.set(v4, outer);
if (frame->isJSTypesFrame()) {
- c->function.set(v4, static_cast<Heap::FunctionObject *>(
+ c->function.set(v4, static_cast<Heap::JavaScriptFunctionObject *>(
Value::fromStaticValue(
static_cast<JSTypesStackFrame *>(frame)->jsFrame->function).m()));
} else {
@@ -74,7 +74,7 @@ Heap::CallContext *ExecutionContext::newCallContext(JSTypesStackFrame *frame)
c->init();
c->outer.set(v4, outer);
- c->function.set(v4, static_cast<Heap::FunctionObject *>(
+ c->function.set(v4, static_cast<Heap::JavaScriptFunctionObject *>(
Value::fromStaticValue(frame->jsFrame->function).m()));
const CompiledData::Function *compiledFunction = function->compiledFunction;
diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h
index 82a9472223..48b6e04025 100644
--- a/src/qml/jsruntime/qv4context_p.h
+++ b/src/qml/jsruntime/qv4context_p.h
@@ -64,7 +64,7 @@ Q_STATIC_ASSERT(offsetof(ExecutionContextData, outer) == 0);
Q_STATIC_ASSERT(offsetof(ExecutionContextData, activation) == offsetof(ExecutionContextData, outer) + QT_POINTER_SIZE);
#define CallContextMembers(class, Member) \
- Member(class, Pointer, FunctionObject *, function) \
+ Member(class, Pointer, JavaScriptFunctionObject *, function) \
Member(class, ValueArray, ValueArray, locals)
DECLARE_HEAP_OBJECT(CallContext, ExecutionContext) {
diff --git a/src/qml/jsruntime/qv4dataview.cpp b/src/qml/jsruntime/qv4dataview.cpp
index f4ca09a127..689eb9232b 100644
--- a/src/qml/jsruntime/qv4dataview.cpp
+++ b/src/qml/jsruntime/qv4dataview.cpp
@@ -13,9 +13,9 @@ using namespace QV4;
DEFINE_OBJECT_VTABLE(DataViewCtor);
DEFINE_OBJECT_VTABLE(DataView);
-void Heap::DataViewCtor::init(QV4::ExecutionContext *scope)
+void Heap::DataViewCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("DataView"));
+ Heap::FunctionObject::init(engine, QStringLiteral("DataView"));
}
static uint toIndex(ExecutionEngine *e, const Value &v)
diff --git a/src/qml/jsruntime/qv4dataview_p.h b/src/qml/jsruntime/qv4dataview_p.h
index ab2e1e589a..b5fa41d964 100644
--- a/src/qml/jsruntime/qv4dataview_p.h
+++ b/src/qml/jsruntime/qv4dataview_p.h
@@ -24,7 +24,7 @@ namespace QV4 {
namespace Heap {
struct DataViewCtor : FunctionObject {
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
};
#define DataViewMembers(class, Member) \
diff --git a/src/qml/jsruntime/qv4dateobject.cpp b/src/qml/jsruntime/qv4dateobject.cpp
index 6b64be3abb..2cb020e495 100644
--- a/src/qml/jsruntime/qv4dateobject.cpp
+++ b/src/qml/jsruntime/qv4dateobject.cpp
@@ -766,9 +766,9 @@ QDate DateObject::dateTimeToDate(const QDateTime &dateTime)
DEFINE_OBJECT_VTABLE(DateCtor);
-void Heap::DateCtor::init(QV4::ExecutionContext *scope)
+void Heap::DateCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("Date"));
+ Heap::FunctionObject::init(engine, QStringLiteral("Date"));
}
ReturnedValue DateCtor::virtualCallAsConstructor(const FunctionObject *that, const Value *argv, int argc, const Value *newTarget)
diff --git a/src/qml/jsruntime/qv4dateobject_p.h b/src/qml/jsruntime/qv4dateobject_p.h
index 7debcff4e9..4c184de897 100644
--- a/src/qml/jsruntime/qv4dateobject_p.h
+++ b/src/qml/jsruntime/qv4dateobject_p.h
@@ -189,7 +189,7 @@ private:
struct DateCtor : FunctionObject {
- void init(QV4::ExecutionContext *scope);
+ void init(QV4::ExecutionEngine *engine);
};
}
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index a2a2e99a01..6754c3c887 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -627,25 +627,23 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
ic = newInternalClass(SequencePrototype::staticVTable(), SequencePrototype::defaultPrototype(this));
jsObjects[SequenceProto] = ScopedValue(scope, memoryManager->allocObject<SequencePrototype>(ic->d()));
- ExecutionContext *global = rootContext();
-
- 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[Object_Ctor] = memoryManager->allocate<ObjectCtor>(this);
+ jsObjects[String_Ctor] = memoryManager->allocate<StringCtor>(this);
+ jsObjects[Symbol_Ctor] = memoryManager->allocate<SymbolCtor>(this);
+ jsObjects[Number_Ctor] = memoryManager->allocate<NumberCtor>(this);
+ jsObjects[Boolean_Ctor] = memoryManager->allocate<BooleanCtor>(this);
+ jsObjects[Array_Ctor] = memoryManager->allocate<ArrayCtor>(this);
+ jsObjects[Function_Ctor] = memoryManager->allocate<FunctionCtor>(this);
+ jsObjects[GeneratorFunction_Ctor] = memoryManager->allocate<GeneratorFunctionCtor>(this);
+ jsObjects[Date_Ctor] = memoryManager->allocate<DateCtor>(this);
+ jsObjects[RegExp_Ctor] = memoryManager->allocate<RegExpCtor>(this);
+ jsObjects[Error_Ctor] = memoryManager->allocate<ErrorCtor>(this);
+ jsObjects[EvalError_Ctor] = memoryManager->allocate<EvalErrorCtor>(this);
+ jsObjects[RangeError_Ctor] = memoryManager->allocate<RangeErrorCtor>(this);
+ jsObjects[ReferenceError_Ctor] = memoryManager->allocate<ReferenceErrorCtor>(this);
+ jsObjects[SyntaxError_Ctor] = memoryManager->allocate<SyntaxErrorCtor>(this);
+ jsObjects[TypeError_Ctor] = memoryManager->allocate<TypeErrorCtor>(this);
+ jsObjects[URIError_Ctor] = memoryManager->allocate<URIErrorCtor>(this);
jsObjects[IteratorProto] = memoryManager->allocate<IteratorPrototype>();
ic = newInternalClass(ForInIteratorPrototype::staticVTable(), iteratorPrototype());
@@ -663,9 +661,9 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
// url
//
- jsObjects[Url_Ctor] = memoryManager->allocate<UrlCtor>(global);
+ jsObjects[Url_Ctor] = memoryManager->allocate<UrlCtor>(this);
jsObjects[UrlProto] = memoryManager->allocate<UrlPrototype>();
- jsObjects[UrlSearchParams_Ctor] = memoryManager->allocate<UrlSearchParamsCtor>(global);
+ jsObjects[UrlSearchParams_Ctor] = memoryManager->allocate<UrlSearchParamsCtor>(this);
jsObjects[UrlSearchParamsProto] = memoryManager->allocate<UrlSearchParamsPrototype>();
str = newString(QStringLiteral("get [Symbol.species]"));
@@ -703,19 +701,19 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
sequencePrototype()->cast<SequencePrototype>()->init();
- jsObjects[WeakMap_Ctor] = memoryManager->allocate<WeakMapCtor>(global);
+ jsObjects[WeakMap_Ctor] = memoryManager->allocate<WeakMapCtor>(this);
jsObjects[WeakMapProto] = memoryManager->allocate<WeakMapPrototype>();
static_cast<WeakMapPrototype *>(weakMapPrototype())->init(this, weakMapCtor());
- jsObjects[Map_Ctor] = memoryManager->allocate<MapCtor>(global);
+ jsObjects[Map_Ctor] = memoryManager->allocate<MapCtor>(this);
jsObjects[MapProto] = memoryManager->allocate<MapPrototype>();
static_cast<MapPrototype *>(mapPrototype())->init(this, mapCtor());
- jsObjects[WeakSet_Ctor] = memoryManager->allocate<WeakSetCtor>(global);
+ jsObjects[WeakSet_Ctor] = memoryManager->allocate<WeakSetCtor>(this);
jsObjects[WeakSetProto] = memoryManager->allocate<WeakSetPrototype>();
static_cast<WeakSetPrototype *>(weakSetPrototype())->init(this, weakSetCtor());
- jsObjects[Set_Ctor] = memoryManager->allocate<SetCtor>(global);
+ jsObjects[Set_Ctor] = memoryManager->allocate<SetCtor>(this);
jsObjects[SetProto] = memoryManager->allocate<SetPrototype>();
static_cast<SetPrototype *>(setPrototype())->init(this, setCtor());
@@ -723,33 +721,34 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
// promises
//
- jsObjects[Promise_Ctor] = memoryManager->allocate<PromiseCtor>(global);
+ jsObjects[Promise_Ctor] = memoryManager->allocate<PromiseCtor>(this);
jsObjects[PromiseProto] = memoryManager->allocate<PromisePrototype>();
static_cast<PromisePrototype *>(promisePrototype())->init(this, promiseCtor());
// typed arrays
- jsObjects[SharedArrayBuffer_Ctor] = memoryManager->allocate<SharedArrayBufferCtor>(global);
+ jsObjects[SharedArrayBuffer_Ctor] = memoryManager->allocate<SharedArrayBufferCtor>(this);
jsObjects[SharedArrayBufferProto] = memoryManager->allocate<SharedArrayBufferPrototype>();
static_cast<SharedArrayBufferPrototype *>(sharedArrayBufferPrototype())->init(this, sharedArrayBufferCtor());
- jsObjects[ArrayBuffer_Ctor] = memoryManager->allocate<ArrayBufferCtor>(global);
+ jsObjects[ArrayBuffer_Ctor] = memoryManager->allocate<ArrayBufferCtor>(this);
jsObjects[ArrayBufferProto] = memoryManager->allocate<ArrayBufferPrototype>();
static_cast<ArrayBufferPrototype *>(arrayBufferPrototype())->init(this, arrayBufferCtor());
- jsObjects[DataView_Ctor] = memoryManager->allocate<DataViewCtor>(global);
+ jsObjects[DataView_Ctor] = memoryManager->allocate<DataViewCtor>(this);
jsObjects[DataViewProto] = memoryManager->allocate<DataViewPrototype>();
static_cast<DataViewPrototype *>(dataViewPrototype())->init(this, dataViewCtor());
jsObjects[ValueTypeProto] = (Heap::Base *) nullptr;
jsObjects[SignalHandlerProto] = (Heap::Base *) nullptr;
+ jsObjects[TypeWrapperProto] = (Heap::Base *) nullptr;
- jsObjects[IntrinsicTypedArray_Ctor] = memoryManager->allocate<IntrinsicTypedArrayCtor>(global);
+ jsObjects[IntrinsicTypedArray_Ctor] = memoryManager->allocate<IntrinsicTypedArrayCtor>(this);
jsObjects[IntrinsicTypedArrayProto] = memoryManager->allocate<IntrinsicTypedArrayPrototype>();
static_cast<IntrinsicTypedArrayPrototype *>(intrinsicTypedArrayPrototype())
->init(this, static_cast<IntrinsicTypedArrayCtor *>(intrinsicTypedArrayCtor()));
for (int i = 0; i < NTypedArrayTypes; ++i) {
- static_cast<Value &>(typedArrayCtors[i]) = memoryManager->allocate<TypedArrayCtor>(global, Heap::TypedArray::Type(i));
+ static_cast<Value &>(typedArrayCtors[i]) = memoryManager->allocate<TypedArrayCtor>(this, 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>()));
}
@@ -796,14 +795,14 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
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->defineDefaultProperty(QStringLiteral("Proxy"), (o = memoryManager->allocate<Proxy>(rootContext())));
+ globalObject->defineDefaultProperty(QStringLiteral("Proxy"), (o = memoryManager->allocate<Proxy>(this)));
globalObject->defineReadonlyProperty(QStringLiteral("undefined"), Value::undefinedValue());
globalObject->defineReadonlyProperty(QStringLiteral("NaN"), Value::fromDouble(std::numeric_limits<double>::quiet_NaN()));
globalObject->defineReadonlyProperty(QStringLiteral("Infinity"), Value::fromDouble(Q_INFINITY));
- jsObjects[Eval_Function] = memoryManager->allocate<EvalFunction>(global);
+ jsObjects[Eval_Function] = memoryManager->allocate<EvalFunction>(this);
globalObject->defineDefaultProperty(QStringLiteral("eval"), *evalFunction());
// ES6: 20.1.2.12 & 20.1.2.13:
@@ -832,7 +831,9 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
globalObject->defineDefaultProperty(QStringLiteral("escape"), GlobalFunctions::method_escape, 1);
globalObject->defineDefaultProperty(QStringLiteral("unescape"), GlobalFunctions::method_unescape, 1);
- ScopedFunctionObject t(scope, memoryManager->allocate<FunctionObject>(rootContext(), nullptr, ::throwTypeError));
+ ScopedFunctionObject t(
+ scope,
+ memoryManager->allocate<DynamicFunctionObject>(this, nullptr, ::throwTypeError));
t->defineReadonlyProperty(id_length(), Value::fromInt32(0));
t->setInternalClass(t->internalClass()->cryopreserved());
jsObjects[ThrowerObject] = t;
@@ -2478,18 +2479,22 @@ bool convertToIterable(QMetaType metaType, void *data, Source *sequence)
return false;
const QMetaType elementMetaType = iterable.valueMetaType();
- QVariant element(elementMetaType);
for (qsizetype i = 0, end = sequence->getLength(); i < end; ++i) {
- if (!ExecutionEngine::metaTypeFromJS(sequence->get(i), elementMetaType, element.data()))
- element = QVariant(elementMetaType);
+ QVariant element(elementMetaType);
+ ExecutionEngine::metaTypeFromJS(sequence->get(i), elementMetaType, element.data());
iterable.addValue(element, QSequentialIterable::AtEnd);
}
return true;
}
-// Converts a JS value to a meta-type.
-// data must point to a place that can store a value of the given type.
-// Returns true if conversion succeeded, false otherwise.
+/*!
+ * \internal
+ *
+ * Converts a JS value to a meta-type.
+ * \a data must point to a default-constructed instance of \a metaType.
+ * Returns \c true if conversion succeeded, \c false otherwise. In the latter case,
+ * \a data is not modified.
+ */
bool ExecutionEngine::metaTypeFromJS(const Value &value, QMetaType metaType, void *data)
{
// check if it's one of the types we know
diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h
index 8e1bd24f6b..0958ab3ab5 100644
--- a/src/qml/jsruntime/qv4engine_p.h
+++ b/src/qml/jsruntime/qv4engine_p.h
@@ -217,6 +217,7 @@ public:
MapProto,
IntrinsicTypedArrayProto,
ValueTypeProto,
+ TypeWrapperProto,
SignalHandlerProto,
IteratorProto,
ForInIteratorProto,
@@ -342,6 +343,7 @@ public:
Object *valueTypeWrapperPrototype() const { return reinterpret_cast<Object *>(jsObjects + ValueTypeProto); }
Object *signalHandlerPrototype() const { return reinterpret_cast<Object *>(jsObjects + SignalHandlerProto); }
+ Object *typeWrapperPrototype() const { return reinterpret_cast<Object *>(jsObjects + TypeWrapperProto); }
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); }
diff --git a/src/qml/jsruntime/qv4errorobject.cpp b/src/qml/jsruntime/qv4errorobject.cpp
index 35b5952d38..02145a0243 100644
--- a/src/qml/jsruntime/qv4errorobject.cpp
+++ b/src/qml/jsruntime/qv4errorobject.cpp
@@ -182,14 +182,14 @@ DEFINE_OBJECT_VTABLE(SyntaxErrorCtor);
DEFINE_OBJECT_VTABLE(TypeErrorCtor);
DEFINE_OBJECT_VTABLE(URIErrorCtor);
-void Heap::ErrorCtor::init(QV4::ExecutionContext *scope)
+void Heap::ErrorCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("Error"));
+ Heap::FunctionObject::init(engine, QStringLiteral("Error"));
}
-void Heap::ErrorCtor::init(QV4::ExecutionContext *scope, const QString &name)
+void Heap::ErrorCtor::init(QV4::ExecutionEngine *engine, const QString &name)
{
- Heap::FunctionObject::init(scope, name);
+ Heap::FunctionObject::init(engine, name);
}
ReturnedValue ErrorCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
@@ -203,9 +203,9 @@ ReturnedValue ErrorCtor::virtualCall(const FunctionObject *f, const Value *, con
return f->callAsConstructor(argv, argc);
}
-void Heap::EvalErrorCtor::init(QV4::ExecutionContext *scope)
+void Heap::EvalErrorCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("EvalError"));
+ Heap::FunctionObject::init(engine, QStringLiteral("EvalError"));
}
ReturnedValue EvalErrorCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
@@ -214,9 +214,9 @@ ReturnedValue EvalErrorCtor::virtualCallAsConstructor(const FunctionObject *f, c
return ErrorObject::create<EvalErrorObject>(f->engine(), v, newTarget)->asReturnedValue();
}
-void Heap::RangeErrorCtor::init(QV4::ExecutionContext *scope)
+void Heap::RangeErrorCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("RangeError"));
+ Heap::FunctionObject::init(engine, QStringLiteral("RangeError"));
}
ReturnedValue RangeErrorCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
@@ -225,9 +225,9 @@ ReturnedValue RangeErrorCtor::virtualCallAsConstructor(const FunctionObject *f,
return ErrorObject::create<RangeErrorObject>(f->engine(), v, newTarget)->asReturnedValue();
}
-void Heap::ReferenceErrorCtor::init(QV4::ExecutionContext *scope)
+void Heap::ReferenceErrorCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("ReferenceError"));
+ Heap::FunctionObject::init(engine, QStringLiteral("ReferenceError"));
}
ReturnedValue ReferenceErrorCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
@@ -236,9 +236,9 @@ ReturnedValue ReferenceErrorCtor::virtualCallAsConstructor(const FunctionObject
return ErrorObject::create<ReferenceErrorObject>(f->engine(), v, newTarget)->asReturnedValue();
}
-void Heap::SyntaxErrorCtor::init(QV4::ExecutionContext *scope)
+void Heap::SyntaxErrorCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("SyntaxError"));
+ Heap::FunctionObject::init(engine, QStringLiteral("SyntaxError"));
}
ReturnedValue SyntaxErrorCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
@@ -247,9 +247,9 @@ ReturnedValue SyntaxErrorCtor::virtualCallAsConstructor(const FunctionObject *f,
return ErrorObject::create<SyntaxErrorObject>(f->engine(), v, newTarget)->asReturnedValue();
}
-void Heap::TypeErrorCtor::init(QV4::ExecutionContext *scope)
+void Heap::TypeErrorCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("TypeError"));
+ Heap::FunctionObject::init(engine, QStringLiteral("TypeError"));
}
ReturnedValue TypeErrorCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
@@ -258,9 +258,9 @@ ReturnedValue TypeErrorCtor::virtualCallAsConstructor(const FunctionObject *f, c
return ErrorObject::create<TypeErrorObject>(f->engine(), v, newTarget)->asReturnedValue();
}
-void Heap::URIErrorCtor::init(QV4::ExecutionContext *scope)
+void Heap::URIErrorCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("URIError"));
+ Heap::FunctionObject::init(engine, QStringLiteral("URIError"));
}
ReturnedValue URIErrorCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
diff --git a/src/qml/jsruntime/qv4errorobject_p.h b/src/qml/jsruntime/qv4errorobject_p.h
index 541f5cae36..f9adbb443b 100644
--- a/src/qml/jsruntime/qv4errorobject_p.h
+++ b/src/qml/jsruntime/qv4errorobject_p.h
@@ -79,32 +79,32 @@ struct URIErrorObject : ErrorObject {
};
struct ErrorCtor : FunctionObject {
- void init(QV4::ExecutionContext *scope);
- void init(QV4::ExecutionContext *scope, const QString &name);
+ void init(ExecutionEngine *engine);
+ void init(ExecutionEngine *engine, const QString &name);
};
struct EvalErrorCtor : ErrorCtor {
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
};
struct RangeErrorCtor : ErrorCtor {
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
};
struct ReferenceErrorCtor : ErrorCtor {
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
};
struct SyntaxErrorCtor : ErrorCtor {
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
};
struct TypeErrorCtor : ErrorCtor {
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
};
struct URIErrorCtor : ErrorCtor {
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
};
}
diff --git a/src/qml/jsruntime/qv4executablecompilationunit_p.h b/src/qml/jsruntime/qv4executablecompilationunit_p.h
index 3f3335ef4e..930e138732 100644
--- a/src/qml/jsruntime/qv4executablecompilationunit_p.h
+++ b/src/qml/jsruntime/qv4executablecompilationunit_p.h
@@ -134,6 +134,7 @@ public:
bool ignoresFunctionSignature() const { return m_compilationUnit->ignoresFunctionSignature(); }
bool valueTypesAreCopied() const { return m_compilationUnit->valueTypesAreCopied(); }
bool valueTypesAreAddressable() const { return m_compilationUnit->valueTypesAreAddressable(); }
+ bool valueTypesAreAssertable() const { return m_compilationUnit->valueTypesAreAssertable(); }
bool componentsAreBound() const { return m_compilationUnit->componentsAreBound(); }
bool isESModule() const { return m_compilationUnit->isESModule(); }
diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp
index ae36b563e0..82646e2822 100644
--- a/src/qml/jsruntime/qv4function.cpp
+++ b/src/qml/jsruntime/qv4function.cpp
@@ -1,20 +1,18 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#include "qml/qqmlprivate.h"
#include "qv4function_p.h"
-#include "qv4managed_p.h"
-#include "qv4string_p.h"
-#include "qv4value_p.h"
-#include "qv4engine_p.h"
-#include <private/qv4mm_p.h>
-#include <private/qv4identifiertable_p.h>
+
+#include <private/qqmlpropertycachecreator_p.h>
+#include <private/qqmltype_p_p.h>
+
+#include <private/qv4engine_p.h>
#include <private/qv4functiontable_p.h>
-#include <assembler/MacroAssemblerCodeRef.h>
-#include <private/qv4vme_moth_p.h>
-#include <private/qqmlglobal_p.h>
+#include <private/qv4identifiertable_p.h>
#include <private/qv4jscall_p.h>
-#include <private/qqmlpropertycachecreator_p.h>
+#include <private/qv4vme_moth_p.h>
+
+#include <assembler/MacroAssemblerCodeRef.h>
QT_BEGIN_NAMESPACE
diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp
index ab6a34435f..e9f91fbc06 100644
--- a/src/qml/jsruntime/qv4functionobject.cpp
+++ b/src/qml/jsruntime/qv4functionobject.cpp
@@ -30,84 +30,57 @@ using namespace QV4;
DEFINE_OBJECT_VTABLE(FunctionObject);
-void Heap::FunctionObject::init(QV4::ExecutionContext *scope, QV4::String *name,
- VTable::Call call, VTable::CallWithMetaTypes callWithMetaTypes)
+void Heap::FunctionObject::init(QV4::ExecutionEngine *engine, QV4::String *name)
{
- jsCall = call;
- jsCallWithMetaTypes = callWithMetaTypes;
- jsConstruct = nullptr;
-
Object::init();
- this->scope.set(scope->engine(), scope->d());
- Scope s(scope->engine());
+ Scope s(engine);
ScopedFunctionObject f(s, this);
if (name)
f->setName(name);
}
-void Heap::FunctionObject::init(QV4::ExecutionContext *scope, QV4::String *name)
+void Heap::FunctionObject::init(QV4::ExecutionEngine *engine, const QString &name)
{
- ExecutionEngine *e = scope->engine();
-
- jsCall = vtable()->call;
- jsCallWithMetaTypes = vtable()->callWithMetaTypes;
- jsConstruct = vtable()->callAsConstructor;
-
- Object::init();
- this->scope.set(scope->engine(), scope->d());
- Scope s(e);
- ScopedFunctionObject f(s, this);
- if (name)
- f->setName(name);
+ Scope valueScope(engine);
+ ScopedString s(valueScope, engine->newString(name));
+ init(engine, s);
}
-
-
-void Heap::FunctionObject::init(QV4::ExecutionContext *scope, Function *function, QV4::String *n)
-{
- jsCall = vtable()->call;
- jsCallWithMetaTypes = vtable()->callWithMetaTypes;
- jsConstruct = vtable()->callAsConstructor;
-
- Object::init();
- setFunction(function);
- this->scope.set(scope->engine(), scope->d());
- Scope s(scope->engine());
- ScopedString name(s, n ? n->d() : function->name());
- ScopedFunctionObject f(s, this);
- if (name)
- f->setName(name);
-}
-
-void Heap::FunctionObject::init(QV4::ExecutionContext *scope, const QString &name)
+void Heap::FunctionObject::init()
{
- Scope valueScope(scope);
- ScopedString s(valueScope, valueScope.engine->newString(name));
- init(scope, s);
+ init(internalClass->engine, static_cast<QV4::String *>(nullptr));
}
-void Heap::FunctionObject::init()
+void Heap::JavaScriptFunctionObject::init(
+ QV4::ExecutionContext *scope, Function *function, QV4::String *n)
{
- jsCall = vtable()->call;
- jsCallWithMetaTypes = vtable()->callWithMetaTypes;
- jsConstruct = vtable()->callAsConstructor;
-
- Object::init();
- this->scope.set(internalClass->engine, internalClass->engine->rootContext()->d());
+ Q_ASSERT(n || function);
+ Scope s(scope->engine());
+ ScopedString name(s, n ? n->d() : function->name());
+ FunctionObject::init(s.engine, name);
+ this->scope.set(s.engine, scope->d());
+ setFunction(function);
}
-void Heap::FunctionObject::setFunction(Function *f)
+void Heap::JavaScriptFunctionObject::setFunction(Function *f)
{
if (f) {
function = f;
function->executableCompilationUnit()->addref();
}
}
-void Heap::FunctionObject::destroy()
+void Heap::JavaScriptFunctionObject::destroy()
{
if (function)
function->executableCompilationUnit()->release();
- Object::destroy();
+ FunctionObject::destroy();
+}
+
+void Heap::DynamicFunctionObject::init(
+ QV4::ExecutionEngine *engine, QV4::String *name, VTable::Call call)
+{
+ FunctionObject::init(engine, name);
+ jsCall = call;
}
void FunctionObject::createDefaultPrototypeProperty(uint protoConstructorSlot)
@@ -121,32 +94,29 @@ void FunctionObject::createDefaultPrototypeProperty(uint protoConstructorSlot)
defineDefaultProperty(s.engine->id_prototype(), proto, Attr_NotEnumerable|Attr_NotConfigurable);
}
-void FunctionObject::call(QObject *thisObject, void **a, const QMetaType *types, int argc)
+ReturnedValue FunctionObject::name() const
{
- if (const auto callWithMetaTypes = d()->jsCallWithMetaTypes) {
- callWithMetaTypes(this, thisObject, a, types, argc);
- return;
- }
-
- QV4::convertAndCall(engine(), thisObject, a, types, argc,
- [this](const Value *thisObject, const Value *argv, int argc) {
- return call(thisObject, argv, argc);
- });
+ return get(engine()->id_name());
}
-ReturnedValue FunctionObject::name() const
+ReturnedValue FunctionObject::failCall() const
{
- return get(scope()->internalClass->engine->id_name());
+ return engine()->throwTypeError(QStringLiteral("Function can only be called with |new|."));
}
-ReturnedValue FunctionObject::virtualCall(const FunctionObject *, const Value *, const Value *, int)
+ReturnedValue FunctionObject::failCallAsConstructor() const
{
- return Encode::undefined();
+ return engine()->throwTypeError(QStringLiteral("Function is not a constructor."));
}
-void FunctionObject::virtualCallWithMetaTypes(
- const FunctionObject *, QObject *, void **, const QMetaType *, int)
+void FunctionObject::virtualConvertAndCall(
+ const FunctionObject *f, QObject *thisObject,
+ void **argv, const QMetaType *types, int argc)
{
+ QV4::convertAndCall(f->engine(), thisObject, argv, types, argc,
+ [f](const Value *thisObject, const Value *argv, int argc) {
+ return f->call(thisObject, argv, argc);
+ });
}
Heap::FunctionObject *FunctionObject::createScriptFunction(ExecutionContext *scope, Function *function)
@@ -156,15 +126,20 @@ Heap::FunctionObject *FunctionObject::createScriptFunction(ExecutionContext *sco
return scope->engine()->memoryManager->allocate<ScriptFunction>(scope, function);
}
-Heap::FunctionObject *FunctionObject::createConstructorFunction(ExecutionContext *scope, Function *function, Object *homeObject, bool isDerivedConstructor)
+Heap::FunctionObject *FunctionObject::createConstructorFunction(
+ ExecutionContext *scope, Function *function, Object *homeObject, bool isDerivedConstructor)
{
+ QV4::ExecutionEngine *engine = scope->engine();
if (!function) {
- Heap::DefaultClassConstructorFunction *c = scope->engine()->memoryManager->allocate<DefaultClassConstructorFunction>(scope);
+ Heap::DefaultClassConstructorFunction *c
+ = engine->memoryManager->allocate<DefaultClassConstructorFunction>(scope);
c->isDerivedConstructor = isDerivedConstructor;
return c;
}
- Heap::ConstructorFunction *c = scope->engine()->memoryManager->allocate<ConstructorFunction>(scope, function);
- c->homeObject.set(scope->engine(), homeObject->d());
+
+ Heap::ConstructorFunction *c
+ = engine->memoryManager->allocate<ConstructorFunction>(scope, function);
+ c->homeObject.set(engine, homeObject->d());
c->isDerivedConstructor = isDerivedConstructor;
return c;
}
@@ -183,7 +158,8 @@ Heap::FunctionObject *FunctionObject::createBuiltinFunction(ExecutionEngine *eng
if (!name)
name = engine->newString(QChar::fromLatin1('[') + QStringView{nameOrSymbol->toQString()}.mid(1) + QChar::fromLatin1(']'));
- ScopedFunctionObject function(scope, engine->memoryManager->allocate<FunctionObject>(engine->rootContext(), name, code));
+ ScopedFunctionObject function(
+ scope, engine->memoryManager->allocate<DynamicFunctionObject>(engine, name, code));
function->defineReadonlyConfigurableProperty(engine->id_length(), Value::fromInt32(argumentCount));
return function->d();
}
@@ -199,16 +175,29 @@ ReturnedValue FunctionObject::getHomeObject() const
return Encode::undefined();
}
-QQmlSourceLocation FunctionObject::sourceLocation() const
+DEFINE_OBJECT_VTABLE(JavaScriptFunctionObject);
+
+QQmlSourceLocation JavaScriptFunctionObject::sourceLocation() const
{
return d()->function->sourceLocation();
}
+DEFINE_OBJECT_VTABLE(DynamicFunctionObject);
+
+ReturnedValue DynamicFunctionObject::virtualCall(
+ const FunctionObject *f, const Value *thisObject, const Value *argv, int argc) {
+ Heap::DynamicFunctionObject *d = static_cast<const DynamicFunctionObject *>(f)->d();
+ if (d->jsCall)
+ return d->jsCall(f, thisObject, argv, argc);
+ return d->internalClass->engine->throwTypeError(
+ QStringLiteral("Function can only be called with |new|."));
+}
+
DEFINE_OBJECT_VTABLE(FunctionCtor);
-void Heap::FunctionCtor::init(QV4::ExecutionContext *scope)
+void Heap::FunctionCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("Function"));
+ Heap::FunctionObject::init(engine, QStringLiteral("Function"));
}
// 15.3.2
@@ -311,6 +300,12 @@ void FunctionPrototype::init(ExecutionEngine *engine, Object *ctor)
defineDefaultProperty(engine->symbol_hasInstance(), method_hasInstance, 1, Attr_ReadOnly);
}
+ReturnedValue FunctionPrototype::virtualCall(
+ const FunctionObject *, const Value *, const Value *, int)
+{
+ return Encode::undefined();
+}
+
ReturnedValue FunctionPrototype::method_toString(const FunctionObject *b, const Value *thisObject, const Value *, int)
{
ExecutionEngine *v4 = b->engine();
@@ -427,10 +422,13 @@ ReturnedValue FunctionPrototype::method_bind(const FunctionObject *b, const Valu
boundArgs->set(scope.engine, i, argv[i + 1]);
}
- ScopedContext ctx(scope, target->scope());
- Scoped<BoundFunction> bound(scope, BoundFunction::create(ctx, target, boundThis, boundArgs));
- bound->d()->setFunction(target->function());
- return bound->asReturnedValue();
+ if (target->isConstructor()) {
+ return scope.engine->memoryManager->allocate<BoundConstructor>(target, boundThis, boundArgs)
+ ->asReturnedValue();
+ }
+
+ return scope.engine->memoryManager->allocate<BoundFunction>(target, boundThis, boundArgs)
+ ->asReturnedValue();
}
ReturnedValue FunctionPrototype::method_hasInstance(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
@@ -490,7 +488,9 @@ DEFINE_OBJECT_VTABLE(ArrowFunction);
void ArrowFunction::virtualCallWithMetaTypes(const FunctionObject *fo, QObject *thisObject,
void **a, const QMetaType *types, int argc)
{
- if (fo->function()->kind != Function::AotCompiled) {
+ const ArrowFunction *self = static_cast<const ArrowFunction *>(fo);
+ Function *function = self->function();
+ if (function->kind != Function::AotCompiled) {
QV4::convertAndCall(fo->engine(), thisObject, a, types, argc,
[fo](const Value *thisObject, const Value *argv, int argc) {
return ArrowFunction::virtualCall(fo, thisObject, argv, argc);
@@ -499,16 +499,17 @@ void ArrowFunction::virtualCallWithMetaTypes(const FunctionObject *fo, QObject *
}
QV4::Scope scope(fo->engine());
- QV4::Scoped<ExecutionContext> context(scope, fo->scope());
+ QV4::Scoped<ExecutionContext> context(scope, self->scope());
MetaTypesStackFrame frame;
- frame.init(fo->function(), thisObject, context, a, types, argc);
+ frame.init(function, thisObject, context, a, types, argc);
frame.push(scope.engine);
Moth::VME::exec(&frame, scope.engine);
frame.pop(scope.engine);
}
-static ReturnedValue qfoDoCall(const QV4::FunctionObject *fo, const QV4::Value *thisObject,
- const QV4::Value *argv, int argc)
+static ReturnedValue qfoDoCall(
+ const QV4::JavaScriptFunctionObject *fo, const QV4::Value *thisObject,
+ const QV4::Value *argv, int argc)
{
ExecutionEngine *engine = fo->engine();
JSTypesStackFrame frame;
@@ -535,7 +536,8 @@ static ReturnedValue qfoDoCall(const QV4::FunctionObject *fo, const QV4::Value *
ReturnedValue ArrowFunction::virtualCall(const QV4::FunctionObject *fo, const Value *thisObject,
const QV4::Value *argv, int argc)
{
- Function *function = fo->function();
+ const ArrowFunction *self = static_cast<const ArrowFunction *>(fo);
+ Function *function = self->function();
switch (function->kind) {
case Function::AotCompiled:
return QV4::convertAndCall(
@@ -546,34 +548,24 @@ ReturnedValue ArrowFunction::virtualCall(const QV4::FunctionObject *fo, const Va
case Function::JsTyped:
return QV4::coerceAndCall(
fo->engine(), &function->jsTypedFunction, function->compiledFunction, argv, argc,
- [fo, thisObject](const Value *argv, int argc) {
- return qfoDoCall(fo, thisObject, argv, argc);
+ [self, thisObject](const Value *argv, int argc) {
+ return qfoDoCall(self, thisObject, argv, argc);
});
default:
break;
}
- return qfoDoCall(fo, thisObject, argv, argc);
+ return qfoDoCall(self, thisObject, argv, argc);
}
void Heap::ArrowFunction::init(QV4::ExecutionContext *scope, Function *function, QV4::String *n)
{
- FunctionObject::init();
- this->scope.set(scope->engine(), scope->d());
-
- setFunction(function);
Q_ASSERT(function);
+ JavaScriptFunctionObject::init(scope, function, n);
Scope s(scope);
- ScopedFunctionObject f(s, this);
-
- ScopedString name(s, n ? n->d() : function->name());
- if (name)
- f->setName(name);
-
Q_ASSERT(internalClass && internalClass->verifyIndex(s.engine->id_length()->propertyKey(), Index_Length));
setProperty(s.engine, Index_Length, Value::fromInt32(int(function->compiledFunction->length)));
- canBeTailCalled = true;
}
void Heap::ScriptFunction::init(QV4::ExecutionContext *scope, Function *function)
@@ -586,6 +578,13 @@ void Heap::ScriptFunction::init(QV4::ExecutionContext *scope, Function *function
f->createDefaultPrototypeProperty(Heap::FunctionObject::Index_ProtoConstructor);
}
+void Heap::DefaultClassConstructorFunction::init(QV4::ExecutionContext *scope)
+{
+ Scope s(scope->engine());
+ FunctionObject::init(s.engine, nullptr);
+ this->scope.set(s.engine, scope->d());
+}
+
Heap::InternalClass *ScriptFunction::classForConstructor() const
{
Scope scope(engine());
@@ -613,8 +612,8 @@ ReturnedValue ConstructorFunction::virtualCallAsConstructor(const FunctionObject
ExecutionEngine *v4 = f->engine();
JSTypesStackFrame frame;
- frame.init(f->function(), argv, argc);
- frame.setupJSFrame(v4->jsStackTop, *f, f->scope(),
+ frame.init(c->function(), argv, argc);
+ frame.setupJSFrame(v4->jsStackTop, *f, c->scope(),
Value::emptyValue(),
newTarget ? *newTarget : Value::undefinedValue());
@@ -668,7 +667,7 @@ ReturnedValue DefaultClassConstructorFunction::virtualCallAsConstructor(const Fu
JSTypesStackFrame frame;
frame.init(nullptr, argv, argc);
- frame.setupJSFrame(v4->jsStackTop, *f, f->scope(),
+ frame.setupJSFrame(v4->jsStackTop, *f, c->scope(),
Value::undefinedValue(),
newTarget ? *newTarget : Value::undefinedValue(), argc, argc);
@@ -705,33 +704,39 @@ DEFINE_OBJECT_VTABLE(IndexedBuiltinFunction);
DEFINE_OBJECT_VTABLE(BoundFunction);
-void Heap::BoundFunction::init(QV4::ExecutionContext *scope, QV4::FunctionObject *target,
- const Value &boundThis, QV4::MemberData *boundArgs)
+void Heap::BoundFunction::init(
+ QV4::FunctionObject *target, const Value &boundThis, QV4::MemberData *boundArgs)
{
- Scope s(scope);
- Heap::FunctionObject::init(scope, QStringLiteral("__bound function__"));
+ ExecutionEngine *engine = target->engine();
+ Scope s(engine);
+ ScopedString name(s, engine->newString(QStringLiteral("__bound function__")));
+ if (auto *js = target->as<QV4::JavaScriptFunctionObject>()) {
+ ScopedContext ctx(s, js->scope());
+ JavaScriptFunctionObject::init(ctx, js->function(), name);
+ } else {
+ Q_ASSERT(name);
+ JavaScriptFunctionObject::init(engine->rootContext(), nullptr, name);
+ }
+
this->target.set(s.engine, target->d());
this->boundArgs.set(s.engine, boundArgs ? boundArgs->d() : nullptr);
- this->boundThis.set(scope->engine(), boundThis);
-
- if (!target->isConstructor())
- jsConstruct = nullptr;
+ this->boundThis.set(s.engine, boundThis);
ScopedObject f(s, this);
- ScopedValue l(s, target->get(s.engine->id_length()));
+ ScopedValue l(s, target->get(engine->id_length()));
int len = l->toUInt32();
if (boundArgs)
len -= boundArgs->size();
if (len < 0)
len = 0;
- f->defineReadonlyConfigurableProperty(s.engine->id_length(), Value::fromInt32(len));
+ f->defineReadonlyConfigurableProperty(engine->id_length(), Value::fromInt32(len));
ScopedProperty pd(s);
- pd->value = s.engine->thrower();
- pd->set = s.engine->thrower();
- f->insertMember(s.engine->id_arguments(), pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
- f->insertMember(s.engine->id_caller(), pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
+ pd->value = engine->thrower();
+ pd->set = engine->thrower();
+ f->insertMember(engine->id_arguments(), pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
+ f->insertMember(engine->id_caller(), pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
}
ReturnedValue BoundFunction::virtualCall(const FunctionObject *fo, const Value *, const Value *argv, int argc)
@@ -755,7 +760,10 @@ ReturnedValue BoundFunction::virtualCall(const FunctionObject *fo, const Value *
return checkedResult(v4, target->call(jsCallData));
}
-ReturnedValue BoundFunction::virtualCallAsConstructor(const FunctionObject *fo, const Value *argv, int argc, const Value *)
+DEFINE_OBJECT_VTABLE(BoundConstructor);
+
+ReturnedValue BoundConstructor::virtualCallAsConstructor(
+ const FunctionObject *fo, const Value *argv, int argc, const Value *)
{
const BoundFunction *f = static_cast<const BoundFunction *>(fo);
Scope scope(f->engine());
diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h
index 573848f62a..f4a2935b5a 100644
--- a/src/qml/jsruntime/qv4functionobject_p.h
+++ b/src/qml/jsruntime/qv4functionobject_p.h
@@ -28,36 +28,41 @@ namespace QV4 {
struct IndexedBuiltinFunction;
struct JSCallData;
-namespace Heap {
-
+// A FunctionObject is generally something that can be called, either with a JavaScript
+// signature (QV4::Value etc) or with a C++ signature (QMetaType etc). For this, it has
+// the Call and CallWithMetaTypes VTable entries.
+// Some FunctionObjects need to select the actual implementation of the call at run time.
+// This comese in two flavors:
+// 1. The implementation is a JavaScript function. For these we have
+// JavaScriptFunctionObject that holds a QV4::Function member to defer the call to.
+// 2. The implementation is a C++ function. For these we have DynamicFunctionObject that
+// holds another Call member in the heap object to defer the call to.
+// In addition, a FunctionObject may want to be called as constructor. For this we have
+// another VTable entry and a flag in the heap object.
-#define FunctionObjectMembers(class, Member) \
- Member(class, Pointer, ExecutionContext *, scope) \
- Member(class, NoMark, Function *, function) \
- Member(class, NoMark, VTable::Call, jsCall) \
- Member(class, NoMark, VTable::CallAsConstructor, jsConstruct) \
- Member(class, NoMark, VTable::CallWithMetaTypes, jsCallWithMetaTypes) \
- Member(class, NoMark, bool, canBeTailCalled)
+namespace Heap {
+#define FunctionObjectMembers(class, Member)
DECLARE_HEAP_OBJECT(FunctionObject, Object) {
- DECLARE_MARKOBJECTS(FunctionObject)
enum {
Index_ProtoConstructor = 0,
Index_Prototype = 0,
Index_HasInstance = 1,
};
- bool isConstructor() const {
- return jsConstruct != nullptr;
- }
-
- Q_QML_EXPORT void init(
- QV4::ExecutionContext *scope, QV4::String *name,
- VTable::Call call, VTable::CallWithMetaTypes callWithMetaTypes = nullptr);
- Q_QML_EXPORT void init(QV4::ExecutionContext *scope, QV4::String *name = nullptr);
- Q_QML_EXPORT void init(QV4::ExecutionContext *scope, QV4::Function *function, QV4::String *n = nullptr);
- Q_QML_EXPORT void init(QV4::ExecutionContext *scope, const QString &name);
+ Q_QML_EXPORT void init(QV4::ExecutionEngine *engine, QV4::String *name = nullptr);
+ Q_QML_EXPORT void init(QV4::ExecutionEngine *engine, const QString &name);
Q_QML_EXPORT void init();
+};
+
+#define JavaScriptFunctionObjectMembers(class, Member) \
+ Member(class, Pointer, ExecutionContext *, scope) \
+ Member(class, NoMark, Function *, function)
+
+DECLARE_HEAP_OBJECT(JavaScriptFunctionObject, FunctionObject) {
+ DECLARE_MARKOBJECTS(JavaScriptFunctionObject)
+
+ void init(QV4::ExecutionContext *scope, QV4::Function *function, QV4::String *n = nullptr);
Q_QML_EXPORT void destroy();
void setFunction(Function *f);
@@ -66,8 +71,18 @@ DECLARE_HEAP_OBJECT(FunctionObject, Object) {
unsigned int varCount() { return function ? function->compiledFunction->nLocals : 0; }
};
+#define DynamicFunctionObjectMembers(class, Member) \
+ Member(class, NoMark, VTable::Call, jsCall)
+
+DECLARE_HEAP_OBJECT(DynamicFunctionObject, FunctionObject) {
+ // NB: We might add a CallWithMetaTypes member to this struct and implement our
+ // builtins with metatypes, to be called from C++ code. This would make them
+ // available to qmlcachegen's C++ code generation.
+ void init(ExecutionEngine *engine, QV4::String *name, VTable::Call call);
+};
+
struct FunctionCtor : FunctionObject {
- void init(QV4::ExecutionContext *scope);
+ void init(QV4::ExecutionEngine *engine);
};
struct FunctionPrototype : FunctionObject {
@@ -76,12 +91,12 @@ struct FunctionPrototype : FunctionObject {
// A function object with an additional index into a list.
// Used by Models to refer to property roles.
-struct IndexedBuiltinFunction : FunctionObject {
- inline void init(QV4::ExecutionContext *scope, qsizetype index, VTable::Call call);
+struct IndexedBuiltinFunction : DynamicFunctionObject {
+ inline void init(QV4::ExecutionEngine *engine, qsizetype index, VTable::Call call);
qsizetype index;
};
-struct ArrowFunction : FunctionObject {
+struct ArrowFunction : JavaScriptFunctionObject {
enum {
Index_Name = Index_HasInstance + 1,
Index_Length
@@ -116,9 +131,15 @@ DECLARE_HEAP_OBJECT(ConstructorFunction, ScriptFunction) {
bool isDerivedConstructor;
};
-struct DefaultClassConstructorFunction : FunctionObject
-{
+#define DefaultClassConstructorFunctionMembers(class, Member) \
+ Member(class, Pointer, ExecutionContext *, scope)
+
+DECLARE_HEAP_OBJECT(DefaultClassConstructorFunction, FunctionObject) {
+ DECLARE_MARKOBJECTS(DefaultClassConstructorFunction)
+
bool isDerivedConstructor;
+
+ void init(QV4::ExecutionContext *scope);
};
#define BoundFunctionMembers(class, Member) \
@@ -126,66 +147,72 @@ struct DefaultClassConstructorFunction : FunctionObject
Member(class, HeapValue, HeapValue, boundThis) \
Member(class, Pointer, MemberData *, boundArgs)
-DECLARE_HEAP_OBJECT(BoundFunction, FunctionObject) {
+DECLARE_HEAP_OBJECT(BoundFunction, JavaScriptFunctionObject) {
DECLARE_MARKOBJECTS(BoundFunction)
- void init(QV4::ExecutionContext *scope, QV4::FunctionObject *target, const Value &boundThis, QV4::MemberData *boundArgs);
+ void init(QV4::FunctionObject *target, const Value &boundThis, QV4::MemberData *boundArgs);
};
+struct BoundConstructor : BoundFunction {};
+
}
struct Q_QML_EXPORT FunctionObject: Object {
- enum {
- IsFunctionObject = true
- };
V4_OBJECT2(FunctionObject, Object)
Q_MANAGED_TYPE(FunctionObject)
V4_INTERNALCLASS(FunctionObject)
V4_PROTOTYPE(functionPrototype)
- V4_NEEDS_DESTROY
enum { NInlineProperties = 1 };
- bool canBeTailCalled() const { return d()->canBeTailCalled; }
- Heap::ExecutionContext *scope() const { return d()->scope; }
- Function *function() const { return d()->function; }
+ bool canBeTailCalled() const { return vtable()->isTailCallable; }
ReturnedValue name() const;
- unsigned int formalParameterCount() const { return d()->formalParameterCount(); }
- unsigned int varCount() const { return d()->varCount(); }
void setName(String *name) {
defineReadonlyConfigurableProperty(engine()->id_name(), *name);
}
void createDefaultPrototypeProperty(uint protoConstructorSlot);
- inline ReturnedValue callAsConstructor(const JSCallData &data) const;
- ReturnedValue callAsConstructor(const Value *argv, int argc, const Value *newTarget = nullptr) const {
- if (!d()->jsConstruct)
- return engine()->throwTypeError(QStringLiteral("Function is not a constructor."));
- return d()->jsConstruct(this, argv, argc, newTarget ? newTarget : this);
+ ReturnedValue callAsConstructor(
+ const Value *argv, int argc, const Value *newTarget = nullptr) const
+ {
+ if (const auto callAsConstructor = vtable()->callAsConstructor)
+ return callAsConstructor(this, argv, argc, newTarget ? newTarget : this);
+ return failCallAsConstructor();
}
- inline ReturnedValue call(const JSCallData &data) const;
- ReturnedValue call(const Value *thisObject, const Value *argv, int argc) const {
- if (!d()->jsCall)
- return engine()->throwTypeError(QStringLiteral("Function can only be called with |new|."));
- return d()->jsCall(this, thisObject, argv, argc);
+
+ ReturnedValue call(const Value *thisObject, const Value *argv, int argc) const
+ {
+ if (const auto call = vtable()->call)
+ return call(this, thisObject, argv, argc);
+ return failCall();
}
- static ReturnedValue virtualCall(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
- void call(QObject *thisObject, void **a, const QMetaType *types, int argc);
- static void virtualCallWithMetaTypes(const FunctionObject *f, QObject *thisObject,
- void **a, const QMetaType *types, int argc);
+
+ void call(QObject *thisObject, void **argv, const QMetaType *types, int argc) const
+ {
+ if (const auto callWithMetaTypes = vtable()->callWithMetaTypes)
+ callWithMetaTypes(this, thisObject, argv, types, argc);
+ else
+ failCall();
+ }
+
+ inline ReturnedValue callAsConstructor(const JSCallData &data) const;
+ inline ReturnedValue call(const JSCallData &data) const;
+
+ ReturnedValue failCall() const;
+ ReturnedValue failCallAsConstructor() const;
+ static void virtualConvertAndCall(
+ const FunctionObject *f, QObject *thisObject,
+ void **argv, const QMetaType *types, int argc);
static Heap::FunctionObject *createScriptFunction(ExecutionContext *scope, Function *function);
static Heap::FunctionObject *createConstructorFunction(ExecutionContext *scope, Function *function, Object *homeObject, bool isDerivedConstructor);
static Heap::FunctionObject *createMemberFunction(ExecutionContext *scope, Function *function, Object *homeObject, String *name);
static Heap::FunctionObject *createBuiltinFunction(ExecutionEngine *engine, StringOrSymbol *nameOrSymbol, VTable::Call code, int argumentCount);
- bool strictMode() const { return d()->function ? d()->function->isStrict() : false; }
bool isBinding() const;
bool isBoundFunction() const;
- bool isConstructor() const {
- return d()->isConstructor();
- }
+ bool isConstructor() const { return vtable()->callAsConstructor; }
ReturnedValue getHomeObject() const;
@@ -195,15 +222,40 @@ struct Q_QML_EXPORT FunctionObject: Object {
bool hasHasInstanceProperty() const {
return !internalClass()->propertyData.at(Heap::FunctionObject::Index_HasInstance).isEmpty();
}
-
- QQmlSourceLocation sourceLocation() const;
};
template<>
inline const FunctionObject *Value::as() const {
- return isManaged() && m()->internalClass->vtable->isFunctionObject ? reinterpret_cast<const FunctionObject *>(this) : nullptr;
+ if (!isManaged())
+ return nullptr;
+
+ const VTable *vtable = m()->internalClass->vtable;
+ return (vtable->call || vtable->callAsConstructor)
+ ? reinterpret_cast<const FunctionObject *>(this)
+ : nullptr;
}
+struct Q_QML_EXPORT JavaScriptFunctionObject: FunctionObject
+{
+ V4_OBJECT2(JavaScriptFunctionObject, FunctionObject)
+ V4_NEEDS_DESTROY
+
+ Heap::ExecutionContext *scope() const { return d()->scope; }
+
+ Function *function() const { return d()->function; }
+ unsigned int formalParameterCount() const { return d()->formalParameterCount(); }
+ unsigned int varCount() const { return d()->varCount(); }
+ bool strictMode() const { return d()->function ? d()->function->isStrict() : false; }
+ QQmlSourceLocation sourceLocation() const;
+};
+
+struct Q_QML_EXPORT DynamicFunctionObject: FunctionObject
+{
+ V4_OBJECT2(DynamicFunctionObject, FunctionObject)
+
+ static ReturnedValue virtualCall(
+ const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
+};
struct FunctionCtor: FunctionObject
{
@@ -225,6 +277,9 @@ struct FunctionPrototype: FunctionObject
void init(ExecutionEngine *engine, Object *ctor);
+ static ReturnedValue virtualCall(
+ const FunctionObject *f, 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_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);
@@ -232,23 +287,26 @@ struct FunctionPrototype: FunctionObject
static ReturnedValue method_hasInstance(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
};
-struct Q_QML_EXPORT IndexedBuiltinFunction : FunctionObject
+struct Q_QML_EXPORT IndexedBuiltinFunction : DynamicFunctionObject
{
- V4_OBJECT2(IndexedBuiltinFunction, FunctionObject)
+ V4_OBJECT2(IndexedBuiltinFunction, DynamicFunctionObject)
};
void Heap::IndexedBuiltinFunction::init(
- QV4::ExecutionContext *scope, qsizetype index, VTable::Call call)
+ QV4::ExecutionEngine *engine, qsizetype index, VTable::Call call)
{
- Heap::FunctionObject::init(scope);
+ Heap::FunctionObject::init(engine);
this->jsCall = call;
this->index = index;
}
-struct ArrowFunction : FunctionObject {
- V4_OBJECT2(ArrowFunction, FunctionObject)
+struct ArrowFunction : JavaScriptFunctionObject {
+ V4_OBJECT2(ArrowFunction, JavaScriptFunctionObject)
V4_INTERNALCLASS(ArrowFunction)
- enum { NInlineProperties = 3 };
+ enum {
+ NInlineProperties = 3,
+ IsTailCallable = true,
+ };
static void virtualCallWithMetaTypes(const FunctionObject *f, QObject *thisObject,
void **a, const QMetaType *types, int argc);
@@ -279,29 +337,33 @@ struct ConstructorFunction : ScriptFunction {
struct DefaultClassConstructorFunction : FunctionObject {
V4_OBJECT2(DefaultClassConstructorFunction, FunctionObject)
+
+ Heap::ExecutionContext *scope() const { return d()->scope; }
static ReturnedValue virtualCallAsConstructor(const FunctionObject *, const Value *argv, int argc, const Value *);
static ReturnedValue virtualCall(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
};
-struct BoundFunction: FunctionObject {
- V4_OBJECT2(BoundFunction, FunctionObject)
-
- static Heap::BoundFunction *create(ExecutionContext *scope, FunctionObject *target, const Value &boundThis, QV4::MemberData *boundArgs)
- {
- return scope->engine()->memoryManager->allocate<BoundFunction>(scope, target, boundThis, boundArgs);
- }
+struct BoundFunction: JavaScriptFunctionObject {
+ V4_OBJECT2(BoundFunction, JavaScriptFunctionObject)
Heap::FunctionObject *target() const { return d()->target; }
Value boundThis() const { return d()->boundThis; }
Heap::MemberData *boundArgs() const { return d()->boundArgs; }
- static ReturnedValue virtualCallAsConstructor(const FunctionObject *, const Value *argv, int argc, const Value *);
static ReturnedValue virtualCall(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
};
+struct BoundConstructor: BoundFunction {
+ V4_OBJECT2(BoundConstructor, BoundFunction)
+
+ static ReturnedValue virtualCallAsConstructor(
+ const FunctionObject *f, const Value *argv, int argc, const Value *);
+};
+
inline bool FunctionObject::isBoundFunction() const
{
- return d()->vtable() == BoundFunction::staticVTable();
+ const VTable *vtable = d()->vtable();
+ return vtable == BoundFunction::staticVTable() || vtable == BoundConstructor::staticVTable();
}
inline ReturnedValue checkedResult(QV4::ExecutionEngine *v4, ReturnedValue result)
diff --git a/src/qml/jsruntime/qv4generatorobject.cpp b/src/qml/jsruntime/qv4generatorobject.cpp
index e7a63ba185..f2d7dffde5 100644
--- a/src/qml/jsruntime/qv4generatorobject.cpp
+++ b/src/qml/jsruntime/qv4generatorobject.cpp
@@ -13,9 +13,9 @@ DEFINE_OBJECT_VTABLE(GeneratorFunctionCtor);
DEFINE_OBJECT_VTABLE(GeneratorFunction);
DEFINE_OBJECT_VTABLE(GeneratorObject);
-void Heap::GeneratorFunctionCtor::init(QV4::ExecutionContext *scope)
+void Heap::GeneratorFunctionCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("GeneratorFunction"));
+ Heap::FunctionObject::init(engine, QStringLiteral("GeneratorFunction"));
}
ReturnedValue GeneratorFunctionCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
diff --git a/src/qml/jsruntime/qv4generatorobject_p.h b/src/qml/jsruntime/qv4generatorobject_p.h
index 55ccc133aa..cb2c1962c5 100644
--- a/src/qml/jsruntime/qv4generatorobject_p.h
+++ b/src/qml/jsruntime/qv4generatorobject_p.h
@@ -33,7 +33,7 @@ enum class GeneratorState {
namespace Heap {
struct GeneratorFunctionCtor : FunctionObject {
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
};
struct GeneratorFunction : ArrowFunction {
diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h
index d15fb356c4..e3fc0ac1b3 100644
--- a/src/qml/jsruntime/qv4global_p.h
+++ b/src/qml/jsruntime/qv4global_p.h
@@ -80,6 +80,7 @@ namespace Heap {
struct ArrayObject;
struct DateObject;
struct FunctionObject;
+ struct JavaScriptFunctionObject;
struct ErrorObject;
struct ArgumentsObject;
struct QObjectWrapper;
diff --git a/src/qml/jsruntime/qv4globalobject.cpp b/src/qml/jsruntime/qv4globalobject.cpp
index 37548ffc9f..989de0de23 100644
--- a/src/qml/jsruntime/qv4globalobject.cpp
+++ b/src/qml/jsruntime/qv4globalobject.cpp
@@ -290,10 +290,10 @@ static QString decode(const QString &input, DecodeMode decodeMode, bool *ok)
DEFINE_OBJECT_VTABLE(EvalFunction);
-void Heap::EvalFunction::init(QV4::ExecutionContext *scope)
+void Heap::EvalFunction::init(QV4::ExecutionEngine *engine)
{
- Scope s(scope);
- Heap::FunctionObject::init(scope, s.engine->id_eval());
+ Scope s(engine);
+ Heap::FunctionObject::init(engine, s.engine->id_eval());
ScopedFunctionObject f(s, this);
f->defineReadonlyConfigurableProperty(s.engine->id_length(), Value::fromInt32(1));
}
diff --git a/src/qml/jsruntime/qv4globalobject_p.h b/src/qml/jsruntime/qv4globalobject_p.h
index 71e06ef417..fd23d71332 100644
--- a/src/qml/jsruntime/qv4globalobject_p.h
+++ b/src/qml/jsruntime/qv4globalobject_p.h
@@ -24,7 +24,7 @@ namespace QV4 {
namespace Heap {
struct EvalFunction : FunctionObject {
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
};
}
diff --git a/src/qml/jsruntime/qv4jscall_p.h b/src/qml/jsruntime/qv4jscall_p.h
index ed1ca983ad..43776e4b62 100644
--- a/src/qml/jsruntime/qv4jscall_p.h
+++ b/src/qml/jsruntime/qv4jscall_p.h
@@ -14,20 +14,17 @@
// We mean it.
//
-#include <private/qqmlengine_p.h>
#include <private/qqmllistwrapper_p.h>
-#include <private/qqmlvaluetype_p.h>
#include <private/qqmlvaluetypewrapper_p.h>
+
#include <private/qv4alloca_p.h>
-#include <private/qv4context_p.h>
#include <private/qv4dateobject_p.h>
#include <private/qv4function_p.h>
#include <private/qv4functionobject_p.h>
-#include <private/qv4object_p.h>
#include <private/qv4qobjectwrapper_p.h>
#include <private/qv4regexpobject_p.h>
#include <private/qv4scopedvalue_p.h>
-#include <private/qv4stackframe_p.h>
+#include <private/qv4sequenceobject_p.h>
#include <private/qv4urlobject_p.h>
#include <private/qv4variantobject_p.h>
diff --git a/src/qml/jsruntime/qv4managed_p.h b/src/qml/jsruntime/qv4managed_p.h
index c5f5fbff8e..aeac8c4914 100644
--- a/src/qml/jsruntime/qv4managed_p.h
+++ b/src/qml/jsruntime/qv4managed_p.h
@@ -77,7 +77,7 @@ struct Q_QML_EXPORT Managed : Value, VTableBase
IsString = false,
IsStringOrSymbol = false,
IsObject = false,
- IsFunctionObject = false,
+ IsTailCallable = false,
IsErrorObject = false,
IsArrayData = false
};
diff --git a/src/qml/jsruntime/qv4mapobject.cpp b/src/qml/jsruntime/qv4mapobject.cpp
index 4bb9617b93..b927efd685 100644
--- a/src/qml/jsruntime/qv4mapobject.cpp
+++ b/src/qml/jsruntime/qv4mapobject.cpp
@@ -12,14 +12,14 @@ DEFINE_OBJECT_VTABLE(WeakMapCtor);
DEFINE_OBJECT_VTABLE(MapCtor);
DEFINE_OBJECT_VTABLE(MapObject);
-void Heap::WeakMapCtor::init(QV4::ExecutionContext *scope)
+void Heap::WeakMapCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("WeakMap"));
+ Heap::FunctionObject::init(engine, QStringLiteral("WeakMap"));
}
-void Heap::MapCtor::init(QV4::ExecutionContext *scope)
+void Heap::MapCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("Map"));
+ Heap::FunctionObject::init(engine, QStringLiteral("Map"));
}
ReturnedValue WeakMapCtor::construct(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget, bool weakMap)
diff --git a/src/qml/jsruntime/qv4mapobject_p.h b/src/qml/jsruntime/qv4mapobject_p.h
index 68bc7ceed8..b5eeb68b0c 100644
--- a/src/qml/jsruntime/qv4mapobject_p.h
+++ b/src/qml/jsruntime/qv4mapobject_p.h
@@ -27,11 +27,11 @@ class ESTable;
namespace Heap {
struct WeakMapCtor : FunctionObject {
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
};
struct MapCtor : WeakMapCtor {
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
};
struct MapObject : Object {
diff --git a/src/qml/jsruntime/qv4numberobject.cpp b/src/qml/jsruntime/qv4numberobject.cpp
index d744e569f5..5299a2568a 100644
--- a/src/qml/jsruntime/qv4numberobject.cpp
+++ b/src/qml/jsruntime/qv4numberobject.cpp
@@ -36,9 +36,9 @@ const NumberLocale *NumberLocale::instance()
return numberLocaleHolder();
}
-void Heap::NumberCtor::init(QV4::ExecutionContext *scope)
+void Heap::NumberCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("Number"));
+ Heap::FunctionObject::init(engine, QStringLiteral("Number"));
}
ReturnedValue NumberCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
diff --git a/src/qml/jsruntime/qv4numberobject_p.h b/src/qml/jsruntime/qv4numberobject_p.h
index 8ac2bd1f79..3f0d6d9425 100644
--- a/src/qml/jsruntime/qv4numberobject_p.h
+++ b/src/qml/jsruntime/qv4numberobject_p.h
@@ -25,7 +25,7 @@ namespace QV4 {
namespace Heap {
struct NumberCtor : FunctionObject {
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
};
}
diff --git a/src/qml/jsruntime/qv4objectproto.cpp b/src/qml/jsruntime/qv4objectproto.cpp
index e7f96a12ba..2a78bb4540 100644
--- a/src/qml/jsruntime/qv4objectproto.cpp
+++ b/src/qml/jsruntime/qv4objectproto.cpp
@@ -19,9 +19,9 @@ using namespace QV4;
DEFINE_OBJECT_VTABLE(ObjectCtor);
-void Heap::ObjectCtor::init(QV4::ExecutionContext *scope)
+void Heap::ObjectCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("Object"));
+ Heap::FunctionObject::init(engine, QStringLiteral("Object"));
}
ReturnedValue ObjectCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
diff --git a/src/qml/jsruntime/qv4objectproto_p.h b/src/qml/jsruntime/qv4objectproto_p.h
index d152bfd175..d74cd64926 100644
--- a/src/qml/jsruntime/qv4objectproto_p.h
+++ b/src/qml/jsruntime/qv4objectproto_p.h
@@ -25,7 +25,7 @@ namespace QV4 {
namespace Heap {
struct ObjectCtor : FunctionObject {
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
};
}
diff --git a/src/qml/jsruntime/qv4promiseobject.cpp b/src/qml/jsruntime/qv4promiseobject.cpp
index 16cffea124..b8ede3e578 100644
--- a/src/qml/jsruntime/qv4promiseobject.cpp
+++ b/src/qml/jsruntime/qv4promiseobject.cpp
@@ -314,9 +314,9 @@ void Heap::PromiseReaction::triggerWithValue(ExecutionEngine *e, const Value *va
handler->addReaction(e, reaction, value);
}
-void Heap::PromiseCtor::init(QV4::ExecutionContext *scope)
+void Heap::PromiseCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("Promise"));
+ Heap::FunctionObject::init(engine, QStringLiteral("Promise"));
}
void Heap::PromiseObject::init(ExecutionEngine *e)
diff --git a/src/qml/jsruntime/qv4promiseobject_p.h b/src/qml/jsruntime/qv4promiseobject_p.h
index ca31f00881..fbde9f95e0 100644
--- a/src/qml/jsruntime/qv4promiseobject_p.h
+++ b/src/qml/jsruntime/qv4promiseobject_p.h
@@ -50,7 +50,7 @@ protected:
namespace Heap {
struct PromiseCtor : FunctionObject {
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
};
#define PromiseObjectMembers(class, Member) \
diff --git a/src/qml/jsruntime/qv4proxy.cpp b/src/qml/jsruntime/qv4proxy.cpp
index 109ab61059..974788d420 100644
--- a/src/qml/jsruntime/qv4proxy.cpp
+++ b/src/qml/jsruntime/qv4proxy.cpp
@@ -13,6 +13,7 @@ using namespace QV4;
DEFINE_OBJECT_VTABLE(ProxyObject);
DEFINE_OBJECT_VTABLE(ProxyFunctionObject);
+DEFINE_OBJECT_VTABLE(ProxyConstructorObject);
void Heap::ProxyObject::init(const QV4::Object *target, const QV4::Object *handler)
{
@@ -25,12 +26,9 @@ void Heap::ProxyObject::init(const QV4::Object *target, const QV4::Object *handl
void Heap::ProxyFunctionObject::init(const QV4::FunctionObject *target, const QV4::Object *handler)
{
ExecutionEngine *e = internalClass->engine;
- FunctionObject::init(e->rootContext());
+ FunctionObject::init(e);
this->target.set(e, target->d());
this->handler.set(e, handler->d());
-
- if (!target->isConstructor())
- jsConstruct = nullptr;
}
@@ -643,7 +641,8 @@ OwnPropertyKeyIterator *ProxyObject::virtualOwnPropertyKeys(const Object *m, Val
}
-ReturnedValue ProxyFunctionObject::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
+ReturnedValue ProxyConstructorObject::virtualCallAsConstructor(
+ const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
{
Scope scope(f);
const ProxyObject *o = static_cast<const ProxyObject *>(f);
@@ -658,10 +657,8 @@ ReturnedValue ProxyFunctionObject::virtualCallAsConstructor(const FunctionObject
if (scope.hasException())
return Encode::undefined();
- if (trap->isNullOrUndefined()) {
- Q_ASSERT(target->isConstructor());
+ if (trap->isNullOrUndefined())
return target->callAsConstructor(argv, argc, newTarget);
- }
if (!trap->isFunctionObject())
return scope.engine->throwTypeError();
@@ -708,11 +705,11 @@ ReturnedValue ProxyFunctionObject::virtualCall(const FunctionObject *f, const Va
DEFINE_OBJECT_VTABLE(Proxy);
-void Heap::Proxy::init(QV4::ExecutionContext *ctx)
+void Heap::Proxy::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(ctx, QStringLiteral("Proxy"));
+ Heap::FunctionObject::init(engine, QStringLiteral("Proxy"));
- Scope scope(ctx);
+ Scope scope(engine);
Scoped<QV4::Proxy> ctor(scope, this);
ctor->defineDefaultProperty(QStringLiteral("revocable"), QV4::Proxy::method_revocable, 2);
ctor->defineReadonlyConfigurableProperty(scope.engine->id_length(), Value::fromInt32(2));
@@ -734,9 +731,18 @@ ReturnedValue Proxy::virtualCallAsConstructor(const FunctionObject *f, const Val
return scope.engine->throwTypeError();
const FunctionObject *targetFunction = target->as<FunctionObject>();
- if (targetFunction)
- return scope.engine->memoryManager->allocate<ProxyFunctionObject>(targetFunction, handler)->asReturnedValue();
- return scope.engine->memoryManager->allocate<ProxyObject>(target, handler)->asReturnedValue();
+ if (!targetFunction) {
+ return scope.engine->memoryManager->allocate<ProxyObject>(target, handler)
+ ->asReturnedValue();
+ }
+
+ if (targetFunction->isConstructor()) {
+ return scope.engine->memoryManager->allocate<ProxyConstructorObject>(
+ targetFunction, handler)->asReturnedValue();
+ }
+
+ return scope.engine->memoryManager->allocate<ProxyFunctionObject>(targetFunction, handler)
+ ->asReturnedValue();
}
ReturnedValue Proxy::virtualCall(const FunctionObject *f, const Value *, const Value *, int)
@@ -753,7 +759,10 @@ ReturnedValue Proxy::method_revocable(const FunctionObject *f, const Value *, co
Q_ASSERT(proxy);
ScopedString revoke(scope, scope.engine->newString(QStringLiteral("revoke")));
- ScopedFunctionObject revoker(scope, scope.engine->memoryManager->allocate<FunctionObject>(scope.engine->rootContext(), nullptr, method_revoke));
+ ScopedFunctionObject revoker(
+ scope,
+ scope.engine->memoryManager->allocate<DynamicFunctionObject>(
+ scope.engine, nullptr, method_revoke));
revoker->defineReadonlyConfigurableProperty(scope.engine->id_length(), Value::fromInt32(0));
revoker->defineDefaultProperty(scope.engine->symbol_revokableProxy(), proxy);
diff --git a/src/qml/jsruntime/qv4proxy_p.h b/src/qml/jsruntime/qv4proxy_p.h
index b3be05a11b..b3ce9c7a96 100644
--- a/src/qml/jsruntime/qv4proxy_p.h
+++ b/src/qml/jsruntime/qv4proxy_p.h
@@ -37,13 +37,15 @@ struct ProxyFunctionObject : ProxyObject {
void init(const QV4::FunctionObject *target, const QV4::Object *handler);
};
+struct ProxyConstructorObject : ProxyFunctionObject {};
+
#define ProxyMembers(class, Member) \
Member(class, Pointer, Symbol *, revokableProxySymbol) \
DECLARE_HEAP_OBJECT(Proxy, FunctionObject) {
DECLARE_MARKOBJECTS(Proxy)
- void init(QV4::ExecutionContext *ctx);
+ void init(ExecutionEngine *engine);
};
}
@@ -60,9 +62,6 @@ struct ProxyObject : FunctionObject {
V4_OBJECT2(ProxyObject, Object)
Q_MANAGED_TYPE(ProxyObject)
V4_INTERNALCLASS(ProxyObject)
- enum {
- IsFunctionObject = false
- };
static ReturnedValue virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty);
static bool virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver);
@@ -81,14 +80,16 @@ struct ProxyFunctionObject : ProxyObject {
V4_OBJECT2(ProxyFunctionObject, FunctionObject)
Q_MANAGED_TYPE(ProxyObject)
V4_INTERNALCLASS(ProxyFunctionObject)
- enum {
- IsFunctionObject = true
- };
- static ReturnedValue virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *);
static ReturnedValue virtualCall(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
};
+struct ProxyConstructorObject : ProxyFunctionObject {
+ V4_OBJECT2(ProxyConstructorObject, ProxyFunctionObject)
+
+ static ReturnedValue virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *);
+};
+
struct Proxy : FunctionObject
{
V4_OBJECT2(Proxy, FunctionObject)
diff --git a/src/qml/jsruntime/qv4qmetaobjectwrapper.cpp b/src/qml/jsruntime/qv4qmetaobjectwrapper.cpp
index 13d93c7122..6521c98dbf 100644
--- a/src/qml/jsruntime/qv4qmetaobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qmetaobjectwrapper.cpp
@@ -16,38 +16,15 @@ namespace QV4 {
void Heap::QMetaObjectWrapper::init(const QMetaObject *metaObject)
{
FunctionObject::init();
- this->metaObject = metaObject;
- constructors = nullptr;
- constructorCount = 0;
+ m_metaObject = metaObject;
}
void Heap::QMetaObjectWrapper::destroy()
{
- delete[] constructors;
+ delete[] m_constructors;
+ FunctionObject::destroy();
}
-void Heap::QMetaObjectWrapper::ensureConstructorsCache() {
-
- const int count = metaObject->constructorCount();
- if (constructorCount != count) {
- delete[] constructors;
- constructorCount = count;
- if (count == 0) {
- constructors = nullptr;
- return;
- }
- constructors = new QQmlPropertyData[count];
-
- for (int i = 0; i < count; ++i) {
- QMetaMethod method = metaObject->constructor(i);
- QQmlPropertyData &d = constructors[i];
- d.load(method);
- d.setCoreIndex(i);
- }
- }
-}
-
-
ReturnedValue QMetaObjectWrapper::create(ExecutionEngine *engine, const QMetaObject* metaObject) {
Scope scope(engine);
@@ -57,7 +34,7 @@ ReturnedValue QMetaObjectWrapper::create(ExecutionEngine *engine, const QMetaObj
}
void QMetaObjectWrapper::init(ExecutionEngine *) {
- const QMetaObject & mo = *d()->metaObject;
+ const QMetaObject &mo = *d()->metaObject();
for (int i = 0; i < mo.enumeratorCount(); i++) {
QMetaEnum Enum = mo.enumerator(i);
@@ -71,41 +48,49 @@ void QMetaObjectWrapper::init(ExecutionEngine *) {
ReturnedValue QMetaObjectWrapper::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *)
{
- const QMetaObjectWrapper *This = static_cast<const QMetaObjectWrapper*>(f);
- return This->constructInternal(argv, argc);
+ Q_ASSERT(f->as<QMetaObjectWrapper>());
+ return construct(static_cast<const QMetaObjectWrapper*>(f)->d(), argv, argc);
}
-ReturnedValue QMetaObjectWrapper::constructInternal(const Value *argv, int argc) const
+ReturnedValue QMetaObjectWrapper::constructInternal(
+ const QMetaObject *mo, const QQmlPropertyData *constructors, Heap::FunctionObject *d,
+ const Value *argv, int argc)
{
+ ExecutionEngine *v4 = d->internalClass->engine;
- d()->ensureConstructorsCache();
-
- ExecutionEngine *v4 = engine();
- const QMetaObject* mo = d()->metaObject;
- if (d()->constructorCount == 0) {
+ if (!constructors) {
return v4->throwTypeError(QLatin1String(mo->className())
+ QLatin1String(" has no invokable constructor"));
}
Scope scope(v4);
- Scoped<QObjectWrapper> object(scope);
+ ScopedObject object(scope);
JSCallData cData(nullptr, argv, argc);
CallData *callData = cData.callData(scope);
const QQmlObjectOrGadget objectOrGadget(mo);
- if (d()->constructorCount == 1) {
+ const auto callType = [](QMetaType metaType) {
+ return metaType.flags() & QMetaType::PointerToQObject
+ ? QMetaObject::CreateInstance
+ : QMetaObject::ConstructInPlace;
+ };
+
+ const int constructorCount = mo->constructorCount();
+ if (constructorCount == 1) {
object = QObjectMethod::callPrecise(
- objectOrGadget, d()->constructors[0], v4, callData, QMetaObject::CreateInstance);
+ objectOrGadget, constructors[0], v4, callData,
+ callType(constructors[0].propType()));
} else if (const QQmlPropertyData *ctor = QObjectMethod::resolveOverloaded(
- objectOrGadget, d()->constructors, d()->constructorCount, v4, callData)) {
+ objectOrGadget, constructors, constructorCount, v4, callData)) {
object = QObjectMethod::callPrecise(
- objectOrGadget, *ctor, v4, callData, QMetaObject::CreateInstance);
+ objectOrGadget, *ctor, v4, callData, callType(ctor->propType()));
}
+
if (object) {
- Scoped<QMetaObjectWrapper> metaObject(scope, this);
- object->defineDefaultProperty(v4->id_constructor(), metaObject);
- object->setPrototypeOf(const_cast<QMetaObjectWrapper*>(this));
+ Scoped<FunctionObject> functionObject(scope, d);
+ object->defineDefaultProperty(v4->id_constructor(), functionObject);
+ object->setPrototypeOf(functionObject);
}
return object.asReturnedValue();
diff --git a/src/qml/jsruntime/qv4qmetaobjectwrapper_p.h b/src/qml/jsruntime/qv4qmetaobjectwrapper_p.h
index 063bc089e7..c44b18f291 100644
--- a/src/qml/jsruntime/qv4qmetaobjectwrapper_p.h
+++ b/src/qml/jsruntime/qv4qmetaobjectwrapper_p.h
@@ -27,14 +27,57 @@ class QQmlPropertyData;
namespace QV4 {
namespace Heap {
-struct QMetaObjectWrapper : FunctionObject {
- const QMetaObject* metaObject;
- QQmlPropertyData *constructors;
- int constructorCount;
-
- void init(const QMetaObject* metaObject);
+struct QMetaObjectWrapper : FunctionObject
+{
+ void init(const QMetaObject *metaObject);
void destroy();
- void ensureConstructorsCache();
+
+ const QMetaObject *metaObject() const { return m_metaObject; }
+ QMetaType metaType() const
+ {
+ const QMetaType type = m_metaObject->metaType();
+ if (type.flags() & QMetaType::IsGadget)
+ return type;
+
+ // QObject* is our best guess because we can't get from a metatype to
+ // the metatype of its pointer.
+ return QMetaType::fromType<QObject *>();
+ }
+
+ const QQmlPropertyData *ensureConstructorsCache(
+ const QMetaObject *metaObject, QMetaType metaType)
+ {
+ Q_ASSERT(metaObject);
+ if (!m_constructors)
+ m_constructors = createConstructors(metaObject, metaType);
+ return m_constructors;
+ }
+
+
+ static const QQmlPropertyData *createConstructors(
+ const QMetaObject *metaObject, QMetaType metaType)
+ {
+ Q_ASSERT(metaObject);
+ const int count = metaObject->constructorCount();
+ if (count == 0)
+ return nullptr;
+
+ QQmlPropertyData *constructors = new QQmlPropertyData[count];
+
+ for (int i = 0; i < count; ++i) {
+ QMetaMethod method = metaObject->constructor(i);
+ QQmlPropertyData &d = constructors[i];
+ d.load(method);
+ d.setPropType(metaType);
+ d.setCoreIndex(i);
+ }
+
+ return constructors;
+ }
+
+private:
+ const QMetaObject *m_metaObject;
+ const QQmlPropertyData *m_constructors;
};
} // namespace Heap
@@ -45,7 +88,15 @@ struct Q_QML_EXPORT QMetaObjectWrapper : public FunctionObject
V4_NEEDS_DESTROY
static ReturnedValue create(ExecutionEngine *engine, const QMetaObject* metaObject);
- const QMetaObject *metaObject() const { return d()->metaObject; }
+ const QMetaObject *metaObject() const { return d()->metaObject(); }
+
+ template<typename HeapObject>
+ ReturnedValue static construct(HeapObject *d, const Value *argv, int argc)
+ {
+ const QMetaObject *mo = d->metaObject();
+ return constructInternal(
+ mo, d->ensureConstructorsCache(mo, d->metaType()), d, argv, argc);
+ }
protected:
static ReturnedValue virtualCallAsConstructor(
@@ -54,7 +105,10 @@ protected:
private:
void init(ExecutionEngine *engine);
- ReturnedValue constructInternal(const Value *argv, int argc) const;
+
+ static ReturnedValue constructInternal(
+ const QMetaObject *mo, const QQmlPropertyData *constructors, Heap::FunctionObject *d,
+ const Value *argv, int argc);
};
} // namespace QV4
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index 5f85aae89e..c0e238c273 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -3,58 +3,50 @@
#include "qv4qobjectwrapper_p.h"
-#include <private/qqmlobjectorgadget_p.h>
-#include <private/qqmlengine_p.h>
-#include <private/qqmlvmemetaobject_p.h>
-#include <private/qqmlbinding_p.h>
#include <private/qjsvalue_p.h>
-#include <private/qqmlexpression_p.h>
-#include <private/qqmlglobal_p.h>
+
+#include <private/qqmlbinding_p.h>
+#include <private/qqmlbuiltinfunctions_p.h>
+#include <private/qqmlengine_p.h>
+#include <private/qqmlobjectorgadget_p.h>
+#include <private/qqmlpropertybinding_p.h>
+#include <private/qqmlscriptstring_p.h>
+#include <private/qqmlsignalnames_p.h>
#include <private/qqmltypewrapper_p.h>
#include <private/qqmlvaluetypewrapper_p.h>
-#include <private/qqmllistwrapper_p.h>
-#include <private/qqmlbuiltinfunctions_p.h>
-#if QT_CONFIG(qml_locale)
-#include <private/qqmllocale_p.h>
-#endif
+#include <private/qqmlvmemetaobject_p.h>
#include <private/qv4arraybuffer_p.h>
+#include <private/qv4compileddata_p.h>
+#include <private/qv4dateobject_p.h>
#include <private/qv4functionobject_p.h>
-#include <private/qv4runtime_p.h>
-#include <private/qv4variantobject_p.h>
#include <private/qv4identifiertable_p.h>
-#include <private/qv4lookup_p.h>
-#include <private/qv4qmlcontext_p.h>
-#include <private/qv4sequenceobject_p.h>
-#include <private/qv4objectproto_p.h>
+#include <private/qv4jscall_p.h>
#include <private/qv4jsonobject_p.h>
+#include <private/qv4lookup_p.h>
+#include <private/qv4mm_p.h>
#include <private/qv4regexpobject_p.h>
-#include <private/qv4dateobject_p.h>
+#include <private/qv4runtime_p.h>
#include <private/qv4scopedvalue_p.h>
-#include <private/qv4jscall_p.h>
-#include <private/qv4mm_p.h>
-#include <private/qqmlscriptstring_p.h>
-#include <private/qv4compileddata_p.h>
-#include <private/qqmlpropertybinding_p.h>
-#include <private/qqmlpropertycachemethodarguments_p.h>
-#include <private/qqmlsignalnames_p.h>
+#include <private/qv4sequenceobject_p.h>
+#include <private/qv4variantobject_p.h>
-#include <QtQml/qjsvalue.h>
#include <QtCore/qjsonarray.h>
#include <QtCore/qjsonobject.h>
#include <QtCore/qjsonvalue.h>
-#include <QtCore/qvarlengtharray.h>
-#include <QtCore/qtimer.h>
-#include <QtCore/qatomic.h>
-#include <QtCore/qmetaobject.h>
-#if QT_CONFIG(qml_itemmodel)
-#include <QtCore/qabstractitemmodel.h>
-#endif
#include <QtCore/qloggingcategory.h>
+#include <QtCore/qmetaobject.h>
#include <QtCore/qqueue.h>
+#include <QtCore/qtimer.h>
#include <QtCore/qtypes.h>
+#include <QtCore/qvarlengtharray.h>
#include <vector>
+
+#if QT_CONFIG(qml_itemmodel)
+#include <QtCore/qabstractitemmodel.h>
+#endif
+
QT_BEGIN_NAMESPACE
Q_LOGGING_CATEGORY(lcBindingRemoval, "qt.qml.binding.removal", QtWarningMsg)
@@ -246,11 +238,8 @@ static ReturnedValue loadProperty(
property.readProperty(object, &v);
return QV4::JsonObject::fromJsonObject(v4, v);
}
- case QMetaType::QJsonArray: {
- QJsonArray v;
- property.readProperty(object, &v);
- return QV4::JsonObject::fromJsonArray(v4, v);
- }
+ case QMetaType::QJsonArray:
+ return encodeSequence(QMetaSequence::fromContainer<QJsonArray>());
case QMetaType::QStringList:
return encodeSequence(QMetaSequence::fromContainer<QStringList>());
case QMetaType::QVariantList:
@@ -360,20 +349,15 @@ ReturnedValue QObjectWrapper::getProperty(
Q_ASSERT(vmemo);
return vmemo->vmeMethod(property->coreIndex());
} else if (property->isV4Function()) {
- Scope scope(engine);
- ScopedContext global(scope, engine->qmlContext());
- if (!global)
- global = engine->rootContext();
return QObjectMethod::create(
- global, (flags & AttachMethods) ? wrapper : nullptr, property->coreIndex());
+ engine, (flags & AttachMethods) ? wrapper : nullptr, property->coreIndex());
} else if (property->isSignalHandler()) {
QmlSignalHandler::initProto(engine);
return engine->memoryManager->allocate<QmlSignalHandler>(
object, property->coreIndex())->asReturnedValue();
} else {
- ExecutionContext *global = engine->rootContext();
return QObjectMethod::create(
- global, (flags & AttachMethods) ? wrapper : nullptr, property->coreIndex());
+ engine, (flags & AttachMethods) ? wrapper : nullptr, property->coreIndex());
}
}
@@ -405,8 +389,7 @@ static OptionalReturnedValue getDestroyOrToStringMethod(
if (hasProperty)
*hasProperty = true;
- ExecutionContext *global = v4->rootContext();
- return OptionalReturnedValue(QObjectMethod::create(global, qobj, index));
+ return OptionalReturnedValue(QObjectMethod::create(v4, qobj, index));
}
static OptionalReturnedValue getPropertyFromImports(
@@ -608,7 +591,9 @@ void QObjectWrapper::setProperty(
Scope scope(engine);
if (ScopedFunctionObject f(scope, value); f) {
- if (!f->isBinding()) {
+ if (f->as<QQmlTypeWrapper>()) {
+ // Ignore. It's probably a singleton or an attached type.
+ } else if (!f->isBinding()) {
const bool isAliasToAllowed = [&]() {
if (property->isAlias()) {
const QQmlPropertyIndex originalIndex(property->coreIndex(), -1);
@@ -641,7 +626,7 @@ void QObjectWrapper::setProperty(
QQmlRefPointer<QQmlContextData> callingQmlContext = scope.engine->callingQmlContext();
Scoped<QQmlBindingFunction> bindingFunction(scope, (const Value &)f);
- ScopedFunctionObject f(scope, bindingFunction->bindingFunction());
+ Scoped<JavaScriptFunctionObject> f(scope, bindingFunction->bindingFunction());
ScopedContext ctx(scope, f->scope());
// binding assignment.
@@ -722,7 +707,9 @@ void QObjectWrapper::setProperty(
const QMetaType propType = property->propType();
// functions are already handled, except for the QJSValue case
- Q_ASSERT(!value.as<FunctionObject>() || propType == QMetaType::fromType<QJSValue>());
+ Q_ASSERT(!value.as<FunctionObject>()
+ || value.as<QV4::QQmlTypeWrapper>()
+ || propType == QMetaType::fromType<QJSValue>());
if (value.isNull() && property->isQObject()) {
PROPERTY_STORE(QObject*, nullptr);
@@ -2559,21 +2546,22 @@ ReturnedValue CallArgument::toValue(ExecutionEngine *engine)
return Encode::undefined();
}
-ReturnedValue QObjectMethod::create(ExecutionContext *scope, Heap::Object *wrapper, int index)
+ReturnedValue QObjectMethod::create(ExecutionEngine *engine, Heap::Object *wrapper, int index)
{
- Scope valueScope(scope);
+ Scope valueScope(engine);
Scoped<QObjectMethod> method(
valueScope,
- valueScope.engine->memoryManager->allocate<QObjectMethod>(scope, wrapper, index));
+ engine->memoryManager->allocate<QObjectMethod>(engine, wrapper, index));
return method.asReturnedValue();
}
-ReturnedValue QObjectMethod::create(ExecutionContext *scope, Heap::QQmlValueTypeWrapper *valueType, int index)
+ReturnedValue QObjectMethod::create(
+ ExecutionEngine *engine, Heap::QQmlValueTypeWrapper *valueType, int index)
{
- Scope valueScope(scope);
+ Scope valueScope(engine);
Scoped<QObjectMethod> method(
valueScope,
- valueScope.engine->memoryManager->allocate<QObjectMethod>(scope, valueType, index));
+ engine->memoryManager->allocate<QObjectMethod>(engine, valueType, index));
return method.asReturnedValue();
}
@@ -2596,11 +2584,10 @@ ReturnedValue QObjectMethod::create(
}
}
- Scoped<ExecutionContext> context(valueScope, cloneFrom->scope.get());
Scoped<QObjectMethod> method(
valueScope,
engine->memoryManager->allocate<QV4::QObjectMethod>(
- context, valueTypeWrapper ? valueTypeWrapper->d() : object, cloneFrom->index));
+ engine, valueTypeWrapper ? valueTypeWrapper->d() : object, cloneFrom->index));
method->d()->methodCount = cloneFrom->methodCount;
@@ -2626,10 +2613,10 @@ ReturnedValue QObjectMethod::create(
return method.asReturnedValue();
}
-void Heap::QObjectMethod::init(QV4::ExecutionContext *scope, Object *object, int methodIndex)
+void Heap::QObjectMethod::init(QV4::ExecutionEngine *engine, Object *object, int methodIndex)
{
- Heap::FunctionObject::init(scope);
- wrapper.set(internalClass->engine, object);
+ Heap::FunctionObject::init(engine);
+ wrapper.set(engine, object);
index = methodIndex;
}
@@ -3106,7 +3093,7 @@ ReturnedValue QmlSignalHandler::call(const Value *thisObject, const Value *argv,
Scope scope(engine());
Scoped<QObjectMethod> method(
scope, QObjectMethod::create(
- scope.engine->rootContext(),
+ scope.engine,
static_cast<Heap::QObjectWrapper *>(nullptr),
signalIndex()));
diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h
index 1af8fc887f..288585f844 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper_p.h
+++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h
@@ -72,7 +72,7 @@ DECLARE_EXPORTED_HEAP_OBJECT(QObjectMethod, FunctionObject) {
int methodCount;
int index;
- void init(QV4::ExecutionContext *scope, Object *wrapper, int index);
+ void init(QV4::ExecutionEngine *engine, Object *wrapper, int index);
void destroy()
{
if (methods != reinterpret_cast<const QQmlPropertyData *>(&_singleMethod))
@@ -348,10 +348,11 @@ struct Q_QML_EXPORT QObjectMethod : public QV4::FunctionObject
enum { DestroyMethod = -1, ToStringMethod = -2 };
- static ReturnedValue create(QV4::ExecutionContext *scope, Heap::Object *wrapper, int index);
+ static ReturnedValue create(ExecutionEngine *engine, Heap::Object *wrapper, int index);
static ReturnedValue create(
- QV4::ExecutionContext *scope, Heap::QQmlValueTypeWrapper *valueType, int index);
- static ReturnedValue create(QV4::ExecutionEngine *engine, Heap::QObjectMethod *cloneFrom,
+ ExecutionEngine *engine, Heap::QQmlValueTypeWrapper *valueType, int index);
+ static ReturnedValue create(
+ ExecutionEngine *engine, Heap::QObjectMethod *cloneFrom,
Heap::Object *wrapper, Heap::Object *object);
int methodIndex() const { return d()->index; }
diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp
index acb9f0acfc..144cd39bcd 100644
--- a/src/qml/jsruntime/qv4regexpobject.cpp
+++ b/src/qml/jsruntime/qv4regexpobject.cpp
@@ -195,9 +195,9 @@ ReturnedValue RegExpObject::builtinExec(ExecutionEngine *engine, const String *s
DEFINE_OBJECT_VTABLE(RegExpCtor);
-void Heap::RegExpCtor::init(QV4::ExecutionContext *scope)
+void Heap::RegExpCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("RegExp"));
+ Heap::FunctionObject::init(engine, QStringLiteral("RegExp"));
clearLastMatch();
}
diff --git a/src/qml/jsruntime/qv4regexpobject_p.h b/src/qml/jsruntime/qv4regexpobject_p.h
index 8d52300013..179a01fb45 100644
--- a/src/qml/jsruntime/qv4regexpobject_p.h
+++ b/src/qml/jsruntime/qv4regexpobject_p.h
@@ -50,7 +50,7 @@ DECLARE_HEAP_OBJECT(RegExpObject, Object) {
DECLARE_HEAP_OBJECT(RegExpCtor, FunctionObject) {
DECLARE_MARKOBJECTS(RegExpCtor)
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
void clearLastMatch();
};
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index c51c94ffe4..5977360080 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -41,6 +41,8 @@
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(lcCoercingTypeAssertion, "qt.qml.coercingTypeAssertion");
+
namespace QV4 {
#ifdef QV4_COUNT_RUNTIME_FUNCTIONS
@@ -380,11 +382,42 @@ QV4::ReturnedValue Runtime::As::call(ExecutionEngine *engine, const Value &lval,
else if (result->isBoolean())
return Encode::null();
+ if (engine->callingQmlContext()->valueTypesAreAssertable())
+ return Encode::undefined();
+
// Try to convert the value type
- if (Scoped<QQmlTypeWrapper> typeWrapper(scope, rval); typeWrapper)
- return coerce(engine, lval, typeWrapper->d()->type(), false);
+ Scoped<QQmlTypeWrapper> typeWrapper(scope, rval);
+ if (!typeWrapper)
+ return Encode::undefined();
- return Encode::undefined();
+ const auto *stackFrame = engine->currentStackFrame;
+ if (lval.as<QQmlValueTypeWrapper>()) {
+ qCWarning(lcCoercingTypeAssertion).nospace().noquote()
+ << stackFrame->source() << ':' << stackFrame->lineNumber() << ':'
+ << " Coercing between incompatible value types mistakenly yields null rather than"
+ << " undefined. Add 'pragma ValueTypeBehavior: Assertable' to prevent this.";
+ return Encode::null();
+ }
+
+ if (lval.as<QV4::QObjectWrapper>()) {
+ qCWarning(lcCoercingTypeAssertion).nospace().noquote()
+ << stackFrame->source() << ':' << stackFrame->lineNumber() << ':'
+ << " Coercing from instances of object types to value types mistakenly yields null"
+ << " rather than undefined. Add 'pragma ValueTypeBehavior: Assertable' to prevent"
+ << " this.";
+ return Encode::null();
+ }
+
+ result = coerce(engine, lval, typeWrapper->d()->type(), false);
+ if (result->isUndefined())
+ return Encode::undefined();
+
+ qCWarning(lcCoercingTypeAssertion).nospace().noquote()
+ << stackFrame->source() << ':' << stackFrame->lineNumber() << ':'
+ << " Coercing a value to " << typeWrapper->toQStringNoThrow()
+ << " using a type assertion. This behavior is deprecated."
+ << " Add 'pragma ValueTypeBehavior: Assertable' to prevent it.";
+ return result->asReturnedValue();
}
QV4::ReturnedValue Runtime::In::call(ExecutionEngine *engine, const Value &left, const Value &right)
@@ -1029,7 +1062,7 @@ ReturnedValue Runtime::LoadName::call(ExecutionEngine *engine, int nameIndex)
static Object *getSuperBase(Scope &scope)
{
- ScopedFunctionObject f(scope);
+ Scoped<JavaScriptFunctionObject> f(scope);
ScopedObject homeObject(scope);
if (scope.engine->currentStackFrame->isJSTypesFrame()) {
JSTypesStackFrame *frame = static_cast<JSTypesStackFrame *>(
@@ -1188,7 +1221,7 @@ ReturnedValue Runtime::LoadSuperConstructor::call(ExecutionEngine *engine, const
if (!f)
return engine->throwTypeError();
Heap::Object *c = static_cast<const Object &>(t).getPrototypeOf();
- if (!c->vtable()->isFunctionObject || !static_cast<Heap::FunctionObject *>(c)->isConstructor())
+ if (!c->vtable()->callAsConstructor)
return engine->throwTypeError();
return c->asReturnedValue();
}
@@ -1627,20 +1660,23 @@ ReturnedValue Runtime::TailCall::call(JSTypesStackFrame *frame, ExecutionEngine
int argc = tos[StackOffsets::tailCall_argc].int_32();
Q_ASSERT(argc >= 0);
- if (!function.isFunctionObject())
+ const JavaScriptFunctionObject *jsfo = function.as<JavaScriptFunctionObject>();
+ if (!jsfo) {
+ if (const FunctionObject *fo = function.as<FunctionObject>())
+ return checkedResult(engine, fo->call(&thisObject, argv, argc));
return engine->throwTypeError();
+ }
- const FunctionObject &fo = static_cast<const FunctionObject &>(function);
- if (!frame->callerCanHandleTailCall() || !fo.canBeTailCalled() || engine->debugger()
- || unsigned(argc) > fo.formalParameterCount()) {
+ if (!frame->callerCanHandleTailCall() || !jsfo->canBeTailCalled() || engine->debugger()
+ || unsigned(argc) > jsfo->formalParameterCount()) {
// Cannot tailcall, do a normal call:
- return checkedResult(engine, fo.call(&thisObject, argv, argc));
+ return checkedResult(engine, jsfo->call(&thisObject, argv, argc));
}
memmove(frame->jsFrame->args, argv, argc * sizeof(Value));
- frame->init(fo.function(), frame->jsFrame->argValues<Value>(), argc,
+ frame->init(jsfo->function(), frame->jsFrame->argValues<Value>(), argc,
frame->callerCanHandleTailCall());
- frame->setupJSFrame(frame->framePointer(), fo, fo.scope(), thisObject,
+ frame->setupJSFrame(frame->framePointer(), *jsfo, jsfo->scope(), thisObject,
Primitive::undefinedValue());
engine->jsStackTop = frame->framePointer() + frame->requiredJSStackFrameSize();
frame->setPendingTailCall(true);
diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp
index cc899428c2..cc05e030c5 100644
--- a/src/qml/jsruntime/qv4sequenceobject.cpp
+++ b/src/qml/jsruntime/qv4sequenceobject.cpp
@@ -250,6 +250,42 @@ QVariant Sequence::at(qsizetype index) const
return result;
}
+QVariant Sequence::shift()
+{
+ auto *p = d();
+ void *storage = p->storagePointer();
+ Q_ASSERT(storage); // Must readReference() before
+ const QMetaType v = p->valueMetaType();
+ const QMetaSequence m = p->metaSequence();
+
+ const auto variantData = [&](QVariant *variant) -> void *{
+ if (v == QMetaType::fromType<QVariant>())
+ return variant;
+
+ *variant = QVariant(v);
+ return variant->data();
+ };
+
+ QVariant result;
+ void *resultData = variantData(&result);
+ m.valueAtIndex(storage, 0, resultData);
+
+ if (m.canRemoveValueAtBegin()) {
+ m.removeValueAtBegin(storage);
+ return result;
+ }
+
+ QVariant t;
+ void *tData = variantData(&t);
+ for (qsizetype i = 1, end = m.size(storage); i < end; ++i) {
+ m.valueAtIndex(storage, i, tData);
+ m.setValueAtIndex(storage, i - 1, tData);
+ }
+ m.removeValueAtEnd(storage);
+
+ return result;
+}
+
template<typename Action>
void convertAndDo(const QVariant &item, const QMetaType v, Action action)
@@ -602,6 +638,7 @@ void SequencePrototype::init()
defineDefaultProperty(QStringLiteral("sort"), method_sort, 1);
defineDefaultProperty(engine()->id_valueOf(), method_valueOf, 0);
defineAccessorProperty(QStringLiteral("length"), method_get_length, method_set_length);
+ defineDefaultProperty(QStringLiteral("shift"), method_shift, 0);
}
ReturnedValue SequencePrototype::method_valueOf(const FunctionObject *f, const Value *thisObject, const Value *, int)
@@ -627,6 +664,29 @@ ReturnedValue SequencePrototype::method_sort(const FunctionObject *b, const Valu
return o.asReturnedValue();
}
+ReturnedValue SequencePrototype::method_shift(
+ const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
+{
+ Scope scope(b);
+ Scoped<Sequence> s(scope, thisObject);
+ if (!s)
+ return ArrayPrototype::method_shift(b, thisObject, argv, argc);
+
+ if (s->d()->isReference() && !s->loadReference())
+ RETURN_UNDEFINED();
+
+ const qsizetype len = s->size();
+ if (!len)
+ RETURN_UNDEFINED();
+
+ ScopedValue result(scope, scope.engine->fromVariant(s->shift()));
+
+ if (s->d()->object())
+ s->storeReference();
+
+ return result->asReturnedValue();
+}
+
ReturnedValue SequencePrototype::newSequence(
QV4::ExecutionEngine *engine, QMetaType type, QMetaSequence metaSequence, const void *data,
Heap::Object *object, int propertyIndex, Heap::ReferenceObject::Flags flags)
diff --git a/src/qml/jsruntime/qv4sequenceobject_p.h b/src/qml/jsruntime/qv4sequenceobject_p.h
index 3d1baf6c77..d00d9c8a8c 100644
--- a/src/qml/jsruntime/qv4sequenceobject_p.h
+++ b/src/qml/jsruntime/qv4sequenceobject_p.h
@@ -35,6 +35,7 @@ struct Q_QML_EXPORT SequencePrototype : public QV4::Object
static ReturnedValue method_valueOf(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_sort(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_shift(const FunctionObject *b, const Value *thisObject, const Value *, int);
static ReturnedValue newSequence(
QV4::ExecutionEngine *engine, QMetaType type, QMetaSequence metaSequence, const void *data,
@@ -101,6 +102,7 @@ public:
qsizetype size() const;
QVariant at(qsizetype index) const;
+ QVariant shift();
void append(const QVariant &item);
void append(qsizetype num, const QVariant &item);
void replace(qsizetype index, const QVariant &item);
diff --git a/src/qml/jsruntime/qv4setobject.cpp b/src/qml/jsruntime/qv4setobject.cpp
index a7589a40db..e182015a32 100644
--- a/src/qml/jsruntime/qv4setobject.cpp
+++ b/src/qml/jsruntime/qv4setobject.cpp
@@ -14,14 +14,14 @@ DEFINE_OBJECT_VTABLE(SetCtor);
DEFINE_OBJECT_VTABLE(WeakSetCtor);
DEFINE_OBJECT_VTABLE(SetObject);
-void Heap::WeakSetCtor::init(QV4::ExecutionContext *scope)
+void Heap::WeakSetCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("WeakSet"));
+ Heap::FunctionObject::init(engine, QStringLiteral("WeakSet"));
}
-void Heap::SetCtor::init(QV4::ExecutionContext *scope)
+void Heap::SetCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("Set"));
+ Heap::FunctionObject::init(engine, QStringLiteral("Set"));
}
ReturnedValue WeakSetCtor::construct(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget, bool isWeak)
diff --git a/src/qml/jsruntime/qv4setobject_p.h b/src/qml/jsruntime/qv4setobject_p.h
index 6ed44b4ed9..5aa10f43c8 100644
--- a/src/qml/jsruntime/qv4setobject_p.h
+++ b/src/qml/jsruntime/qv4setobject_p.h
@@ -29,12 +29,12 @@ class ESTable;
namespace Heap {
struct WeakSetCtor : FunctionObject {
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
};
struct SetCtor : WeakSetCtor {
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
};
struct SetObject : Object {
diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp
index ad3c39c7b9..5f3d833f33 100644
--- a/src/qml/jsruntime/qv4stringobject.cpp
+++ b/src/qml/jsruntime/qv4stringobject.cpp
@@ -131,9 +131,9 @@ PropertyAttributes StringObject::virtualGetOwnProperty(const Managed *m, Propert
DEFINE_OBJECT_VTABLE(StringCtor);
-void Heap::StringCtor::init(QV4::ExecutionContext *scope)
+void Heap::StringCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("String"));
+ Heap::FunctionObject::init(engine, QStringLiteral("String"));
}
ReturnedValue StringCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
diff --git a/src/qml/jsruntime/qv4stringobject_p.h b/src/qml/jsruntime/qv4stringobject_p.h
index 451a989ef4..73c2bd7b34 100644
--- a/src/qml/jsruntime/qv4stringobject_p.h
+++ b/src/qml/jsruntime/qv4stringobject_p.h
@@ -44,7 +44,7 @@ DECLARE_HEAP_OBJECT(StringObject, Object) {
};
struct StringCtor : FunctionObject {
- void init(QV4::ExecutionContext *scope);
+ void init(QV4::ExecutionEngine *engine);
};
}
diff --git a/src/qml/jsruntime/qv4symbol.cpp b/src/qml/jsruntime/qv4symbol.cpp
index 5f7ec89fd2..85ef57f680 100644
--- a/src/qml/jsruntime/qv4symbol.cpp
+++ b/src/qml/jsruntime/qv4symbol.cpp
@@ -19,9 +19,9 @@ void Heap::Symbol::init(const QString &s)
identifier = PropertyKey::fromStringOrSymbol(internalClass->engine, this);
}
-void Heap::SymbolCtor::init(QV4::ExecutionContext *scope)
+void Heap::SymbolCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("Symbol"));
+ Heap::FunctionObject::init(engine, QStringLiteral("Symbol"));
}
void Heap::SymbolObject::init(const QV4::Symbol *s)
diff --git a/src/qml/jsruntime/qv4symbol_p.h b/src/qml/jsruntime/qv4symbol_p.h
index e56510bd69..29a0189b69 100644
--- a/src/qml/jsruntime/qv4symbol_p.h
+++ b/src/qml/jsruntime/qv4symbol_p.h
@@ -25,7 +25,7 @@ namespace QV4 {
namespace Heap {
struct SymbolCtor : FunctionObject {
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
};
struct Symbol : StringOrSymbol {
diff --git a/src/qml/jsruntime/qv4typedarray.cpp b/src/qml/jsruntime/qv4typedarray.cpp
index 6c72eaba5f..9c752f43bb 100644
--- a/src/qml/jsruntime/qv4typedarray.cpp
+++ b/src/qml/jsruntime/qv4typedarray.cpp
@@ -236,9 +236,9 @@ const TypedArrayOperations operations[NTypedArrayTypes] = {
};
-void Heap::TypedArrayCtor::init(QV4::ExecutionContext *scope, TypedArray::Type t)
+void Heap::TypedArrayCtor::init(QV4::ExecutionEngine *engine, TypedArray::Type t)
{
- Heap::FunctionObject::init(scope, QLatin1String(operations[t].name));
+ Heap::FunctionObject::init(engine, QLatin1String(operations[t].name));
type = t;
}
@@ -762,8 +762,6 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_fill(const FunctionObject *b,
fin = static_cast<uint>(std::min(relativeEnd, dlen));
}
- double val = argc ? argv[0].toNumber() : std::numeric_limits<double>::quiet_NaN();
- Value value = Value::fromDouble(val);
if (scope.hasException() || v->hasDetachedArrayData())
return scope.engine->throwTypeError();
@@ -771,6 +769,14 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_fill(const FunctionObject *b,
uint bytesPerElement = v->bytesPerElement();
uint byteOffset = v->byteOffset();
+ Value value;
+ if (!argc)
+ value.setDouble(std::numeric_limits<double>::quiet_NaN());
+ else if (argv[0].isNumber())
+ value = argv[0];
+ else
+ value.setDouble(argv[0].toNumber());
+
while (k < fin) {
v->d()->type->write(data + byteOffset + k * bytesPerElement, value);
k++;
diff --git a/src/qml/jsruntime/qv4typedarray_p.h b/src/qml/jsruntime/qv4typedarray_p.h
index 9747eac411..50db9610c7 100644
--- a/src/qml/jsruntime/qv4typedarray_p.h
+++ b/src/qml/jsruntime/qv4typedarray_p.h
@@ -90,7 +90,7 @@ struct IntrinsicTypedArrayCtor : FunctionObject {
};
struct TypedArrayCtor : FunctionObject {
- void init(QV4::ExecutionContext *scope, TypedArray::Type t);
+ void init(ExecutionEngine *engine, TypedArray::Type t);
TypedArray::Type type;
};
@@ -141,8 +141,6 @@ struct IntrinsicTypedArrayCtor: FunctionObject
{
V4_OBJECT2(IntrinsicTypedArrayCtor, FunctionObject)
- static constexpr VTable::Call virtualCall = nullptr;
-
static ReturnedValue method_of(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_from(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
};
diff --git a/src/qml/jsruntime/qv4urlobject.cpp b/src/qml/jsruntime/qv4urlobject.cpp
index 4ece91a2a2..89c8b9cda2 100644
--- a/src/qml/jsruntime/qv4urlobject.cpp
+++ b/src/qml/jsruntime/qv4urlobject.cpp
@@ -18,9 +18,9 @@ DEFINE_OBJECT_VTABLE(UrlSearchParamsObject);
DEFINE_OBJECT_VTABLE(UrlSearchParamsCtor);
-void Heap::UrlCtor::init(QV4::ExecutionContext *scope)
+void Heap::UrlCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QLatin1String("URL"));
+ Heap::FunctionObject::init(engine, QLatin1String("URL"));
}
void UrlPrototype::init(ExecutionEngine *engine, Object *ctor)
@@ -750,9 +750,9 @@ ReturnedValue UrlCtor::virtualCallAsConstructor(const FunctionObject *that, cons
}
-void Heap::UrlSearchParamsCtor::init(QV4::ExecutionContext *scope)
+void Heap::UrlSearchParamsCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QLatin1String("URLSearchParams"));
+ Heap::FunctionObject::init(engine, QLatin1String("URLSearchParams"));
}
void UrlSearchParamsPrototype::init(ExecutionEngine *engine, Object *ctor)
diff --git a/src/qml/jsruntime/qv4urlobject_p.h b/src/qml/jsruntime/qv4urlobject_p.h
index d45b74fcaa..b3b76e1158 100644
--- a/src/qml/jsruntime/qv4urlobject_p.h
+++ b/src/qml/jsruntime/qv4urlobject_p.h
@@ -47,7 +47,7 @@ DECLARE_HEAP_OBJECT(UrlObject, Object)
struct UrlCtor : FunctionObject
{
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
};
// clang-format off
@@ -66,7 +66,7 @@ DECLARE_HEAP_OBJECT(UrlSearchParamsObject, Object)
struct UrlSearchParamsCtor : FunctionObject
{
- void init(QV4::ExecutionContext *scope);
+ void init(ExecutionEngine *engine);
};
}
diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h
index f2d01c56cd..eaa57a36aa 100644
--- a/src/qml/jsruntime/qv4value_p.h
+++ b/src/qml/jsruntime/qv4value_p.h
@@ -309,7 +309,10 @@ inline bool Value::isObject() const
inline bool Value::isFunctionObject() const
{
HeapBasePtr b = heapObject();
- return b && b->internalClass->vtable->isFunctionObject;
+ if (!b)
+ return false;
+ const VTable *vtable = b->internalClass->vtable;
+ return vtable->call || vtable->callAsConstructor;
}
inline bool Value::isPrimitive() const
diff --git a/src/qml/jsruntime/qv4vtable_p.h b/src/qml/jsruntime/qv4vtable_p.h
index 8ec8c87a31..0532fdc32d 100644
--- a/src/qml/jsruntime/qv4vtable_p.h
+++ b/src/qml/jsruntime/qv4vtable_p.h
@@ -64,7 +64,7 @@ struct VTable
quint8 isExecutionContext;
quint8 isString;
quint8 isObject;
- quint8 isFunctionObject;
+ quint8 isTailCallable;
quint8 isErrorObject;
quint8 isArrayData;
quint8 isStringOrSymbol;
@@ -110,20 +110,38 @@ template<class Class>
constexpr VTable::CallWithMetaTypes vtableMetaTypesCallEntry()
{
// If Class overrides virtualCallWithMetaTypes, return that.
- // Otherwise, if it overrides virtualCall, return nullptr so that we convert calls.
+ // Otherwise, if it overrides virtualCall, return convertAndCall.
// Otherwise, just return whatever the base class had.
- // A simple != is not considered constexpr, so we have to jump through some hoops.
- if constexpr (!std::is_same_v<
- VTableCallWithMetaTypesWrapper<Class::virtualCallWithMetaTypes>,
- VTableCallWithMetaTypesWrapper<Class::SuperClass::virtualCallWithMetaTypes>>) {
- return Class::virtualCallWithMetaTypes;
- }
-
- if constexpr (!std::is_same_v<
- VTableCallWrapper<Class::virtualCall>,
- VTableCallWrapper<Class::SuperClass::virtualCall>>) {
- return nullptr;
+ // A simple == on methods is not considered constexpr, so we have to jump through some hoops.
+
+ static_assert(
+ std::is_same_v<
+ VTableCallWithMetaTypesWrapper<Class::virtualCallWithMetaTypes>,
+ VTableCallWithMetaTypesWrapper<Class::SuperClass::virtualCallWithMetaTypes>>
+ || !std::is_same_v<
+ VTableCallWithMetaTypesWrapper<Class::virtualCallWithMetaTypes>,
+ VTableCallWithMetaTypesWrapper<nullptr>>,
+ "You mustn't override virtualCallWithMetaTypes with nullptr");
+
+ static_assert(
+ std::is_same_v<
+ VTableCallWithMetaTypesWrapper<Class::virtualConvertAndCall>,
+ VTableCallWithMetaTypesWrapper<Class::SuperClass::virtualConvertAndCall>>
+ || !std::is_same_v<
+ VTableCallWithMetaTypesWrapper<Class::virtualConvertAndCall>,
+ VTableCallWithMetaTypesWrapper<nullptr>>,
+ "You mustn't override virtualConvertAndCall with nullptr");
+
+ if constexpr (
+ std::is_same_v<
+ VTableCallWithMetaTypesWrapper<Class::virtualCallWithMetaTypes>,
+ VTableCallWithMetaTypesWrapper<Class::SuperClass::virtualCallWithMetaTypes>>
+ && !std::is_same_v<
+ VTableCallWrapper<Class::virtualCall>,
+ VTableCallWrapper<Class::SuperClass::virtualCall>>) {
+ // Converting from metatypes to JS signature is easy.
+ return Class::virtualConvertAndCall;
}
return Class::virtualCallWithMetaTypes;
@@ -133,21 +151,27 @@ template<class Class>
constexpr VTable::Call vtableJsTypesCallEntry()
{
// If Class overrides virtualCall, return that.
- // Otherwise, if it overrides virtualCallWithMetaTypes, return nullptr so that we convert calls.
+ // Otherwise, if it overrides virtualCallWithMetaTypes, fail.
+ // (We cannot determine the target types to call virtualCallWithMetaTypes in that case)
// Otherwise, just return whatever the base class had.
- // A simple != is not considered constexpr, so we have to jump through some hoops.
- if constexpr (!std::is_same_v<
- VTableCallWrapper<Class::virtualCall>,
- VTableCallWrapper<Class::SuperClass::virtualCall>>) {
- return Class::virtualCall;
- }
+ // A simple == on methods is not considered constexpr, so we have to jump through some hoops.
- if constexpr (!std::is_same_v<
- VTableCallWithMetaTypesWrapper<Class::virtualCallWithMetaTypes>,
- VTableCallWithMetaTypesWrapper<Class::SuperClass::virtualCallWithMetaTypes>>) {
- return nullptr;
- }
+ static_assert(
+ !std::is_same_v<
+ VTableCallWrapper<Class::virtualCall>,
+ VTableCallWrapper<Class::SuperClass::virtualCall>>
+ || std::is_same_v<
+ VTableCallWithMetaTypesWrapper<Class::virtualCallWithMetaTypes>,
+ VTableCallWithMetaTypesWrapper<Class::SuperClass::virtualCallWithMetaTypes>>,
+ "If you override virtualCallWithMetaTypes, override virtualCall, too");
+
+ static_assert(
+ std::is_same_v<
+ VTableCallWrapper<Class::virtualCall>,
+ VTableCallWrapper<Class::SuperClass::virtualCall>>
+ || VTableCallWrapper<Class::virtualCall>::c != nullptr,
+ "You mustn't override virtualCall with nullptr");
return Class::virtualCall;
}
@@ -174,6 +198,7 @@ protected:
static constexpr VTable::Call virtualCall = nullptr;
static constexpr VTable::CallAsConstructor virtualCallAsConstructor = nullptr;
static constexpr VTable::CallWithMetaTypes virtualCallWithMetaTypes = nullptr;
+ static constexpr VTable::CallWithMetaTypes virtualConvertAndCall = nullptr;
static constexpr VTable::ResolveLookupGetter virtualResolveLookupGetter = nullptr;
static constexpr VTable::ResolveLookupSetter virtualResolveLookupSetter = nullptr;
@@ -196,7 +221,7 @@ protected:
classname::IsExecutionContext, \
classname::IsString, \
classname::IsObject, \
- classname::IsFunctionObject, \
+ classname::IsTailCallable, \
classname::IsErrorObject, \
classname::IsArrayData, \
classname::IsStringOrSymbol, \
diff --git a/src/qml/parser/qqmljs.g b/src/qml/parser/qqmljs.g
index 57954d7d1a..32b609f5ff 100644
--- a/src/qml/parser/qqmljs.g
+++ b/src/qml/parser/qqmljs.g
@@ -3399,6 +3399,7 @@ BindingProperty: PropertyName T_COLON BindingIdentifier InitializerOpt_In;
case $rule_number: {
AST::PatternProperty *node = new (pool) AST::PatternProperty(sym(1).PropertyName, stringRef(3), sym(4).Expression);
node->colonToken = loc(2);
+ node->identifierToken = loc(3);
sym(1).Node = node;
} break;
./
@@ -3567,6 +3568,11 @@ IterationStatement: T_FOR T_LPAREN LexicalDeclaration T_SEMICOLON ExpressionOpt_
AST::ForStatement *node = new (pool) AST::ForStatement(
static_cast<AST::VariableStatement *>(sym(3).Node)->declarations, sym(5).Expression,
sym(7).Expression, sym(9).Statement);
+ if (node->declarations) {
+ AST::PatternElement *pe = node->declarations->declaration;
+ pe->isForDeclaration = true;
+ pe->declarationKindToken = loc(3);
+ }
node->forToken = loc(1);
node->lparenToken = loc(2);
node->firstSemicolonToken = loc(4);
@@ -3638,6 +3644,7 @@ ForDeclaration: Var BindingIdentifier TypeAnnotationOpt;
node->identifierToken = loc(2);
node->scope = sym(1).scope;
node->isForDeclaration = true;
+ node->declarationKindToken = loc(1);
sym(1).Node = node;
} break;
./
@@ -3650,6 +3657,7 @@ ForDeclaration: Var BindingPattern;
auto *node = new (pool) AST::PatternElement(sym(2).Pattern, nullptr);
node->scope = sym(1).scope;
node->isForDeclaration = true;
+ node->declarationKindToken = loc(1);
sym(1).Node = node;
} break;
./
diff --git a/src/qml/parser/qqmljsast_p.h b/src/qml/parser/qqmljsast_p.h
index 2bb9b3f001..bfeab7518c 100644
--- a/src/qml/parser/qqmljsast_p.h
+++ b/src/qml/parser/qqmljsast_p.h
@@ -995,6 +995,7 @@ public:
Type type = Literal;
TypeAnnotation *typeAnnotation = nullptr;
// when used in a VariableDeclarationList
+ SourceLocation declarationKindToken;
VariableScope scope = VariableScope::NoScope;
bool isForDeclaration = false;
bool isInjectedSignalParameter = false;
diff --git a/src/qml/parser/qqmljslexer.cpp b/src/qml/parser/qqmljslexer.cpp
index 704c7eb00d..cdb3dde5c6 100644
--- a/src/qml/parser/qqmljslexer.cpp
+++ b/src/qml/parser/qqmljslexer.cpp
@@ -1214,6 +1214,32 @@ int Lexer::scanString(ScanStringMode mode)
int Lexer::scanNumber(QChar ch)
{
+ auto scanOptionalNumericSeparator = [this](auto isNextCharacterValid){
+ if (_state.currentChar == u'_') {
+ if (peekChar() == u'_') {
+ _state.errorCode = IllegalNumber;
+ _errorMessage = QCoreApplication::translate(
+ "QQmlParser",
+ "There can be at most one numeric separator beetwen digits"
+ );
+ return false;
+ }
+
+ if (!isNextCharacterValid()) {
+ _state.errorCode = IllegalNumber;
+ _errorMessage = QCoreApplication::translate(
+ "QQmlParser",
+ "A trailing numeric separator is not allowed in numeric literals"
+ );
+ return false;
+ }
+
+ scanChar();
+ }
+
+ return true;
+ };
+
if (ch == u'0') {
if (_state.currentChar == u'x' || _state.currentChar == u'X') {
ch = _state.currentChar; // remember the x or X to use it in the error message below.
@@ -1238,6 +1264,9 @@ int Lexer::scanNumber(QChar ch)
d *= 16;
d += digit;
scanChar();
+
+ if (!scanOptionalNumericSeparator([this](){ return isHexDigit(peekChar()); }))
+ return T_ERROR;
}
_state.tokenValue = d;
@@ -1265,6 +1294,12 @@ int Lexer::scanNumber(QChar ch)
d *= 8;
d += digit;
scanChar();
+
+ if (!scanOptionalNumericSeparator([this](){
+ return isOctalDigit(peekChar().unicode());
+ })) {
+ return T_ERROR;
+ }
}
_state.tokenValue = d;
@@ -1294,6 +1329,12 @@ int Lexer::scanNumber(QChar ch)
d *= 2;
d += digit;
scanChar();
+
+ if (!scanOptionalNumericSeparator([this](){
+ return peekChar().unicode() == u'0' || peekChar().unicode() == u'1';
+ })) {
+ return T_ERROR;
+ }
}
_state.tokenValue = d;
@@ -1311,9 +1352,15 @@ int Lexer::scanNumber(QChar ch)
chars.append(ch.unicode());
if (ch != u'.') {
+ if (!scanOptionalNumericSeparator([this](){ return peekChar().isDigit(); }))
+ return T_ERROR;
+
while (_state.currentChar.isDigit()) {
chars.append(_state.currentChar.unicode());
scanChar(); // consume the digit
+
+ if (!scanOptionalNumericSeparator([this](){ return peekChar().isDigit(); }))
+ return T_ERROR;
}
if (_state.currentChar == u'.') {
@@ -1325,6 +1372,9 @@ int Lexer::scanNumber(QChar ch)
while (_state.currentChar.isDigit()) {
chars.append(_state.currentChar.unicode());
scanChar();
+
+ if (!scanOptionalNumericSeparator([this](){ return peekChar().isDigit(); }))
+ return T_ERROR;
}
if (_state.currentChar == u'e' || _state.currentChar == u'E') {
@@ -1342,6 +1392,9 @@ int Lexer::scanNumber(QChar ch)
while (_state.currentChar.isDigit()) {
chars.append(_state.currentChar.unicode());
scanChar();
+
+ if (!scanOptionalNumericSeparator([this](){ return peekChar().isDigit(); }))
+ return T_ERROR;
}
}
}
diff --git a/src/qml/qml/ftw/qqmlnullablevalue_p.h b/src/qml/qml/ftw/qqmlnullablevalue_p.h
index 9a3f032b68..62899e4644 100644
--- a/src/qml/qml/ftw/qqmlnullablevalue_p.h
+++ b/src/qml/qml/ftw/qqmlnullablevalue_p.h
@@ -30,7 +30,7 @@ struct QQmlNullableValue
{}
QQmlNullableValue(QQmlNullableValue<T> &&o) noexcept
- : m_value(std::move(o.value))
+ : m_value(std::move(o.m_value))
, m_isNull(std::exchange(o.m_isNull, true))
{}
diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp
index 47f8e5c429..4dfee0a3c6 100644
--- a/src/qml/qml/qqmlbinding.cpp
+++ b/src/qml/qml/qqmlbinding.cpp
@@ -533,7 +533,8 @@ Q_NEVER_INLINE bool QQmlBinding::slowWrite(const QQmlPropertyData &core,
delayedError()->setErrorDescription(QLatin1String("Unable to assign [undefined] to ")
+ typeName);
return false;
- } else if (const QV4::FunctionObject *f = result.as<QV4::FunctionObject>()) {
+ } else if (const QV4::FunctionObject *f = result.as<QV4::FunctionObject>();
+ f && !f->as<QV4::QQmlTypeWrapper>()) {
if (f->isBinding())
delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration."));
else
diff --git a/src/qml/qml/qqmlboundsignal.cpp b/src/qml/qml/qqmlboundsignal.cpp
index 3f9ce26764..0bac2f45a2 100644
--- a/src/qml/qml/qqmlboundsignal.cpp
+++ b/src/qml/qml/qqmlboundsignal.cpp
@@ -62,7 +62,8 @@ QQmlBoundSignalExpression::QQmlBoundSignalExpression(const QObject *target, int
function += QLatin1String(") { ") + expression + QLatin1String(" })");
QV4::Scope valueScope(v4);
- QV4::ScopedFunctionObject f(valueScope, evalFunction(context(), scopeObject(), function, fileName, line));
+ QV4::Scoped<QV4::JavaScriptFunctionObject> f(
+ valueScope, evalFunction(context(), scopeObject(), function, fileName, line));
QV4::ScopedContext context(valueScope, f->scope());
setupFunction(context, f->function());
}
@@ -107,7 +108,7 @@ QQmlBoundSignalExpression::QQmlBoundSignalExpression(const QObject *target, int
// we need to run the outer function to get the nested one.
if (function->isClosureWrapper()) {
bool isUndefined = false;
- QV4::ScopedFunctionObject result(
+ QV4::Scoped<QV4::JavaScriptFunctionObject> result(
valueScope, QQmlJavaScriptExpression::evaluate(&isUndefined));
Q_ASSERT(!isUndefined);
diff --git a/src/qml/qml/qqmlbuiltinfunctions.cpp b/src/qml/qml/qqmlbuiltinfunctions.cpp
index 5c6daa0969..316334a63d 100644
--- a/src/qml/qml/qqmlbuiltinfunctions.cpp
+++ b/src/qml/qml/qqmlbuiltinfunctions.cpp
@@ -3,48 +3,35 @@
#include "qqmlbuiltinfunctions_p.h"
-#include <QtQml/qqmlcomponent.h>
-#include <QtQml/qqmlfile.h>
-#include <private/qqmlengine_p.h>
#include <private/qqmlcomponent_p.h>
-#include <private/qqmlloggingcategory_p.h>
-#include <private/qqmlstringconverters_p.h>
-#if QT_CONFIG(qml_locale)
-#include <private/qqmllocale_p.h>
-#endif
-#include <private/qqmldelayedcallqueue_p.h>
-#include <QFileInfo>
-
#include <private/qqmldebugconnector_p.h>
#include <private/qqmldebugserviceinterfaces_p.h>
-#include <private/qqmlglobal_p.h>
-
+#include <private/qqmldelayedcallqueue_p.h>
+#include <private/qqmlengine_p.h>
+#include <private/qqmlloggingcategory_p.h>
#include <private/qqmlplatform_p.h>
+#include <private/qqmlstringconverters_p.h>
+#include <private/qv4dateobject_p.h>
#include <private/qv4engine_p.h>
#include <private/qv4functionobject_p.h>
#include <private/qv4include_p.h>
-#include <private/qv4context_p.h>
-#include <private/qv4stringobject_p.h>
-#include <private/qv4dateobject_p.h>
#include <private/qv4mm_p.h>
-#include <private/qv4jsonobject_p.h>
-#include <private/qv4objectproto_p.h>
#include <private/qv4qobjectwrapper_p.h>
#include <private/qv4stackframe_p.h>
-#include <QtCore/qstring.h>
-#include <QtCore/qdatetime.h>
+#include <QtQml/qqmlfile.h>
+
+#include <QtCore/qcoreapplication.h>
#include <QtCore/qcryptographichash.h>
+#include <QtCore/qdatetime.h>
+#include <QtCore/qfileinfo.h>
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qpoint.h>
#include <QtCore/qrect.h>
#include <QtCore/qsize.h>
-#include <QtCore/qpoint.h>
+#include <QtCore/qstring.h>
#include <QtCore/qurl.h>
-#include <QtCore/qfile.h>
-#include <QtCore/qcoreapplication.h>
-#include <QtCore/qloggingcategory.h>
-
-#include <QDebug>
QT_BEGIN_NAMESPACE
@@ -172,6 +159,7 @@ The following functions are also on the Qt object.
\li \c "android" - Android
\li \c "ios" - iOS
\li \c "tvos" - tvOS
+ \li \c "visionos" - visionOS
\li \c "linux" - Linux
\li \c "osx" - \macos
\li \c "qnx" - QNX (since Qt 5.9.3)
@@ -180,6 +168,9 @@ The following functions are also on the Qt object.
\li \c "wasm" - WebAssembly
\endlist
+ \note The property's value on \macos is "osx", regardless of Apple naming convention.
+ The returned value will be updated to "macos" for Qt 7.
+
\row
\li \c platform.pluginName
\li This is the name of the platform set on the QGuiApplication instance
@@ -262,6 +253,9 @@ The \c status property will be updated as the operation progresses.
If provided, \a callback is invoked when the operation completes. The callback is passed
the same object as is returned from the Qt.include() call.
+
+\warning Using this function is strict mode does not actually put identifier into the
+current context.
*/
// Qt.include() is implemented in qv4include.cpp
@@ -1469,11 +1463,12 @@ use \l{QtQml::Qt::createQmlObject()}{Qt.createQmlObject()}.
*/
/*!
+\since 6.5
\qmlmethod Component Qt::createComponent(string moduleUri, string typeName, enumeration mode, QtObject parent)
\overload
Returns a \l Component object created for the type specified by \a moduleUri and \a typeName.
\qml
-import QtQuick
+import QtQml
QtObject {
id: root
property Component myComponent: Qt.createComponent("QtQuick", "Rectangle", Component.Asynchronous, root)
@@ -1613,14 +1608,21 @@ QLocale QtObject::locale(const QString &name) const
}
#endif
-void Heap::QQmlBindingFunction::init(const QV4::FunctionObject *bindingFunction)
+void Heap::QQmlBindingFunction::init(const QV4::JavaScriptFunctionObject *bindingFunction)
{
Scope scope(bindingFunction->engine());
ScopedContext context(scope, bindingFunction->scope());
- FunctionObject::init(context, bindingFunction->function());
+ JavaScriptFunctionObject::init(context, bindingFunction->function());
this->bindingFunction.set(internalClass->engine, bindingFunction->d());
}
+ReturnedValue QQmlBindingFunction::virtualCall(
+ const FunctionObject *f, const Value *, const Value *, int)
+{
+ // Mark this as a callable object, so that we can perform the binding magic on it.
+ return f->engine()->throwTypeError(QStringLiteral("Bindings must not be called directly."));
+}
+
QQmlSourceLocation QQmlBindingFunction::currentLocation() const
{
QV4::CppStackFrame *frame = engine()->currentStackFrame;
@@ -1675,7 +1677,8 @@ DEFINE_OBJECT_VTABLE(QQmlBindingFunction);
*/
QJSValue QtObject::binding(const QJSValue &function) const
{
- const QV4::FunctionObject *f = QJSValuePrivate::asManagedType<FunctionObject>(&function);
+ const QV4::JavaScriptFunctionObject *f
+ = QJSValuePrivate::asManagedType<JavaScriptFunctionObject>(&function);
QV4::ExecutionEngine *e = v4Engine();
if (!f) {
return QJSValuePrivate::fromReturnedValue(
@@ -2138,7 +2141,7 @@ ReturnedValue GlobalExtensions::method_qsTranslate(const FunctionObject *b, cons
}
/*!
- \qmlmethod string Qt::qsTranslateNoOp(string context, string sourceText, string disambiguation)
+ \qmlmethod string Qt::QT_TRANSLATE_NOOP(string context, string sourceText, string disambiguation)
Marks \a sourceText for dynamic translation in the given \a context; i.e, the stored \a sourceText
will not be altered.
@@ -2253,7 +2256,7 @@ ReturnedValue GlobalExtensions::method_qsTr(const FunctionObject *b, const Value
}
/*!
- \qmlmethod string Qt::qsTrNoOp(string sourceText, string disambiguation)
+ \qmlmethod string Qt::QT_TR_NOOP(string sourceText, string disambiguation)
Marks \a sourceText for dynamic translation; i.e, the stored \a sourceText
will not be altered.
@@ -2334,7 +2337,7 @@ ReturnedValue GlobalExtensions::method_qsTrId(const FunctionObject *b, const Val
}
/*!
- \qmlmethod string Qt::qsTrIdNoOp(string id)
+ \qmlmethod string Qt::QT_TRID_NOOP(string id)
Marks \a id for dynamic translation.
diff --git a/src/qml/qml/qqmlbuiltinfunctions_p.h b/src/qml/qml/qqmlbuiltinfunctions_p.h
index 9ceedad28b..379b9b67ff 100644
--- a/src/qml/qml/qqmlbuiltinfunctions_p.h
+++ b/src/qml/qml/qqmlbuiltinfunctions_p.h
@@ -199,10 +199,10 @@ struct ConsoleObject : Object {
};
#define QQmlBindingFunctionMembers(class, Member) \
- Member(class, Pointer, FunctionObject *, bindingFunction)
-DECLARE_HEAP_OBJECT(QQmlBindingFunction, FunctionObject) {
+ Member(class, Pointer, JavaScriptFunctionObject *, bindingFunction)
+DECLARE_HEAP_OBJECT(QQmlBindingFunction, JavaScriptFunctionObject) {
DECLARE_MARKOBJECTS(QQmlBindingFunction)
- void init(const QV4::FunctionObject *bindingFunction);
+ void init(const QV4::JavaScriptFunctionObject *bindingFunction);
};
}
@@ -245,11 +245,14 @@ struct Q_QML_EXPORT GlobalExtensions {
};
-struct QQmlBindingFunction : public QV4::FunctionObject
+struct QQmlBindingFunction : public QV4::JavaScriptFunctionObject
{
- V4_OBJECT2(QQmlBindingFunction, FunctionObject)
+ V4_OBJECT2(QQmlBindingFunction, JavaScriptFunctionObject)
- Heap::FunctionObject *bindingFunction() const { return d()->bindingFunction; }
+ static ReturnedValue virtualCall(
+ const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
+
+ Heap::JavaScriptFunctionObject *bindingFunction() const { return d()->bindingFunction; }
QQmlSourceLocation currentLocation() const; // from caller stack trace
};
diff --git a/src/qml/qml/qqmlcontextdata_p.h b/src/qml/qml/qqmlcontextdata_p.h
index c8e362ec8d..3aeabf72fa 100644
--- a/src/qml/qml/qqmlcontextdata_p.h
+++ b/src/qml/qml/qqmlcontextdata_p.h
@@ -292,6 +292,10 @@ public:
return m_typeCompilationUnit && m_typeCompilationUnit->valueTypesAreAddressable();
}
+ bool valueTypesAreAssertable() const {
+ return m_typeCompilationUnit && m_typeCompilationUnit->valueTypesAreAssertable();
+ }
+
private:
friend class QQmlGuardedContextData;
friend class QQmlContextPrivate;
diff --git a/src/qml/qml/qqmldelayedcallqueue.cpp b/src/qml/qml/qqmldelayedcallqueue.cpp
index efd8519a58..ead8a717f5 100644
--- a/src/qml/qml/qqmldelayedcallqueue.cpp
+++ b/src/qml/qml/qqmldelayedcallqueue.cpp
@@ -126,8 +126,9 @@ QV4::ReturnedValue QQmlDelayedCallQueue::addUniquelyAndExecuteLater(QV4::Executi
// if it's a qobject function wrapper, guard against qobject deletion
dfc.m_objectGuard = QQmlGuard<QObject>(functionData.first);
dfc.m_guarded = true;
- } else if (func->scope()->type == QV4::Heap::ExecutionContext::Type_QmlContext) {
- QV4::QmlContext::Data *g = static_cast<QV4::QmlContext::Data *>(func->scope());
+ } else if (const auto *js = func->as<QV4::JavaScriptFunctionObject>();
+ js && js->scope()->type == QV4::Heap::ExecutionContext::Type_QmlContext) {
+ QV4::QmlContext::Data *g = static_cast<QV4::QmlContext::Data *>(js->scope());
Q_ASSERT(g->qml()->scopeObject);
dfc.m_objectGuard = QQmlGuard<QObject>(g->qml()->scopeObject);
dfc.m_guarded = true;
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index c7812059a1..b4e212ae0b 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -4,57 +4,44 @@
#include "qqmlengine_p.h"
#include "qqmlengine.h"
-#include "qqmlcontext_p.h"
-#include "qqml.h"
-#include "qqmlcontext.h"
-#include "qqmlscriptstring.h"
-#include "qqmlglobal_p.h"
-#include "qqmlnotifier_p.h"
-#include "qqmlincubator.h"
-#include "qqmlabstracturlinterceptor.h"
-
-#include <private/qqmldirparser_p.h>
+#include <private/qqmlabstractbinding_p.h>
#include <private/qqmlboundsignal_p.h>
-#include <private/qqmljsdiagnosticmessage_p.h>
-#include <private/qqmltype_p_p.h>
+#include <private/qqmlcontext_p.h>
+#include <private/qqmlnotifier_p.h>
#include <private/qqmlpluginimporter_p.h>
-#include <QtCore/qstandardpaths.h>
-#include <QtCore/qmetaobject.h>
-#include <QDebug>
+#include <private/qqmlprofiler_p.h>
+#include <private/qqmlscriptdata_p.h>
+#include <private/qqmlsourcecoordinate_p.h>
+#include <private/qqmltype_p.h>
+#include <private/qqmltypedata_p.h>
+#include <private/qqmlvmemetaobject_p.h>
+
+#include <private/qobject_p.h>
+#include <private/qthread_p.h>
+
+#include <QtQml/qqml.h>
+#include <QtQml/qqmlcomponent.h>
+#include <QtQml/qqmlcontext.h>
+#include <QtQml/qqmlincubator.h>
+#include <QtQml/qqmlscriptstring.h>
+
#include <QtCore/qcoreapplication.h>
#include <QtCore/qcryptographichash.h>
#include <QtCore/qdir.h>
+#include <QtCore/qmetaobject.h>
#include <QtCore/qmutex.h>
+#include <QtCore/qstandardpaths.h>
#include <QtCore/qthread.h>
-#include <private/qthread_p.h>
-#include <private/qqmlscriptdata_p.h>
-#include <QtQml/private/qqmlcomponentattached_p.h>
-#include <QtQml/private/qqmlsourcecoordinate_p.h>
-#include <QtQml/private/qqmlcomponent_p.h>
#if QT_CONFIG(qml_network)
-#include "qqmlnetworkaccessmanagerfactory.h"
-#include <QNetworkAccessManager>
-#endif
-
-#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(qml_animation)
-#include <private/qqmltimer_p.h>
+#include <QtQml/qqmlnetworkaccessmanagerfactory.h>
+#include <QtNetwork/qnetworkaccessmanager.h>
#endif
-#include <private/qqmlplatform_p.h>
-#include <private/qqmlloggingcategory_p.h>
-#include <private/qv4sequenceobject_p.h>
#ifdef Q_OS_WIN // for %APPDATA%
# include <qt_windows.h>
# include <shlobj.h>
-# include <qlibrary.h>
+# include <QtCore/qlibrary.h>
# ifndef CSIDL_APPDATA
# define CSIDL_APPDATA 0x001a // <username>\Application Data
# endif
@@ -1945,7 +1932,7 @@ void QQmlEnginePrivate::executeRuntimeFunction(const QV4::ExecutableCompilationU
// different version of ExecutionEngine::callInContext() that returns a
// QV4::ReturnedValue with no arguments since they are not needed by the
// outer function anyhow
- QV4::ScopedFunctionObject result(scope,
+ QV4::Scoped<QV4::JavaScriptFunctionObject> result(scope,
v4->callInContext(function, thisObject, callContext, 0, nullptr));
Q_ASSERT(result->function());
Q_ASSERT(result->function()->compilationUnit == function->compilationUnit);
diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp
index 86380294ba..217cb44669 100644
--- a/src/qml/qml/qqmlimport.cpp
+++ b/src/qml/qml/qqmlimport.cpp
@@ -1516,8 +1516,9 @@ QQmlImportDatabase::QQmlImportDatabase(QQmlEngine *e)
// 6. $QML_IMPORT_PATH
// 7. QLibraryInfo::QmlImportsPath
- QString installImportsPath = QLibraryInfo::path(QLibraryInfo::QmlImportsPath);
- addImportPath(installImportsPath);
+ const auto paths = QLibraryInfo::paths(QLibraryInfo::QmlImportsPath);
+ for (const auto &installImportsPath: paths)
+ addImportPath(installImportsPath);
auto addEnvImportPath = [this](const char *var) {
if (Q_UNLIKELY(!qEnvironmentVariableIsEmpty(var))) {
diff --git a/src/qml/qml/qqmlirloader.cpp b/src/qml/qml/qqmlirloader.cpp
index b29ce185ef..e1019b804f 100644
--- a/src/qml/qml/qqmlirloader.cpp
+++ b/src/qml/qml/qqmlirloader.cpp
@@ -85,6 +85,8 @@ void QQmlIRLoader::load()
valueTypeBehavior |= Pragma::Copy;
if (unit->flags & QV4::CompiledData::Unit::ValueTypesAddressable)
valueTypeBehavior |= Pragma::Addressable;
+ if (unit->flags & QV4::CompiledData::Unit::ValueTypesAssertable)
+ valueTypeBehavior |= Pragma::Assertable;
if (valueTypeBehavior)
createValueTypePragma(Pragma::ValueTypeBehavior, valueTypeBehavior);
diff --git a/src/qml/qml/qqmlplatform.cpp b/src/qml/qml/qqmlplatform.cpp
index dbd54b5f11..dd52ee2090 100644
--- a/src/qml/qml/qqmlplatform.cpp
+++ b/src/qml/qml/qqmlplatform.cpp
@@ -22,13 +22,18 @@ QQmlPlatform::~QQmlPlatform()
QString QQmlPlatform::os()
{
+ // ### Qt7: Consider implementing in terms of QSysInfo
+
#if defined(Q_OS_ANDROID)
return QStringLiteral("android");
#elif defined(Q_OS_IOS)
return QStringLiteral("ios");
#elif defined(Q_OS_TVOS)
return QStringLiteral("tvos");
-#elif defined(Q_OS_MAC)
+#elif defined(Q_OS_VISIONOS)
+ return QStringLiteral("visionos");
+#elif defined(Q_OS_MACOS)
+ // ### Qt7: Replace with "macos"
return QStringLiteral("osx");
#elif defined(Q_OS_WIN)
return QStringLiteral("windows");
diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp
index a225f94a3f..805113ad97 100644
--- a/src/qml/qml/qqmlpropertycache.cpp
+++ b/src/qml/qml/qqmlpropertycache.cpp
@@ -95,7 +95,6 @@ void QQmlPropertyData::load(const QMetaMethod &m)
case QMetaMethod::Constructor:
m_flags.setIsSignal(false);
m_flags.setIsConstructor(true);
- setPropType(QMetaType::fromType<QObject *>());
break;
default:
m_flags.setIsSignal(false);
@@ -687,28 +686,9 @@ const QQmlPropertyData *QQmlPropertyCache::findProperty(
return nullptr;
}
-QString QQmlPropertyData::name(QObject *object) const
-{
- if (!object)
- return QString();
-
- return name(object->metaObject());
-}
-QString QQmlPropertyData::name(const QMetaObject *metaObject) const
-{
- if (!metaObject || coreIndex() == -1)
- return QString();
- if (isFunction()) {
- QMetaMethod m = metaObject->method(coreIndex());
- return QString::fromUtf8(m.name().constData());
- } else {
- QMetaProperty p = metaObject->property(coreIndex());
- return QString::fromUtf8(p.name());
- }
-}
bool QQmlPropertyData::markAsOverrideOf(QQmlPropertyData *predecessor)
{
diff --git a/src/qml/qml/qqmlpropertydata_p.h b/src/qml/qml/qqmlpropertydata_p.h
index 0fa7984f05..bdfa41ab7a 100644
--- a/src/qml/qml/qqmlpropertydata_p.h
+++ b/src/qml/qml/qqmlpropertydata_p.h
@@ -338,8 +338,17 @@ public:
static Flags flagsForProperty(const QMetaProperty &);
void load(const QMetaProperty &);
void load(const QMetaMethod &);
- QString name(QObject *) const;
- QString name(const QMetaObject *) const;
+
+ QString name(QObject *object) const { return object ? name(object->metaObject()) : QString(); }
+ QString name(const QMetaObject *metaObject) const
+ {
+ if (!metaObject || m_coreIndex == -1)
+ return QString();
+
+ return QString::fromUtf8(isFunction()
+ ? metaObject->method(m_coreIndex).name().constData()
+ : metaObject->property(m_coreIndex).name());
+ }
bool markAsOverrideOf(QQmlPropertyData *predecessor);
diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp
index 0d8786a9df..2ab81102c7 100644
--- a/src/qml/qml/qqmltypewrapper.cpp
+++ b/src/qml/qml/qqmltypewrapper.cpp
@@ -3,63 +3,122 @@
#include "qqmltypewrapper_p.h"
-#include <private/qqmlengine_p.h>
+#include <private/qjsvalue_p.h>
+
#include <private/qqmlcontext_p.h>
+#include <private/qqmlengine_p.h>
#include <private/qqmlmetaobject_p.h>
#include <private/qqmltypedata_p.h>
#include <private/qqmlvaluetypewrapper_p.h>
-#include <private/qjsvalue_p.h>
-#include <private/qv4functionobject_p.h>
-#include <private/qv4objectproto_p.h>
-#include <private/qv4qobjectwrapper_p.h>
#include <private/qv4identifiertable_p.h>
#include <private/qv4lookup_p.h>
+#include <private/qv4objectproto_p.h>
+#include <private/qv4qobjectwrapper_p.h>
+#include <private/qv4symbol_p.h>
QT_BEGIN_NAMESPACE
using namespace QV4;
DEFINE_OBJECT_VTABLE(QQmlTypeWrapper);
+DEFINE_OBJECT_VTABLE(QQmlTypeConstructor);
DEFINE_OBJECT_VTABLE(QQmlScopedEnumWrapper);
void Heap::QQmlTypeWrapper::init(TypeNameMode m, QObject *o, const QQmlTypePrivate *type)
{
Q_ASSERT(type);
- Object::init();
- mode = m;
+ FunctionObject::init();
+ flags = quint8(m) | quint8(Type);
object.init(o);
- typePrivate = type;
- QQmlType::refHandle(typePrivate);
+ QQmlType::refHandle(type);
+ t.typePrivate = type;
}
void Heap::QQmlTypeWrapper::init(
TypeNameMode m, QObject *o, QQmlTypeNameCache *type, const QQmlImportRef *import)
{
Q_ASSERT(type);
- Object::init();
- mode = m;
+ FunctionObject::init();
+ flags = quint8(m) | quint8(Namespace);
object.init(o);
- typeNamespace = type;
- typeNamespace->addref();
- importNamespace = import;
+ n.typeNamespace = type;
+ n.typeNamespace->addref();
+ n.importNamespace = import;
}
void Heap::QQmlTypeWrapper::destroy()
{
- Q_ASSERT(typePrivate || typeNamespace);
- QQmlType::derefHandle(typePrivate);
- typePrivate = nullptr;
- if (typeNamespace)
- typeNamespace->release();
+ switch (kind()) {
+ case Type:
+ Q_ASSERT(t.typePrivate);
+ QQmlType::derefHandle(t.typePrivate);
+ delete[] t.constructors;
+ break;
+ case Namespace:
+ Q_ASSERT(n.typeNamespace);
+ n.typeNamespace->release();
+ break;
+ }
+
object.destroy();
- Object::destroy();
+ FunctionObject::destroy();
}
QQmlType Heap::QQmlTypeWrapper::type() const
{
- return QQmlType(typePrivate);
+ switch (kind()) {
+ case Type:
+ return QQmlType(t.typePrivate);
+ case Namespace:
+ return QQmlType();
+ }
+
+ Q_UNREACHABLE_RETURN(QQmlType());
+}
+
+QQmlTypeNameCache::Result Heap::QQmlTypeWrapper::queryNamespace(
+ const QV4::String *name, QQmlEnginePrivate *enginePrivate) const
+{
+ Q_ASSERT(kind() == Namespace);
+ Q_ASSERT(n.typeNamespace);
+ Q_ASSERT(n.importNamespace);
+ return n.typeNamespace->query(name, n.importNamespace, QQmlTypeLoader::get(enginePrivate));
+
+}
+
+template<typename Callback>
+void warnWithLocation(const Heap::QQmlTypeWrapper *wrapper, Callback &&callback)
+{
+ auto log = qWarning().noquote().nospace();
+ if (const CppStackFrame *frame = wrapper->internalClass->engine->currentStackFrame)
+ log << frame->source() << ':' << frame->lineNumber() << ':';
+ callback(log.space());
+}
+
+void Heap::QQmlTypeWrapper::warnIfUncreatable() const
+{
+ const QQmlType t = type();
+ Q_ASSERT(t.isValid());
+
+ if (t.isValueType())
+ return;
+
+ if (t.isSingleton()) {
+ warnWithLocation(this, [&](QDebug &log) {
+ log << "You are calling a Q_INVOKABLE constructor of" << t.typeName()
+ << "which is a singleton in QML.";
+ });
+ return;
+ }
+
+ if (!t.isCreatable()) {
+ warnWithLocation(this, [&](QDebug &log) {
+ log << "You are calling a Q_INVOKABLE constructor of" << t.typeName()
+ << "which is uncreatable in QML.";
+ });
+ }
}
bool QQmlTypeWrapper::isSingleton() const
@@ -136,17 +195,59 @@ QVariant QQmlTypeWrapper::toVariant() const
return QVariant::fromValue<QObject*>(e->singletonInstance<QObject*>(type));
}
+ReturnedValue QQmlTypeWrapper::method_hasInstance(
+ const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
+{
+ // we want to immediately call instanceOf rather than going through Function
+
+ if (!argc)
+ return Encode(false);
+ if (const Object *o = thisObject->as<Object>())
+ return o->instanceOf(argv[0]);
+ return Encode(false);
+}
+
+ReturnedValue QQmlTypeWrapper::method_toString(
+ const FunctionObject *b, const Value *thisObject, const Value *, int)
+{
+ const QQmlTypeWrapper *typeWrapper = thisObject->as<QQmlTypeWrapper>();
+ if (!typeWrapper)
+ RETURN_UNDEFINED();
+
+ const QString name = typeWrapper->d()->type().qmlTypeName();
+ return Encode(b->engine()->newString(name.isEmpty()
+ ? QLatin1String("Unknown Type")
+ : name));
+}
+
+void QQmlTypeWrapper::initProto(ExecutionEngine *v4)
+{
+ if (v4->typeWrapperPrototype()->d_unchecked())
+ return;
+
+ Scope scope(v4);
+ ScopedObject o(scope, v4->newObject());
+
+ o->defineDefaultProperty(v4->symbol_hasInstance(), method_hasInstance, 1, Attr_ReadOnly);
+ o->defineDefaultProperty(v4->id_toString(), method_toString, 0);
+ o->setPrototypeOf(v4->functionPrototype());
+
+ v4->jsObjects[QV4::ExecutionEngine::TypeWrapperProto] = o->d();
+}
// Returns a type wrapper for type t on o. This allows access of enums, and attached properties.
ReturnedValue QQmlTypeWrapper::create(QV4::ExecutionEngine *engine, QObject *o, const QQmlType &t,
Heap::QQmlTypeWrapper::TypeNameMode mode)
{
Q_ASSERT(t.isValid());
- Scope scope(engine);
+ initProto(engine);
- Scoped<QQmlTypeWrapper> w(scope, engine->memoryManager->allocate<QQmlTypeWrapper>(
- mode, o, t.priv()));
- return w.asReturnedValue();
+ QV4::MemoryManager *mm = engine->memoryManager;
+
+ if (const QMetaObject *mo = t.metaObject(); !mo || mo->constructorCount() == 0)
+ return mm->allocate<QQmlTypeWrapper>(mode, o, t.priv())->asReturnedValue();
+
+ return mm->allocate<QQmlTypeConstructor>(mode, o, t.priv())->asReturnedValue();
}
// Returns a type wrapper for importNamespace (of t) on o. This allows nested resolution of a type in a
@@ -157,6 +258,8 @@ ReturnedValue QQmlTypeWrapper::create(
{
Q_ASSERT(t);
Q_ASSERT(importNamespace);
+ initProto(engine);
+
Scope scope(engine);
Scoped<QQmlTypeWrapper> w(scope, engine->memoryManager->allocate<QQmlTypeWrapper>(
@@ -203,7 +306,8 @@ ReturnedValue QQmlTypeWrapper::virtualGet(const Managed *m, PropertyKey id, cons
if (type.isQObjectSingleton() || type.isCompositeSingleton()) {
if (QObject *qobjectSingleton = enginePrivate->singletonInstance<QObject*>(type)) {
// check for enum value
- const bool includeEnums = w->d()->mode == Heap::QQmlTypeWrapper::IncludeEnums;
+ const bool includeEnums
+ = w->d()->typeNameMode() == Heap::QQmlTypeWrapper::IncludeEnums;
if (includeEnums && name->startsWithUpper()) {
bool ok = false;
int value = enumForSingleton(v4, name, type, &ok);
@@ -278,14 +382,11 @@ ReturnedValue QQmlTypeWrapper::virtualGet(const Managed *m, PropertyKey id, cons
// Fall through to base implementation
- } else if (w->d()->typeNamespace) {
- Q_ASSERT(w->d()->importNamespace);
- QQmlTypeNameCache::Result r = w->d()->typeNamespace->query(
- name, w->d()->importNamespace, QQmlTypeLoader::get(enginePrivate));
-
+ } else if (w->d()->kind() == Heap::QQmlTypeWrapper::Namespace) {
+ const QQmlTypeNameCache::Result r = w->d()->queryNamespace(name, enginePrivate);
if (r.isValid()) {
if (r.type.isValid()) {
- return create(scope.engine, object, r.type, w->d()->mode);
+ return create(scope.engine, object, r.type, w->d()->typeNameMode());
} else if (r.scriptIndex != -1) {
QV4::ScopedObject scripts(scope, context->importedScripts().valueRef());
return scripts->get(r.scriptIndex);
@@ -389,15 +490,16 @@ bool QQmlTypeWrapper::virtualIsEqualTo(Managed *a, Managed *b)
return false;
}
-static ReturnedValue instanceOfQObject(const QV4::QQmlTypeWrapper *typeWrapper, const QObjectWrapper *objectWrapper)
+static ReturnedValue instanceOfQObject(
+ const QV4::QQmlTypeWrapper *typeWrapper, QObject *wrapperObject)
{
QV4::ExecutionEngine *engine = typeWrapper->internalClass()->engine;
// in case the wrapper outlived the QObject*
- const QObject *wrapperObject = objectWrapper->object();
if (!wrapperObject)
return engine->throwTypeError();
- const QMetaType myTypeId = typeWrapper->d()->type().typeId();
+ const QQmlType type = typeWrapper->d()->type();
+ const QMetaType myTypeId = type.typeId();
QQmlMetaObject myQmlType;
if (!myTypeId.isValid()) {
// we're a composite type; a composite type cannot be equal to a
@@ -422,7 +524,12 @@ static ReturnedValue instanceOfQObject(const QV4::QQmlTypeWrapper *typeWrapper,
const QMetaObject *theirType = wrapperObject->metaObject();
- return QV4::Encode(QQmlMetaObject::canConvert(theirType, myQmlType));
+ if (QQmlMetaObject::canConvert(theirType, myQmlType))
+ return Encode(true);
+ else if (type.isValueType())
+ return Encode::undefined();
+ else
+ return Encode(false);
}
ReturnedValue QQmlTypeWrapper::virtualInstanceOf(const Object *typeObject, const Value &var)
@@ -431,21 +538,46 @@ ReturnedValue QQmlTypeWrapper::virtualInstanceOf(const Object *typeObject, const
const QV4::QQmlTypeWrapper *typeWrapper = static_cast<const QV4::QQmlTypeWrapper *>(typeObject);
if (const QObjectWrapper *objectWrapper = var.as<QObjectWrapper>())
- return instanceOfQObject(typeWrapper, objectWrapper);
+ return instanceOfQObject(typeWrapper, objectWrapper->object());
+
+ if (const QQmlTypeWrapper *varTypeWrapper = var.as<QQmlTypeWrapper>()) {
+ // Singleton or attachment
+ if (QObject *varObject = varTypeWrapper->object())
+ return instanceOfQObject(typeWrapper, varObject);
+ }
const QQmlType type = typeWrapper->d()->type();
- if (type.isValueType()) {
+
+ // If the target type is an object type we want null.
+ if (!type.isValueType())
+ return Encode(false);
+
+ const auto canCastValueType = [&]() -> bool {
if (const QQmlValueTypeWrapper *valueWrapper = var.as<QQmlValueTypeWrapper>()) {
- return QV4::Encode(QQmlMetaObject::canConvert(valueWrapper->metaObject(),
- type.metaObjectForValueType()));
+ return QQmlMetaObject::canConvert(
+ valueWrapper->metaObject(), type.metaObjectForValueType());
}
- // We want "foo as valuetype" to return undefined if it doesn't match.
- return Encode::undefined();
- }
+ switch (type.typeId().id()) {
+ case QMetaType::Void:
+ return var.isUndefined();
+ case QMetaType::QVariant:
+ return true; // Everything is a var
+ case QMetaType::Int:
+ return var.isInteger();
+ case QMetaType::Double:
+ return var.isDouble(); // Integers are also doubles
+ case QMetaType::QString:
+ return var.isString();
+ case QMetaType::Bool:
+ return var.isBoolean();
+ }
- // If the target type is an object type we want null.
- return Encode(false);
+ return false;
+ };
+
+ // We want "foo as valuetype" to return undefined if it doesn't match.
+ return canCastValueType() ? Encode(true) : Encode::undefined();
}
ReturnedValue QQmlTypeWrapper::virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine, Lookup *lookup)
@@ -469,7 +601,8 @@ ReturnedValue QQmlTypeWrapper::virtualResolveLookupGetter(const Object *object,
QQmlEnginePrivate *e = QQmlEnginePrivate::get(engine->qmlEngine());
if (type.isQObjectSingleton() || type.isCompositeSingleton()) {
if (QObject *qobjectSingleton = e->singletonInstance<QObject*>(type)) {
- const bool includeEnums = w->d()->mode == Heap::QQmlTypeWrapper::IncludeEnums;
+ const bool includeEnums
+ = w->d()->typeNameMode() == Heap::QQmlTypeWrapper::IncludeEnums;
if (!includeEnums || !name->startsWithUpper()) {
QQmlData *ddata = QQmlData::get(qobjectSingleton, false);
if (ddata && ddata->propertyCache) {
diff --git a/src/qml/qml/qqmltypewrapper_p.h b/src/qml/qml/qqmltypewrapper_p.h
index 717efaf20e..fa859dd118 100644
--- a/src/qml/qml/qqmltypewrapper_p.h
+++ b/src/qml/qml/qqmltypewrapper_p.h
@@ -19,7 +19,8 @@
#include <QtCore/qpointer.h>
#include <private/qv4value_p.h>
-#include <private/qv4object_p.h>
+#include <private/qv4functionobject_p.h>
+#include <private/qv4qmetaobjectwrapper_p.h>
QT_BEGIN_NAMESPACE
@@ -32,26 +33,65 @@ namespace QV4 {
namespace Heap {
-struct QQmlTypeWrapper : Object {
- enum TypeNameMode {
- IncludeEnums,
- ExcludeEnums
+struct QQmlTypeWrapper : FunctionObject {
+
+ enum TypeNameMode : quint8 {
+ ExcludeEnums = 0x0,
+ IncludeEnums = 0x1,
+ TypeNameModeMask = 0x1,
+ };
+
+ enum Kind : quint8 {
+ Type = 0x0,
+ Namespace = 0x2,
+ KindMask = 0x2
};
void init(TypeNameMode m, QObject *o, const QQmlTypePrivate *type);
void init(TypeNameMode m, QObject *o, QQmlTypeNameCache *type, const QQmlImportRef *import);
void destroy();
- TypeNameMode mode;
- QV4QPointer<QObject> object;
+
+ const QMetaObject *metaObject() const { return type().metaObject(); }
+ QMetaType metaType() const { return type().typeId(); }
QQmlType type() const;
+ TypeNameMode typeNameMode() const { return TypeNameMode(flags & TypeNameModeMask); }
+ Kind kind() const { return Kind(flags & KindMask); }
+
+ const QQmlPropertyData *ensureConstructorsCache(
+ const QMetaObject *metaObject, QMetaType metaType)
+ {
+ Q_ASSERT(kind() == Type);
+ if (!t.constructors && metaObject) {
+ t.constructors = QMetaObjectWrapper::createConstructors(metaObject, metaType);
+ warnIfUncreatable();
+ }
+ return t.constructors;
+ }
+ void warnIfUncreatable() const;
+
+ QQmlTypeNameCache::Result queryNamespace(
+ const QV4::String *name, QQmlEnginePrivate *enginePrivate) const;
- const QQmlTypePrivate *typePrivate;
- QQmlTypeNameCache *typeNamespace;
- const QQmlImportRef *importNamespace;
+ QV4QPointer<QObject> object;
+
+ union {
+ struct {
+ const QQmlTypePrivate *typePrivate;
+ const QQmlPropertyData *constructors;
+ } t;
+ struct {
+ QQmlTypeNameCache *typeNamespace;
+ const QQmlImportRef *importNamespace;
+ } n;
+ };
+
+ quint8 flags;
};
+using QQmlTypeConstructor = QQmlTypeWrapper;
+
struct QQmlScopedEnumWrapper : Object {
void init() { Object::init(); }
void destroy();
@@ -62,9 +102,10 @@ struct QQmlScopedEnumWrapper : Object {
}
-struct Q_QML_EXPORT QQmlTypeWrapper : Object
+struct Q_QML_EXPORT QQmlTypeWrapper : FunctionObject
{
- V4_OBJECT2(QQmlTypeWrapper, Object)
+ V4_OBJECT2(QQmlTypeWrapper, FunctionObject)
+ V4_PROTOTYPE(typeWrapperPrototype)
V4_NEEDS_DESTROY
bool isSingleton() const;
@@ -74,6 +115,8 @@ struct Q_QML_EXPORT QQmlTypeWrapper : Object
QVariant toVariant() const;
+ static void initProto(ExecutionEngine *v4);
+
static ReturnedValue create(ExecutionEngine *, QObject *, const QQmlType &,
Heap::QQmlTypeWrapper::TypeNameMode = Heap::QQmlTypeWrapper::IncludeEnums);
static ReturnedValue create(ExecutionEngine *, QObject *, const QQmlRefPointer<QQmlTypeNameCache> &, const QQmlImportRef *,
@@ -95,6 +138,25 @@ protected:
static PropertyAttributes virtualGetOwnProperty(const Managed *m, PropertyKey id, Property *p);
static bool virtualIsEqualTo(Managed *that, Managed *o);
static ReturnedValue virtualInstanceOf(const Object *typeObject, const Value &var);
+
+private:
+ static ReturnedValue method_hasInstance(
+ const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_toString(
+ const FunctionObject *b, const Value *thisObject, const Value *, int);
+};
+
+struct QQmlTypeConstructor : QQmlTypeWrapper
+{
+ V4_OBJECT2(QQmlTypeConstructor, QQmlTypeWrapper)
+
+ static ReturnedValue virtualCallAsConstructor(
+ const FunctionObject *f, const Value *argv, int argc, const Value *)
+ {
+ Q_ASSERT(f->as<QQmlTypeWrapper>());
+ return QMetaObjectWrapper::construct(
+ static_cast<const QQmlTypeWrapper *>(f)->d(), argv, argc);
+ }
};
struct Q_QML_EXPORT QQmlScopedEnumWrapper : Object
diff --git a/src/qml/qml/qqmlvaluetype_p.h b/src/qml/qml/qqmlvaluetype_p.h
index 8815c914ce..e6728e0706 100644
--- a/src/qml/qml/qqmlvaluetype_p.h
+++ b/src/qml/qml/qqmlvaluetype_p.h
@@ -116,7 +116,7 @@ struct Q_QML_EXPORT QQmlPointFValueType
QML_STRUCTURED_VALUE
public:
- QQmlPointFValueType() = default;
+ Q_INVOKABLE QQmlPointFValueType() = default;
Q_INVOKABLE QQmlPointFValueType(const QPoint &point) : v(point) {}
Q_INVOKABLE QString toString() const;
qreal x() const;
@@ -164,7 +164,7 @@ struct Q_QML_EXPORT QQmlSizeFValueType
QML_STRUCTURED_VALUE
public:
- QQmlSizeFValueType() = default;
+ Q_INVOKABLE QQmlSizeFValueType() = default;
Q_INVOKABLE QQmlSizeFValueType(const QSize &size) : v(size) {}
Q_INVOKABLE QString toString() const;
qreal width() const;
@@ -218,7 +218,7 @@ struct Q_QML_EXPORT QQmlRectFValueType
QML_STRUCTURED_VALUE
public:
- QQmlRectFValueType() = default;
+ Q_INVOKABLE QQmlRectFValueType() = default;
Q_INVOKABLE QQmlRectFValueType(const QRect &rect) : v(rect) {}
Q_INVOKABLE QString toString() const;
qreal x() const;
diff --git a/src/qml/qml/qqmlvaluetypewrapper.cpp b/src/qml/qml/qqmlvaluetypewrapper.cpp
index 7075d0f5f6..f68bdbf8fe 100644
--- a/src/qml/qml/qqmlvaluetypewrapper.cpp
+++ b/src/qml/qml/qqmlvaluetypewrapper.cpp
@@ -3,37 +3,30 @@
#include "qqmlvaluetypewrapper_p.h"
-#include <private/qqmlvaluetype_p.h>
#include <private/qqmlbinding_p.h>
-#include <private/qqmlglobal_p.h>
#include <private/qqmlbuiltinfunctions_p.h>
+#include <private/qqmlvaluetype_p.h>
-#include <private/qv4engine_p.h>
-#include <private/qv4functionobject_p.h>
-#include <private/qv4variantobject_p.h>
#include <private/qv4alloca_p.h>
-#include <private/qv4stackframe_p.h>
-#include <private/qv4objectiterator_p.h>
-#include <private/qv4qobjectwrapper_p.h>
-#include <private/qv4identifiertable_p.h>
-#include <private/qv4lookup_p.h>
-#include <private/qv4sequenceobject_p.h>
#include <private/qv4arraybuffer_p.h>
#include <private/qv4dateobject_p.h>
+#include <private/qv4engine_p.h>
+#include <private/qv4functionobject_p.h>
+#include <private/qv4identifiertable_p.h>
#include <private/qv4jsonobject_p.h>
+#include <private/qv4lookup_p.h>
+#include <private/qv4qobjectwrapper_p.h>
+#include <private/qv4stackframe_p.h>
+#include <private/qv4variantobject_p.h>
+
+#include <QtCore/qline.h>
+#include <QtCore/qsize.h>
+#include <QtCore/qdatetime.h>
+#include <QtCore/qloggingcategory.h>
+
#if QT_CONFIG(regularexpression)
#include <private/qv4regexpobject_p.h>
#endif
-#if QT_CONFIG(qml_locale)
-#include <private/qqmllocale_p.h>
-#endif
-#include <QtCore/qloggingcategory.h>
-#include <QtCore/qdatetime.h>
-#include <QtCore/QLine>
-#include <QtCore/QLineF>
-#include <QtCore/QSize>
-#include <QtCore/QSizeF>
-#include <QtCore/QTimeZone>
QT_BEGIN_NAMESPACE
@@ -304,7 +297,7 @@ static ReturnedValue getGadgetProperty(ExecutionEngine *engine,
{
if (isFunction) {
// calling a Q_INVOKABLE function of a value type
- return QV4::QObjectMethod::create(engine->rootContext(), valueTypeWrapper, coreIndex);
+ return QV4::QObjectMethod::create(engine, valueTypeWrapper, coreIndex);
}
const QMetaObject *metaObject = valueTypeWrapper->metaObject();
@@ -785,7 +778,7 @@ bool QQmlValueTypeWrapper::virtualPut(Managed *m, PropertyKey id, const Value &v
QV4::Scoped<QQmlBindingFunction> bindingFunction(scope, (const Value &)f);
- QV4::ScopedFunctionObject f(scope, bindingFunction->bindingFunction());
+ QV4::Scoped<JavaScriptFunctionObject> f(scope, bindingFunction->bindingFunction());
QV4::ScopedContext ctx(scope, f->scope());
QQmlBinding *newBinding = QQmlBinding::create(&cacheData, f->function(), referenceObject, context, ctx);
newBinding->setSourceLocation(bindingFunction->currentLocation());
diff --git a/src/qml/qml/qqmlvaluetypewrapper_p.h b/src/qml/qml/qqmlvaluetypewrapper_p.h
index 5b3894a07f..97709dfb4c 100644
--- a/src/qml/qml/qqmlvaluetypewrapper_p.h
+++ b/src/qml/qml/qqmlvaluetypewrapper_p.h
@@ -19,14 +19,6 @@
#include <private/qtqmlglobal_p.h>
#include <private/qv4referenceobject_p.h>
-#include <private/qqmlpropertycache_p.h>
-#include <private/qqmltype_p_p.h>
-#include <private/qqmltypewrapper_p.h>
-#include <private/qv4object_p.h>
-#include <private/qv4qobjectwrapper_p.h>
-#include <private/qv4sequenceobject_p.h>
-#include <private/qv4value_p.h>
-#include <private/qv4referenceobject_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp
index 5f3b6975ca..dffddd2e0d 100644
--- a/src/qml/qml/qqmlvmemetaobject.cpp
+++ b/src/qml/qml/qqmlvmemetaobject.cpp
@@ -1141,7 +1141,7 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
QV4::Scope scope(v4);
- QV4::ScopedFunctionObject function(scope, method(id));
+ QV4::Scoped<QV4::JavaScriptFunctionObject> function(scope, method(id));
if (!function) {
// The function was not compiled. There are some exceptional cases which the
// expression rewriter does not rewrite properly (e.g., \r-terminated lines
diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp
index c5d18860db..b4800584a3 100644
--- a/src/qml/qml/qqmlxmlhttprequest.cpp
+++ b/src/qml/qml/qqmlxmlhttprequest.cpp
@@ -1708,7 +1708,7 @@ DEFINE_OBJECT_VTABLE(QQmlXMLHttpRequestWrapper);
void Heap::QQmlXMLHttpRequestCtor::init(ExecutionEngine *engine)
{
- Heap::FunctionObject::init(engine->rootContext(), QStringLiteral("XMLHttpRequest"));
+ Heap::FunctionObject::init(engine, QStringLiteral("XMLHttpRequest"));
Scope scope(engine);
Scoped<QV4::QQmlXMLHttpRequestCtor> ctor(scope, this);
diff --git a/src/qml/qqmlbuiltins_p.h b/src/qml/qqmlbuiltins_p.h
index edf2579760..d95ed26ab6 100644
--- a/src/qml/qqmlbuiltins_p.h
+++ b/src/qml/qqmlbuiltins_p.h
@@ -35,6 +35,9 @@
#include <QtCore/qvariantmap.h>
#include <QtCore/qtypes.h>
#include <QtCore/qchar.h>
+#include <QtCore/qjsonobject.h>
+#include <QtCore/qjsonvalue.h>
+#include <QtCore/qjsonarray.h>
#include <climits>
@@ -337,6 +340,14 @@ struct QQmlQByteArrayForeign
QML_FOREIGN(QByteArray)
};
+struct QQmlQByteArrayListForeign
+{
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_FOREIGN(QByteArrayList)
+ QML_SEQUENTIAL_CONTAINER(QByteArray)
+};
+
struct QQmlQStringListForeign
{
Q_GADGET
@@ -393,6 +404,30 @@ struct QQmlV4FunctionPtrForeign
QML_EXTENDED(QQmlV4FunctionPtrForeign)
};
+struct QQmlQJsonObjectForeign
+{
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_FOREIGN(QJsonObject)
+ QML_EXTENDED_JAVASCRIPT(Object)
+};
+
+struct QQmlQJsonValueForeign
+{
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_FOREIGN(QJsonValue)
+ QML_EXTENDED_JAVASCRIPT(Object)
+};
+
+struct QQmlQJsonArrayForeign
+{
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_FOREIGN(QJsonArray)
+ QML_SEQUENTIAL_CONTAINER(QJsonValue)
+};
+
QT_END_NAMESPACE
#endif // QQMLBUILTINS_H
diff --git a/src/qml/types/qqmlconnections.cpp b/src/qml/types/qqmlconnections.cpp
index 19363f9f76..99541a64dc 100644
--- a/src/qml/types/qqmlconnections.cpp
+++ b/src/qml/types/qqmlconnections.cpp
@@ -415,13 +415,12 @@ void QQmlConnections::connectSignalsToMethods()
auto *signal = new QQmlBoundSignal(target, signalIndex, this, qmlEngine(this));
signal->setEnabled(d->enabled);
- QV4::ScopedFunctionObject method(
+ QV4::Scoped<QV4::JavaScriptFunctionObject> method(
scope, vmeMetaObject->vmeMethod(handler->coreIndex()));
QQmlBoundSignalExpression *expression = ctxtdata
? new QQmlBoundSignalExpression(
- target, signalIndex, ctxtdata, this,
- method->as<QV4::FunctionObject>()->function())
+ target, signalIndex, ctxtdata, this, method->function())
: nullptr;
signal->takeExpression(expression);