2022-05-13 13:12:05 +00:00
|
|
|
// Copyright (C) 2021 The Qt Company Ltd.
|
|
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
2021-11-16 15:49:49 +00:00
|
|
|
|
|
|
|
#include "qqmljscodegenerator_p.h"
|
2022-12-13 00:43:09 +00:00
|
|
|
#include "qqmljsmetatypes_p.h"
|
|
|
|
#include "qqmljsregistercontent_p.h"
|
|
|
|
#include "qqmljsscope_p.h"
|
|
|
|
#include "qqmljsutils_p.h"
|
2021-11-16 15:49:49 +00:00
|
|
|
|
|
|
|
#include <private/qqmljstypepropagator_p.h>
|
|
|
|
|
|
|
|
#include <private/qqmlirbuilder_p.h>
|
|
|
|
#include <private/qqmljsscope_p.h>
|
2021-12-17 14:52:17 +00:00
|
|
|
#include <private/qqmljsutils_p.h>
|
2021-11-16 15:49:49 +00:00
|
|
|
#include <private/qv4compilerscanfunctions_p.h>
|
2022-02-16 13:01:52 +00:00
|
|
|
#include <private/qduplicatetracker_p.h>
|
2021-11-16 15:49:49 +00:00
|
|
|
|
|
|
|
#include <QtCore/qdir.h>
|
|
|
|
#include <QtCore/qfileinfo.h>
|
|
|
|
|
|
|
|
QT_BEGIN_NAMESPACE
|
|
|
|
|
2022-03-21 09:21:18 +00:00
|
|
|
using namespace Qt::StringLiterals;
|
|
|
|
|
2021-11-16 15:49:49 +00:00
|
|
|
/*!
|
|
|
|
* \internal
|
|
|
|
* \class QQmlJSCodeGenerator
|
|
|
|
*
|
|
|
|
* This is a final compile pass that generates C++ code from a function and the
|
|
|
|
* annotations produced by previous passes. Such annotations are produced by
|
|
|
|
* QQmlJSTypePropagator, and possibly amended by other passes.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define BYTECODE_UNIMPLEMENTED() Q_ASSERT_X(false, Q_FUNC_INFO, "not implemented");
|
|
|
|
|
|
|
|
#define INJECT_TRACE_INFO(function) \
|
|
|
|
static const bool injectTraceInfo = true; \
|
|
|
|
if (injectTraceInfo) { \
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u"// "_s + QStringLiteral(#function) + u'\n'; \
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
2022-11-18 10:40:10 +00:00
|
|
|
|
|
|
|
static bool isTypeStorable(const QQmlJSTypeResolver *resolver, const QQmlJSScope::ConstPtr &type)
|
|
|
|
{
|
|
|
|
return !type.isNull()
|
|
|
|
&& !resolver->equals(type, resolver->nullType())
|
|
|
|
&& !resolver->equals(type, resolver->voidType());
|
|
|
|
}
|
|
|
|
|
2021-11-16 15:49:49 +00:00
|
|
|
QString QQmlJSCodeGenerator::castTargetName(const QQmlJSScope::ConstPtr &type) const
|
|
|
|
{
|
2021-12-17 14:52:17 +00:00
|
|
|
return type->augmentedInternalName();
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
QQmlJSCodeGenerator::QQmlJSCodeGenerator(const QV4::Compiler::Context *compilerContext,
|
|
|
|
const QV4::Compiler::JSUnitGenerator *unitGenerator,
|
|
|
|
const QQmlJSTypeResolver *typeResolver,
|
2023-02-22 10:06:54 +00:00
|
|
|
QQmlJSLogger *logger)
|
2021-11-16 15:49:49 +00:00
|
|
|
: QQmlJSCompilePass(unitGenerator, typeResolver, logger)
|
|
|
|
, m_context(compilerContext)
|
|
|
|
{}
|
|
|
|
|
|
|
|
QString QQmlJSCodeGenerator::metaTypeFromType(const QQmlJSScope::ConstPtr &type) const
|
|
|
|
{
|
2022-03-21 09:21:18 +00:00
|
|
|
return u"QMetaType::fromType<"_s + type->augmentedInternalName() + u">()"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
QString QQmlJSCodeGenerator::metaTypeFromName(const QQmlJSScope::ConstPtr &type) const
|
|
|
|
{
|
2022-03-21 09:21:18 +00:00
|
|
|
return u"[]() { static const auto t = QMetaType::fromName(\""_s
|
2022-03-16 08:32:24 +00:00
|
|
|
+ QString::fromUtf8(QMetaObject::normalizedType(type->augmentedInternalName().toUtf8()))
|
2022-03-21 09:21:18 +00:00
|
|
|
+ u"\"); return t; }()"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
QString QQmlJSCodeGenerator::metaObject(const QQmlJSScope::ConstPtr &objectType)
|
|
|
|
{
|
2022-02-24 15:36:14 +00:00
|
|
|
if (!objectType->isComposite()) {
|
2022-03-21 09:21:18 +00:00
|
|
|
if (objectType->internalName() == u"QObject"_s
|
|
|
|
|| objectType->internalName() == u"QQmlComponent"_s) {
|
|
|
|
return u'&' + objectType->internalName() + u"::staticMetaObject"_s;
|
2022-02-24 15:36:14 +00:00
|
|
|
}
|
2022-03-21 09:21:18 +00:00
|
|
|
return metaTypeFromName(objectType) + u".metaObject()"_s;
|
2022-02-24 15:36:14 +00:00
|
|
|
}
|
2021-11-16 15:49:49 +00:00
|
|
|
|
2022-03-21 09:21:18 +00:00
|
|
|
reject(u"retrieving the metaObject of a composite type without using an instance."_s);
|
2021-11-16 15:49:49 +00:00
|
|
|
return QString();
|
|
|
|
}
|
|
|
|
|
2023-02-16 09:54:34 +00:00
|
|
|
QString QQmlJSCodeGenerator::metaType(const QQmlJSScope::ConstPtr &type)
|
|
|
|
{
|
|
|
|
return m_typeResolver->equals(m_typeResolver->genericType(type), type)
|
|
|
|
? metaTypeFromType(type)
|
|
|
|
: metaTypeFromName(type);
|
|
|
|
}
|
|
|
|
|
2021-11-16 15:49:49 +00:00
|
|
|
QQmlJSAotFunction QQmlJSCodeGenerator::run(
|
|
|
|
const Function *function, const InstructionAnnotations *annotations,
|
|
|
|
QQmlJS::DiagnosticMessage *error)
|
|
|
|
{
|
|
|
|
m_annotations = annotations;
|
|
|
|
m_function = function;
|
|
|
|
m_error = error;
|
|
|
|
|
2022-02-16 13:01:52 +00:00
|
|
|
QHash<int, QHash<QQmlJSScope::ConstPtr, QString>> registerNames;
|
2021-11-16 15:49:49 +00:00
|
|
|
|
2022-02-02 18:08:29 +00:00
|
|
|
auto addVariable = [&](int registerIndex, const QQmlJSScope::ConstPtr &seenType) {
|
|
|
|
// Don't generate any variables for registers that are initialized with undefined.
|
2022-02-16 13:01:52 +00:00
|
|
|
if (registerIndex == InvalidRegister || !isTypeStorable(m_typeResolver, seenType))
|
2022-02-02 18:08:29 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
auto &typesForRegisters = m_registerVariables[registerIndex];
|
|
|
|
if (!typesForRegisters.contains(seenType)) {
|
2022-02-16 13:01:52 +00:00
|
|
|
auto ¤tRegisterNames = registerNames[registerIndex];
|
|
|
|
QString &name = currentRegisterNames[m_typeResolver->comparableType(seenType)];
|
|
|
|
if (name.isEmpty())
|
2022-10-05 05:29:16 +00:00
|
|
|
name = u"r%1_%2"_s.arg(registerIndex).arg(currentRegisterNames.size());
|
2022-02-16 13:01:52 +00:00
|
|
|
typesForRegisters[seenType] = name;
|
2022-02-02 18:08:29 +00:00
|
|
|
}
|
|
|
|
};
|
2021-11-16 15:49:49 +00:00
|
|
|
|
2022-03-01 11:30:24 +00:00
|
|
|
QT_WARNING_PUSH
|
|
|
|
QT_WARNING_DISABLE_CLANG("-Wrange-loop-analysis")
|
2022-02-16 14:12:26 +00:00
|
|
|
for (const auto &annotation : *m_annotations) {
|
|
|
|
addVariable(annotation.second.changedRegisterIndex,
|
|
|
|
annotation.second.changedRegister.storedType());
|
|
|
|
for (auto it = annotation.second.typeConversions.begin(),
|
|
|
|
end = annotation.second.typeConversions.end();
|
2022-02-02 18:08:29 +00:00
|
|
|
it != end; ++it) {
|
2022-11-28 15:07:24 +00:00
|
|
|
addVariable(it.key(), it.value().content.storedType());
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
}
|
2022-03-01 11:30:24 +00:00
|
|
|
QT_WARNING_POP
|
2021-11-16 15:49:49 +00:00
|
|
|
|
|
|
|
// ensure we have m_labels for loops
|
|
|
|
for (const auto loopLabel : m_context->labelInfo)
|
2022-10-05 05:29:16 +00:00
|
|
|
m_labels.insert(loopLabel, u"label_%1"_s.arg(m_labels.size()));
|
2021-11-16 15:49:49 +00:00
|
|
|
|
2022-06-28 20:04:43 +00:00
|
|
|
// Initialize the first instruction's state to hold the arguments.
|
|
|
|
// After this, the arguments (or whatever becomes of them) are carried
|
|
|
|
// over into any further basic blocks automatically.
|
|
|
|
m_state.State::operator=(initialState(m_function));
|
|
|
|
|
2021-11-16 15:49:49 +00:00
|
|
|
const QByteArray byteCode = function->code;
|
2022-10-05 05:29:16 +00:00
|
|
|
decode(byteCode.constData(), static_cast<uint>(byteCode.size()));
|
2021-11-16 15:49:49 +00:00
|
|
|
|
|
|
|
QQmlJSAotFunction result;
|
|
|
|
result.includes.swap(m_includes);
|
|
|
|
|
2023-02-22 10:06:54 +00:00
|
|
|
result.code += u"// %1 at line %2, column %3\n"_s
|
|
|
|
.arg(m_context->name).arg(m_context->line).arg(m_context->column);
|
|
|
|
|
2022-02-16 13:01:52 +00:00
|
|
|
QDuplicateTracker<QString> generatedVariables;
|
2022-06-27 14:26:43 +00:00
|
|
|
for (auto registerIt = m_registerVariables.cbegin(), registerEnd = m_registerVariables.cend();
|
|
|
|
registerIt != registerEnd; ++registerIt) {
|
|
|
|
const auto ®isterTypes = *registerIt;
|
|
|
|
const int registerIndex = registerIt.key();
|
|
|
|
|
|
|
|
const bool registerIsArgument = isArgument(registerIndex);
|
|
|
|
|
2021-11-16 15:49:49 +00:00
|
|
|
for (auto registerTypeIt = registerTypes.constBegin(), end = registerTypes.constEnd();
|
|
|
|
registerTypeIt != end; ++registerTypeIt) {
|
|
|
|
|
|
|
|
const QQmlJSScope::ConstPtr storedType = registerTypeIt.key();
|
2022-02-16 13:01:52 +00:00
|
|
|
|
|
|
|
if (generatedVariables.hasSeen(registerTypeIt.value()))
|
2022-02-03 16:31:33 +00:00
|
|
|
continue;
|
|
|
|
|
2021-11-16 15:49:49 +00:00
|
|
|
result.code += storedType->internalName();
|
|
|
|
|
2022-06-29 12:01:22 +00:00
|
|
|
const bool isPointer
|
|
|
|
= (storedType->accessSemantics() == QQmlJSScope::AccessSemantics::Reference);
|
|
|
|
if (isPointer)
|
2022-03-21 09:21:18 +00:00
|
|
|
result.code += u" *"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
else
|
2022-06-29 12:01:22 +00:00
|
|
|
result.code += u' ';
|
2021-11-16 15:49:49 +00:00
|
|
|
|
2023-04-17 12:12:05 +00:00
|
|
|
if (!registerIsArgument
|
|
|
|
&& registerIndex != Accumulator
|
|
|
|
&& registerIndex != This
|
2022-06-30 15:45:07 +00:00
|
|
|
&& !m_typeResolver->registerIsStoredIn(
|
|
|
|
function->registerTypes[registerIndex - firstRegisterIndex()],
|
|
|
|
m_typeResolver->voidType())) {
|
|
|
|
result.code += registerTypeIt.value() + u" = "_s;
|
2023-02-21 10:47:08 +00:00
|
|
|
result.code += convertStored(m_typeResolver->voidType(), storedType, QString());
|
2022-06-30 15:45:07 +00:00
|
|
|
} else if (registerIsArgument && m_typeResolver->registerIsStoredIn(
|
|
|
|
argumentType(registerIndex), storedType)) {
|
2022-06-27 14:26:43 +00:00
|
|
|
const int argumentIndex = registerIndex - FirstArgument;
|
2023-02-21 10:47:08 +00:00
|
|
|
const QQmlJSRegisterContent argument
|
|
|
|
= m_function->argumentTypes[argumentIndex];
|
|
|
|
const QQmlJSRegisterContent original
|
|
|
|
= m_typeResolver->original(argument);
|
2022-06-29 12:01:22 +00:00
|
|
|
|
|
|
|
const bool needsConversion = argument != original;
|
|
|
|
if (!isPointer && registerTypes.size() == 1 && !needsConversion) {
|
|
|
|
// Not a pointer, never written to, and doesn't need any initial conversion.
|
|
|
|
// This is a readonly argument.
|
|
|
|
//
|
|
|
|
// We would like to make the variable a const ref if it's a readonly argument,
|
|
|
|
// but due to the various call interfaces accepting non-const values, we can't.
|
|
|
|
// We rely on those calls to still not modify their arguments in place.
|
|
|
|
result.code += u'&';
|
|
|
|
}
|
|
|
|
|
|
|
|
result.code += registerTypeIt.value() + u" = "_s;
|
|
|
|
|
2023-02-21 10:47:08 +00:00
|
|
|
const QString originalValue = u"*static_cast<"_s + castTargetName(original.storedType())
|
2022-06-27 14:26:43 +00:00
|
|
|
+ u"*>(argumentsPtr["_s + QString::number(argumentIndex) + u"])"_s;
|
2022-06-29 12:01:22 +00:00
|
|
|
|
|
|
|
if (needsConversion)
|
|
|
|
result.code += conversion(original, argument, originalValue);
|
|
|
|
else
|
|
|
|
result.code += originalValue;
|
|
|
|
} else {
|
|
|
|
result.code += registerTypeIt.value();
|
2022-06-27 14:26:43 +00:00
|
|
|
}
|
2022-03-21 09:21:18 +00:00
|
|
|
result.code += u";\n"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-17 12:04:35 +00:00
|
|
|
result.code += m_body;
|
2021-11-16 15:49:49 +00:00
|
|
|
|
2022-10-06 09:30:50 +00:00
|
|
|
for (const QQmlJSRegisterContent &argType : std::as_const(function->argumentTypes)) {
|
2022-02-21 16:35:44 +00:00
|
|
|
if (argType.isValid()) {
|
2022-06-29 12:01:22 +00:00
|
|
|
result.argumentTypes.append(
|
|
|
|
m_typeResolver->originalType(argType.storedType())
|
|
|
|
->augmentedInternalName());
|
2021-11-16 15:49:49 +00:00
|
|
|
} else {
|
2022-03-21 09:21:18 +00:00
|
|
|
result.argumentTypes.append(u"void"_s);
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (function->returnType) {
|
|
|
|
result.returnType = function->returnType->internalName();
|
|
|
|
if (function->returnType->accessSemantics() == QQmlJSScope::AccessSemantics::Reference)
|
|
|
|
result.returnType += u'*';
|
|
|
|
} else {
|
2022-03-21 09:21:18 +00:00
|
|
|
result.returnType = u"void"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2022-02-03 16:31:33 +00:00
|
|
|
QString QQmlJSCodeGenerator::errorReturnValue()
|
2021-11-16 15:49:49 +00:00
|
|
|
{
|
2022-06-20 09:19:58 +00:00
|
|
|
if (auto ret = m_function->returnType) {
|
|
|
|
return ret->accessSemantics() == QQmlJSScope::AccessSemantics::Reference
|
2023-02-21 10:47:08 +00:00
|
|
|
? convertStored(m_typeResolver->nullType(), ret, QString())
|
2022-06-20 09:19:58 +00:00
|
|
|
: ret->internalName() + u"()"_s;
|
|
|
|
}
|
2021-11-16 15:49:49 +00:00
|
|
|
return QString();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_Ret()
|
|
|
|
{
|
|
|
|
INJECT_TRACE_INFO(generate_Ret);
|
|
|
|
|
|
|
|
if (m_function->returnType) {
|
2022-03-21 09:21:18 +00:00
|
|
|
const QString signalUndefined = u"aotContext->setReturnValueUndefined();\n"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
if (!m_state.accumulatorVariableIn.isEmpty()) {
|
2022-02-17 12:04:35 +00:00
|
|
|
const QString in = m_state.accumulatorVariableIn;
|
2022-02-04 21:35:23 +00:00
|
|
|
if (m_typeResolver->registerIsStoredIn(
|
|
|
|
m_state.accumulatorIn(), m_typeResolver->varType())) {
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u"if (!"_s + in + u".isValid())\n"_s;
|
|
|
|
m_body += u" "_s + signalUndefined;
|
2022-02-04 21:35:23 +00:00
|
|
|
} else if (m_typeResolver->registerIsStoredIn(
|
|
|
|
m_state.accumulatorIn(), m_typeResolver->jsPrimitiveType())) {
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u"if ("_s + in
|
|
|
|
+ u".type() == QJSPrimitiveValue::Undefined)\n"_s;
|
|
|
|
m_body += u" "_s + signalUndefined;
|
2022-02-04 21:35:23 +00:00
|
|
|
} else if (m_typeResolver->registerIsStoredIn(
|
|
|
|
m_state.accumulatorIn(), m_typeResolver->jsValueType())) {
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u"if ("_s + in + u".isUndefined())\n"_s;
|
|
|
|
m_body += u" "_s + signalUndefined;
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u"return "_s
|
2023-02-21 10:47:08 +00:00
|
|
|
+ convertStored(m_state.accumulatorIn().storedType(), m_function->returnType, in);
|
2022-02-16 13:01:52 +00:00
|
|
|
} else {
|
|
|
|
if (m_typeResolver->equals(m_state.accumulatorIn().storedType(),
|
|
|
|
m_typeResolver->voidType())) {
|
|
|
|
m_body += signalUndefined;
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
2023-02-21 10:47:08 +00:00
|
|
|
m_body += u"return "_s + convertStored(
|
2022-02-16 13:01:52 +00:00
|
|
|
m_state.accumulatorIn().storedType(), m_function->returnType, QString());
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
} else {
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u"return"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u";\n"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
m_skipUntilNextLabel = true;
|
2022-06-27 14:26:43 +00:00
|
|
|
resetState();
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_Debug()
|
|
|
|
{
|
|
|
|
BYTECODE_UNIMPLEMENTED();
|
|
|
|
}
|
|
|
|
|
|
|
|
static QString toNumericString(double value)
|
|
|
|
{
|
|
|
|
if (value >= std::numeric_limits<int>::min() && value <= std::numeric_limits<int>::max()) {
|
|
|
|
const int i = value;
|
|
|
|
if (i == value)
|
|
|
|
return QString::number(i);
|
|
|
|
}
|
|
|
|
|
2022-02-17 09:02:51 +00:00
|
|
|
switch (qFpClassify(value)) {
|
|
|
|
case FP_INFINITE: {
|
2022-03-21 09:21:18 +00:00
|
|
|
const QString inf = u"std::numeric_limits<double>::infinity()"_s;
|
2022-02-17 09:02:51 +00:00
|
|
|
return std::signbit(value) ? (u'-' + inf) : inf;
|
|
|
|
}
|
|
|
|
case FP_NAN:
|
2022-03-21 09:21:18 +00:00
|
|
|
return u"std::numeric_limits<double>::quiet_NaN()"_s;
|
2022-02-17 09:02:51 +00:00
|
|
|
case FP_ZERO:
|
2022-03-21 09:21:18 +00:00
|
|
|
return std::signbit(value) ? u"-0.0"_s : u"0"_s;
|
2022-02-17 09:02:51 +00:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2021-11-16 15:49:49 +00:00
|
|
|
return QString::number(value, 'f', std::numeric_limits<double>::max_digits10);
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_LoadConst(int index)
|
|
|
|
{
|
|
|
|
INJECT_TRACE_INFO(generate_LoadConst);
|
|
|
|
|
2022-07-29 14:13:43 +00:00
|
|
|
// You cannot actually get it to generate LoadConst for anything but double. We have
|
|
|
|
// a numer of specialized instructions for the other types, after all. However, let's
|
|
|
|
// play it safe.
|
|
|
|
|
|
|
|
const QV4::ReturnedValue encodedConst = m_jsUnitGenerator->constant(index);
|
|
|
|
const QV4::StaticValue value = QV4::StaticValue::fromReturnedValue(encodedConst);
|
|
|
|
const QQmlJSScope::ConstPtr type = m_typeResolver->typeForConst(encodedConst);
|
|
|
|
|
|
|
|
m_body += m_state.accumulatorVariableOut + u" = "_s;
|
|
|
|
if (type == m_typeResolver->realType()) {
|
|
|
|
m_body += conversion(
|
2023-02-21 10:47:08 +00:00
|
|
|
type, m_state.accumulatorOut(),
|
2022-07-29 14:13:43 +00:00
|
|
|
toNumericString(value.doubleValue()));
|
2023-03-27 16:00:46 +00:00
|
|
|
} else if (type == m_typeResolver->int32Type()) {
|
2022-07-29 14:13:43 +00:00
|
|
|
m_body += conversion(
|
2023-02-21 10:47:08 +00:00
|
|
|
type, m_state.accumulatorOut(),
|
2022-07-29 14:13:43 +00:00
|
|
|
QString::number(value.integerValue()));
|
|
|
|
} else if (type == m_typeResolver->boolType()) {
|
|
|
|
m_body += conversion(
|
2023-02-21 10:47:08 +00:00
|
|
|
type, m_state.accumulatorOut(),
|
2022-07-29 14:13:43 +00:00
|
|
|
value.booleanValue() ? u"true"_s : u"false"_s);
|
|
|
|
} else if (type == m_typeResolver->voidType()) {
|
|
|
|
m_body += conversion(
|
2023-02-21 10:47:08 +00:00
|
|
|
type, m_state.accumulatorOut(),
|
2022-07-29 14:13:43 +00:00
|
|
|
QString());
|
|
|
|
} else if (type == m_typeResolver->nullType()) {
|
|
|
|
m_body += conversion(
|
2023-02-21 10:47:08 +00:00
|
|
|
type, m_state.accumulatorOut(),
|
2022-07-29 14:13:43 +00:00
|
|
|
u"nullptr"_s);
|
|
|
|
} else {
|
|
|
|
reject(u"unsupported constant type"_s);
|
|
|
|
}
|
2022-02-16 15:34:56 +00:00
|
|
|
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u";\n"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_LoadZero()
|
|
|
|
{
|
|
|
|
INJECT_TRACE_INFO(generate_LoadZero);
|
|
|
|
|
|
|
|
m_body += m_state.accumulatorVariableOut;
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u" = "_s + conversion(
|
2023-03-27 16:00:46 +00:00
|
|
|
m_typeResolver->int32Type(), m_state.accumulatorOut(), u"0"_s);
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u";\n"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_LoadTrue()
|
|
|
|
{
|
|
|
|
INJECT_TRACE_INFO(generate_LoadTrue);
|
|
|
|
|
|
|
|
m_body += m_state.accumulatorVariableOut;
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u" = "_s + conversion(
|
2023-02-21 10:47:08 +00:00
|
|
|
m_typeResolver->boolType(), m_state.accumulatorOut(), u"true"_s);
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u";\n"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_LoadFalse()
|
|
|
|
{
|
|
|
|
INJECT_TRACE_INFO(generate_LoadFalse);
|
|
|
|
|
|
|
|
m_body += m_state.accumulatorVariableOut;
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u" = "_s + conversion(
|
2023-02-21 10:47:08 +00:00
|
|
|
m_typeResolver->boolType(), m_state.accumulatorOut(), u"false"_s);
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u";\n"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_LoadNull()
|
|
|
|
{
|
|
|
|
INJECT_TRACE_INFO(generate_LoadNull);
|
2022-02-16 13:01:52 +00:00
|
|
|
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += m_state.accumulatorVariableOut + u" = "_s;
|
2023-02-21 10:47:08 +00:00
|
|
|
m_body += conversion(m_typeResolver->nullType(), m_state.accumulatorOut(),
|
2022-03-21 09:21:18 +00:00
|
|
|
u"nullptr"_s);
|
|
|
|
m_body += u";\n"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_LoadUndefined()
|
|
|
|
{
|
|
|
|
INJECT_TRACE_INFO(generate_LoadUndefined);
|
2022-02-16 13:01:52 +00:00
|
|
|
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += m_state.accumulatorVariableOut + u" = "_s;
|
2023-02-21 10:47:08 +00:00
|
|
|
m_body += conversion(m_typeResolver->voidType(), m_state.accumulatorOut(),
|
2022-02-16 13:01:52 +00:00
|
|
|
QString());
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u";\n"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_LoadInt(int value)
|
|
|
|
{
|
|
|
|
INJECT_TRACE_INFO(generate_LoadInt);
|
|
|
|
|
|
|
|
m_body += m_state.accumulatorVariableOut;
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u" = "_s;
|
2023-03-27 16:00:46 +00:00
|
|
|
m_body += conversion(m_typeResolver->int32Type(), m_state.accumulatorOut(),
|
2022-02-16 13:01:52 +00:00
|
|
|
QString::number(value));
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u";\n"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_MoveConst(int constIndex, int destTemp)
|
|
|
|
{
|
|
|
|
INJECT_TRACE_INFO(generate_MoveConst);
|
|
|
|
|
2022-02-02 18:08:29 +00:00
|
|
|
Q_ASSERT(destTemp == m_state.changedRegisterIndex());
|
|
|
|
|
|
|
|
auto var = changedRegisterVariable();
|
2021-11-16 15:49:49 +00:00
|
|
|
if (var.isEmpty())
|
|
|
|
return; // Do not load 'undefined'
|
|
|
|
|
|
|
|
const auto v4Value = QV4::StaticValue::fromReturnedValue(
|
|
|
|
m_jsUnitGenerator->constant(constIndex));
|
|
|
|
|
2023-02-21 10:47:08 +00:00
|
|
|
const auto changed = m_state.changedRegister();
|
2022-02-16 15:34:56 +00:00
|
|
|
QQmlJSScope::ConstPtr contained;
|
|
|
|
QString input;
|
2021-11-16 15:49:49 +00:00
|
|
|
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += var + u" = "_s;
|
2022-02-24 07:53:07 +00:00
|
|
|
if (v4Value.isNull()) {
|
2022-02-16 15:34:56 +00:00
|
|
|
contained = m_typeResolver->nullType();
|
2022-02-24 07:53:07 +00:00
|
|
|
} else if (v4Value.isUndefined()) {
|
2022-02-16 15:34:56 +00:00
|
|
|
contained = m_typeResolver->voidType();
|
2022-02-24 07:53:07 +00:00
|
|
|
} else if (v4Value.isBoolean()) {
|
2022-02-16 15:34:56 +00:00
|
|
|
contained = m_typeResolver->boolType();
|
2022-03-21 09:21:18 +00:00
|
|
|
input = v4Value.booleanValue() ? u"true"_s : u"false"_s;
|
2022-02-24 07:53:07 +00:00
|
|
|
} else if (v4Value.isInteger()) {
|
2023-03-27 16:00:46 +00:00
|
|
|
contained = m_typeResolver->int32Type();
|
2022-02-16 15:34:56 +00:00
|
|
|
input = QString::number(v4Value.int_32());
|
2022-02-24 07:53:07 +00:00
|
|
|
} else if (v4Value.isDouble()) {
|
2022-02-16 15:34:56 +00:00
|
|
|
contained = m_typeResolver->realType();
|
|
|
|
input = toNumericString(v4Value.doubleValue());
|
2022-02-24 07:53:07 +00:00
|
|
|
} else {
|
2022-03-21 09:21:18 +00:00
|
|
|
reject(u"unknown const type"_s);
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += conversion(contained, changed, input) + u";\n"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_LoadReg(int reg)
|
|
|
|
{
|
|
|
|
INJECT_TRACE_INFO(generate_LoadReg);
|
|
|
|
|
|
|
|
m_body += m_state.accumulatorVariableOut;
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u" = "_s;
|
2022-11-28 15:07:24 +00:00
|
|
|
m_body += conversion(
|
|
|
|
registerType(reg), m_state.accumulatorOut(), consumedRegisterVariable(reg));
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u";\n"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_StoreReg(int reg)
|
|
|
|
{
|
|
|
|
INJECT_TRACE_INFO(generate_StoreReg);
|
|
|
|
|
2022-02-02 18:08:29 +00:00
|
|
|
Q_ASSERT(m_state.changedRegisterIndex() == reg);
|
|
|
|
Q_ASSERT(m_state.accumulatorIn().isValid());
|
|
|
|
const QString var = changedRegisterVariable();
|
2021-11-16 15:49:49 +00:00
|
|
|
if (var.isEmpty())
|
|
|
|
return; // don't store "undefined"
|
|
|
|
m_body += var;
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u" = "_s;
|
2022-02-02 18:08:29 +00:00
|
|
|
m_body += conversion(m_state.accumulatorIn(), m_state.changedRegister(),
|
2022-11-28 15:07:24 +00:00
|
|
|
consumedAccumulatorVariableIn());
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u";\n"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_MoveReg(int srcReg, int destReg)
|
|
|
|
{
|
|
|
|
INJECT_TRACE_INFO(generate_MoveReg);
|
|
|
|
|
2022-02-02 18:08:29 +00:00
|
|
|
Q_ASSERT(m_state.changedRegisterIndex() == destReg);
|
|
|
|
const QString destRegName = changedRegisterVariable();
|
2022-03-01 07:44:28 +00:00
|
|
|
if (destRegName.isEmpty())
|
|
|
|
return; // don't store things we cannot store.
|
2021-11-16 15:49:49 +00:00
|
|
|
m_body += destRegName;
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u" = "_s;
|
2022-11-28 15:07:24 +00:00
|
|
|
m_body += conversion(
|
|
|
|
registerType(srcReg), m_state.changedRegister(), consumedRegisterVariable(srcReg));
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u";\n"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_LoadImport(int index)
|
|
|
|
{
|
|
|
|
Q_UNUSED(index)
|
|
|
|
BYTECODE_UNIMPLEMENTED();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_LoadLocal(int index)
|
|
|
|
{
|
|
|
|
Q_UNUSED(index);
|
2022-03-21 09:21:18 +00:00
|
|
|
reject(u"LoadLocal"_s);
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_StoreLocal(int index)
|
|
|
|
{
|
|
|
|
Q_UNUSED(index)
|
|
|
|
BYTECODE_UNIMPLEMENTED();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_LoadScopedLocal(int scope, int index)
|
|
|
|
{
|
|
|
|
Q_UNUSED(scope)
|
|
|
|
Q_UNUSED(index)
|
|
|
|
BYTECODE_UNIMPLEMENTED();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_StoreScopedLocal(int scope, int index)
|
|
|
|
{
|
|
|
|
Q_UNUSED(scope)
|
|
|
|
Q_UNUSED(index)
|
|
|
|
BYTECODE_UNIMPLEMENTED();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_LoadRuntimeString(int stringId)
|
|
|
|
{
|
|
|
|
INJECT_TRACE_INFO(generate_LoadRuntimeString);
|
|
|
|
|
|
|
|
m_body += m_state.accumulatorVariableOut;
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u" = "_s;
|
2023-02-21 10:47:08 +00:00
|
|
|
m_body += conversion(m_typeResolver->stringType(), m_state.accumulatorOut(),
|
2022-02-16 13:01:52 +00:00
|
|
|
QQmlJSUtils::toLiteral(m_jsUnitGenerator->stringForIndex(stringId)));
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u";\n"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_MoveRegExp(int regExpId, int destReg)
|
|
|
|
{
|
|
|
|
Q_UNUSED(regExpId)
|
|
|
|
Q_UNUSED(destReg)
|
|
|
|
BYTECODE_UNIMPLEMENTED();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_LoadClosure(int value)
|
|
|
|
{
|
|
|
|
Q_UNUSED(value)
|
2022-05-18 12:39:52 +00:00
|
|
|
reject(u"LoadClosure"_s);
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_LoadName(int nameIndex)
|
|
|
|
{
|
|
|
|
Q_UNUSED(nameIndex)
|
2022-03-21 09:21:18 +00:00
|
|
|
reject(u"LoadName"_s);
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_LoadGlobalLookup(int index)
|
|
|
|
{
|
|
|
|
INJECT_TRACE_INFO(generate_LoadGlobalLookup);
|
|
|
|
|
2022-02-16 15:34:56 +00:00
|
|
|
AccumulatorConverter registers(this);
|
|
|
|
|
2022-03-21 09:21:18 +00:00
|
|
|
const QString lookup = u"aotContext->loadGlobalLookup("_s + QString::number(index)
|
|
|
|
+ u", &"_s + m_state.accumulatorVariableOut + u", "_s
|
2022-02-02 18:08:29 +00:00
|
|
|
+ metaTypeFromType(m_state.accumulatorOut().storedType()) + u')';
|
2022-03-21 09:21:18 +00:00
|
|
|
const QString initialization = u"aotContext->initLoadGlobalLookup("_s
|
2021-11-16 15:49:49 +00:00
|
|
|
+ QString::number(index) + u')';
|
|
|
|
generateLookup(lookup, initialization);
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_LoadQmlContextPropertyLookup(int index)
|
|
|
|
{
|
|
|
|
INJECT_TRACE_INFO(generate_LoadQmlContextPropertyLookup);
|
|
|
|
|
2022-02-16 13:01:52 +00:00
|
|
|
AccumulatorConverter registers(this);
|
|
|
|
|
2021-11-16 15:49:49 +00:00
|
|
|
const int nameIndex = m_jsUnitGenerator->lookupNameIndex(index);
|
|
|
|
const QString name = m_jsUnitGenerator->stringForIndex(nameIndex);
|
2022-02-02 18:08:29 +00:00
|
|
|
if (m_state.accumulatorOut().variant() == QQmlJSRegisterContent::JavaScriptGlobal) {
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += m_state.accumulatorVariableOut + u" = "_s
|
2021-11-16 15:49:49 +00:00
|
|
|
+ conversion(
|
2023-02-21 10:47:08 +00:00
|
|
|
m_typeResolver->original(m_state.accumulatorOut()), m_state.accumulatorOut(),
|
2022-03-21 09:21:18 +00:00
|
|
|
u"aotContext->javaScriptGlobalProperty("_s + QString::number(nameIndex) + u")")
|
|
|
|
+ u";\n"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const QString indexString = QString::number(index);
|
2022-02-02 18:08:29 +00:00
|
|
|
if (m_state.accumulatorOut().variant() == QQmlJSRegisterContent::ObjectById) {
|
2022-03-21 09:21:18 +00:00
|
|
|
const QString lookup = u"aotContext->loadContextIdLookup("_s
|
|
|
|
+ indexString + u", "_s
|
2022-02-02 18:08:29 +00:00
|
|
|
+ contentPointer(m_state.accumulatorOut(), m_state.accumulatorVariableOut) + u')';
|
2022-03-21 09:21:18 +00:00
|
|
|
const QString initialization = u"aotContext->initLoadContextIdLookup("_s
|
2021-11-16 15:49:49 +00:00
|
|
|
+ indexString + u')';
|
|
|
|
generateLookup(lookup, initialization);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-02-02 18:08:29 +00:00
|
|
|
const bool isProperty = m_state.accumulatorOut().isProperty();
|
|
|
|
const QQmlJSScope::ConstPtr scope = m_state.accumulatorOut().scopeType();
|
|
|
|
const QQmlJSScope::ConstPtr stored = m_state.accumulatorOut().storedType();
|
2021-11-16 15:49:49 +00:00
|
|
|
if (isProperty) {
|
2022-02-02 18:08:29 +00:00
|
|
|
const auto lookupType = contentType(m_state.accumulatorOut(), m_state.accumulatorVariableOut);
|
2021-11-16 15:49:49 +00:00
|
|
|
|
2022-03-21 09:21:18 +00:00
|
|
|
const QString lookup = u"aotContext->loadScopeObjectPropertyLookup("_s
|
|
|
|
+ indexString + u", "_s
|
2022-02-02 18:08:29 +00:00
|
|
|
+ contentPointer(m_state.accumulatorOut(), m_state.accumulatorVariableOut) + u')';
|
2021-11-16 15:49:49 +00:00
|
|
|
const QString initialization
|
2022-03-21 09:21:18 +00:00
|
|
|
= u"aotContext->initLoadScopeObjectPropertyLookup("_s
|
|
|
|
+ indexString + u", "_s
|
2021-11-16 15:49:49 +00:00
|
|
|
+ lookupType + u')';
|
|
|
|
const QString preparation = getLookupPreparation(
|
2022-02-02 18:08:29 +00:00
|
|
|
m_state.accumulatorOut(), m_state.accumulatorVariableOut, index);
|
2021-11-16 15:49:49 +00:00
|
|
|
|
|
|
|
generateLookup(lookup, initialization, preparation);
|
2022-02-02 18:08:29 +00:00
|
|
|
} else if (m_state.accumulatorOut().isType() || m_state.accumulatorOut().isImportNamespace()) {
|
2021-11-16 15:49:49 +00:00
|
|
|
generateTypeLookup(index);
|
|
|
|
} else {
|
2022-03-21 09:21:18 +00:00
|
|
|
reject(u"lookup of %1"_s.arg(m_state.accumulatorOut().descriptiveName()));
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_StoreNameSloppy(int nameIndex)
|
|
|
|
{
|
|
|
|
INJECT_TRACE_INFO(generate_StoreNameSloppy);
|
|
|
|
|
|
|
|
const QString name = m_jsUnitGenerator->stringForIndex(nameIndex);
|
2023-02-24 12:00:33 +00:00
|
|
|
const QQmlJSRegisterContent type = m_typeResolver->scopedType(m_function->qmlScope, name);
|
2021-11-16 15:49:49 +00:00
|
|
|
Q_ASSERT(type.isProperty());
|
|
|
|
|
|
|
|
switch (type.variant()) {
|
|
|
|
case QQmlJSRegisterContent::ScopeProperty:
|
|
|
|
case QQmlJSRegisterContent::ExtensionScopeProperty: {
|
2022-06-24 12:40:02 +00:00
|
|
|
// Do not convert here. We may intentionally pass the "wrong" type, for example to trigger
|
|
|
|
// a property reset.
|
|
|
|
m_body += u"aotContext->storeNameSloppy("_s + QString::number(nameIndex)
|
|
|
|
+ u", "_s
|
|
|
|
+ contentPointer(m_state.accumulatorIn(), m_state.accumulatorVariableIn)
|
|
|
|
+ u", "_s
|
|
|
|
+ contentType(m_state.accumulatorIn(), m_state.accumulatorVariableIn) + u')';
|
|
|
|
m_body += u";\n"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case QQmlJSRegisterContent::ScopeMethod:
|
|
|
|
case QQmlJSRegisterContent::ExtensionScopeMethod:
|
2022-03-21 09:21:18 +00:00
|
|
|
reject(u"assignment to scope method"_s);
|
2021-11-16 15:49:49 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
Q_UNREACHABLE();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_StoreNameStrict(int name)
|
|
|
|
{
|
|
|
|
Q_UNUSED(name)
|
|
|
|
BYTECODE_UNIMPLEMENTED();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_LoadElement(int base)
|
|
|
|
{
|
|
|
|
INJECT_TRACE_INFO(generate_LoadElement);
|
|
|
|
|
|
|
|
const QQmlJSRegisterContent baseType = registerType(base);
|
|
|
|
|
2022-05-19 14:38:55 +00:00
|
|
|
if (!m_typeResolver->isNumeric(m_state.accumulatorIn())
|
|
|
|
|| (!baseType.isList()
|
|
|
|
&& !m_typeResolver->registerIsStoredIn(baseType, m_typeResolver->stringType()))) {
|
2022-03-21 09:21:18 +00:00
|
|
|
reject(u"LoadElement with non-list base type or non-numeric arguments"_s);
|
2021-11-16 15:49:49 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-02-16 15:34:56 +00:00
|
|
|
AccumulatorConverter registers(this);
|
|
|
|
|
2022-02-17 12:04:35 +00:00
|
|
|
const QString baseName = registerVariable(base);
|
|
|
|
const QString indexName = m_state.accumulatorVariableIn;
|
2021-11-16 15:49:49 +00:00
|
|
|
|
2022-05-17 12:40:00 +00:00
|
|
|
const QString voidAssignment = u" "_s + m_state.accumulatorVariableOut + u" = "_s +
|
|
|
|
conversion(m_typeResolver->globalType(m_typeResolver->voidType()),
|
|
|
|
m_state.accumulatorOut(), QString()) + u";\n"_s;
|
|
|
|
|
|
|
|
if (!m_typeResolver->isIntegral(m_state.accumulatorIn())) {
|
|
|
|
m_body += u"if (!QJSNumberCoercion::isInteger("_s + indexName + u"))\n"_s
|
|
|
|
+ voidAssignment
|
|
|
|
+ u"else "_s;
|
|
|
|
}
|
2022-05-19 13:50:31 +00:00
|
|
|
|
2023-03-27 16:00:46 +00:00
|
|
|
if (!m_typeResolver->isUnsignedInteger(
|
|
|
|
m_typeResolver->containedType(m_state.accumulatorIn()))) {
|
|
|
|
m_body += u"if ("_s + indexName + u" < 0)\n"_s
|
|
|
|
+ voidAssignment
|
|
|
|
+ u"else "_s;
|
|
|
|
}
|
|
|
|
|
2022-05-19 13:50:31 +00:00
|
|
|
if (m_typeResolver->registerIsStoredIn(baseType, m_typeResolver->listPropertyType())) {
|
|
|
|
// Our QQmlListProperty only keeps plain QObject*.
|
|
|
|
const auto valueType = m_typeResolver->valueType(baseType);
|
|
|
|
const auto elementType = m_typeResolver->globalType(
|
|
|
|
m_typeResolver->genericType(m_typeResolver->containedType(valueType)));
|
|
|
|
|
2023-03-27 16:00:46 +00:00
|
|
|
m_body += u"if ("_s + indexName + u" < "_s + baseName
|
|
|
|
+ u".count(&"_s + baseName + u"))\n"_s;
|
2022-05-19 13:50:31 +00:00
|
|
|
m_body += u" "_s + m_state.accumulatorVariableOut + u" = "_s +
|
|
|
|
conversion(elementType, m_state.accumulatorOut(),
|
|
|
|
baseName + u".at(&"_s + baseName + u", "_s
|
|
|
|
+ indexName + u')') + u";\n"_s;
|
|
|
|
m_body += u"else\n"_s
|
|
|
|
+ voidAssignment;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const auto elementType = m_typeResolver->valueType(baseType);
|
2021-11-16 15:49:49 +00:00
|
|
|
|
2022-05-19 14:38:55 +00:00
|
|
|
QString access = baseName + u".at("_s + indexName + u')';
|
|
|
|
|
|
|
|
// TODO: Once we get a char type in QML, use it here.
|
|
|
|
if (m_typeResolver->registerIsStoredIn(baseType, m_typeResolver->stringType()))
|
|
|
|
access = u"QString("_s + access + u")"_s;
|
2023-04-28 12:02:20 +00:00
|
|
|
else if (m_state.isRegisterAffectedBySideEffects(base))
|
|
|
|
reject(u"LoadElement on a sequence potentially affected by side effects"_s);
|
2022-05-19 14:38:55 +00:00
|
|
|
|
2023-03-27 16:00:46 +00:00
|
|
|
m_body += u"if ("_s + indexName + u" < "_s + baseName + u".size())\n"_s;
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u" "_s + m_state.accumulatorVariableOut + u" = "_s +
|
2022-05-19 14:38:55 +00:00
|
|
|
conversion(elementType, m_state.accumulatorOut(), access) + u";\n"_s;
|
2022-05-17 12:40:00 +00:00
|
|
|
m_body += u"else\n"_s
|
|
|
|
+ voidAssignment;
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_StoreElement(int base, int index)
|
|
|
|
{
|
|
|
|
INJECT_TRACE_INFO(generate_StoreElement);
|
|
|
|
|
|
|
|
const QQmlJSRegisterContent baseType = registerType(base);
|
2022-05-17 12:40:00 +00:00
|
|
|
const QQmlJSRegisterContent indexType = registerType(index);
|
2021-11-16 15:49:49 +00:00
|
|
|
|
|
|
|
if (!m_typeResolver->isNumeric(registerType(index)) || !baseType.isList()) {
|
2022-03-21 09:21:18 +00:00
|
|
|
reject(u"StoreElement with non-list base type or non-numeric arguments"_s);
|
2021-11-16 15:49:49 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-02-04 21:35:23 +00:00
|
|
|
if (!m_typeResolver->registerIsStoredIn(baseType, m_typeResolver->listPropertyType())) {
|
2023-04-28 12:02:20 +00:00
|
|
|
reject(u"indirect StoreElement"_s);
|
2021-11-16 15:49:49 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-02-17 12:04:35 +00:00
|
|
|
const QString baseName = registerVariable(base);
|
|
|
|
const QString indexName = registerVariable(index);
|
2021-11-16 15:49:49 +00:00
|
|
|
|
|
|
|
const auto valueType = m_typeResolver->valueType(baseType);
|
|
|
|
const auto elementType = m_typeResolver->globalType(m_typeResolver->genericType(
|
|
|
|
m_typeResolver->containedType(valueType)));
|
|
|
|
|
2022-05-17 12:40:00 +00:00
|
|
|
m_body += u"if ("_s;
|
|
|
|
if (!m_typeResolver->isIntegral(indexType))
|
|
|
|
m_body += u"QJSNumberCoercion::isInteger("_s + indexName + u") && "_s;
|
2023-03-27 16:00:46 +00:00
|
|
|
if (!m_typeResolver->isUnsignedInteger(m_typeResolver->containedType(indexType)))
|
|
|
|
m_body += indexName + u" >= 0 && "_s;
|
|
|
|
m_body += indexName + u" < "_s + baseName + u".count(&"_s + baseName
|
2022-03-21 09:21:18 +00:00
|
|
|
+ u"))\n"_s;
|
|
|
|
m_body += u" "_s + baseName + u".replace(&"_s + baseName
|
|
|
|
+ u", "_s + indexName + u", "_s;
|
2022-02-17 12:04:35 +00:00
|
|
|
m_body += conversion(m_state.accumulatorIn(), elementType, m_state.accumulatorVariableIn)
|
2022-03-21 09:21:18 +00:00
|
|
|
+ u");\n"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_LoadProperty(int nameIndex)
|
|
|
|
{
|
|
|
|
Q_UNUSED(nameIndex)
|
2022-03-21 09:21:18 +00:00
|
|
|
reject(u"LoadProperty"_s);
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_LoadOptionalProperty(int name, int offset)
|
|
|
|
{
|
|
|
|
Q_UNUSED(name)
|
|
|
|
Q_UNUSED(offset)
|
|
|
|
BYTECODE_UNIMPLEMENTED();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generateEnumLookup(int index)
|
|
|
|
{
|
2022-02-02 18:08:29 +00:00
|
|
|
const QString enumMember = m_state.accumulatorOut().enumMember();
|
2021-11-16 15:49:49 +00:00
|
|
|
|
|
|
|
// If we're referring to the type, there's nothing to do.
|
|
|
|
if (enumMember.isEmpty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
// If the metaenum has the value, just use it and skip all the rest.
|
2022-02-02 18:08:29 +00:00
|
|
|
const QQmlJSMetaEnum metaEnum = m_state.accumulatorOut().enumeration();
|
2021-11-16 15:49:49 +00:00
|
|
|
if (metaEnum.hasValues()) {
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += m_state.accumulatorVariableOut + u" = "_s
|
2021-11-16 15:49:49 +00:00
|
|
|
+ QString::number(metaEnum.value(enumMember));
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u";\n"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-02-02 18:08:29 +00:00
|
|
|
const QQmlJSScope::ConstPtr scopeType = m_state.accumulatorOut().scopeType();
|
2021-11-16 15:49:49 +00:00
|
|
|
|
|
|
|
// Otherwise we would have found an enum with values.
|
|
|
|
Q_ASSERT(!scopeType->isComposite());
|
|
|
|
|
|
|
|
const QString enumName = metaEnum.isFlag() ? metaEnum.alias() : metaEnum.name();
|
2022-03-21 09:21:18 +00:00
|
|
|
const QString lookup = u"aotContext->getEnumLookup("_s + QString::number(index)
|
|
|
|
+ u", &"_s + m_state.accumulatorVariableOut + u')';
|
|
|
|
const QString initialization = u"aotContext->initGetEnumLookup("_s
|
|
|
|
+ QString::number(index) + u", "_s + metaObject(scopeType)
|
|
|
|
+ u", \""_s + enumName + u"\", \""_s + enumMember
|
|
|
|
+ u"\")"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
generateLookup(lookup, initialization);
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generateTypeLookup(int index)
|
|
|
|
{
|
|
|
|
const QString indexString = QString::number(index);
|
2022-11-28 15:07:24 +00:00
|
|
|
const QQmlJSRegisterContent accumulatorIn = m_state.registers.value(Accumulator).content;
|
2021-11-16 15:49:49 +00:00
|
|
|
const QString namespaceString
|
2022-02-02 18:08:29 +00:00
|
|
|
= accumulatorIn.isImportNamespace()
|
|
|
|
? QString::number(accumulatorIn.importNamespace())
|
2022-03-21 09:21:18 +00:00
|
|
|
: u"QQmlPrivate::AOTCompiledContext::InvalidStringId"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
|
2022-02-02 18:08:29 +00:00
|
|
|
switch (m_state.accumulatorOut().variant()) {
|
2021-11-16 15:49:49 +00:00
|
|
|
case QQmlJSRegisterContent::Singleton: {
|
2022-03-21 09:21:18 +00:00
|
|
|
rejectIfNonQObjectOut(u"non-QObject singleton type"_s);
|
|
|
|
const QString lookup = u"aotContext->loadSingletonLookup("_s + indexString
|
|
|
|
+ u", &"_s + m_state.accumulatorVariableOut + u')';
|
|
|
|
const QString initialization = u"aotContext->initLoadSingletonLookup("_s + indexString
|
|
|
|
+ u", "_s + namespaceString + u')';
|
2021-11-16 15:49:49 +00:00
|
|
|
generateLookup(lookup, initialization);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case QQmlJSRegisterContent::ScopeModulePrefix:
|
|
|
|
break;
|
|
|
|
case QQmlJSRegisterContent::ScopeAttached: {
|
2022-03-21 09:21:18 +00:00
|
|
|
rejectIfNonQObjectOut(u"non-QObject attached type"_s);
|
|
|
|
const QString lookup = u"aotContext->loadAttachedLookup("_s + indexString
|
|
|
|
+ u", aotContext->qmlScopeObject, &"_s + m_state.accumulatorVariableOut + u')';
|
|
|
|
const QString initialization = u"aotContext->initLoadAttachedLookup("_s + indexString
|
|
|
|
+ u", "_s + namespaceString + u", aotContext->qmlScopeObject)"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
generateLookup(lookup, initialization);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case QQmlJSRegisterContent::Script:
|
2022-03-21 09:21:18 +00:00
|
|
|
reject(u"script lookup"_s);
|
2021-11-16 15:49:49 +00:00
|
|
|
break;
|
|
|
|
case QQmlJSRegisterContent::MetaType: {
|
2022-04-22 11:36:23 +00:00
|
|
|
if (!m_typeResolver->registerIsStoredIn(
|
|
|
|
m_state.accumulatorOut(), m_typeResolver->metaObjectType())) {
|
|
|
|
// TODO: Can we trigger this somehow?
|
|
|
|
// It might be impossible, but we better be safe here.
|
2022-03-21 09:21:18 +00:00
|
|
|
reject(u"meta-object stored in different type"_s);
|
2022-04-22 11:36:23 +00:00
|
|
|
}
|
2022-03-21 09:21:18 +00:00
|
|
|
const QString lookup = u"aotContext->loadTypeLookup("_s + indexString
|
|
|
|
+ u", &"_s + m_state.accumulatorVariableOut + u')';
|
|
|
|
const QString initialization = u"aotContext->initLoadTypeLookup("_s + indexString
|
|
|
|
+ u", "_s + namespaceString + u")"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
generateLookup(lookup, initialization);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
Q_UNREACHABLE();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-13 00:43:09 +00:00
|
|
|
void QQmlJSCodeGenerator::generateVariantEqualityComparison(
|
|
|
|
const QQmlJSRegisterContent &nonStorableContent, const QString ®isterName, bool invert)
|
|
|
|
{
|
|
|
|
const auto nonStorableType = m_typeResolver->containedType(nonStorableContent);
|
|
|
|
QQmlJSScope::ConstPtr comparedType =
|
|
|
|
m_typeResolver->equals(nonStorableType, m_typeResolver->nullType())
|
|
|
|
? m_typeResolver->nullType()
|
|
|
|
: m_typeResolver->voidType();
|
|
|
|
|
|
|
|
// The common operations for both nulltype and voidtype
|
|
|
|
m_body += u"if ("_s + registerName
|
|
|
|
+ u".metaType() == QMetaType::fromType<QJSPrimitiveValue>()) {\n"_s
|
|
|
|
+ m_state.accumulatorVariableOut + u" = "_s
|
2023-02-21 10:47:08 +00:00
|
|
|
+ conversion(m_typeResolver->boolType(), m_state.accumulatorOut(),
|
2022-12-13 00:43:09 +00:00
|
|
|
u"static_cast<const QJSPrimitiveValue *>("_s + registerName
|
|
|
|
+ u".constData())"_s + u"->type() "_s
|
|
|
|
+ (invert ? u"!="_s : u"=="_s)
|
|
|
|
+ (m_typeResolver->equals(comparedType, m_typeResolver->nullType())
|
|
|
|
? u"QJSPrimitiveValue::Null"_s
|
|
|
|
: u"QJSPrimitiveValue::Undefined"_s))
|
|
|
|
+ u";\n} else if ("_s + registerName
|
|
|
|
+ u".metaType() == QMetaType::fromType<QJSValue>()) {\n"_s
|
|
|
|
+ m_state.accumulatorVariableOut + u" = "_s
|
2023-02-21 10:47:08 +00:00
|
|
|
+ conversion(m_typeResolver->boolType(), m_state.accumulatorOut(),
|
2022-12-13 00:43:09 +00:00
|
|
|
(invert ? u"!"_s : QString()) + u"static_cast<const QJSValue *>("_s
|
|
|
|
+ registerName + u".constData())"_s + u"->"_s
|
|
|
|
+ (m_typeResolver->equals(comparedType, m_typeResolver->nullType())
|
|
|
|
? u"isNull()"_s
|
|
|
|
: u"isUndefined()"_s))
|
|
|
|
+ u";\n}"_s;
|
|
|
|
|
|
|
|
// Generate nullType specific operations (the case when variant contains QObject * or
|
|
|
|
// std::nullptr_t)
|
|
|
|
if (m_typeResolver->equals(nonStorableType, m_typeResolver->nullType())) {
|
|
|
|
m_body += u"else if ("_s + registerName
|
|
|
|
+ u".metaType().flags().testFlag(QMetaType::PointerToQObject)) {\n"_s
|
|
|
|
+ m_state.accumulatorVariableOut + u" = "_s
|
2023-02-21 10:47:08 +00:00
|
|
|
+ conversion(m_typeResolver->boolType(), m_state.accumulatorOut(),
|
2022-12-13 00:43:09 +00:00
|
|
|
u"*static_cast<QObject *const *>("_s + registerName
|
|
|
|
+ u".constData())"_s + (invert ? u"!="_s : u"=="_s)
|
|
|
|
+ u" nullptr"_s)
|
|
|
|
+ u";\n} else if ("_s + registerName
|
|
|
|
+ u".metaType() == QMetaType::fromType<std::nullptr_t>()) {\n"_s
|
|
|
|
+ m_state.accumulatorVariableOut + u" = "_s + (invert ? u"false"_s : u"true"_s)
|
|
|
|
+ u";\n}\n"_s;
|
|
|
|
}
|
|
|
|
|
|
|
|
// fallback case (if variant contains a different type, then it is not null or undefined)
|
|
|
|
m_body += u"else {\n"_s + m_state.accumulatorVariableOut + u" = "_s
|
|
|
|
+ (invert ? (registerName + u".isValid() ? true : false"_s)
|
|
|
|
: (registerName + u".isValid() ? false : true"_s))
|
|
|
|
+ u";}\n"_s;
|
|
|
|
}
|
|
|
|
|
2022-04-22 11:36:23 +00:00
|
|
|
void QQmlJSCodeGenerator::rejectIfNonQObjectOut(const QString &error)
|
|
|
|
{
|
|
|
|
if (m_state.accumulatorOut().storedType()->accessSemantics()
|
|
|
|
!= QQmlJSScope::AccessSemantics::Reference) {
|
|
|
|
reject(error);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-18 08:55:20 +00:00
|
|
|
/*!
|
|
|
|
* \internal
|
|
|
|
*
|
|
|
|
* generates a check for the content pointer to be valid.
|
|
|
|
* Returns true if the content pointer needs to be retrieved from a QVariant, or
|
|
|
|
* false if the variable can be used as-is.
|
|
|
|
*/
|
2023-02-16 09:54:34 +00:00
|
|
|
bool QQmlJSCodeGenerator::generateContentPointerCheck(
|
|
|
|
const QQmlJSScope::ConstPtr &required, const QQmlJSRegisterContent &actual,
|
|
|
|
const QString &variable, const QString &errorMessage)
|
|
|
|
{
|
|
|
|
const QQmlJSScope::ConstPtr scope = required;
|
|
|
|
const QQmlJSScope::ConstPtr input = m_typeResolver->containedType(actual);
|
|
|
|
if (QQmlJSUtils::searchBaseAndExtensionTypes(input,
|
|
|
|
[&](const QQmlJSScope::ConstPtr &base) {
|
|
|
|
return m_typeResolver->equals(base, scope);
|
|
|
|
})) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!m_typeResolver->canHold(input, scope)) {
|
|
|
|
reject(u"lookup of members of %1 in %2"_s.arg(
|
|
|
|
scope->internalName(), input->internalName()));
|
|
|
|
}
|
2023-04-18 08:55:20 +00:00
|
|
|
|
|
|
|
bool needsVarContentConversion = false;
|
|
|
|
QString processedErrorMessage;
|
|
|
|
if (actual.storedType()->isReferenceType()) {
|
|
|
|
// Since we have verified the type in qqmljstypepropagator.cpp we now know
|
|
|
|
// that we can only have either null or the actual type here. Therefore,
|
|
|
|
// it's enough to check the pointer for null.
|
|
|
|
m_body += u"if ("_s + variable + u" == nullptr) {\n "_s;
|
|
|
|
processedErrorMessage = errorMessage.arg(u"null");
|
|
|
|
} else if (m_typeResolver->equals(actual.storedType(), m_typeResolver->varType())) {
|
|
|
|
// Since we have verified the type in qqmljstypepropagator.cpp we now know
|
|
|
|
// that we can only have either undefined or the actual type here. Therefore,
|
|
|
|
// it's enough to check the QVariant for isValid().
|
|
|
|
m_body += u"if (!"_s + variable + u".isValid()) {\n "_s;
|
|
|
|
needsVarContentConversion = true;
|
|
|
|
processedErrorMessage = errorMessage.arg(u"undefined");
|
|
|
|
} else {
|
2023-02-16 09:54:34 +00:00
|
|
|
reject(u"retrieving metatype from %1"_s.arg(actual.descriptiveName()));
|
|
|
|
}
|
|
|
|
|
|
|
|
generateSetInstructionPointer();
|
|
|
|
m_body += u" aotContext->engine->throwError(QJSValue::TypeError, "_s;
|
2023-04-18 08:55:20 +00:00
|
|
|
m_body += u"QLatin1String(\"%1\"));\n"_s.arg(processedErrorMessage);
|
2023-02-16 09:54:34 +00:00
|
|
|
m_body += u" return "_s + errorReturnValue() + u";\n"_s;
|
|
|
|
m_body += u"}\n"_s;
|
2023-04-18 08:55:20 +00:00
|
|
|
return needsVarContentConversion;
|
2023-02-16 09:54:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
QString QQmlJSCodeGenerator::resolveValueTypeContentPointer(
|
|
|
|
const QQmlJSScope::ConstPtr &required, const QQmlJSRegisterContent &actual,
|
|
|
|
const QString &variable, const QString &errorMessage)
|
|
|
|
{
|
|
|
|
if (generateContentPointerCheck(required, actual, variable, errorMessage))
|
|
|
|
return variable + u".data()"_s;
|
|
|
|
return contentPointer(actual, variable);
|
|
|
|
}
|
|
|
|
|
|
|
|
QString QQmlJSCodeGenerator::resolveQObjectPointer(
|
|
|
|
const QQmlJSScope::ConstPtr &required, const QQmlJSRegisterContent &actual,
|
|
|
|
const QString &variable, const QString &errorMessage)
|
|
|
|
{
|
|
|
|
if (generateContentPointerCheck(required, actual, variable, errorMessage))
|
|
|
|
return u"*static_cast<QObject *const *>("_s + variable + u".constData())"_s;
|
|
|
|
return variable;
|
|
|
|
}
|
|
|
|
|
2021-11-16 15:49:49 +00:00
|
|
|
void QQmlJSCodeGenerator::generate_GetLookup(int index)
|
|
|
|
{
|
|
|
|
INJECT_TRACE_INFO(generate_GetLookup);
|
|
|
|
|
2022-02-02 18:08:29 +00:00
|
|
|
if (m_state.accumulatorOut().isMethod()) {
|
2022-03-21 09:21:18 +00:00
|
|
|
reject(u"lookup of function property."_s);
|
2021-11-16 15:49:49 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-02-16 13:01:52 +00:00
|
|
|
if (m_state.accumulatorOut().isImportNamespace()) {
|
|
|
|
Q_ASSERT(m_state.accumulatorOut().variant() == QQmlJSRegisterContent::ObjectModulePrefix);
|
|
|
|
// If we have an object module prefix, we need to pass through the original object.
|
|
|
|
if (m_state.accumulatorVariableIn != m_state.accumulatorVariableOut) {
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += m_state.accumulatorVariableOut + u" = "_s
|
2022-02-16 13:01:52 +00:00
|
|
|
+ conversion(m_state.accumulatorIn(), m_state.accumulatorOut(),
|
2022-02-17 12:04:35 +00:00
|
|
|
m_state.accumulatorVariableIn)
|
2022-03-21 09:21:18 +00:00
|
|
|
+ u";\n"_s;
|
2022-02-16 13:01:52 +00:00
|
|
|
}
|
2021-11-16 15:49:49 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-02-16 13:01:52 +00:00
|
|
|
AccumulatorConverter registers(this);
|
|
|
|
|
|
|
|
if (m_state.accumulatorOut().isEnumeration()) {
|
|
|
|
generateEnumLookup(index);
|
|
|
|
return;
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const QString indexString = QString::number(index);
|
2022-02-02 18:08:29 +00:00
|
|
|
const QString namespaceString = m_state.accumulatorIn().isImportNamespace()
|
|
|
|
? QString::number(m_state.accumulatorIn().importNamespace())
|
2022-03-21 09:21:18 +00:00
|
|
|
: u"QQmlPrivate::AOTCompiledContext::InvalidStringId"_s;
|
2022-02-04 21:35:23 +00:00
|
|
|
const auto accumulatorIn = m_state.accumulatorIn();
|
2023-02-16 09:54:34 +00:00
|
|
|
const QQmlJSScope::ConstPtr scope = m_state.accumulatorOut().scopeType();
|
|
|
|
const bool isReferenceType = scope->isReferenceType();
|
2022-02-16 12:33:47 +00:00
|
|
|
|
|
|
|
switch (m_state.accumulatorOut().variant()) {
|
|
|
|
case QQmlJSRegisterContent::ObjectAttached: {
|
2021-12-17 10:21:35 +00:00
|
|
|
if (!isReferenceType) {
|
|
|
|
// This can happen on incomplete type information. We contextually know that the
|
|
|
|
// type must be a QObject, but we cannot construct the inheritance chain. Then we
|
|
|
|
// store it in a generic type. Technically we could even convert it to QObject*, but
|
|
|
|
// that would be expensive.
|
2022-03-21 09:21:18 +00:00
|
|
|
reject(u"attached object for non-QObject type"_s);
|
2021-12-17 10:21:35 +00:00
|
|
|
}
|
2023-04-03 08:15:07 +00:00
|
|
|
|
|
|
|
if (!m_state.accumulatorIn().storedType()->isReferenceType()) {
|
|
|
|
// This can happen if we retroactively determine that the property might not be
|
|
|
|
// what we think it is (ie, it can be shadowed).
|
|
|
|
reject(u"attached object of potentially non-QObject base"_s);
|
|
|
|
}
|
|
|
|
|
2022-03-21 09:21:18 +00:00
|
|
|
rejectIfNonQObjectOut(u"non-QObject attached type"_s);
|
2021-12-17 10:21:35 +00:00
|
|
|
|
2022-03-21 09:21:18 +00:00
|
|
|
const QString lookup = u"aotContext->loadAttachedLookup("_s + indexString
|
|
|
|
+ u", "_s + m_state.accumulatorVariableIn
|
|
|
|
+ u", &"_s + m_state.accumulatorVariableOut + u')';
|
|
|
|
const QString initialization = u"aotContext->initLoadAttachedLookup("_s
|
|
|
|
+ indexString + u", "_s + namespaceString + u", "_s
|
2022-02-17 12:04:35 +00:00
|
|
|
+ m_state.accumulatorVariableIn + u')';
|
2021-11-16 15:49:49 +00:00
|
|
|
generateLookup(lookup, initialization);
|
|
|
|
return;
|
2022-02-16 12:33:47 +00:00
|
|
|
}
|
2022-04-22 11:36:23 +00:00
|
|
|
case QQmlJSRegisterContent::ScopeAttached:
|
|
|
|
case QQmlJSRegisterContent::Singleton:
|
2022-03-23 09:04:22 +00:00
|
|
|
case QQmlJSRegisterContent::MetaType: {
|
2022-04-22 11:36:23 +00:00
|
|
|
generateTypeLookup(index);
|
2022-03-23 09:04:22 +00:00
|
|
|
return;
|
|
|
|
}
|
2022-02-16 12:33:47 +00:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2021-11-16 15:49:49 +00:00
|
|
|
|
2022-02-02 18:08:29 +00:00
|
|
|
Q_ASSERT(m_state.accumulatorOut().isProperty());
|
2021-11-16 15:49:49 +00:00
|
|
|
|
2023-02-16 09:54:34 +00:00
|
|
|
if (m_typeResolver->registerIsStoredIn(accumulatorIn, m_typeResolver->jsValueType())) {
|
|
|
|
reject(u"lookup in QJSValue"_s);
|
|
|
|
} else if (isReferenceType) {
|
|
|
|
const QString inputPointer = resolveQObjectPointer(
|
|
|
|
scope, accumulatorIn, m_state.accumulatorVariableIn,
|
2023-04-18 08:55:20 +00:00
|
|
|
u"Cannot read property '%1' of %2"_s.arg(
|
2023-02-16 09:54:34 +00:00
|
|
|
m_jsUnitGenerator->lookupName(index)));
|
2022-03-21 09:21:18 +00:00
|
|
|
const QString lookup = u"aotContext->getObjectLookup("_s + indexString
|
2023-02-16 09:54:34 +00:00
|
|
|
+ u", "_s + inputPointer + u", "_s
|
2022-02-02 18:08:29 +00:00
|
|
|
+ contentPointer(m_state.accumulatorOut(), m_state.accumulatorVariableOut) + u')';
|
2022-03-21 09:21:18 +00:00
|
|
|
const QString initialization = u"aotContext->initGetObjectLookup("_s
|
2023-02-16 09:54:34 +00:00
|
|
|
+ indexString + u", "_s + inputPointer
|
2022-03-21 09:21:18 +00:00
|
|
|
+ u", "_s + contentType(m_state.accumulatorOut(), m_state.accumulatorVariableOut)
|
2021-11-16 15:49:49 +00:00
|
|
|
+ u')';
|
|
|
|
const QString preparation = getLookupPreparation(
|
2022-02-02 18:08:29 +00:00
|
|
|
m_state.accumulatorOut(), m_state.accumulatorVariableOut, index);
|
2021-11-16 15:49:49 +00:00
|
|
|
generateLookup(lookup, initialization, preparation);
|
2022-03-14 13:11:05 +00:00
|
|
|
} else if (m_typeResolver->registerIsStoredIn(accumulatorIn, m_typeResolver->listPropertyType())
|
2022-03-21 09:21:18 +00:00
|
|
|
&& m_jsUnitGenerator->lookupName(index) == u"length"_s) {
|
|
|
|
m_body += m_state.accumulatorVariableOut + u" = "_s;
|
2022-03-14 13:11:05 +00:00
|
|
|
m_body += conversion(
|
2023-03-27 16:00:46 +00:00
|
|
|
m_typeResolver->globalType(m_typeResolver->int32Type()),
|
|
|
|
m_state.accumulatorOut(),
|
2022-03-21 09:21:18 +00:00
|
|
|
m_state.accumulatorVariableIn + u".count("_s + u'&'
|
2022-03-14 13:11:05 +00:00
|
|
|
+ m_state.accumulatorVariableIn + u')');
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u";\n"_s;
|
2023-02-20 08:57:06 +00:00
|
|
|
} else if (m_typeResolver->registerIsStoredIn(accumulatorIn,
|
|
|
|
m_typeResolver->variantMapType())) {
|
|
|
|
QString mapLookup = m_state.accumulatorVariableIn + u"["_s
|
|
|
|
+ QQmlJSUtils::toLiteral(m_jsUnitGenerator->lookupName(index)) + u"]"_s;
|
|
|
|
m_body += m_state.accumulatorVariableOut + u" = "_s;
|
|
|
|
m_body += conversion(m_typeResolver->globalType(m_typeResolver->varType()),
|
|
|
|
m_state.accumulatorOut(), mapLookup);
|
|
|
|
m_body += u";\n"_s;
|
2022-02-04 21:35:23 +00:00
|
|
|
} else if ((m_typeResolver->registerIsStoredIn(accumulatorIn, m_typeResolver->stringType())
|
|
|
|
|| accumulatorIn.storedType()->accessSemantics()
|
|
|
|
== QQmlJSScope::AccessSemantics::Sequence)
|
2022-03-21 09:21:18 +00:00
|
|
|
&& m_jsUnitGenerator->lookupName(index) == u"length"_s) {
|
|
|
|
m_body += m_state.accumulatorVariableOut + u" = "_s
|
2023-03-27 16:00:46 +00:00
|
|
|
+ conversion(m_typeResolver->globalType(m_typeResolver->int32Type()),
|
2022-03-14 13:11:05 +00:00
|
|
|
m_state.accumulatorOut(),
|
2022-03-21 09:21:18 +00:00
|
|
|
m_state.accumulatorVariableIn + u".length()"_s)
|
|
|
|
+ u";\n"_s;
|
2023-04-28 12:02:20 +00:00
|
|
|
} else {
|
|
|
|
if (m_state.isRegisterAffectedBySideEffects(Accumulator))
|
|
|
|
reject(u"reading from a value that's potentially affected by side effects"_s);
|
2023-02-16 09:54:34 +00:00
|
|
|
|
|
|
|
const QString inputContentPointer = resolveValueTypeContentPointer(
|
|
|
|
scope, accumulatorIn, m_state.accumulatorVariableIn,
|
2023-04-18 08:55:20 +00:00
|
|
|
u"Cannot read property '%1' of %2"_s.arg(
|
2023-02-16 09:54:34 +00:00
|
|
|
m_jsUnitGenerator->lookupName(index)));
|
|
|
|
|
2022-03-21 09:21:18 +00:00
|
|
|
const QString lookup = u"aotContext->getValueLookup("_s + indexString
|
2023-02-16 09:54:34 +00:00
|
|
|
+ u", "_s + inputContentPointer
|
|
|
|
+ u", "_s + contentPointer(m_state.accumulatorOut(), m_state.accumulatorVariableOut)
|
2021-11-16 15:49:49 +00:00
|
|
|
+ u')';
|
2022-03-21 09:21:18 +00:00
|
|
|
const QString initialization = u"aotContext->initGetValueLookup("_s
|
|
|
|
+ indexString + u", "_s
|
2023-02-16 09:54:34 +00:00
|
|
|
+ metaObject(scope) + u", "_s
|
2022-02-02 18:08:29 +00:00
|
|
|
+ contentType(m_state.accumulatorOut(), m_state.accumulatorVariableOut) + u')';
|
2021-11-16 15:49:49 +00:00
|
|
|
const QString preparation = getLookupPreparation(
|
2022-02-02 18:08:29 +00:00
|
|
|
m_state.accumulatorOut(), m_state.accumulatorVariableOut, index);
|
2021-11-16 15:49:49 +00:00
|
|
|
generateLookup(lookup, initialization, preparation);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_GetOptionalLookup(int index, int offset)
|
|
|
|
{
|
|
|
|
Q_UNUSED(index)
|
|
|
|
Q_UNUSED(offset)
|
|
|
|
BYTECODE_UNIMPLEMENTED();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_StoreProperty(int nameIndex, int baseReg)
|
|
|
|
{
|
|
|
|
Q_UNUSED(nameIndex)
|
|
|
|
Q_UNUSED(baseReg)
|
2022-03-21 09:21:18 +00:00
|
|
|
reject(u"StoreProperty"_s);
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
QString QQmlJSCodeGenerator::setLookupPreparation(
|
|
|
|
const QQmlJSRegisterContent &content, const QString &arg, int lookup)
|
|
|
|
{
|
2022-02-04 21:35:23 +00:00
|
|
|
if (m_typeResolver->registerContains(content, content.storedType()))
|
2021-11-16 15:49:49 +00:00
|
|
|
return QString();
|
2022-02-04 21:35:23 +00:00
|
|
|
|
|
|
|
if (m_typeResolver->registerIsStoredIn(content, m_typeResolver->varType())) {
|
2022-03-21 09:21:18 +00:00
|
|
|
return u"const QMetaType argType = aotContext->lookupResultMetaType("_s
|
|
|
|
+ QString::number(lookup) + u");\n"_s
|
|
|
|
+ u"if (argType.isValid())\n "_s + arg + u".convert(argType)";
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
// TODO: We could make sure they're compatible, for example QObject pointers.
|
|
|
|
return QString();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_SetLookup(int index, int baseReg)
|
|
|
|
{
|
|
|
|
INJECT_TRACE_INFO(generate_SetLookup);
|
|
|
|
|
|
|
|
const QString indexString = QString::number(index);
|
2022-02-02 18:08:29 +00:00
|
|
|
const QQmlJSScope::ConstPtr valueType = m_state.accumulatorIn().storedType();
|
2023-04-18 08:55:20 +00:00
|
|
|
const QQmlJSRegisterContent callBase = m_typeResolver->original(registerType(baseReg));
|
2021-11-16 15:49:49 +00:00
|
|
|
const QQmlJSRegisterContent specific = m_typeResolver->memberType(
|
|
|
|
callBase, m_jsUnitGenerator->lookupName(index));
|
2023-04-18 08:55:20 +00:00
|
|
|
|
|
|
|
// We have checked that in the type propagator.
|
|
|
|
Q_ASSERT(!specific.storedType().isNull());
|
2023-03-14 13:53:26 +00:00
|
|
|
|
|
|
|
// Choose a container that can hold both, the "in" accumulator and what we actually want.
|
|
|
|
// If the types are all the same because we can all store them as verbatim C++ types,
|
|
|
|
// the container will also be that type.
|
|
|
|
const QQmlJSScope::ConstPtr container = m_typeResolver->merge(specific.storedType(), valueType);
|
|
|
|
const QQmlJSRegisterContent property = specific.storedIn(container);
|
2021-11-16 15:49:49 +00:00
|
|
|
|
2022-02-17 12:04:35 +00:00
|
|
|
const QString object = registerVariable(baseReg);
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u"{\n"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
QString variableIn;
|
|
|
|
QString variableInType;
|
|
|
|
QString preparation;
|
|
|
|
QString argType;
|
2022-02-04 21:35:23 +00:00
|
|
|
if (!m_typeResolver->registerContains(
|
|
|
|
m_state.accumulatorIn(), m_typeResolver->containedType(property))) {
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u"auto converted = "_s
|
2022-11-28 15:07:24 +00:00
|
|
|
+ conversion(m_state.accumulatorIn(), property, consumedAccumulatorVariableIn())
|
2022-03-21 09:21:18 +00:00
|
|
|
+ u";\n"_s;
|
|
|
|
variableIn = contentPointer(property, u"converted"_s);
|
|
|
|
variableInType = contentType(property, u"converted"_s);
|
|
|
|
preparation = setLookupPreparation(property, u"converted"_s, index);
|
2021-11-16 15:49:49 +00:00
|
|
|
if (preparation.isEmpty())
|
2022-03-21 09:21:18 +00:00
|
|
|
argType = contentType(property, u"converted"_s);
|
2021-11-16 15:49:49 +00:00
|
|
|
else
|
2022-03-21 09:21:18 +00:00
|
|
|
argType = u"argType"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
} else {
|
2022-02-17 12:04:35 +00:00
|
|
|
variableIn = contentPointer(property, m_state.accumulatorVariableIn);
|
|
|
|
variableInType = contentType(property, m_state.accumulatorVariableIn);
|
2021-11-16 15:49:49 +00:00
|
|
|
argType = variableInType;
|
|
|
|
}
|
|
|
|
|
2023-02-16 09:54:34 +00:00
|
|
|
switch (property.scopeType()->accessSemantics()) {
|
2021-11-16 15:49:49 +00:00
|
|
|
case QQmlJSScope::AccessSemantics::Reference: {
|
2023-02-16 09:54:34 +00:00
|
|
|
const QString basePointer = resolveQObjectPointer(
|
|
|
|
property.scopeType(), registerType(baseReg), object,
|
2023-04-18 08:55:20 +00:00
|
|
|
u"TypeError: Value is %1 and could not be converted to an object"_s);
|
2023-02-16 09:54:34 +00:00
|
|
|
|
2022-03-21 09:21:18 +00:00
|
|
|
const QString lookup = u"aotContext->setObjectLookup("_s + indexString
|
2023-02-16 09:54:34 +00:00
|
|
|
+ u", "_s + basePointer + u", "_s + variableIn + u')';
|
2022-03-21 09:21:18 +00:00
|
|
|
const QString initialization = u"aotContext->initSetObjectLookup("_s
|
2023-02-16 09:54:34 +00:00
|
|
|
+ indexString + u", "_s + basePointer + u", "_s + argType + u')';
|
2021-11-16 15:49:49 +00:00
|
|
|
generateLookup(lookup, initialization, preparation);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case QQmlJSScope::AccessSemantics::Sequence: {
|
|
|
|
const QString propertyName = m_jsUnitGenerator->lookupName(index);
|
2022-03-21 09:21:18 +00:00
|
|
|
if (propertyName != u"length"_s) {
|
|
|
|
reject(u"setting non-length property on a sequence type"_s);
|
2021-11-16 15:49:49 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2023-04-18 08:55:20 +00:00
|
|
|
if (!callBase.storedType()->isListProperty()) {
|
2023-04-28 12:02:20 +00:00
|
|
|
reject(u"resizing sequence types (because of missing write-back)"_s);
|
2021-11-16 15:49:49 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We can resize without write back on a list property because it's actually a reference.
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u"const int begin = "_s + object + u".count(&" + object + u");\n"_s;
|
|
|
|
m_body += u"const int end = "_s
|
2021-11-16 15:49:49 +00:00
|
|
|
+ (variableIn.startsWith(u'&') ? variableIn.mid(1) : (u'*' + variableIn))
|
2022-03-21 09:21:18 +00:00
|
|
|
+ u";\n"_s;
|
|
|
|
m_body += u"for (int i = begin; i < end; ++i)\n"_s;
|
|
|
|
m_body += u" "_s + object + u".append(&"_s + object + u", nullptr);\n"_s;
|
|
|
|
m_body += u"for (int i = begin; i > end; --i)\n"_s;
|
|
|
|
m_body += u" "_s + object + u".removeLast(&"_s + object + u')'
|
|
|
|
+ u";\n"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case QQmlJSScope::AccessSemantics::Value: {
|
|
|
|
const QString propertyName = m_jsUnitGenerator->lookupName(index);
|
|
|
|
Q_ASSERT(specific.isProperty());
|
|
|
|
const QQmlJSRegisterContent property = specific.storedIn(
|
|
|
|
m_typeResolver->genericType(specific.storedType()));
|
|
|
|
|
2023-02-16 09:54:34 +00:00
|
|
|
const QString baseContentPointer = resolveValueTypeContentPointer(
|
|
|
|
property.scopeType(), registerType(baseReg), object,
|
2023-04-18 08:55:20 +00:00
|
|
|
u"TypeError: Value is %1 and could not be converted to an object"_s);
|
2023-02-16 09:54:34 +00:00
|
|
|
|
2022-03-21 09:21:18 +00:00
|
|
|
const QString lookup = u"aotContext->setValueLookup("_s + indexString
|
2023-02-16 09:54:34 +00:00
|
|
|
+ u", "_s + baseContentPointer
|
2022-03-21 09:21:18 +00:00
|
|
|
+ u", "_s + variableIn + u')';
|
|
|
|
const QString initialization = u"aotContext->initSetValueLookup("_s
|
|
|
|
+ indexString + u", "_s + metaObject(property.scopeType())
|
2023-02-16 09:54:34 +00:00
|
|
|
+ u", "_s + argType + u')';
|
2021-11-16 15:49:49 +00:00
|
|
|
|
|
|
|
generateLookup(lookup, initialization, preparation);
|
2023-04-28 12:02:20 +00:00
|
|
|
reject(u"SetLookup on value types (because of missing write-back)"_s);
|
2021-11-16 15:49:49 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case QQmlJSScope::AccessSemantics::None:
|
|
|
|
Q_UNREACHABLE();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u"}\n"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_LoadSuperProperty(int property)
|
|
|
|
{
|
|
|
|
Q_UNUSED(property)
|
|
|
|
BYTECODE_UNIMPLEMENTED();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_StoreSuperProperty(int property)
|
|
|
|
{
|
|
|
|
Q_UNUSED(property)
|
|
|
|
BYTECODE_UNIMPLEMENTED();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_Yield()
|
|
|
|
{
|
|
|
|
BYTECODE_UNIMPLEMENTED();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_YieldStar()
|
|
|
|
{
|
|
|
|
BYTECODE_UNIMPLEMENTED();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_Resume(int)
|
|
|
|
{
|
|
|
|
BYTECODE_UNIMPLEMENTED();
|
|
|
|
}
|
|
|
|
|
|
|
|
QString QQmlJSCodeGenerator::argumentsList(int argc, int argv, QString *outVar)
|
|
|
|
{
|
|
|
|
QString types;
|
|
|
|
QString args;
|
|
|
|
QString conversions;
|
|
|
|
|
2022-02-16 13:01:52 +00:00
|
|
|
if (m_state.changedRegisterIndex() == InvalidRegister ||
|
|
|
|
m_typeResolver->registerContains(
|
|
|
|
m_state.accumulatorOut(), m_typeResolver->voidType())) {
|
2022-03-21 09:21:18 +00:00
|
|
|
types = u"QMetaType()"_s;
|
|
|
|
args = u"nullptr"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
} else {
|
2022-03-21 09:21:18 +00:00
|
|
|
*outVar = u"callResult"_s;
|
2022-02-02 18:08:29 +00:00
|
|
|
const QQmlJSScope::ConstPtr outType = m_state.accumulatorOut().storedType();
|
2021-11-16 15:49:49 +00:00
|
|
|
m_body += outType->internalName();
|
|
|
|
if (outType->accessSemantics() == QQmlJSScope::AccessSemantics::Reference)
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u" *"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
else
|
|
|
|
m_body += u' ';
|
|
|
|
m_body += *outVar + u";\n";
|
|
|
|
|
2022-02-02 18:08:29 +00:00
|
|
|
types = metaTypeFromType(m_state.accumulatorOut().storedType());
|
2021-11-16 15:49:49 +00:00
|
|
|
args = u'&' + *outVar;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < argc; ++i) {
|
2022-02-04 21:35:23 +00:00
|
|
|
const QQmlJSRegisterContent content = registerType(argv + i);
|
|
|
|
if (m_typeResolver->registerIsStoredIn(content, m_typeResolver->jsPrimitiveType())) {
|
2022-03-21 09:21:18 +00:00
|
|
|
QString argName = u"arg"_s + QString::number(i);
|
|
|
|
conversions += u"QVariant "_s + argName + u" = "_s
|
2023-02-21 10:47:08 +00:00
|
|
|
+ convertStored(content.storedType(), m_typeResolver->varType(),
|
|
|
|
consumedRegisterVariable(argv + i)) + u";\n"_s;
|
2022-03-21 09:21:18 +00:00
|
|
|
args += u", "_s + argName + u".data()"_s;
|
|
|
|
types += u", "_s + argName + u".metaType()"_s;
|
2022-11-29 15:33:57 +00:00
|
|
|
} else if (m_typeResolver->registerIsStoredIn(content, m_typeResolver->varType())
|
|
|
|
&& !m_typeResolver->registerContains(content, m_typeResolver->varType())) {
|
2022-11-28 15:07:24 +00:00
|
|
|
const QString var = registerVariable(argv + i);
|
2022-03-21 09:21:18 +00:00
|
|
|
args += u", "_s + var + u".data()"_s;
|
|
|
|
types += u", "_s + var + u".metaType()"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
} else {
|
2022-11-28 15:07:24 +00:00
|
|
|
const QString var = registerVariable(argv + i);
|
2022-03-21 09:21:18 +00:00
|
|
|
args += u", &"_s + var;
|
|
|
|
types += u", "_s + metaTypeFromType(content.storedType());
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return conversions
|
2022-03-21 09:21:18 +00:00
|
|
|
+ u"void *args[] = { "_s + args + u" };\n"_s
|
|
|
|
+ u"const QMetaType types[] = { "_s + types + u" };\n"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generateMoveOutVar(const QString &outVar)
|
|
|
|
{
|
2022-02-16 12:33:47 +00:00
|
|
|
if (m_state.accumulatorVariableOut.isEmpty() || outVar.isEmpty())
|
|
|
|
return;
|
2021-11-16 15:49:49 +00:00
|
|
|
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += m_state.accumulatorVariableOut + u" = "_s;
|
2022-02-16 12:33:47 +00:00
|
|
|
m_body += u"std::move(" + outVar + u");\n";
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_CallValue(int name, int argc, int argv)
|
|
|
|
{
|
|
|
|
Q_UNUSED(name)
|
|
|
|
Q_UNUSED(argc)
|
|
|
|
Q_UNUSED(argv)
|
|
|
|
BYTECODE_UNIMPLEMENTED();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_CallWithReceiver(int name, int thisObject, int argc, int argv)
|
|
|
|
{
|
|
|
|
Q_UNUSED(name)
|
|
|
|
Q_UNUSED(thisObject)
|
|
|
|
Q_UNUSED(argc)
|
|
|
|
Q_UNUSED(argv)
|
|
|
|
BYTECODE_UNIMPLEMENTED();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_CallProperty(int nameIndex, int baseReg, int argc, int argv)
|
|
|
|
{
|
|
|
|
Q_UNUSED(nameIndex);
|
|
|
|
Q_UNUSED(baseReg);
|
|
|
|
Q_UNUSED(argc);
|
|
|
|
Q_UNUSED(argv);
|
2022-03-21 09:21:18 +00:00
|
|
|
reject(u"CallProperty"_s);
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
2022-06-03 08:51:26 +00:00
|
|
|
bool QQmlJSCodeGenerator::inlineStringMethod(const QString &name, int base, int argc, int argv)
|
|
|
|
{
|
|
|
|
if (name != u"arg"_s || argc != 1)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
const auto arg = [&](const QQmlJSScope::ConstPtr &type) {
|
2023-02-21 10:47:08 +00:00
|
|
|
return convertStored(registerType(argv).storedType(), type, consumedRegisterVariable(argv));
|
2022-06-03 08:51:26 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
const auto ret = [&](const QString &arg) {
|
2023-02-21 10:47:08 +00:00
|
|
|
const QString expression = convertStored(
|
2022-06-03 08:51:26 +00:00
|
|
|
registerType(base).storedType(), m_typeResolver->stringType(),
|
2022-11-28 15:07:24 +00:00
|
|
|
consumedRegisterVariable(base)) + u".arg("_s + arg + u')';
|
2022-06-03 08:51:26 +00:00
|
|
|
return conversion(
|
2023-02-21 10:47:08 +00:00
|
|
|
m_typeResolver->stringType(), m_state.accumulatorOut(), expression);
|
2022-06-03 08:51:26 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
const QQmlJSRegisterContent input = m_state.readRegister(argv);
|
|
|
|
m_body += m_state.accumulatorVariableOut + u" = "_s;
|
|
|
|
|
2023-03-27 16:00:46 +00:00
|
|
|
if (m_typeResolver->isNumeric(input))
|
|
|
|
m_body += ret(arg(m_typeResolver->containedType(input)));
|
2022-06-03 08:51:26 +00:00
|
|
|
else if (m_typeResolver->registerContains(input, m_typeResolver->boolType()))
|
|
|
|
m_body += ret(arg(m_typeResolver->boolType()));
|
|
|
|
else
|
|
|
|
m_body += ret(arg(m_typeResolver->stringType()));
|
|
|
|
m_body += u";\n"_s;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-05-25 13:46:13 +00:00
|
|
|
bool QQmlJSCodeGenerator::inlineTranslateMethod(const QString &name, int argc, int argv)
|
|
|
|
{
|
|
|
|
addInclude(u"qcoreapplication.h"_s);
|
|
|
|
|
|
|
|
const auto arg = [&](int i, const QQmlJSScope::ConstPtr &type) {
|
|
|
|
Q_ASSERT(i < argc);
|
2023-02-21 10:47:08 +00:00
|
|
|
return convertStored(registerType(argv + i).storedType(), type,
|
|
|
|
consumedRegisterVariable(argv + i));
|
2022-05-25 13:46:13 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
const auto stringArg = [&](int i) {
|
|
|
|
return i < argc
|
|
|
|
? (arg(i, m_typeResolver->stringType()) + u".toUtf8().constData()"_s)
|
|
|
|
: u"\"\""_s;
|
|
|
|
};
|
|
|
|
|
|
|
|
const auto intArg = [&](int i) {
|
2023-03-27 16:00:46 +00:00
|
|
|
return i < argc ? arg(i, m_typeResolver->int32Type()) : u"-1"_s;
|
2022-05-25 13:46:13 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
const auto stringRet = [&](const QString &expression) {
|
|
|
|
return conversion(
|
2023-02-21 10:47:08 +00:00
|
|
|
m_typeResolver->stringType(), m_state.accumulatorOut(), expression);
|
2022-05-25 13:46:13 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
const auto capture = [&]() {
|
|
|
|
m_body += u"aotContext->captureTranslation();\n"_s;
|
|
|
|
};
|
|
|
|
|
|
|
|
if (name == u"QT_TRID_NOOP"_s || name == u"QT_TR_NOOP"_s) {
|
|
|
|
Q_ASSERT(argc > 0);
|
|
|
|
m_body += m_state.accumulatorVariableOut + u" = "_s
|
|
|
|
+ stringRet(arg(0, m_typeResolver->stringType())) + u";\n"_s;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (name == u"QT_TRANSLATE_NOOP"_s) {
|
|
|
|
Q_ASSERT(argc > 1);
|
|
|
|
m_body += m_state.accumulatorVariableOut + u" = "_s
|
|
|
|
+ stringRet(arg(1, m_typeResolver->stringType())) + u";\n"_s;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (name == u"qsTrId"_s) {
|
|
|
|
capture();
|
|
|
|
// We inline qtTrId() here because in the !QT_CONFIG(translation) case it's unavailable.
|
|
|
|
// QCoreApplication::translate() is always available in some primitive form.
|
|
|
|
// Also, this saves a function call.
|
|
|
|
m_body += m_state.accumulatorVariableOut + u" = "_s
|
|
|
|
+ stringRet(u"QCoreApplication::translate(nullptr, "_s + stringArg(0) +
|
|
|
|
u", nullptr, "_s + intArg(1) + u")"_s) + u";\n"_s;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (name == u"qsTr"_s) {
|
|
|
|
capture();
|
|
|
|
m_body += m_state.accumulatorVariableOut + u" = "_s
|
|
|
|
+ stringRet(u"QCoreApplication::translate("_s
|
|
|
|
+ u"aotContext->translationContext().toUtf8().constData(), "_s
|
|
|
|
+ stringArg(0) + u", "_s + stringArg(1) + u", "_s
|
|
|
|
+ intArg(2) + u")"_s) + u";\n"_s;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (name == u"qsTranslate"_s) {
|
|
|
|
capture();
|
|
|
|
m_body += m_state.accumulatorVariableOut + u" = "_s
|
|
|
|
+ stringRet(u"QCoreApplication::translate("_s
|
|
|
|
+ stringArg(0) + u", "_s + stringArg(1) + u", "_s
|
|
|
|
+ stringArg(2) + u", "_s + intArg(3) + u")"_s) + u";\n"_s;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2023-02-14 15:18:06 +00:00
|
|
|
static QString maxExpression(int argc)
|
|
|
|
{
|
|
|
|
Q_ASSERT_X(argc >= 2, Q_FUNC_INFO, "max() expects at least two arguments.");
|
|
|
|
|
|
|
|
QString expression =
|
|
|
|
u"[&]() { \nauto tmpMax = (qIsNull(arg2) && qIsNull(arg1) && std::copysign(1.0, arg2) == 1) ? arg2 : ((arg2 > arg1 || std::isnan(arg2)) ? arg2 : arg1);\n"_s;
|
|
|
|
for (int i = 2; i < argc; i++) {
|
|
|
|
expression +=
|
|
|
|
"\ttmpMax = (qIsNull(%1) && qIsNull(tmpMax) && std::copysign(1.0, %1) == 1) ? arg2 : ((%1 > tmpMax || std::isnan(%1)) ? %1 : tmpMax);\n"_L1
|
|
|
|
.arg("arg"_L1 + QString::number(i + 1));
|
|
|
|
}
|
|
|
|
expression += "return tmpMax;\n}()"_L1;
|
|
|
|
|
|
|
|
return expression;
|
|
|
|
}
|
|
|
|
|
|
|
|
static QString minExpression(int argc)
|
|
|
|
{
|
|
|
|
Q_ASSERT_X(argc >= 2, Q_FUNC_INFO, "min() expects at least two arguments.");
|
|
|
|
|
|
|
|
QString expression =
|
|
|
|
u"[&]() { \nauto tmpMin = (qIsNull(arg2) && qIsNull(arg1) && std::copysign(1.0, arg2) == -1) ? arg2 : ((arg2 < arg1 || std::isnan(arg2)) ? arg2 : arg1);\n"_s;
|
|
|
|
for (int i = 2; i < argc; i++) {
|
|
|
|
expression +=
|
|
|
|
"tmpMin = (qIsNull(%1) && qIsNull(tmpMin) && std::copysign(1.0, %1) == -1) ? arg2 : ((%1 < tmpMin || std::isnan(%1)) ? %1 : tmpMin);\n"_L1
|
|
|
|
.arg("arg"_L1 + QString::number(i + 1));
|
|
|
|
}
|
|
|
|
expression += "return tmpMin;\n}()"_L1;
|
|
|
|
|
|
|
|
return expression;
|
|
|
|
}
|
|
|
|
|
2021-11-16 15:49:49 +00:00
|
|
|
bool QQmlJSCodeGenerator::inlineMathMethod(const QString &name, int argc, int argv)
|
|
|
|
{
|
2022-03-21 09:21:18 +00:00
|
|
|
addInclude(u"cmath"_s);
|
|
|
|
addInclude(u"limits"_s);
|
|
|
|
addInclude(u"qalgorithms.h"_s);
|
|
|
|
addInclude(u"qrandom.h"_s);
|
2022-07-19 12:00:28 +00:00
|
|
|
addInclude(u"qjsprimitivevalue.h"_s);
|
2021-11-16 15:49:49 +00:00
|
|
|
|
2022-02-16 13:01:52 +00:00
|
|
|
// If the result is not stored, we don't need to generate any code. All the math methods are
|
|
|
|
// conceptually pure functions.
|
|
|
|
if (m_state.changedRegisterIndex() != Accumulator)
|
|
|
|
return true;
|
2021-11-16 15:49:49 +00:00
|
|
|
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u"{\n"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
for (int i = 0; i < argc; ++i) {
|
2023-02-21 10:47:08 +00:00
|
|
|
m_body += u"const double arg%1 = "_s.arg(i + 1) + convertStored(
|
2021-11-16 15:49:49 +00:00
|
|
|
registerType(argv + i).storedType(),
|
2022-11-28 15:07:24 +00:00
|
|
|
m_typeResolver->realType(), consumedRegisterVariable(argv + i))
|
2022-03-21 09:21:18 +00:00
|
|
|
+ u";\n"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
2022-03-21 09:21:18 +00:00
|
|
|
const QString qNaN = u"std::numeric_limits<double>::quiet_NaN()"_s;
|
|
|
|
const QString inf = u"std::numeric_limits<double>::infinity()"_s;
|
|
|
|
m_body += m_state.accumulatorVariableOut + u" = "_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
|
2022-02-16 13:01:52 +00:00
|
|
|
QString expression;
|
|
|
|
|
2021-11-16 15:49:49 +00:00
|
|
|
if (name == u"abs" && argc == 1) {
|
2022-03-21 09:21:18 +00:00
|
|
|
expression = u"(qIsNull(arg1) ? 0 : (arg1 < 0.0 ? -arg1 : arg1))"_s;
|
|
|
|
} else if (name == u"acos"_s && argc == 1) {
|
|
|
|
expression = u"arg1 > 1.0 ? %1 : std::acos(arg1)"_s.arg(qNaN);
|
|
|
|
} else if (name == u"acosh"_s && argc == 1) {
|
|
|
|
expression = u"arg1 < 1.0 ? %1 : std::acosh(arg1)"_s.arg(qNaN);
|
|
|
|
} else if (name == u"asin"_s && argc == 1) {
|
|
|
|
expression = u"arg1 > 1.0 ? %1 : std::asin(arg1)"_s.arg(qNaN);
|
|
|
|
} else if (name == u"asinh"_s && argc == 1) {
|
|
|
|
expression = u"qIsNull(arg1) ? arg1 : std::asinh(arg1)"_s;
|
|
|
|
} else if (name == u"atan"_s && argc == 1) {
|
|
|
|
expression = u"qIsNull(arg1) ? arg1 : std::atan(arg1)"_s;
|
|
|
|
} else if (name == u"atanh"_s && argc == 1) {
|
|
|
|
expression = u"qIsNull(arg1) ? arg1 : std::atanh(arg1)"_s;
|
|
|
|
} else if (name == u"atan2"_s) {
|
2021-11-16 15:49:49 +00:00
|
|
|
// TODO: complicated
|
|
|
|
return false;
|
2022-03-21 09:21:18 +00:00
|
|
|
} else if (name == u"cbrt"_s && argc == 1) {
|
|
|
|
expression = u"std::cbrt(arg1)"_s;
|
|
|
|
} else if (name == u"ceil"_s && argc == 1) {
|
|
|
|
expression = u"(arg1 < 0.0 && arg1 > -1.0) ? std::copysign(0.0, -1.0) : std::ceil(arg1)"_s;
|
|
|
|
} else if (name == u"clz32"_s && argc == 1) {
|
|
|
|
expression = u"qint32(qCountLeadingZeroBits(quint32(QJSNumberCoercion::toInteger(arg1))))"_s;
|
|
|
|
} else if (name == u"cos"_s && argc == 1) {
|
|
|
|
expression = u"std::cos(arg1)"_s;
|
|
|
|
} else if (name == u"cosh"_s && argc == 1) {
|
|
|
|
expression = u"std::cosh(arg1)"_s;
|
|
|
|
} else if (name == u"exp"_s && argc == 1) {
|
2022-02-16 13:01:52 +00:00
|
|
|
expression = u"std::isinf(arg1) "
|
2021-11-16 15:49:49 +00:00
|
|
|
"? (std::copysign(1.0, arg1) == -1 ? 0.0 : %1) "
|
2022-03-21 09:21:18 +00:00
|
|
|
": std::exp(arg1)"_s.arg(inf);
|
|
|
|
} else if (name == u"expm1"_s) {
|
2021-11-16 15:49:49 +00:00
|
|
|
// TODO: complicated
|
|
|
|
return false;
|
2022-03-21 09:21:18 +00:00
|
|
|
} else if (name == u"floor"_s && argc == 1) {
|
|
|
|
expression = u"std::floor(arg1)"_s;
|
|
|
|
} else if (name == u"fround"_s && argc == 1) {
|
2022-02-16 13:01:52 +00:00
|
|
|
expression = u"(std::isnan(arg1) || std::isinf(arg1) || qIsNull(arg1)) "
|
2021-11-16 15:49:49 +00:00
|
|
|
"? arg1 "
|
2022-03-21 09:21:18 +00:00
|
|
|
": double(float(arg1))"_s;
|
|
|
|
} else if (name == u"hypot"_s) {
|
2021-11-16 15:49:49 +00:00
|
|
|
// TODO: complicated
|
|
|
|
return false;
|
2022-03-21 09:21:18 +00:00
|
|
|
} else if (name == u"imul"_s && argc == 2) {
|
2022-02-16 13:01:52 +00:00
|
|
|
expression = u"qint32(quint32(QJSNumberCoercion::toInteger(arg1)) "
|
2022-03-21 09:21:18 +00:00
|
|
|
"* quint32(QJSNumberCoercion::toInteger(arg2)))"_s;
|
|
|
|
} else if (name == u"log"_s && argc == 1) {
|
|
|
|
expression = u"arg1 < 0.0 ? %1 : std::log(arg1)"_s.arg(qNaN);
|
|
|
|
} else if (name == u"log10"_s && argc == 1) {
|
|
|
|
expression = u"arg1 < 0.0 ? %1 : std::log10(arg1)"_s.arg(qNaN);
|
|
|
|
} else if (name == u"log1p"_s && argc == 1) {
|
|
|
|
expression = u"arg1 < -1.0 ? %1 : std::log1p(arg1)"_s.arg(qNaN);
|
|
|
|
} else if (name == u"log2"_s && argc == 1) {
|
|
|
|
expression = u"arg1 < -0.0 ? %1 : std::log2(arg1)"_s.arg(qNaN);
|
2023-02-14 15:18:06 +00:00
|
|
|
} else if (name == u"max"_s && argc >= 2) {
|
|
|
|
expression = maxExpression(argc);
|
|
|
|
} else if (name == u"min"_s && argc >= 2) {
|
|
|
|
expression = minExpression(argc);
|
2022-03-21 09:21:18 +00:00
|
|
|
} else if (name == u"pow"_s) {
|
2022-07-19 12:00:28 +00:00
|
|
|
expression = u"QQmlPrivate::jsExponentiate(arg1, arg2)"_s;
|
2022-03-21 09:21:18 +00:00
|
|
|
} else if (name == u"random"_s && argc == 0) {
|
|
|
|
expression = u"QRandomGenerator::global()->generateDouble()"_s;
|
|
|
|
} else if (name == u"round"_s && argc == 1) {
|
2022-02-16 13:01:52 +00:00
|
|
|
expression = u"std::isfinite(arg1) "
|
2021-11-16 15:49:49 +00:00
|
|
|
"? ((arg1 < 0.5 && arg1 >= -0.5) "
|
|
|
|
"? std::copysign(0.0, arg1) "
|
|
|
|
": std::floor(arg1 + 0.5)) "
|
2022-03-21 09:21:18 +00:00
|
|
|
": arg1"_s;
|
|
|
|
} else if (name == u"sign"_s && argc == 1) {
|
2022-02-16 13:01:52 +00:00
|
|
|
expression = u"std::isnan(arg1) "
|
2021-11-16 15:49:49 +00:00
|
|
|
"? %1 "
|
|
|
|
": (qIsNull(arg1) "
|
|
|
|
"? arg1 "
|
2022-03-21 09:21:18 +00:00
|
|
|
": (std::signbit(arg1) ? -1.0 : 1.0))"_s.arg(qNaN);
|
|
|
|
} else if (name == u"sin"_s && argc == 1) {
|
|
|
|
expression = u"qIsNull(arg1) ? arg1 : std::sin(arg1)"_s;
|
|
|
|
} else if (name == u"sinh"_s && argc == 1) {
|
|
|
|
expression = u"qIsNull(arg1) ? arg1 : std::sinh(arg1)"_s;
|
|
|
|
} else if (name == u"sqrt"_s && argc == 1) {
|
|
|
|
expression = u"std::sqrt(arg1)"_s;
|
|
|
|
} else if (name == u"tan"_s && argc == 1) {
|
|
|
|
expression = u"qIsNull(arg1) ? arg1 : std::tan(arg1)"_s;
|
|
|
|
} else if (name == u"tanh"_s && argc == 1) {
|
|
|
|
expression = u"qIsNull(arg1) ? arg1 : std::tanh(arg1)"_s;
|
|
|
|
} else if (name == u"trunc"_s && argc == 1) {
|
|
|
|
expression = u"std::trunc(arg1)"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2023-02-21 10:47:08 +00:00
|
|
|
m_body += conversion(m_typeResolver->realType(), m_state.accumulatorOut(), expression);
|
2022-02-16 13:01:52 +00:00
|
|
|
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u";\n"_s;
|
|
|
|
m_body += u"}\n"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-11-15 09:18:37 +00:00
|
|
|
static QString messageTypeForMethod(const QString &method)
|
|
|
|
{
|
|
|
|
if (method == u"log" || method == u"debug")
|
|
|
|
return u"QtDebugMsg"_s;
|
|
|
|
if (method == u"info")
|
|
|
|
return u"QtInfoMsg"_s;
|
|
|
|
if (method == u"warn")
|
|
|
|
return u"QtWarningMsg"_s;
|
|
|
|
if (method == u"error")
|
|
|
|
return u"QtCriticalMsg"_s;
|
|
|
|
return QString();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool QQmlJSCodeGenerator::inlineConsoleMethod(const QString &name, int argc, int argv)
|
|
|
|
{
|
|
|
|
const QString type = messageTypeForMethod(name);
|
|
|
|
if (type.isEmpty())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
addInclude(u"qloggingcategory.h"_s);
|
|
|
|
|
|
|
|
m_body += u"{\n";
|
|
|
|
m_body += u" bool firstArgIsCategory = false;\n";
|
|
|
|
const QQmlJSRegisterContent firstArg = argc > 0 ? registerType(argv) : QQmlJSRegisterContent();
|
|
|
|
|
|
|
|
// We could check for internalName == "QQmlLoggingCategory" here, but we don't want to
|
|
|
|
// because QQmlLoggingCategory is not a builtin. Tying the specific internal name and
|
|
|
|
// intheritance hierarchy in here would be fragile.
|
|
|
|
// TODO: We could drop the check for firstArg in some cases if we made some base class
|
|
|
|
// of QQmlLoggingCategory a builtin.
|
|
|
|
const bool firstArgIsReference = argc > 0
|
|
|
|
&& m_typeResolver->containedType(firstArg)->isReferenceType();
|
|
|
|
|
|
|
|
if (firstArgIsReference) {
|
|
|
|
m_body += u" QObject *firstArg = ";
|
2023-02-21 10:47:08 +00:00
|
|
|
m_body += convertStored(
|
2022-11-15 09:18:37 +00:00
|
|
|
firstArg.storedType(),
|
|
|
|
m_typeResolver->genericType(firstArg.storedType()),
|
|
|
|
registerVariable(argv));
|
|
|
|
m_body += u";\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
m_body += u" const QLoggingCategory *category = aotContext->resolveLoggingCategory(";
|
|
|
|
m_body += firstArgIsReference ? u"firstArg" : u"nullptr";
|
|
|
|
m_body += u", &firstArgIsCategory);\n";
|
|
|
|
m_body += u" if (category && category->isEnabled(" + type + u")) {\n";
|
|
|
|
|
|
|
|
m_body += u" const QString message = ";
|
|
|
|
if (argc > 0) {
|
2023-02-21 10:47:08 +00:00
|
|
|
const QString firstArgStringConversion = convertStored(
|
2022-11-15 09:18:37 +00:00
|
|
|
registerType(argv).storedType(),
|
|
|
|
m_typeResolver->stringType(), registerVariable(argv));
|
|
|
|
if (firstArgIsReference) {
|
|
|
|
m_body += u"(firstArgIsCategory ? QString() : (" + firstArgStringConversion;
|
|
|
|
if (argc > 1)
|
|
|
|
m_body += u".append(QLatin1Char(' ')))).append(";
|
|
|
|
else
|
|
|
|
m_body += u"))";
|
|
|
|
} else {
|
|
|
|
m_body += firstArgStringConversion;
|
|
|
|
if (argc > 1)
|
|
|
|
m_body += u".append(QLatin1Char(' ')).append(";
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 1; i < argc; ++i) {
|
|
|
|
if (i > 1)
|
|
|
|
m_body += u".append(QLatin1Char(' ')).append("_s;
|
2023-02-21 10:47:08 +00:00
|
|
|
m_body += convertStored(
|
2022-11-15 09:18:37 +00:00
|
|
|
registerType(argv + i).storedType(),
|
2022-11-28 15:07:24 +00:00
|
|
|
m_typeResolver->stringType(), consumedRegisterVariable(argv + i)) + u')';
|
2022-11-15 09:18:37 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
m_body += u"QString()";
|
|
|
|
}
|
|
|
|
m_body += u";\n";
|
|
|
|
|
|
|
|
m_body += u" aotContext->writeToConsole(" + type + u", message, category);\n";
|
|
|
|
m_body += u" }\n";
|
|
|
|
m_body += u"}\n";
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2023-04-18 13:54:49 +00:00
|
|
|
bool QQmlJSCodeGenerator::inlineArrayMethod(const QString &name, int base, int argc, int argv)
|
|
|
|
{
|
|
|
|
const auto intType = m_typeResolver->int32Type();
|
|
|
|
const auto valueType = registerType(base).storedType()->valueType();
|
|
|
|
const auto boolType = m_typeResolver->boolType();
|
|
|
|
const auto stringType = m_typeResolver->stringType();
|
|
|
|
const auto baseType = registerType(base);
|
|
|
|
|
|
|
|
const QString baseVar = registerVariable(base);
|
|
|
|
const QString qjsListMethod = u"QJSList(&"_s + baseVar + u", aotContext->engine)."
|
|
|
|
+ name + u"(";
|
|
|
|
|
|
|
|
addInclude(u"qjslist.h"_s);
|
|
|
|
|
|
|
|
if (name == u"includes" && argc > 0 && argc < 3) {
|
|
|
|
QString call = qjsListMethod
|
|
|
|
+ convertStored(registerType(argv).storedType(), valueType,
|
|
|
|
consumedRegisterVariable(argv));
|
|
|
|
if (argc == 2) {
|
|
|
|
call += u", " + convertStored(registerType(argv + 1).storedType(), intType,
|
|
|
|
consumedRegisterVariable(argv + 1));
|
|
|
|
}
|
|
|
|
call += u")";
|
|
|
|
|
|
|
|
m_body += m_state.accumulatorVariableOut + u" = "_s
|
|
|
|
+ conversion(boolType, m_state.accumulatorOut(), call) + u";\n"_s;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (name == u"toString" || (name == u"join" && argc < 2)) {
|
|
|
|
QString call = qjsListMethod;
|
|
|
|
if (argc == 1) {
|
|
|
|
call += convertStored(registerType(argv).storedType(), stringType,
|
|
|
|
consumedRegisterVariable(argv));
|
|
|
|
}
|
|
|
|
call += u")";
|
|
|
|
|
|
|
|
m_body += m_state.accumulatorVariableOut + u" = "_s
|
|
|
|
+ conversion(stringType, m_state.accumulatorOut(), call) + u";\n"_s;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (name == u"slice" && argc < 3) {
|
|
|
|
QString call = qjsListMethod;
|
|
|
|
for (int i = 0; i < argc; ++i) {
|
|
|
|
if (i > 0)
|
|
|
|
call += u", ";
|
|
|
|
call += convertStored(registerType(argv + i).storedType(), intType,
|
|
|
|
consumedRegisterVariable(argv + i));
|
|
|
|
}
|
|
|
|
call += u")";
|
|
|
|
|
|
|
|
const auto outType = baseType.storedType()->isListProperty()
|
|
|
|
? m_typeResolver->globalType(m_typeResolver->qObjectListType())
|
|
|
|
: baseType;
|
|
|
|
|
|
|
|
m_body += m_state.accumulatorVariableOut + u" = "_s
|
|
|
|
+ conversion(outType, m_state.accumulatorOut(), call) + u";\n"_s;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((name == u"indexOf" || name == u"lastIndexOf") && argc > 0 && argc < 3) {
|
|
|
|
QString call = qjsListMethod
|
|
|
|
+ convertStored(registerType(argv).storedType(), valueType,
|
|
|
|
consumedRegisterVariable(argv));
|
|
|
|
if (argc == 2) {
|
|
|
|
call += u", " + convertStored(registerType(argv + 1).storedType(), intType,
|
|
|
|
consumedRegisterVariable(argv + 1));
|
|
|
|
}
|
|
|
|
call += u")";
|
|
|
|
|
|
|
|
m_body += m_state.accumulatorVariableOut + u" = "_s
|
|
|
|
+ conversion(intType, m_state.accumulatorOut(), call) + u";\n"_s;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-11-16 15:49:49 +00:00
|
|
|
void QQmlJSCodeGenerator::generate_CallPropertyLookup(int index, int base, int argc, int argv)
|
|
|
|
{
|
|
|
|
INJECT_TRACE_INFO(generate_CallPropertyLookup);
|
|
|
|
|
2022-02-25 12:02:22 +00:00
|
|
|
if (m_state.accumulatorOut().variant() == QQmlJSRegisterContent::JavaScriptReturnValue)
|
2022-03-21 09:21:18 +00:00
|
|
|
reject(u"call to untyped JavaScript function"_s);
|
2022-02-25 12:02:22 +00:00
|
|
|
|
2022-02-16 15:34:56 +00:00
|
|
|
AccumulatorConverter registers(this);
|
|
|
|
|
2021-11-16 15:49:49 +00:00
|
|
|
const QQmlJSRegisterContent baseType = registerType(base);
|
|
|
|
if (baseType.storedType()->accessSemantics() != QQmlJSScope::AccessSemantics::Reference) {
|
|
|
|
const QString name = m_jsUnitGenerator->stringForIndex(
|
|
|
|
m_jsUnitGenerator->lookupNameIndex(index));
|
2022-02-16 13:01:52 +00:00
|
|
|
if (m_typeResolver->equals(m_typeResolver->originalContainedType(baseType), mathObject())) {
|
2021-11-16 15:49:49 +00:00
|
|
|
if (inlineMathMethod(name, argc, argv))
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-11-15 09:18:37 +00:00
|
|
|
if (m_typeResolver->equals(m_typeResolver->originalContainedType(baseType), consoleObject())) {
|
|
|
|
if (inlineConsoleMethod(name, argc, argv))
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-06-03 08:51:26 +00:00
|
|
|
if (m_typeResolver->equals(m_typeResolver->originalContainedType(baseType),
|
|
|
|
m_typeResolver->stringType())) {
|
|
|
|
if (inlineStringMethod(name, base, argc, argv))
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-04-18 13:54:49 +00:00
|
|
|
if (baseType.storedType()->accessSemantics() == QQmlJSScope::AccessSemantics::Sequence) {
|
|
|
|
if (inlineArrayMethod(name, base, argc, argv))
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-04-28 12:02:20 +00:00
|
|
|
// This is possible, once we establish the right kind of lookup for it
|
|
|
|
reject(u"call to property '%1' of %2"_s.arg(name, baseType.descriptiveName()));
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const QString indexString = QString::number(index);
|
|
|
|
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u"{\n"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
|
|
|
|
QString outVar;
|
|
|
|
m_body += argumentsList(argc, argv, &outVar);
|
2022-03-21 09:21:18 +00:00
|
|
|
const QString lookup = u"aotContext->callObjectPropertyLookup("_s + indexString
|
|
|
|
+ u", "_s + registerVariable(base)
|
|
|
|
+ u", args, types, "_s + QString::number(argc) + u')';
|
|
|
|
const QString initialization = u"aotContext->initCallObjectPropertyLookup("_s
|
2021-11-16 15:49:49 +00:00
|
|
|
+ indexString + u')';
|
|
|
|
generateLookup(lookup, initialization);
|
|
|
|
generateMoveOutVar(outVar);
|
|
|
|
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u"}\n"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_CallName(int name, int argc, int argv)
|
|
|
|
{
|
|
|
|
Q_UNUSED(name);
|
|
|
|
Q_UNUSED(argc);
|
|
|
|
Q_UNUSED(argv);
|
2022-03-21 09:21:18 +00:00
|
|
|
reject(u"CallName"_s);
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_CallPossiblyDirectEval(int argc, int argv)
|
|
|
|
{
|
|
|
|
Q_UNUSED(argc)
|
|
|
|
Q_UNUSED(argv)
|
|
|
|
BYTECODE_UNIMPLEMENTED();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_CallGlobalLookup(int index, int argc, int argv)
|
|
|
|
{
|
|
|
|
Q_UNUSED(index);
|
|
|
|
Q_UNUSED(argc);
|
|
|
|
Q_UNUSED(argv);
|
2022-03-21 09:21:18 +00:00
|
|
|
reject(u"CallGlobalLookup"_s);
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_CallQmlContextPropertyLookup(int index, int argc, int argv)
|
|
|
|
{
|
|
|
|
INJECT_TRACE_INFO(generate_CallQmlContextPropertyLookup);
|
|
|
|
|
2022-02-25 12:02:22 +00:00
|
|
|
if (m_state.accumulatorOut().variant() == QQmlJSRegisterContent::JavaScriptReturnValue)
|
2022-03-21 09:21:18 +00:00
|
|
|
reject(u"call to untyped JavaScript function"_s);
|
2022-02-25 12:02:22 +00:00
|
|
|
|
2022-05-25 13:46:13 +00:00
|
|
|
if (m_typeResolver->equals(m_state.accumulatorOut().scopeType(),
|
|
|
|
m_typeResolver->jsGlobalObject())) {
|
|
|
|
const QString name = m_jsUnitGenerator->stringForIndex(
|
|
|
|
m_jsUnitGenerator->lookupNameIndex(index));
|
|
|
|
if (inlineTranslateMethod(name, argc, argv))
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-02-16 15:34:56 +00:00
|
|
|
AccumulatorConverter registers(this);
|
|
|
|
|
2021-11-16 15:49:49 +00:00
|
|
|
const QString indexString = QString::number(index);
|
|
|
|
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u"{\n"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
QString outVar;
|
|
|
|
m_body += argumentsList(argc, argv, &outVar);
|
2022-03-21 09:21:18 +00:00
|
|
|
const QString lookup = u"aotContext->callQmlContextPropertyLookup("_s + indexString
|
|
|
|
+ u", args, types, "_s + QString::number(argc) + u')';
|
|
|
|
const QString initialization = u"aotContext->initCallQmlContextPropertyLookup("_s
|
2021-11-16 15:49:49 +00:00
|
|
|
+ indexString + u')';
|
|
|
|
generateLookup(lookup, initialization);
|
|
|
|
generateMoveOutVar(outVar);
|
|
|
|
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u"}\n"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_CallWithSpread(int func, int thisObject, int argc, int argv)
|
|
|
|
{
|
|
|
|
Q_UNUSED(func)
|
|
|
|
Q_UNUSED(thisObject)
|
|
|
|
Q_UNUSED(argc)
|
|
|
|
Q_UNUSED(argv)
|
|
|
|
BYTECODE_UNIMPLEMENTED();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_TailCall(int func, int thisObject, int argc, int argv)
|
|
|
|
{
|
|
|
|
Q_UNUSED(func)
|
|
|
|
Q_UNUSED(thisObject)
|
|
|
|
Q_UNUSED(argc)
|
|
|
|
Q_UNUSED(argv)
|
|
|
|
BYTECODE_UNIMPLEMENTED();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_Construct(int func, int argc, int argv)
|
|
|
|
{
|
|
|
|
Q_UNUSED(func);
|
|
|
|
Q_UNUSED(argc);
|
|
|
|
Q_UNUSED(argv);
|
2022-03-21 09:21:18 +00:00
|
|
|
reject(u"Construct"_s);
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_ConstructWithSpread(int func, int argc, int argv)
|
|
|
|
{
|
|
|
|
Q_UNUSED(func)
|
|
|
|
Q_UNUSED(argc)
|
|
|
|
Q_UNUSED(argv)
|
|
|
|
BYTECODE_UNIMPLEMENTED();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_SetUnwindHandler(int offset)
|
|
|
|
{
|
|
|
|
Q_UNUSED(offset)
|
2022-03-21 09:21:18 +00:00
|
|
|
reject(u"SetUnwindHandlerh"_s);
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_UnwindDispatch()
|
|
|
|
{
|
2022-03-21 09:21:18 +00:00
|
|
|
reject(u"UnwindDispatch"_s);
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_UnwindToLabel(int level, int offset)
|
|
|
|
{
|
|
|
|
Q_UNUSED(level)
|
|
|
|
Q_UNUSED(offset)
|
|
|
|
BYTECODE_UNIMPLEMENTED();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_DeadTemporalZoneCheck(int name)
|
|
|
|
{
|
|
|
|
Q_UNUSED(name)
|
2023-04-17 12:12:05 +00:00
|
|
|
// Nothing to do here. If we have statically asserted the dtz check in the type propagator
|
|
|
|
// the value cannot be empty. Otherwise we can't get here.
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_ThrowException()
|
|
|
|
{
|
|
|
|
INJECT_TRACE_INFO(generate_ThrowException);
|
|
|
|
|
|
|
|
generateSetInstructionPointer();
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u"aotContext->engine->throwError("_s
|
2022-02-02 18:08:29 +00:00
|
|
|
+ conversion(m_state.accumulatorIn(), m_typeResolver->globalType(
|
2021-11-16 15:49:49 +00:00
|
|
|
m_typeResolver->jsValueType()),
|
2022-03-21 09:21:18 +00:00
|
|
|
m_state.accumulatorVariableIn) + u");\n"_s;
|
|
|
|
m_body += u"return "_s + errorReturnValue() + u";\n"_s;
|
2022-06-27 14:26:43 +00:00
|
|
|
m_skipUntilNextLabel = true;
|
|
|
|
resetState();
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_GetException()
|
|
|
|
{
|
|
|
|
BYTECODE_UNIMPLEMENTED();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_SetException()
|
|
|
|
{
|
|
|
|
BYTECODE_UNIMPLEMENTED();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_CreateCallContext()
|
|
|
|
{
|
|
|
|
INJECT_TRACE_INFO(generate_CreateCallContext);
|
|
|
|
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u"{\n"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_PushCatchContext(int index, int nameIndex)
|
|
|
|
{
|
|
|
|
Q_UNUSED(index)
|
|
|
|
Q_UNUSED(nameIndex)
|
2022-03-21 09:21:18 +00:00
|
|
|
reject(u"PushCatchContext"_s);
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_PushWithContext()
|
|
|
|
{
|
|
|
|
BYTECODE_UNIMPLEMENTED();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_PushBlockContext(int index)
|
|
|
|
{
|
|
|
|
Q_UNUSED(index)
|
|
|
|
BYTECODE_UNIMPLEMENTED();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_CloneBlockContext()
|
|
|
|
{
|
|
|
|
BYTECODE_UNIMPLEMENTED();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_PushScriptContext(int index)
|
|
|
|
{
|
|
|
|
Q_UNUSED(index)
|
|
|
|
BYTECODE_UNIMPLEMENTED();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_PopScriptContext()
|
|
|
|
{
|
|
|
|
BYTECODE_UNIMPLEMENTED();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_PopContext()
|
|
|
|
{
|
|
|
|
INJECT_TRACE_INFO(generate_PopContext);
|
|
|
|
|
|
|
|
// Add a semicolon before the closing brace, in case there was a bare label before it.
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u";}\n"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_GetIterator(int iterator)
|
|
|
|
{
|
|
|
|
Q_UNUSED(iterator)
|
|
|
|
BYTECODE_UNIMPLEMENTED();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_IteratorNext(int value, int done)
|
|
|
|
{
|
|
|
|
Q_UNUSED(value)
|
|
|
|
Q_UNUSED(done)
|
|
|
|
BYTECODE_UNIMPLEMENTED();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_IteratorNextForYieldStar(int iterator, int object)
|
|
|
|
{
|
|
|
|
Q_UNUSED(iterator)
|
|
|
|
Q_UNUSED(object)
|
|
|
|
BYTECODE_UNIMPLEMENTED();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_IteratorClose(int done)
|
|
|
|
{
|
|
|
|
Q_UNUSED(done)
|
|
|
|
BYTECODE_UNIMPLEMENTED();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_DestructureRestElement()
|
|
|
|
{
|
|
|
|
BYTECODE_UNIMPLEMENTED();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_DeleteProperty(int base, int index)
|
|
|
|
{
|
|
|
|
Q_UNUSED(base)
|
|
|
|
Q_UNUSED(index)
|
|
|
|
BYTECODE_UNIMPLEMENTED();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_DeleteName(int name)
|
|
|
|
{
|
|
|
|
Q_UNUSED(name)
|
|
|
|
BYTECODE_UNIMPLEMENTED();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_TypeofName(int name)
|
|
|
|
{
|
|
|
|
Q_UNUSED(name);
|
2022-03-21 09:21:18 +00:00
|
|
|
reject(u"TypeofName"_s);
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_TypeofValue()
|
|
|
|
{
|
2022-03-21 09:21:18 +00:00
|
|
|
reject(u"TypeofValue"_s);
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_DeclareVar(int varName, int isDeletable)
|
|
|
|
{
|
|
|
|
Q_UNUSED(varName)
|
|
|
|
Q_UNUSED(isDeletable)
|
|
|
|
BYTECODE_UNIMPLEMENTED();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_DefineArray(int argc, int args)
|
|
|
|
{
|
2022-02-24 07:57:44 +00:00
|
|
|
INJECT_TRACE_INFO(generate_DefineArray);
|
2022-02-16 13:01:52 +00:00
|
|
|
|
2023-02-21 10:47:08 +00:00
|
|
|
const QQmlJSScope::ConstPtr stored = m_state.accumulatorOut().storedType();
|
2022-02-24 07:57:44 +00:00
|
|
|
if (stored->accessSemantics() != QQmlJSScope::AccessSemantics::Sequence) {
|
|
|
|
// This rejects any attempt to store the list into a QVariant.
|
|
|
|
// Therefore, we don't have to adjust the contained type below.
|
2022-03-21 09:21:18 +00:00
|
|
|
reject(u"storing an array in a non-sequence type"_s);
|
2022-02-24 07:57:44 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const QQmlJSScope::ConstPtr value = stored->valueType();
|
|
|
|
Q_ASSERT(value);
|
|
|
|
|
|
|
|
QStringList initializer;
|
|
|
|
for (int i = 0; i < argc; ++i) {
|
2023-02-21 10:47:08 +00:00
|
|
|
initializer += convertStored(
|
|
|
|
registerType(args + i).storedType(), value,
|
|
|
|
consumedRegisterVariable(args + i));
|
2022-02-24 07:57:44 +00:00
|
|
|
}
|
|
|
|
|
2022-10-19 12:35:24 +00:00
|
|
|
if (stored->isListProperty()) {
|
|
|
|
reject(u"creating a QQmlListProperty not backed by a property"_s);
|
|
|
|
|
|
|
|
// We can, technically, generate code for this. But it's dangerous:
|
|
|
|
//
|
|
|
|
// const QString storage = m_state.accumulatorVariableOut + u"_storage"_s;
|
|
|
|
// m_body += stored->internalName() + u"::ListType " + storage
|
|
|
|
// + u" = {"_s + initializer.join(u", "_s) + u"};\n"_s;
|
|
|
|
// m_body += m_state.accumulatorVariableOut
|
|
|
|
// + u" = " + stored->internalName() + u"(nullptr, &"_s + storage + u");\n"_s;
|
|
|
|
} else {
|
|
|
|
m_body += m_state.accumulatorVariableOut + u" = "_s + stored->internalName() + u'{';
|
|
|
|
m_body += initializer.join(u", "_s);
|
|
|
|
m_body += u"};\n";
|
|
|
|
}
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_DefineObjectLiteral(int internalClassId, int argc, int args)
|
|
|
|
{
|
|
|
|
Q_UNUSED(internalClassId)
|
|
|
|
Q_UNUSED(argc)
|
|
|
|
Q_UNUSED(args)
|
2022-03-21 09:21:18 +00:00
|
|
|
reject(u"DefineObjectLiteral"_s);
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_CreateClass(int classIndex, int heritage, int computedNames)
|
|
|
|
{
|
|
|
|
Q_UNUSED(classIndex)
|
|
|
|
Q_UNUSED(heritage)
|
|
|
|
Q_UNUSED(computedNames)
|
|
|
|
BYTECODE_UNIMPLEMENTED();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_CreateMappedArgumentsObject()
|
|
|
|
{
|
|
|
|
BYTECODE_UNIMPLEMENTED();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_CreateUnmappedArgumentsObject()
|
|
|
|
{
|
|
|
|
BYTECODE_UNIMPLEMENTED();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_CreateRestParameter(int argIndex)
|
|
|
|
{
|
|
|
|
Q_UNUSED(argIndex)
|
|
|
|
BYTECODE_UNIMPLEMENTED();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_ConvertThisToObject()
|
|
|
|
{
|
2023-05-04 13:39:57 +00:00
|
|
|
m_body += changedRegisterVariable() + u" = "_s
|
|
|
|
+ conversion(m_typeResolver->qObjectType(), m_state.changedRegister(),
|
|
|
|
u"aotContext->thisObject()"_s)
|
|
|
|
+ u";\n"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_LoadSuperConstructor()
|
|
|
|
{
|
|
|
|
BYTECODE_UNIMPLEMENTED();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_ToObject()
|
|
|
|
{
|
|
|
|
BYTECODE_UNIMPLEMENTED();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_Jump(int offset)
|
|
|
|
{
|
|
|
|
INJECT_TRACE_INFO(generate_Jump);
|
|
|
|
|
2022-02-17 12:04:35 +00:00
|
|
|
generateJumpCodeWithTypeConversions(offset);
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u";\n"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
m_skipUntilNextLabel = true;
|
2022-06-27 14:26:43 +00:00
|
|
|
resetState();
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_JumpTrue(int offset)
|
|
|
|
{
|
|
|
|
INJECT_TRACE_INFO(generate_JumpTrue);
|
|
|
|
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u"if ("_s;
|
2023-02-21 10:47:08 +00:00
|
|
|
m_body += convertStored(m_state.accumulatorIn().storedType(), m_typeResolver->boolType(),
|
|
|
|
m_state.accumulatorVariableIn);
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u") "_s;
|
2022-02-17 12:04:35 +00:00
|
|
|
generateJumpCodeWithTypeConversions(offset);
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u";\n"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_JumpFalse(int offset)
|
|
|
|
{
|
|
|
|
INJECT_TRACE_INFO(generate_JumpFalse);
|
|
|
|
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u"if (!"_s;
|
2023-02-21 10:47:08 +00:00
|
|
|
m_body += convertStored(m_state.accumulatorIn().storedType(), m_typeResolver->boolType(),
|
|
|
|
m_state.accumulatorVariableIn);
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u") "_s;
|
2022-02-17 12:04:35 +00:00
|
|
|
generateJumpCodeWithTypeConversions(offset);
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u";\n"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_JumpNoException(int offset)
|
|
|
|
{
|
|
|
|
INJECT_TRACE_INFO(generate_JumpNoException);
|
|
|
|
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u"if (!context->engine->hasException()) "_s;
|
2022-02-17 12:04:35 +00:00
|
|
|
generateJumpCodeWithTypeConversions(offset);
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u";\n"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_JumpNotUndefined(int offset)
|
|
|
|
{
|
|
|
|
Q_UNUSED(offset)
|
|
|
|
BYTECODE_UNIMPLEMENTED();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_CheckException()
|
|
|
|
{
|
|
|
|
INJECT_TRACE_INFO(generate_CheckException);
|
|
|
|
|
|
|
|
generateExceptionCheck();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_CmpEqNull()
|
|
|
|
{
|
|
|
|
INJECT_TRACE_INFO(generate_CmlEqNull);
|
|
|
|
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += m_state.accumulatorVariableOut + u" = "_s;
|
2022-02-16 15:34:56 +00:00
|
|
|
m_body += conversion(
|
2023-02-21 10:47:08 +00:00
|
|
|
m_typeResolver->boolType(), m_state.accumulatorOut(),
|
2022-03-21 09:21:18 +00:00
|
|
|
u"QJSPrimitiveValue(QJSPrimitiveNull()).equals("_s
|
2023-02-21 10:47:08 +00:00
|
|
|
+ convertStored(
|
2022-02-16 15:34:56 +00:00
|
|
|
m_state.accumulatorIn().storedType(), m_typeResolver->jsPrimitiveType(),
|
2022-11-28 15:07:24 +00:00
|
|
|
consumedAccumulatorVariableIn()) + u')');
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u";\n"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_CmpNeNull()
|
|
|
|
{
|
|
|
|
INJECT_TRACE_INFO(generate_CmlNeNull);
|
|
|
|
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += m_state.accumulatorVariableOut + u" = "_s;
|
2022-02-16 15:34:56 +00:00
|
|
|
m_body += conversion(
|
2023-02-21 10:47:08 +00:00
|
|
|
m_typeResolver->boolType(), m_state.accumulatorOut(),
|
2022-03-21 09:21:18 +00:00
|
|
|
u"!QJSPrimitiveValue(QJSPrimitiveNull()).equals("_s
|
2023-02-21 10:47:08 +00:00
|
|
|
+ convertStored(
|
2022-02-16 15:34:56 +00:00
|
|
|
m_state.accumulatorIn().storedType(), m_typeResolver->jsPrimitiveType(),
|
2022-11-28 15:07:24 +00:00
|
|
|
consumedAccumulatorVariableIn()) + u')');
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u";\n"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
QString QQmlJSCodeGenerator::eqIntExpression(int lhsConst)
|
|
|
|
{
|
2023-03-27 16:00:46 +00:00
|
|
|
if (m_typeResolver->isIntegral(m_state.accumulatorIn()))
|
2022-03-21 09:21:18 +00:00
|
|
|
return QString::number(lhsConst) + u" == "_s + m_state.accumulatorVariableIn;
|
2021-11-16 15:49:49 +00:00
|
|
|
|
2022-02-04 21:35:23 +00:00
|
|
|
if (m_typeResolver->registerIsStoredIn(m_state.accumulatorIn(), m_typeResolver->boolType())) {
|
2022-03-21 09:21:18 +00:00
|
|
|
return QString::number(lhsConst) + u" == "_s
|
2023-03-27 16:00:46 +00:00
|
|
|
+ convertStored(m_state.accumulatorIn().storedType(), m_typeResolver->int32Type(),
|
2023-02-21 10:47:08 +00:00
|
|
|
consumedAccumulatorVariableIn());
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
2022-02-02 18:08:29 +00:00
|
|
|
if (m_typeResolver->isNumeric(m_state.accumulatorIn())) {
|
2023-03-27 16:00:46 +00:00
|
|
|
return convertStored(m_typeResolver->int32Type(), m_typeResolver->realType(),
|
2023-02-21 10:47:08 +00:00
|
|
|
QString::number(lhsConst)) + u" == "_s
|
|
|
|
+ convertStored(m_state.accumulatorIn().storedType(), m_typeResolver->realType(),
|
|
|
|
consumedAccumulatorVariableIn());
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
QString result;
|
2023-03-27 16:00:46 +00:00
|
|
|
result += convertStored(m_typeResolver->int32Type(), m_typeResolver->jsPrimitiveType(),
|
2023-02-21 10:47:08 +00:00
|
|
|
QString::number(lhsConst));
|
2022-03-21 09:21:18 +00:00
|
|
|
result += u".equals("_s;
|
2023-02-21 10:47:08 +00:00
|
|
|
result += convertStored(m_state.accumulatorIn().storedType(), m_typeResolver->jsPrimitiveType(),
|
|
|
|
consumedAccumulatorVariableIn());
|
2021-11-16 15:49:49 +00:00
|
|
|
result += u')';
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString QQmlJSCodeGenerator::getLookupPreparation(
|
|
|
|
const QQmlJSRegisterContent &content, const QString &var, int lookup)
|
|
|
|
{
|
2022-02-04 21:35:23 +00:00
|
|
|
if (m_typeResolver->registerContains(content, content.storedType()))
|
2021-11-16 15:49:49 +00:00
|
|
|
return QString();
|
2022-02-04 21:35:23 +00:00
|
|
|
|
|
|
|
if (m_typeResolver->registerIsStoredIn(content, m_typeResolver->varType())) {
|
2022-03-21 09:21:18 +00:00
|
|
|
return var + u" = QVariant(aotContext->lookupResultMetaType("_s
|
|
|
|
+ QString::number(lookup) + u"))"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
// TODO: We could make sure they're compatible, for example QObject pointers.
|
|
|
|
return QString();
|
|
|
|
}
|
|
|
|
|
|
|
|
QString QQmlJSCodeGenerator::contentPointer(const QQmlJSRegisterContent &content, const QString &var)
|
|
|
|
{
|
|
|
|
const QQmlJSScope::ConstPtr stored = content.storedType();
|
2022-02-04 21:35:23 +00:00
|
|
|
if (m_typeResolver->registerContains(content, stored))
|
2021-11-16 15:49:49 +00:00
|
|
|
return u'&' + var;
|
2022-07-04 15:00:15 +00:00
|
|
|
|
2023-03-14 13:51:36 +00:00
|
|
|
if (m_typeResolver->registerIsStoredIn(content, m_typeResolver->varType())
|
|
|
|
|| m_typeResolver->registerIsStoredIn(content, m_typeResolver->jsPrimitiveType())) {
|
2022-03-21 09:21:18 +00:00
|
|
|
return var + u".data()"_s;
|
2023-03-14 13:51:36 +00:00
|
|
|
}
|
2022-07-04 15:00:15 +00:00
|
|
|
|
|
|
|
if (stored->accessSemantics() == QQmlJSScope::AccessSemantics::Reference)
|
2021-11-16 15:49:49 +00:00
|
|
|
return u'&' + var;
|
2022-07-04 15:00:15 +00:00
|
|
|
|
2023-03-27 16:00:46 +00:00
|
|
|
if (m_typeResolver->isNumeric(content.storedType())
|
2022-07-04 15:00:15 +00:00
|
|
|
&& m_typeResolver->containedType(content)->scopeType() == QQmlJSScope::EnumScope) {
|
|
|
|
return u'&' + var;
|
|
|
|
}
|
|
|
|
|
2022-10-19 12:35:24 +00:00
|
|
|
if (stored->isListProperty() && m_typeResolver->containedType(content)->isListProperty())
|
|
|
|
return u'&' + var;
|
|
|
|
|
2023-03-14 13:51:36 +00:00
|
|
|
reject(u"content pointer of unsupported wrapper type "_s + content.descriptiveName());
|
2021-11-16 15:49:49 +00:00
|
|
|
return QString();
|
|
|
|
}
|
|
|
|
|
|
|
|
QString QQmlJSCodeGenerator::contentType(const QQmlJSRegisterContent &content, const QString &var)
|
|
|
|
{
|
|
|
|
const QQmlJSScope::ConstPtr stored = content.storedType();
|
|
|
|
const QQmlJSScope::ConstPtr contained = QQmlJSScope::nonCompositeBaseType(
|
|
|
|
m_typeResolver->containedType(content));
|
2022-02-04 21:35:23 +00:00
|
|
|
if (m_typeResolver->equals(contained, stored))
|
2021-11-16 15:49:49 +00:00
|
|
|
return metaTypeFromType(stored);
|
2022-07-04 15:00:15 +00:00
|
|
|
|
2023-03-14 13:51:36 +00:00
|
|
|
if (m_typeResolver->equals(stored, m_typeResolver->varType())
|
|
|
|
|| m_typeResolver->registerIsStoredIn(content, m_typeResolver->jsPrimitiveType())) {
|
|
|
|
return var + u".metaType()"_s; // We expect the container to be initialized
|
|
|
|
}
|
2022-07-04 15:00:15 +00:00
|
|
|
|
|
|
|
if (stored->accessSemantics() == QQmlJSScope::AccessSemantics::Reference)
|
2021-11-16 15:49:49 +00:00
|
|
|
return metaTypeFromName(contained);
|
2022-07-04 15:00:15 +00:00
|
|
|
|
2023-03-27 16:00:46 +00:00
|
|
|
if (m_typeResolver->isNumeric(stored) && contained->scopeType() == QQmlJSScope::EnumScope)
|
|
|
|
return metaTypeFromType(contained->baseType());
|
2022-07-04 15:00:15 +00:00
|
|
|
|
2022-10-19 12:35:24 +00:00
|
|
|
if (stored->isListProperty() && m_typeResolver->containedType(content)->isListProperty())
|
|
|
|
return metaTypeFromType(m_typeResolver->listPropertyType());
|
|
|
|
|
2023-03-14 13:51:36 +00:00
|
|
|
reject(u"content type of unsupported wrapper type "_s + content.descriptiveName());
|
2021-11-16 15:49:49 +00:00
|
|
|
return QString();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_CmpEqInt(int lhsConst)
|
|
|
|
{
|
|
|
|
INJECT_TRACE_INFO(generate_CmpEqInt);
|
|
|
|
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += m_state.accumulatorVariableOut + u" = "_s;
|
2023-02-21 10:47:08 +00:00
|
|
|
m_body += conversion(m_typeResolver->boolType(), m_state.accumulatorOut(),
|
2022-03-21 09:21:18 +00:00
|
|
|
eqIntExpression(lhsConst)) + u";\n"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_CmpNeInt(int lhsConst)
|
|
|
|
{
|
|
|
|
INJECT_TRACE_INFO(generate_CmpNeInt);
|
|
|
|
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += m_state.accumulatorVariableOut + u" = "_s;
|
2023-02-21 10:47:08 +00:00
|
|
|
m_body += conversion(m_typeResolver->boolType(), m_state.accumulatorOut(),
|
2022-03-21 09:21:18 +00:00
|
|
|
u"!("_s + eqIntExpression(lhsConst) + u')') + u";\n"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_CmpEq(int lhs)
|
|
|
|
{
|
|
|
|
INJECT_TRACE_INFO(generate_CmpEq);
|
2022-03-21 09:21:18 +00:00
|
|
|
generateEqualityOperation(lhs, u"equals"_s, false);
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_CmpNe(int lhs)
|
|
|
|
{
|
|
|
|
INJECT_TRACE_INFO(generate_CmpNe);
|
2022-03-21 09:21:18 +00:00
|
|
|
generateEqualityOperation(lhs, u"equals"_s, true);
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_CmpGt(int lhs)
|
|
|
|
{
|
|
|
|
INJECT_TRACE_INFO(generate_CmpGt);
|
2022-03-21 09:21:18 +00:00
|
|
|
generateCompareOperation(lhs, u">"_s);
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_CmpGe(int lhs)
|
|
|
|
{
|
|
|
|
INJECT_TRACE_INFO(generate_CmpGe);
|
2022-03-21 09:21:18 +00:00
|
|
|
generateCompareOperation(lhs, u">="_s);
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_CmpLt(int lhs)
|
|
|
|
{
|
|
|
|
INJECT_TRACE_INFO(generate_CmpLt);
|
2022-03-21 09:21:18 +00:00
|
|
|
generateCompareOperation(lhs, u"<"_s);
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_CmpLe(int lhs)
|
|
|
|
{
|
|
|
|
INJECT_TRACE_INFO(generate_CmpLe);
|
2022-03-21 09:21:18 +00:00
|
|
|
generateCompareOperation(lhs, u"<="_s);
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_CmpStrictEqual(int lhs)
|
|
|
|
{
|
|
|
|
INJECT_TRACE_INFO(generate_CmpStrictEqual);
|
2022-03-21 09:21:18 +00:00
|
|
|
generateEqualityOperation(lhs, u"strictlyEquals"_s, false);
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_CmpStrictNotEqual(int lhs)
|
|
|
|
{
|
|
|
|
INJECT_TRACE_INFO(generate_CmpStrictNotEqual);
|
2022-03-21 09:21:18 +00:00
|
|
|
generateEqualityOperation(lhs, u"strictlyEquals"_s, true);
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_CmpIn(int lhs)
|
|
|
|
{
|
|
|
|
Q_UNUSED(lhs)
|
2022-03-21 09:21:18 +00:00
|
|
|
reject(u"CmpIn"_s);
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_CmpInstanceOf(int lhs)
|
|
|
|
{
|
|
|
|
Q_UNUSED(lhs)
|
|
|
|
BYTECODE_UNIMPLEMENTED();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_As(int lhs)
|
|
|
|
{
|
|
|
|
INJECT_TRACE_INFO(generate_As);
|
|
|
|
|
2022-02-17 12:04:35 +00:00
|
|
|
const QString input = registerVariable(lhs);
|
2023-02-16 09:54:34 +00:00
|
|
|
const QQmlJSRegisterContent inputContent = m_state.readRegister(lhs);
|
|
|
|
const QQmlJSRegisterContent outputContent = m_state.accumulatorOut();
|
2021-11-16 15:49:49 +00:00
|
|
|
|
2023-02-23 14:59:44 +00:00
|
|
|
// If the original output is a conversion, we're supposed to check for the contained
|
|
|
|
// type and if it doesn't match, set the result to null or undefined.
|
|
|
|
const QQmlJSRegisterContent originalContent = m_typeResolver->original(outputContent);
|
|
|
|
|
|
|
|
const QQmlJSScope::ConstPtr contained = m_typeResolver->containedType(originalContent);
|
|
|
|
|
2023-02-16 09:54:34 +00:00
|
|
|
if (contained->isReferenceType()) {
|
2023-03-17 09:46:42 +00:00
|
|
|
const QQmlJSScope::ConstPtr genericContained = m_typeResolver->genericType(contained);
|
|
|
|
const QString inputConversion = inputContent.storedType()->isReferenceType()
|
|
|
|
? input
|
|
|
|
: convertStored(inputContent.storedType(), genericContained, input);
|
|
|
|
|
2023-02-16 09:54:34 +00:00
|
|
|
m_body += m_state.accumulatorVariableOut + u" = "_s;
|
|
|
|
if (m_typeResolver->equals(
|
|
|
|
m_state.accumulatorIn().storedType(), m_typeResolver->metaObjectType())
|
|
|
|
&& contained->isComposite()) {
|
|
|
|
m_body += conversion(
|
2023-03-17 09:46:42 +00:00
|
|
|
genericContained, outputContent,
|
|
|
|
m_state.accumulatorVariableIn + u"->cast("_s + inputConversion + u')');
|
2023-02-16 09:54:34 +00:00
|
|
|
} else {
|
|
|
|
m_body += conversion(
|
2023-03-17 09:46:42 +00:00
|
|
|
genericContained, outputContent,
|
|
|
|
u'(' + metaObject(contained) + u")->cast("_s + inputConversion + u')');
|
2023-02-16 09:54:34 +00:00
|
|
|
}
|
|
|
|
m_body += u";\n"_s;
|
|
|
|
return;
|
|
|
|
} else if (m_typeResolver->equals(inputContent.storedType(), m_typeResolver->varType())) {
|
|
|
|
if (originalContent.isConversion()) {
|
|
|
|
const auto origins = originalContent.conversionOrigins();
|
|
|
|
Q_ASSERT(origins.size() == 2);
|
|
|
|
|
|
|
|
const auto target = m_typeResolver->equals(origins[0], m_typeResolver->voidType())
|
|
|
|
? origins[1]
|
|
|
|
: origins[0];
|
|
|
|
|
|
|
|
Q_ASSERT(!m_typeResolver->equals(target, m_typeResolver->voidType()));
|
|
|
|
|
|
|
|
m_body += m_state.accumulatorVariableOut + u" = "_s;
|
|
|
|
m_body += input + u".metaType() == "_s + metaType(target)
|
|
|
|
+ u" ? " + conversion(inputContent, outputContent, input)
|
|
|
|
+ u" : " + conversion(m_typeResolver->globalType(m_typeResolver->voidType()),
|
|
|
|
outputContent, QString());
|
|
|
|
m_body += u";\n"_s;
|
|
|
|
return;
|
|
|
|
}
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
2023-02-16 09:54:34 +00:00
|
|
|
|
|
|
|
reject(u"unsupported type assertion"_s);
|
|
|
|
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_UNot()
|
|
|
|
{
|
|
|
|
INJECT_TRACE_INFO(generate_UNot);
|
2022-03-21 09:21:18 +00:00
|
|
|
generateUnaryOperation(u"!"_s);
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_UPlus()
|
|
|
|
{
|
|
|
|
INJECT_TRACE_INFO(generate_UPlus);
|
2022-03-21 09:21:18 +00:00
|
|
|
generateUnaryOperation(u"+"_s);
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_UMinus()
|
|
|
|
{
|
|
|
|
INJECT_TRACE_INFO(generate_UMinus);
|
2022-03-21 09:21:18 +00:00
|
|
|
generateUnaryOperation(u"-"_s);
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_UCompl()
|
|
|
|
{
|
2022-07-29 14:27:57 +00:00
|
|
|
INJECT_TRACE_INFO(generate_UCompl);
|
|
|
|
generateUnaryOperation(u"~"_s);
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_Increment()
|
|
|
|
{
|
|
|
|
INJECT_TRACE_INFO(generate_Increment);
|
2022-03-21 09:21:18 +00:00
|
|
|
generateInPlaceOperation(u"++"_s);
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_Decrement()
|
|
|
|
{
|
|
|
|
INJECT_TRACE_INFO(generate_Decrement);
|
2022-03-21 09:21:18 +00:00
|
|
|
generateInPlaceOperation(u"--"_s);
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_Add(int lhs)
|
|
|
|
{
|
|
|
|
INJECT_TRACE_INFO(generate_Add);
|
2022-03-21 09:21:18 +00:00
|
|
|
generateArithmeticOperation(lhs, u"+"_s);
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_BitAnd(int lhs)
|
|
|
|
{
|
2022-07-29 14:27:57 +00:00
|
|
|
INJECT_TRACE_INFO(generate_BitAnd);
|
|
|
|
generateArithmeticOperation(lhs, u"&"_s);
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_BitOr(int lhs)
|
|
|
|
{
|
2022-07-29 14:27:57 +00:00
|
|
|
INJECT_TRACE_INFO(generate_BitOr);
|
|
|
|
generateArithmeticOperation(lhs, u"|"_s);
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_BitXor(int lhs)
|
|
|
|
{
|
2022-07-29 14:27:57 +00:00
|
|
|
INJECT_TRACE_INFO(generate_BitXor);
|
|
|
|
generateArithmeticOperation(lhs, u"^"_s);
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_UShr(int lhs)
|
|
|
|
{
|
2022-07-29 14:27:57 +00:00
|
|
|
INJECT_TRACE_INFO(generate_BitUShr);
|
|
|
|
generateShiftOperation(lhs, u">>"_s);
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_Shr(int lhs)
|
|
|
|
{
|
2022-07-29 14:27:57 +00:00
|
|
|
INJECT_TRACE_INFO(generate_Shr);
|
|
|
|
generateShiftOperation(lhs, u">>"_s);
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_Shl(int lhs)
|
|
|
|
{
|
2022-07-29 14:27:57 +00:00
|
|
|
INJECT_TRACE_INFO(generate_Shl);
|
|
|
|
generateShiftOperation(lhs, u"<<"_s);
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_BitAndConst(int rhs)
|
|
|
|
{
|
2022-07-29 14:27:57 +00:00
|
|
|
INJECT_TRACE_INFO(generate_BitAndConst);
|
|
|
|
generateArithmeticConstOperation(rhs, u"&"_s);
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_BitOrConst(int rhs)
|
|
|
|
{
|
2022-07-29 14:27:57 +00:00
|
|
|
INJECT_TRACE_INFO(generate_BitOrConst);
|
|
|
|
generateArithmeticConstOperation(rhs, u"|"_s);
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_BitXorConst(int rhs)
|
|
|
|
{
|
2022-07-29 14:27:57 +00:00
|
|
|
INJECT_TRACE_INFO(generate_BitXorConst);
|
|
|
|
generateArithmeticConstOperation(rhs, u"^"_s);
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_UShrConst(int rhs)
|
|
|
|
{
|
2022-07-29 14:27:57 +00:00
|
|
|
INJECT_TRACE_INFO(generate_UShrConst);
|
|
|
|
generateArithmeticConstOperation(rhs & 0x1f, u">>"_s);
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
2022-07-29 14:27:57 +00:00
|
|
|
void QQmlJSCodeGenerator::generate_ShrConst(int rhs)
|
2021-11-16 15:49:49 +00:00
|
|
|
{
|
2022-07-29 14:27:57 +00:00
|
|
|
INJECT_TRACE_INFO(generate_ShrConst);
|
|
|
|
generateArithmeticConstOperation(rhs & 0x1f, u">>"_s);
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
2022-07-29 14:27:57 +00:00
|
|
|
void QQmlJSCodeGenerator::generate_ShlConst(int rhs)
|
2021-11-16 15:49:49 +00:00
|
|
|
{
|
2022-07-29 14:27:57 +00:00
|
|
|
INJECT_TRACE_INFO(generate_ShlConst);
|
|
|
|
generateArithmeticConstOperation(rhs & 0x1f, u"<<"_s);
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_Exp(int lhs)
|
|
|
|
{
|
2022-07-29 14:27:57 +00:00
|
|
|
INJECT_TRACE_INFO(generate_Exp);
|
|
|
|
|
|
|
|
const QString lhsString = conversion(
|
2022-11-28 15:07:24 +00:00
|
|
|
registerType(lhs), m_state.readRegister(lhs), consumedRegisterVariable(lhs));
|
2022-07-29 14:27:57 +00:00
|
|
|
const QString rhsString = conversion(
|
2022-11-28 15:07:24 +00:00
|
|
|
m_state.accumulatorIn(), m_state.readAccumulator(),
|
|
|
|
consumedAccumulatorVariableIn());
|
2022-07-29 14:27:57 +00:00
|
|
|
|
|
|
|
Q_ASSERT(m_error->isValid() || !lhsString.isEmpty());
|
|
|
|
Q_ASSERT(m_error->isValid() || !rhsString.isEmpty());
|
|
|
|
|
|
|
|
const QQmlJSRegisterContent originalOut = m_typeResolver->original(m_state.accumulatorOut());
|
|
|
|
m_body += m_state.accumulatorVariableOut + u" = "_s;
|
|
|
|
m_body += conversion(
|
|
|
|
originalOut, m_state.accumulatorOut(),
|
|
|
|
u"QQmlPrivate::jsExponentiate("_s + lhsString + u", "_s + rhsString + u')');
|
|
|
|
m_body += u";\n"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_Mul(int lhs)
|
|
|
|
{
|
|
|
|
INJECT_TRACE_INFO(generate_Mul);
|
2022-03-21 09:21:18 +00:00
|
|
|
generateArithmeticOperation(lhs, u"*"_s);
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_Div(int lhs)
|
|
|
|
{
|
|
|
|
INJECT_TRACE_INFO(generate_Div);
|
2022-03-21 09:21:18 +00:00
|
|
|
generateArithmeticOperation(lhs, u"/"_s);
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_Mod(int lhs)
|
|
|
|
{
|
|
|
|
INJECT_TRACE_INFO(generate_Mod);
|
|
|
|
|
2023-02-21 10:47:08 +00:00
|
|
|
const auto lhsVar = convertStored(
|
2021-11-16 15:49:49 +00:00
|
|
|
registerType(lhs).storedType(), m_typeResolver->jsPrimitiveType(),
|
2022-11-28 15:07:24 +00:00
|
|
|
consumedRegisterVariable(lhs));
|
2023-02-21 10:47:08 +00:00
|
|
|
const auto rhsVar = convertStored(
|
2022-02-02 18:08:29 +00:00
|
|
|
m_state.accumulatorIn().storedType(), m_typeResolver->jsPrimitiveType(),
|
2022-11-28 15:07:24 +00:00
|
|
|
consumedAccumulatorVariableIn());
|
2022-06-03 13:12:10 +00:00
|
|
|
Q_ASSERT(m_error->isValid() || !lhsVar.isEmpty());
|
|
|
|
Q_ASSERT(m_error->isValid() || !rhsVar.isEmpty());
|
2021-11-16 15:49:49 +00:00
|
|
|
|
|
|
|
m_body += m_state.accumulatorVariableOut;
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u" = "_s;
|
2023-02-21 10:47:08 +00:00
|
|
|
m_body += conversion(m_typeResolver->jsPrimitiveType(), m_state.accumulatorOut(),
|
2022-03-21 09:21:18 +00:00
|
|
|
u'(' + lhsVar + u" % "_s + rhsVar + u')');
|
|
|
|
m_body += u";\n"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_Sub(int lhs)
|
|
|
|
{
|
|
|
|
INJECT_TRACE_INFO(generate_Sub);
|
2022-03-21 09:21:18 +00:00
|
|
|
generateArithmeticOperation(lhs, u"-"_s);
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_InitializeBlockDeadTemporalZone(int firstReg, int count)
|
|
|
|
{
|
|
|
|
Q_UNUSED(firstReg)
|
|
|
|
Q_UNUSED(count)
|
2022-11-10 13:50:18 +00:00
|
|
|
// Ignore. We reject uninitialized values anyway.
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_ThrowOnNullOrUndefined()
|
|
|
|
{
|
|
|
|
BYTECODE_UNIMPLEMENTED();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generate_GetTemplateObject(int index)
|
|
|
|
{
|
|
|
|
Q_UNUSED(index)
|
|
|
|
BYTECODE_UNIMPLEMENTED();
|
|
|
|
}
|
|
|
|
|
2022-01-17 10:40:44 +00:00
|
|
|
QV4::Moth::ByteCodeHandler::Verdict QQmlJSCodeGenerator::startInstruction(
|
|
|
|
QV4::Moth::Instr::Type type)
|
2021-11-16 15:49:49 +00:00
|
|
|
{
|
|
|
|
m_state.State::operator=(nextStateFromAnnotations(m_state, *m_annotations));
|
2022-02-02 18:08:29 +00:00
|
|
|
const auto accumulatorIn = m_state.registers.find(Accumulator);
|
2022-02-16 13:01:52 +00:00
|
|
|
if (accumulatorIn != m_state.registers.end()
|
2022-11-28 15:07:24 +00:00
|
|
|
&& isTypeStorable(m_typeResolver, accumulatorIn.value().content.storedType())) {
|
2022-02-02 18:08:29 +00:00
|
|
|
m_state.accumulatorVariableIn = m_registerVariables.value(Accumulator)
|
2022-11-28 15:07:24 +00:00
|
|
|
.value(accumulatorIn.value().content.storedType());
|
2022-02-02 18:08:29 +00:00
|
|
|
Q_ASSERT(!m_state.accumulatorVariableIn.isEmpty());
|
|
|
|
} else {
|
|
|
|
m_state.accumulatorVariableIn.clear();
|
|
|
|
}
|
2021-11-16 15:49:49 +00:00
|
|
|
|
|
|
|
auto labelIt = m_labels.constFind(currentInstructionOffset());
|
|
|
|
if (labelIt != m_labels.constEnd()) {
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += *labelIt + u":;\n"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
m_skipUntilNextLabel = false;
|
2022-01-17 10:40:44 +00:00
|
|
|
} else if (m_skipUntilNextLabel && !instructionManipulatesContext(type)) {
|
2021-11-16 15:49:49 +00:00
|
|
|
return SkipInstruction;
|
|
|
|
}
|
|
|
|
|
2022-02-02 18:08:29 +00:00
|
|
|
if (m_state.changedRegisterIndex() == Accumulator)
|
|
|
|
m_state.accumulatorVariableOut = changedRegisterVariable();
|
|
|
|
else
|
|
|
|
m_state.accumulatorVariableOut.clear();
|
|
|
|
|
2021-11-16 15:49:49 +00:00
|
|
|
// If the accumulator type is valid, we want an accumulator variable.
|
|
|
|
// If not, we don't want one.
|
2022-02-02 18:08:29 +00:00
|
|
|
Q_ASSERT(m_state.changedRegisterIndex() == Accumulator
|
|
|
|
|| m_state.accumulatorVariableOut.isEmpty());
|
|
|
|
Q_ASSERT(m_state.changedRegisterIndex() != Accumulator
|
2022-02-16 13:01:52 +00:00
|
|
|
|| !m_state.accumulatorVariableOut.isEmpty()
|
|
|
|
|| !isTypeStorable(m_typeResolver, m_state.changedRegister().storedType()));
|
2021-11-16 15:49:49 +00:00
|
|
|
|
2022-02-16 13:01:52 +00:00
|
|
|
// If the instruction has no side effects and doesn't write any register, it's dead.
|
|
|
|
// We might still need the label, though, and the source code comment.
|
2022-02-16 15:34:56 +00:00
|
|
|
if (!m_state.hasSideEffects() && changedRegisterVariable().isEmpty())
|
2022-02-16 13:01:52 +00:00
|
|
|
return SkipInstruction;
|
|
|
|
|
2021-11-16 15:49:49 +00:00
|
|
|
return ProcessInstruction;
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::endInstruction(QV4::Moth::Instr::Type)
|
|
|
|
{
|
2022-06-27 14:26:43 +00:00
|
|
|
if (!m_skipUntilNextLabel)
|
|
|
|
generateJumpCodeWithTypeConversions(0);
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generateSetInstructionPointer()
|
|
|
|
{
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u"aotContext->setInstructionPointer("_s
|
|
|
|
+ QString::number(nextInstructionOffset()) + u");\n"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generateExceptionCheck()
|
|
|
|
{
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u"if (aotContext->engine->hasError())\n"_s;
|
|
|
|
m_body += u" return "_s + errorReturnValue() + u";\n"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generateEqualityOperation(int lhs, const QString &function, bool invert)
|
|
|
|
{
|
|
|
|
const QQmlJSRegisterContent lhsContent = registerType(lhs);
|
2023-01-30 21:33:00 +00:00
|
|
|
const bool strictlyComparableWithVar = function == "strictlyEquals"_L1
|
|
|
|
&& canStrictlyCompareWithVar(m_typeResolver, lhsContent, m_state.accumulatorIn());
|
2021-11-16 15:49:49 +00:00
|
|
|
auto isComparable = [&]() {
|
|
|
|
if (m_typeResolver->isPrimitive(lhsContent)
|
2022-02-02 18:08:29 +00:00
|
|
|
&& m_typeResolver->isPrimitive(m_state.accumulatorIn())) {
|
2021-11-16 15:49:49 +00:00
|
|
|
return true;
|
|
|
|
}
|
2022-02-02 18:08:29 +00:00
|
|
|
if (m_typeResolver->isNumeric(lhsContent) && m_state.accumulatorIn().isEnumeration())
|
2021-11-16 15:49:49 +00:00
|
|
|
return true;
|
2022-02-02 18:08:29 +00:00
|
|
|
if (m_typeResolver->isNumeric(m_state.accumulatorIn()) && lhsContent.isEnumeration())
|
2021-11-16 15:49:49 +00:00
|
|
|
return true;
|
2023-01-30 21:33:00 +00:00
|
|
|
if (strictlyComparableWithVar)
|
2022-12-13 00:43:09 +00:00
|
|
|
return true;
|
2023-01-06 15:39:43 +00:00
|
|
|
if (canCompareWithQObject(m_typeResolver, lhsContent, m_state.accumulatorIn()))
|
|
|
|
return true;
|
2023-02-15 12:25:25 +00:00
|
|
|
if (canCompareWithQUrl(m_typeResolver, lhsContent, m_state.accumulatorIn()))
|
|
|
|
return true;
|
2021-11-16 15:49:49 +00:00
|
|
|
return false;
|
|
|
|
};
|
|
|
|
|
2022-02-16 13:01:52 +00:00
|
|
|
if (!isComparable()) {
|
2023-01-30 21:33:00 +00:00
|
|
|
reject(u"incomparable types %1 and %2"_s.arg(m_state.accumulatorIn().descriptiveName(),
|
|
|
|
lhsContent.descriptiveName()));
|
2022-02-16 13:01:52 +00:00
|
|
|
}
|
2021-11-16 15:49:49 +00:00
|
|
|
|
|
|
|
const QQmlJSScope::ConstPtr lhsType = lhsContent.storedType();
|
2022-02-02 18:08:29 +00:00
|
|
|
const QQmlJSScope::ConstPtr rhsType = m_state.accumulatorIn().storedType();
|
2021-11-16 15:49:49 +00:00
|
|
|
|
|
|
|
const auto primitive = m_typeResolver->jsPrimitiveType();
|
2022-02-04 21:35:23 +00:00
|
|
|
if (m_typeResolver->equals(lhsType, rhsType) && !m_typeResolver->equals(lhsType, primitive)) {
|
2022-12-13 00:43:09 +00:00
|
|
|
m_body += m_state.accumulatorVariableOut + u" = "_s;
|
2022-11-18 10:40:10 +00:00
|
|
|
if (isTypeStorable(m_typeResolver, lhsType)) {
|
2023-02-21 10:47:08 +00:00
|
|
|
m_body += conversion(m_typeResolver->boolType(), m_state.accumulatorOut(),
|
2022-11-28 15:07:24 +00:00
|
|
|
consumedRegisterVariable(lhs) + (invert ? u" != "_s : u" == "_s)
|
|
|
|
+ consumedAccumulatorVariableIn());
|
2022-11-18 10:40:10 +00:00
|
|
|
} else {
|
|
|
|
// null === null and undefined === undefined
|
|
|
|
m_body += invert ? u"false"_s : u"true"_s;
|
|
|
|
}
|
2023-01-30 21:33:00 +00:00
|
|
|
} else if (strictlyComparableWithVar) {
|
2022-12-13 00:43:09 +00:00
|
|
|
// Determine which side is holding a storable type
|
|
|
|
if (const auto registerVariableName = registerVariable(lhs);
|
|
|
|
!registerVariableName.isEmpty()) {
|
|
|
|
// lhs register holds var type
|
|
|
|
generateVariantEqualityComparison(m_state.accumulatorIn(), registerVariableName,
|
|
|
|
invert);
|
|
|
|
} else {
|
|
|
|
// lhs content is not storable and rhs is var type
|
|
|
|
generateVariantEqualityComparison(lhsContent, m_state.accumulatorVariableIn, invert);
|
|
|
|
}
|
2023-01-06 15:39:43 +00:00
|
|
|
} else if (canCompareWithQObject(m_typeResolver, lhsContent, m_state.accumulatorIn())) {
|
|
|
|
m_body += m_state.accumulatorVariableOut + u" = "_s;
|
|
|
|
m_body += u'('
|
|
|
|
+ (isTypeStorable(m_typeResolver, lhsContent.storedType())
|
|
|
|
? registerVariable(lhs)
|
|
|
|
: m_state.accumulatorVariableIn)
|
|
|
|
+ (invert ? u" != "_s : u" == "_s) + u"nullptr)"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
} else {
|
2022-12-13 00:43:09 +00:00
|
|
|
m_body += m_state.accumulatorVariableOut + u" = "_s;
|
2022-02-16 15:34:56 +00:00
|
|
|
m_body += conversion(
|
2023-02-21 10:47:08 +00:00
|
|
|
m_typeResolver->boolType(), m_state.accumulatorOut(),
|
2022-03-21 09:21:18 +00:00
|
|
|
(invert ? u"!"_s : QString())
|
2023-02-21 10:47:08 +00:00
|
|
|
+ convertStored(registerType(lhs).storedType(), primitive,
|
|
|
|
consumedRegisterVariable(lhs))
|
|
|
|
+ u'.' + function + u'(' + convertStored(
|
2022-02-16 15:34:56 +00:00
|
|
|
m_state.accumulatorIn().storedType(), primitive,
|
2022-11-28 15:07:24 +00:00
|
|
|
consumedAccumulatorVariableIn())
|
2022-02-16 15:34:56 +00:00
|
|
|
+ u')');
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u";\n"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generateCompareOperation(int lhs, const QString &cppOperator)
|
|
|
|
{
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += m_state.accumulatorVariableOut + u" = "_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
|
|
|
|
const auto lhsType = registerType(lhs);
|
|
|
|
const QQmlJSScope::ConstPtr compareType =
|
2022-02-02 18:08:29 +00:00
|
|
|
m_typeResolver->isNumeric(lhsType) && m_typeResolver->isNumeric(m_state.accumulatorIn())
|
|
|
|
? m_typeResolver->merge(lhsType, m_state.accumulatorIn()).storedType()
|
2021-11-16 15:49:49 +00:00
|
|
|
: m_typeResolver->jsPrimitiveType();
|
2022-02-16 15:34:56 +00:00
|
|
|
|
|
|
|
m_body += conversion(
|
2023-02-21 10:47:08 +00:00
|
|
|
m_typeResolver->boolType(), m_state.accumulatorOut(),
|
|
|
|
convertStored(registerType(lhs).storedType(), compareType,
|
|
|
|
consumedRegisterVariable(lhs))
|
2022-02-16 15:34:56 +00:00
|
|
|
+ u' ' + cppOperator + u' '
|
2023-02-21 10:47:08 +00:00
|
|
|
+ convertStored(m_state.accumulatorIn().storedType(), compareType,
|
|
|
|
consumedAccumulatorVariableIn()));
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u";\n"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generateArithmeticOperation(int lhs, const QString &cppOperator)
|
|
|
|
{
|
2022-07-29 14:27:57 +00:00
|
|
|
generateArithmeticOperation(
|
2022-11-28 15:07:24 +00:00
|
|
|
conversion(registerType(lhs), m_state.readRegister(lhs),
|
|
|
|
consumedRegisterVariable(lhs)),
|
2022-07-29 14:27:57 +00:00
|
|
|
conversion(m_state.accumulatorIn(), m_state.readAccumulator(),
|
2022-11-28 15:07:24 +00:00
|
|
|
consumedAccumulatorVariableIn()),
|
2022-07-29 14:27:57 +00:00
|
|
|
cppOperator);
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generateShiftOperation(int lhs, const QString &cppOperator)
|
|
|
|
{
|
|
|
|
generateArithmeticOperation(
|
2022-11-28 15:07:24 +00:00
|
|
|
conversion(registerType(lhs), m_state.readRegister(lhs),
|
|
|
|
consumedRegisterVariable(lhs)),
|
2022-07-29 14:27:57 +00:00
|
|
|
u'(' + conversion(m_state.accumulatorIn(), m_state.readAccumulator(),
|
2022-11-28 15:07:24 +00:00
|
|
|
consumedAccumulatorVariableIn()) + u" & 0x1f)"_s,
|
2022-07-29 14:27:57 +00:00
|
|
|
cppOperator);
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generateArithmeticOperation(
|
|
|
|
const QString &lhs, const QString &rhs, const QString &cppOperator)
|
|
|
|
{
|
|
|
|
Q_ASSERT(m_error->isValid() || !lhs.isEmpty());
|
|
|
|
Q_ASSERT(m_error->isValid() || !rhs.isEmpty());
|
2021-11-16 15:49:49 +00:00
|
|
|
|
2022-02-16 15:34:56 +00:00
|
|
|
const QQmlJSRegisterContent originalOut = m_typeResolver->original(m_state.accumulatorOut());
|
2021-11-16 15:49:49 +00:00
|
|
|
m_body += m_state.accumulatorVariableOut;
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u" = "_s;
|
2022-02-16 13:01:52 +00:00
|
|
|
m_body += conversion(
|
2022-02-16 15:34:56 +00:00
|
|
|
originalOut, m_state.accumulatorOut(),
|
2022-07-29 14:27:57 +00:00
|
|
|
u'(' + lhs + u' ' + cppOperator + u' ' + rhs + u')');
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u";\n"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
2022-07-29 14:27:57 +00:00
|
|
|
void QQmlJSCodeGenerator::generateArithmeticConstOperation(int rhsConst, const QString &cppOperator)
|
|
|
|
{
|
|
|
|
generateArithmeticOperation(
|
|
|
|
conversion(m_state.accumulatorIn(), m_state.readAccumulator(),
|
2022-11-28 15:07:24 +00:00
|
|
|
consumedAccumulatorVariableIn()),
|
2023-03-27 16:00:46 +00:00
|
|
|
conversion(m_typeResolver->globalType(m_typeResolver->int32Type()),
|
2022-07-29 14:27:57 +00:00
|
|
|
m_state.readAccumulator(), QString::number(rhsConst)),
|
|
|
|
cppOperator);
|
|
|
|
}
|
|
|
|
|
2022-02-16 13:01:52 +00:00
|
|
|
void QQmlJSCodeGenerator::generateUnaryOperation(const QString &cppOperator)
|
|
|
|
{
|
|
|
|
const auto var = conversion(m_state.accumulatorIn(), m_state.readAccumulator(),
|
2022-11-28 15:07:24 +00:00
|
|
|
consumedAccumulatorVariableIn());
|
2022-02-16 13:01:52 +00:00
|
|
|
|
|
|
|
if (var == m_state.accumulatorVariableOut) {
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += m_state.accumulatorVariableOut + u" = "_s + cppOperator + var + u";\n"_s;
|
2022-02-16 13:01:52 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const auto original = m_typeResolver->original(m_state.accumulatorOut());
|
|
|
|
if (m_state.accumulatorOut() == original) {
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += m_state.accumulatorVariableOut + u" = "_s + var + u";\n"_s;
|
|
|
|
m_body += m_state.accumulatorVariableOut + u" = "_s
|
|
|
|
+ cppOperator + m_state.accumulatorVariableOut + u";\n"_s;
|
2022-02-16 13:01:52 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += m_state.accumulatorVariableOut + u" = "_s + conversion(
|
2023-02-21 10:47:08 +00:00
|
|
|
original, m_state.accumulatorOut(), cppOperator + var) + u";\n"_s;
|
2022-02-16 13:01:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSCodeGenerator::generateInPlaceOperation(const QString &cppOperator)
|
|
|
|
{
|
2022-11-28 15:07:24 +00:00
|
|
|
{
|
|
|
|
// If actually in place, we cannot consume the variable.
|
|
|
|
const QString var = conversion(m_state.accumulatorIn(), m_state.readAccumulator(),
|
|
|
|
m_state.accumulatorVariableIn);
|
|
|
|
if (var == m_state.accumulatorVariableOut) {
|
|
|
|
m_body += cppOperator + var + u";\n"_s;
|
|
|
|
return;
|
|
|
|
}
|
2022-02-16 13:01:52 +00:00
|
|
|
}
|
|
|
|
|
2022-11-28 15:07:24 +00:00
|
|
|
const QString var = conversion(m_state.accumulatorIn(), m_state.readAccumulator(),
|
|
|
|
consumedAccumulatorVariableIn());
|
|
|
|
|
2022-02-16 13:01:52 +00:00
|
|
|
const auto original = m_typeResolver->original(m_state.accumulatorOut());
|
|
|
|
if (m_state.accumulatorOut() == original) {
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += m_state.accumulatorVariableOut + u" = "_s + var + u";\n"_s;
|
|
|
|
m_body += cppOperator + m_state.accumulatorVariableOut + u";\n"_s;
|
2022-02-16 13:01:52 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u"{\n"_s;
|
|
|
|
m_body += u"auto converted = "_s + var + u";\n"_s;
|
|
|
|
m_body += m_state.accumulatorVariableOut + u" = "_s + conversion(
|
2023-02-21 10:47:08 +00:00
|
|
|
original, m_state.accumulatorOut(), u'('
|
|
|
|
+ cppOperator + u"converted)"_s) + u";\n"_s;
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u"}\n"_s;
|
2022-02-16 13:01:52 +00:00
|
|
|
}
|
|
|
|
|
2021-11-16 15:49:49 +00:00
|
|
|
void QQmlJSCodeGenerator::generateLookup(const QString &lookup, const QString &initialization,
|
|
|
|
const QString &resultPreparation)
|
|
|
|
{
|
|
|
|
if (!resultPreparation.isEmpty())
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += resultPreparation + u";\n"_s;
|
|
|
|
m_body += u"while (!"_s + lookup + u") {\n"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
generateSetInstructionPointer();
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += initialization + u";\n"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
generateExceptionCheck();
|
|
|
|
if (!resultPreparation.isEmpty())
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += resultPreparation + u";\n"_s;
|
|
|
|
m_body += u"}\n"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
2022-02-17 12:04:35 +00:00
|
|
|
void QQmlJSCodeGenerator::generateJumpCodeWithTypeConversions(int relativeOffset)
|
2021-11-16 15:49:49 +00:00
|
|
|
{
|
2022-03-28 07:21:21 +00:00
|
|
|
QString conversionCode;
|
|
|
|
const int absoluteOffset = nextInstructionOffset() + relativeOffset;
|
2022-02-16 14:12:26 +00:00
|
|
|
const auto annotation = m_annotations->find(absoluteOffset);
|
2021-11-16 15:49:49 +00:00
|
|
|
if (annotation != m_annotations->constEnd()) {
|
2022-02-16 14:12:26 +00:00
|
|
|
const auto &conversions = annotation->second.typeConversions;
|
2021-11-16 15:49:49 +00:00
|
|
|
|
|
|
|
for (auto regIt = conversions.constBegin(), regEnd = conversions.constEnd();
|
|
|
|
regIt != regEnd; ++regIt) {
|
|
|
|
int registerIndex = regIt.key();
|
2022-11-28 15:07:24 +00:00
|
|
|
const QQmlJSRegisterContent targetType = regIt.value().content;
|
2022-02-02 18:08:29 +00:00
|
|
|
if (!targetType.isValid())
|
2021-11-16 15:49:49 +00:00
|
|
|
continue;
|
2022-02-02 18:08:29 +00:00
|
|
|
|
|
|
|
QQmlJSRegisterContent currentType;
|
|
|
|
QString currentVariable;
|
|
|
|
if (registerIndex == m_state.changedRegisterIndex()) {
|
|
|
|
currentType = m_state.changedRegister();
|
|
|
|
currentVariable = changedRegisterVariable();
|
|
|
|
} else {
|
|
|
|
auto it = m_state.registers.find(registerIndex);
|
|
|
|
if (it == m_state.registers.end())
|
|
|
|
continue;
|
2022-11-28 15:07:24 +00:00
|
|
|
currentType = it.value().content;
|
|
|
|
currentVariable = consumedRegisterVariable(registerIndex);
|
2022-02-02 18:08:29 +00:00
|
|
|
}
|
|
|
|
|
2022-02-04 21:35:23 +00:00
|
|
|
// Actually == here. We want the jump code also for equal types
|
2022-02-16 13:01:52 +00:00
|
|
|
if (currentType == targetType
|
|
|
|
|| !isTypeStorable(m_typeResolver, targetType.storedType())) {
|
2021-11-16 15:49:49 +00:00
|
|
|
continue;
|
2022-02-16 13:01:52 +00:00
|
|
|
}
|
|
|
|
|
2021-11-16 15:49:49 +00:00
|
|
|
Q_ASSERT(m_registerVariables.contains(registerIndex));
|
|
|
|
const auto ¤tRegisterVariables = m_registerVariables[registerIndex];
|
|
|
|
const auto variable = currentRegisterVariables.constFind(targetType.storedType());
|
2022-02-02 18:08:29 +00:00
|
|
|
if (variable == currentRegisterVariables.end() || *variable == currentVariable)
|
2021-11-16 15:49:49 +00:00
|
|
|
continue;
|
|
|
|
|
2022-03-28 07:21:21 +00:00
|
|
|
conversionCode += *variable;
|
2022-03-21 09:21:18 +00:00
|
|
|
conversionCode += u" = "_s;
|
2022-03-28 07:21:21 +00:00
|
|
|
conversionCode += conversion(currentType, targetType, currentVariable);
|
2022-03-21 09:21:18 +00:00
|
|
|
conversionCode += u";\n"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (relativeOffset) {
|
|
|
|
auto labelIt = m_labels.find(absoluteOffset);
|
|
|
|
if (labelIt == m_labels.end())
|
2022-10-05 05:29:16 +00:00
|
|
|
labelIt = m_labels.insert(absoluteOffset, u"label_%1"_s.arg(m_labels.size()));
|
2022-03-21 09:21:18 +00:00
|
|
|
conversionCode += u" goto "_s + *labelIt + u";\n"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
2022-03-28 07:21:21 +00:00
|
|
|
|
|
|
|
if (!conversionCode.isEmpty())
|
2022-03-21 09:21:18 +00:00
|
|
|
m_body += u"{\n"_s + conversionCode + u"}\n"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
QString QQmlJSCodeGenerator::registerVariable(int index) const
|
|
|
|
{
|
2022-06-20 12:44:35 +00:00
|
|
|
auto it = m_registerVariables.find(index);
|
|
|
|
if (it != m_registerVariables.end()) {
|
|
|
|
const QString variable = it->value(registerType(index).storedType());
|
|
|
|
if (!variable.isEmpty())
|
|
|
|
return variable;
|
|
|
|
}
|
|
|
|
|
|
|
|
return QString();
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
2022-11-28 15:07:24 +00:00
|
|
|
QString QQmlJSCodeGenerator::consumedRegisterVariable(int index) const
|
|
|
|
{
|
|
|
|
const QString var = registerVariable(index);
|
|
|
|
if (var.isEmpty() || !m_state.canMoveReadRegister(index))
|
|
|
|
return var;
|
|
|
|
return u"std::move(" + var + u")";
|
|
|
|
}
|
|
|
|
|
|
|
|
QString QQmlJSCodeGenerator::consumedAccumulatorVariableIn() const
|
|
|
|
{
|
|
|
|
return m_state.canMoveReadRegister(Accumulator)
|
|
|
|
? u"std::move(" + m_state.accumulatorVariableIn + u")"
|
|
|
|
: m_state.accumulatorVariableIn;
|
|
|
|
}
|
|
|
|
|
2022-02-02 18:08:29 +00:00
|
|
|
QString QQmlJSCodeGenerator::changedRegisterVariable() const
|
|
|
|
{
|
|
|
|
return m_registerVariables.value(m_state.changedRegisterIndex()).value(
|
|
|
|
m_state.changedRegister().storedType());
|
|
|
|
}
|
|
|
|
|
2021-11-16 15:49:49 +00:00
|
|
|
QQmlJSRegisterContent QQmlJSCodeGenerator::registerType(int index) const
|
|
|
|
{
|
2022-06-20 12:44:35 +00:00
|
|
|
auto it = m_state.registers.find(index);
|
|
|
|
if (it != m_state.registers.end())
|
2022-11-28 15:07:24 +00:00
|
|
|
return it.value().content;
|
2022-06-20 12:44:35 +00:00
|
|
|
|
|
|
|
return QQmlJSRegisterContent();
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
2023-03-14 13:51:36 +00:00
|
|
|
QString QQmlJSCodeGenerator::conversion(
|
|
|
|
const QQmlJSRegisterContent &from, const QQmlJSRegisterContent &to, const QString &variable)
|
|
|
|
{
|
|
|
|
const QQmlJSScope::ConstPtr contained = m_typeResolver->containedType(to);
|
|
|
|
|
|
|
|
// If both types are stored in QJSPrimitiveValue we coerce using QJSPrimitiveValue
|
|
|
|
if (m_typeResolver->registerIsStoredIn(from, m_typeResolver->jsPrimitiveType())
|
|
|
|
&& m_typeResolver->registerIsStoredIn(to, m_typeResolver->jsPrimitiveType())) {
|
|
|
|
if (m_typeResolver->equals(contained, m_typeResolver->jsPrimitiveType()))
|
|
|
|
return variable;
|
|
|
|
|
|
|
|
const QString conversion = variable + u".to<QJSPrimitiveValue::%1>()"_s;
|
|
|
|
if (m_typeResolver->equals(contained, m_typeResolver->boolType()))
|
|
|
|
return conversion.arg(u"Boolean"_s);
|
2023-03-27 16:00:46 +00:00
|
|
|
if (m_typeResolver->isIntegral(to))
|
2023-03-14 13:51:36 +00:00
|
|
|
return conversion.arg(u"Integer"_s);
|
|
|
|
if (m_typeResolver->equals(contained, m_typeResolver->realType()))
|
|
|
|
return conversion.arg(u"Double"_s);
|
|
|
|
if (m_typeResolver->equals(contained, m_typeResolver->stringType()))
|
|
|
|
return conversion.arg(u"String"_s);
|
|
|
|
reject(u"Conversion of QJSPrimitiveValue to "_s + contained->internalName());
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_typeResolver->registerIsStoredIn(to, contained)
|
2023-05-02 09:08:13 +00:00
|
|
|
|| m_typeResolver->isNumeric(to.storedType())
|
2023-03-14 13:51:36 +00:00
|
|
|
|| to.storedType()->isReferenceType()
|
|
|
|
|| m_typeResolver->registerContains(from, contained)) {
|
|
|
|
// If:
|
|
|
|
// * the output is not actually wrapped at all, or
|
2023-05-02 09:08:13 +00:00
|
|
|
// * the output is stored in a numeric type (as there are no internals to a number), or
|
2023-03-14 13:51:36 +00:00
|
|
|
// * the output is a QObject pointer, or
|
|
|
|
// * we merely wrap the value into a new container,
|
|
|
|
// we can convert by stored type.
|
|
|
|
return convertStored(from.storedType(), to.storedType(), variable);
|
|
|
|
} else {
|
|
|
|
return convertContained(from, to, variable);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-21 10:47:08 +00:00
|
|
|
QString QQmlJSCodeGenerator::convertStored(
|
|
|
|
const QQmlJSScope::ConstPtr &from, const QQmlJSScope::ConstPtr &to, const QString &variable)
|
2021-11-16 15:49:49 +00:00
|
|
|
{
|
|
|
|
// TODO: most values can be moved, which is much more efficient with the common types.
|
|
|
|
// add a move(from, to, variable) function that implements the moves.
|
|
|
|
Q_ASSERT(!to->isComposite()); // We cannot directly convert to composites.
|
|
|
|
|
2022-02-03 16:31:33 +00:00
|
|
|
const auto jsValueType = m_typeResolver->jsValueType();
|
|
|
|
const auto varType = m_typeResolver->varType();
|
|
|
|
const auto jsPrimitiveType = m_typeResolver->jsPrimitiveType();
|
|
|
|
const auto boolType = m_typeResolver->boolType();
|
|
|
|
|
2023-02-15 12:04:03 +00:00
|
|
|
auto zeroBoolOrInt = [&](const QQmlJSScope::ConstPtr &to) {
|
2022-02-16 12:33:47 +00:00
|
|
|
if (m_typeResolver->equals(to, boolType))
|
2022-03-21 09:21:18 +00:00
|
|
|
return u"false"_s;
|
2023-03-27 16:00:46 +00:00
|
|
|
if (m_typeResolver->isSignedInteger(to))
|
2022-03-21 09:21:18 +00:00
|
|
|
return u"0"_s;
|
2023-03-27 16:00:46 +00:00
|
|
|
if (m_typeResolver->isUnsignedInteger(to))
|
2022-07-29 14:25:22 +00:00
|
|
|
return u"0u"_s;
|
2022-02-16 12:33:47 +00:00
|
|
|
return QString();
|
|
|
|
};
|
|
|
|
|
|
|
|
if (m_typeResolver->equals(from, m_typeResolver->voidType())) {
|
|
|
|
if (to->accessSemantics() == QQmlJSScope::AccessSemantics::Reference)
|
2022-03-21 09:21:18 +00:00
|
|
|
return u"static_cast<"_s + to->internalName() + u" *>(nullptr)"_s;
|
2023-02-15 12:04:03 +00:00
|
|
|
const QString zero = zeroBoolOrInt(to);
|
2022-02-16 12:33:47 +00:00
|
|
|
if (!zero.isEmpty())
|
|
|
|
return zero;
|
2023-02-15 12:04:03 +00:00
|
|
|
if (m_typeResolver->equals(to, m_typeResolver->floatType()))
|
|
|
|
return u"std::numeric_limits<float>::quiet_NaN()"_s;
|
|
|
|
if (m_typeResolver->equals(to, m_typeResolver->realType()))
|
|
|
|
return u"std::numeric_limits<double>::quiet_NaN()"_s;
|
2022-02-16 12:33:47 +00:00
|
|
|
if (m_typeResolver->equals(to, m_typeResolver->stringType()))
|
2022-03-21 09:21:18 +00:00
|
|
|
return QQmlJSUtils::toLiteral(u"undefined"_s);
|
2022-02-16 12:33:47 +00:00
|
|
|
if (m_typeResolver->equals(from, to))
|
|
|
|
return QString();
|
2022-02-24 15:36:14 +00:00
|
|
|
// Anything else is just the default constructed type.
|
2022-03-21 09:21:18 +00:00
|
|
|
return to->augmentedInternalName() + u"()"_s;
|
2022-02-16 12:33:47 +00:00
|
|
|
}
|
|
|
|
|
2022-02-04 21:35:23 +00:00
|
|
|
if (m_typeResolver->equals(from, m_typeResolver->nullType())) {
|
2022-02-03 16:31:33 +00:00
|
|
|
if (to->accessSemantics() == QQmlJSScope::AccessSemantics::Reference)
|
2022-03-21 09:21:18 +00:00
|
|
|
return u"static_cast<"_s + to->internalName() + u" *>(nullptr)"_s;
|
2022-02-04 21:35:23 +00:00
|
|
|
if (m_typeResolver->equals(to, jsValueType))
|
2022-03-21 09:21:18 +00:00
|
|
|
return u"QJSValue(QJSValue::NullValue)"_s;
|
2022-02-04 21:35:23 +00:00
|
|
|
if (m_typeResolver->equals(to, jsPrimitiveType))
|
2022-03-21 09:21:18 +00:00
|
|
|
return u"QJSPrimitiveValue(QJSPrimitiveNull())"_s;
|
2022-02-04 21:35:23 +00:00
|
|
|
if (m_typeResolver->equals(to, varType))
|
2022-03-21 09:21:18 +00:00
|
|
|
return u"QVariant::fromValue<std::nullptr_t>(nullptr)"_s;
|
2023-02-15 12:04:03 +00:00
|
|
|
const QString zero = zeroBoolOrInt(to);
|
2022-02-16 12:33:47 +00:00
|
|
|
if (!zero.isEmpty())
|
|
|
|
return zero;
|
2023-02-15 12:04:03 +00:00
|
|
|
if (m_typeResolver->equals(to, m_typeResolver->floatType()))
|
|
|
|
return u"0.0f"_s;
|
|
|
|
if (m_typeResolver->equals(to, m_typeResolver->realType()))
|
|
|
|
return u"0.0"_s;
|
2022-02-04 21:35:23 +00:00
|
|
|
if (m_typeResolver->equals(to, m_typeResolver->stringType()))
|
2022-03-21 09:21:18 +00:00
|
|
|
return QQmlJSUtils::toLiteral(u"null"_s);
|
2022-02-04 21:35:23 +00:00
|
|
|
if (m_typeResolver->equals(from, to))
|
2022-02-03 16:31:33 +00:00
|
|
|
return QString();
|
2022-03-21 09:21:18 +00:00
|
|
|
reject(u"Conversion from null to %1"_s.arg(to->internalName()));
|
2022-02-03 16:31:33 +00:00
|
|
|
}
|
2022-02-03 13:45:49 +00:00
|
|
|
|
2022-02-04 21:35:23 +00:00
|
|
|
if (m_typeResolver->equals(from, to))
|
2021-11-16 15:49:49 +00:00
|
|
|
return variable;
|
|
|
|
|
2022-01-04 17:59:14 +00:00
|
|
|
if (from->accessSemantics() == QQmlJSScope::AccessSemantics::Reference) {
|
|
|
|
if (to->accessSemantics() == QQmlJSScope::AccessSemantics::Reference) {
|
2022-03-23 09:04:22 +00:00
|
|
|
// Compare internalName here. The same C++ type can be exposed muliple times in
|
|
|
|
// different QML types. However, the C++ names have to be unique. We can always
|
|
|
|
// static_cast to those.
|
|
|
|
|
2022-01-04 17:59:14 +00:00
|
|
|
for (QQmlJSScope::ConstPtr base = from; base; base = base->baseType()) {
|
|
|
|
// We still have to cast as other execution paths may result in different types.
|
2022-03-23 09:04:22 +00:00
|
|
|
if (base->internalName() == to->internalName())
|
2022-03-21 09:21:18 +00:00
|
|
|
return u"static_cast<"_s + to->internalName() + u" *>("_s + variable + u')';
|
2022-01-04 17:59:14 +00:00
|
|
|
}
|
|
|
|
for (QQmlJSScope::ConstPtr base = to; base; base = base->baseType()) {
|
2022-03-23 09:04:22 +00:00
|
|
|
if (base->internalName() == from->internalName())
|
2022-03-21 09:21:18 +00:00
|
|
|
return u"static_cast<"_s + to->internalName() + u" *>("_s + variable + u')';
|
2022-01-04 17:59:14 +00:00
|
|
|
}
|
2022-02-04 21:35:23 +00:00
|
|
|
} else if (m_typeResolver->equals(to, m_typeResolver->boolType())) {
|
2022-03-21 09:21:18 +00:00
|
|
|
return u'(' + variable + u" != nullptr)"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
auto isJsValue = [&](const QQmlJSScope::ConstPtr &candidate) {
|
2022-02-04 21:35:23 +00:00
|
|
|
return m_typeResolver->equals(candidate, jsValueType) || candidate->isScript();
|
2021-11-16 15:49:49 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
if (isJsValue(from) && isJsValue(to))
|
|
|
|
return variable;
|
|
|
|
|
|
|
|
const auto isBoolOrNumber = [&](const QQmlJSScope::ConstPtr &type) {
|
|
|
|
return m_typeResolver->isNumeric(m_typeResolver->globalType(type))
|
2022-02-04 21:35:23 +00:00
|
|
|
|| m_typeResolver->equals(type, m_typeResolver->boolType())
|
2021-11-16 15:49:49 +00:00
|
|
|
|| type->scopeType() == QQmlJSScope::EnumScope;
|
|
|
|
};
|
|
|
|
|
2022-02-04 21:35:23 +00:00
|
|
|
if (m_typeResolver->equals(from, m_typeResolver->realType())
|
2022-07-29 14:25:22 +00:00
|
|
|
|| m_typeResolver->equals(from, m_typeResolver->floatType())) {
|
2023-03-27 16:00:46 +00:00
|
|
|
if (m_typeResolver->isSignedInteger(to))
|
2022-07-29 14:25:22 +00:00
|
|
|
return u"QJSNumberCoercion::toInteger("_s + variable + u')';
|
2023-03-27 16:00:46 +00:00
|
|
|
if (m_typeResolver->isUnsignedInteger(to))
|
2022-07-29 14:25:22 +00:00
|
|
|
return u"uint(QJSNumberCoercion::toInteger("_s + variable + u"))"_s;
|
|
|
|
if (m_typeResolver->equals(to, m_typeResolver->boolType()))
|
|
|
|
return u'(' + variable + u" && !std::isnan("_s + variable + u"))"_s;
|
2022-02-04 21:35:23 +00:00
|
|
|
}
|
2021-11-16 15:49:49 +00:00
|
|
|
|
|
|
|
if (isBoolOrNumber(from) && isBoolOrNumber(to))
|
|
|
|
return to->internalName() + u'(' + variable + u')';
|
|
|
|
|
2022-02-04 21:35:23 +00:00
|
|
|
|
|
|
|
if (m_typeResolver->equals(from, jsPrimitiveType)) {
|
|
|
|
if (m_typeResolver->equals(to, m_typeResolver->realType()))
|
2022-03-21 09:21:18 +00:00
|
|
|
return variable + u".toDouble()"_s;
|
2022-02-04 21:35:23 +00:00
|
|
|
if (m_typeResolver->equals(to, boolType))
|
2022-03-21 09:21:18 +00:00
|
|
|
return variable + u".toBoolean()"_s;
|
2023-03-27 16:00:46 +00:00
|
|
|
if (m_typeResolver->isSignedInteger(to))
|
2022-03-21 09:21:18 +00:00
|
|
|
return variable + u".toInteger()"_s;
|
2023-03-27 16:00:46 +00:00
|
|
|
if (m_typeResolver->isUnsignedInteger(to))
|
2022-07-29 14:25:22 +00:00
|
|
|
return u"uint("_s + variable + u".toInteger())"_s;
|
2022-02-04 21:35:23 +00:00
|
|
|
if (m_typeResolver->equals(to, m_typeResolver->stringType()))
|
2022-03-21 09:21:18 +00:00
|
|
|
return variable + u".toString()"_s;
|
2022-02-04 21:35:23 +00:00
|
|
|
if (m_typeResolver->equals(to, jsValueType))
|
2022-03-21 09:21:18 +00:00
|
|
|
return u"QJSValue(QJSPrimitiveValue("_s + variable + u"))"_s;
|
2022-02-04 21:35:23 +00:00
|
|
|
if (m_typeResolver->equals(to, varType))
|
2022-03-21 09:21:18 +00:00
|
|
|
return variable + u".toVariant()"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
if (to->accessSemantics() == QQmlJSScope::AccessSemantics::Reference)
|
2022-03-21 09:21:18 +00:00
|
|
|
return u"static_cast<"_s + to->internalName() + u" *>(nullptr)"_s;
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (isJsValue(from)) {
|
2022-02-04 21:35:23 +00:00
|
|
|
if (m_typeResolver->equals(to, jsPrimitiveType))
|
2022-03-21 09:21:18 +00:00
|
|
|
return variable + u".toPrimitive()"_s;
|
2022-02-04 21:35:23 +00:00
|
|
|
if (m_typeResolver->equals(to, varType))
|
2022-03-21 09:21:18 +00:00
|
|
|
return variable + u".toVariant(QJSValue::RetainJSObjects)"_s;
|
|
|
|
return u"qjsvalue_cast<"_s + castTargetName(to) + u">("_s + variable + u')';
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
2022-12-01 16:09:23 +00:00
|
|
|
if (m_typeResolver->equals(to, jsPrimitiveType)) {
|
|
|
|
// null and undefined have been handled above already
|
|
|
|
Q_ASSERT(!m_typeResolver->equals(from, m_typeResolver->nullType()));
|
|
|
|
Q_ASSERT(!m_typeResolver->equals(from, m_typeResolver->voidType()));
|
|
|
|
|
|
|
|
if (m_typeResolver->equals(from, m_typeResolver->boolType())
|
2023-03-27 16:00:46 +00:00
|
|
|
|| m_typeResolver->equals(from, m_typeResolver->int32Type())
|
2022-12-01 16:09:23 +00:00
|
|
|
|| m_typeResolver->equals(from, m_typeResolver->realType())
|
|
|
|
|| m_typeResolver->equals(from, m_typeResolver->stringType())) {
|
|
|
|
return u"QJSPrimitiveValue("_s + variable + u')';
|
2023-03-27 16:00:46 +00:00
|
|
|
} else if (m_typeResolver->isSignedInteger(from)
|
|
|
|
|| m_typeResolver->equals(from, m_typeResolver->uint16Type())
|
|
|
|
|| m_typeResolver->equals(from, m_typeResolver->uint8Type())) {
|
|
|
|
return u"QJSPrimitiveValue(int("_s + variable + u"))"_s;
|
2022-12-01 16:09:23 +00:00
|
|
|
} else if (m_typeResolver->isNumeric(from)) {
|
|
|
|
return u"QJSPrimitiveValue(double("_s + variable + u"))"_s;
|
|
|
|
}
|
|
|
|
}
|
2021-11-16 15:49:49 +00:00
|
|
|
|
2022-02-04 21:35:23 +00:00
|
|
|
if (m_typeResolver->equals(to, jsValueType))
|
2022-03-21 09:21:18 +00:00
|
|
|
return u"aotContext->engine->toScriptValue("_s + variable + u')';
|
2021-11-16 15:49:49 +00:00
|
|
|
|
2022-02-04 21:35:23 +00:00
|
|
|
if (m_typeResolver->equals(from, varType)) {
|
|
|
|
if (m_typeResolver->equals(to, m_typeResolver->listPropertyType()))
|
2022-03-21 09:21:18 +00:00
|
|
|
return u"QQmlListReference("_s + variable + u", aotContext->qmlEngine())"_s;
|
|
|
|
return u"aotContext->engine->fromVariant<"_s + castTargetName(to) + u">("_s
|
2022-02-16 09:47:04 +00:00
|
|
|
+ variable + u')';
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
2022-02-04 21:35:23 +00:00
|
|
|
if (m_typeResolver->equals(to, varType))
|
2022-03-21 09:21:18 +00:00
|
|
|
return u"QVariant::fromValue("_s + variable + u')';
|
2021-11-16 15:49:49 +00:00
|
|
|
|
2022-02-24 15:36:14 +00:00
|
|
|
if (m_typeResolver->equals(from, m_typeResolver->urlType())
|
|
|
|
&& m_typeResolver->equals(to, m_typeResolver->stringType())) {
|
2022-03-21 09:21:18 +00:00
|
|
|
return variable + u".toString()"_s;
|
2022-02-24 15:36:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (m_typeResolver->equals(from, m_typeResolver->stringType())
|
|
|
|
&& m_typeResolver->equals(to, m_typeResolver->urlType())) {
|
2022-03-21 09:21:18 +00:00
|
|
|
return u"QUrl("_s + variable + u')';
|
2022-02-24 15:36:14 +00:00
|
|
|
}
|
|
|
|
|
2022-07-18 12:16:11 +00:00
|
|
|
if (m_typeResolver->equals(from, m_typeResolver->byteArrayType())
|
|
|
|
&& m_typeResolver->equals(to, m_typeResolver->stringType())) {
|
|
|
|
return u"QString::fromUtf8("_s + variable + u')';
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_typeResolver->equals(from, m_typeResolver->stringType())
|
|
|
|
&& m_typeResolver->equals(to, m_typeResolver->byteArrayType())) {
|
|
|
|
return variable + u".toUtf8()"_s;
|
|
|
|
}
|
|
|
|
|
2023-01-12 09:06:35 +00:00
|
|
|
for (const auto &originType : {
|
|
|
|
m_typeResolver->dateTimeType(),
|
|
|
|
m_typeResolver->dateType(),
|
|
|
|
m_typeResolver->timeType()}) {
|
|
|
|
if (m_typeResolver->equals(from, originType)) {
|
|
|
|
for (const auto &targetType : {
|
|
|
|
m_typeResolver->dateTimeType(),
|
|
|
|
m_typeResolver->dateType(),
|
|
|
|
m_typeResolver->timeType(),
|
|
|
|
m_typeResolver->stringType()}) {
|
|
|
|
if (m_typeResolver->equals(to, targetType)) {
|
|
|
|
return u"aotContext->engine->coerceValue<%1, %2>(%3)"_s.arg(
|
|
|
|
originType->internalName(), targetType->internalName(), variable);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-29 14:25:22 +00:00
|
|
|
const auto retrieveFromPrimitive = [&](
|
|
|
|
const QQmlJSScope::ConstPtr &type, const QString &expression) -> QString
|
2022-02-24 15:36:14 +00:00
|
|
|
{
|
|
|
|
if (m_typeResolver->equals(type, m_typeResolver->boolType()))
|
2022-07-29 14:25:22 +00:00
|
|
|
return expression + u".toBoolean()"_s;
|
2023-03-27 16:00:46 +00:00
|
|
|
if (m_typeResolver->isSignedInteger(type))
|
2022-07-29 14:25:22 +00:00
|
|
|
return expression + u".toInteger()"_s;
|
2023-03-27 16:00:46 +00:00
|
|
|
if (m_typeResolver->isUnsignedInteger(type))
|
2022-07-29 14:25:22 +00:00
|
|
|
return u"uint("_s + expression + u".toInteger())"_s;
|
2022-02-24 15:36:14 +00:00
|
|
|
if (m_typeResolver->equals(type, m_typeResolver->realType()))
|
2022-07-29 14:25:22 +00:00
|
|
|
return expression + u".toDouble()"_s;
|
|
|
|
if (m_typeResolver->equals(type, m_typeResolver->floatType()))
|
|
|
|
return u"float("_s + expression + u".toDouble())"_s;
|
2022-02-24 15:36:14 +00:00
|
|
|
if (m_typeResolver->equals(type, m_typeResolver->stringType()))
|
2022-07-29 14:25:22 +00:00
|
|
|
return expression + u".toString()"_s;
|
2022-02-24 15:36:14 +00:00
|
|
|
return QString();
|
|
|
|
};
|
|
|
|
|
2022-07-29 14:25:22 +00:00
|
|
|
if (!retrieveFromPrimitive(from, u"x"_s).isEmpty()) {
|
|
|
|
const QString retrieve = retrieveFromPrimitive(
|
2023-02-21 10:47:08 +00:00
|
|
|
to, convertStored(from, m_typeResolver->jsPrimitiveType(), variable));
|
2022-02-24 15:36:14 +00:00
|
|
|
if (!retrieve.isEmpty())
|
2022-07-29 14:25:22 +00:00
|
|
|
return retrieve;
|
2022-02-24 15:36:14 +00:00
|
|
|
}
|
|
|
|
|
2022-11-15 10:57:47 +00:00
|
|
|
if (from->isReferenceType() && m_typeResolver->equals(to, m_typeResolver->stringType())) {
|
|
|
|
return u"aotContext->engine->coerceValue<"_s + castTargetName(from) + u", "
|
|
|
|
+ castTargetName(to) + u">("_s + variable + u')';
|
|
|
|
}
|
|
|
|
|
2023-02-23 14:55:52 +00:00
|
|
|
// Any value type is a non-null JS 'object' and therefore coerces to true.
|
|
|
|
if (m_typeResolver->equals(to, m_typeResolver->boolType())) {
|
|
|
|
// All the interesting cases are already handled above:
|
|
|
|
Q_ASSERT(!m_typeResolver->equals(from, m_typeResolver->nullType()));
|
|
|
|
Q_ASSERT(!m_typeResolver->equals(from, m_typeResolver->voidType()));
|
|
|
|
Q_ASSERT(retrieveFromPrimitive(from, u"x"_s).isEmpty());
|
|
|
|
Q_ASSERT(!isBoolOrNumber(from));
|
|
|
|
|
|
|
|
return u"true"_s;
|
|
|
|
}
|
|
|
|
|
2023-04-17 11:17:21 +00:00
|
|
|
if (m_typeResolver->areEquivalentLists(from, to))
|
|
|
|
return variable;
|
|
|
|
|
2023-04-17 10:44:09 +00:00
|
|
|
if (from->isListProperty()
|
|
|
|
&& to->accessSemantics() == QQmlJSScope::AccessSemantics::Sequence
|
|
|
|
&& to->valueType()->isReferenceType()
|
|
|
|
&& !to->isListProperty()) {
|
|
|
|
return variable + u".toList<"_s + to->internalName() + u">()"_s;
|
|
|
|
}
|
|
|
|
|
2023-02-21 10:47:08 +00:00
|
|
|
bool isExtension = false;
|
|
|
|
if (const auto ctor = m_typeResolver->selectConstructor(to, from, &isExtension); ctor.isValid()) {
|
|
|
|
const auto argumentTypes = ctor.parameters();
|
|
|
|
return (isExtension ? to->extensionType().scope->internalName() : to->internalName())
|
|
|
|
+ u"("_s + convertStored(from, argumentTypes[0].type(), variable) + u")"_s;
|
|
|
|
}
|
|
|
|
|
2022-06-03 13:12:10 +00:00
|
|
|
// TODO: add more conversions
|
2021-11-16 15:49:49 +00:00
|
|
|
|
2022-06-03 13:12:10 +00:00
|
|
|
reject(u"conversion from "_s + from->internalName() + u" to "_s + to->internalName());
|
|
|
|
return QString();
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
2023-02-21 10:47:08 +00:00
|
|
|
QString QQmlJSCodeGenerator::convertContained(const QQmlJSRegisterContent &from, const QQmlJSRegisterContent &to, const QString &variable)
|
|
|
|
{
|
|
|
|
const QQmlJSScope::ConstPtr containedFrom = m_typeResolver->containedType(from);
|
|
|
|
const QQmlJSScope::ConstPtr containedTo = m_typeResolver->containedType(to);
|
|
|
|
|
|
|
|
// Those should be handled before, by convertStored().
|
|
|
|
Q_ASSERT(!to.storedType()->isReferenceType());
|
|
|
|
Q_ASSERT(!m_typeResolver->registerIsStoredIn(to, containedTo));
|
2023-03-27 16:00:46 +00:00
|
|
|
Q_ASSERT(!m_typeResolver->isIntegral(from.storedType()));
|
2023-02-21 10:47:08 +00:00
|
|
|
Q_ASSERT(!m_typeResolver->equals(containedFrom, containedTo));
|
|
|
|
|
2023-03-14 13:51:36 +00:00
|
|
|
if (!m_typeResolver->registerIsStoredIn(to, m_typeResolver->varType()) &&
|
|
|
|
!m_typeResolver->registerIsStoredIn(to, m_typeResolver->jsPrimitiveType())) {
|
|
|
|
reject(u"internal conversion into unsupported wrapper type."_s);
|
|
|
|
}
|
2023-02-21 10:47:08 +00:00
|
|
|
|
|
|
|
bool isExtension = false;
|
|
|
|
if (const auto ctor = m_typeResolver->selectConstructor(
|
|
|
|
containedTo, containedFrom, &isExtension); ctor.isValid()) {
|
|
|
|
const auto argumentTypes = ctor.parameters();
|
|
|
|
const QQmlJSScope::ConstPtr argumentType = argumentTypes[0].type();
|
|
|
|
|
|
|
|
// We need to store the converted argument in a temporary
|
|
|
|
// because it might not be an lvalue.
|
|
|
|
|
|
|
|
QString input;
|
|
|
|
QString argPointer;
|
|
|
|
|
|
|
|
if (m_typeResolver->equals(argumentType, containedFrom)) {
|
|
|
|
input = variable;
|
|
|
|
argPointer = contentPointer(from, u"arg"_s);
|
|
|
|
} else {
|
|
|
|
const QQmlJSRegisterContent argument
|
|
|
|
= m_typeResolver->globalType(argumentType)
|
|
|
|
.storedIn(m_typeResolver->genericType(argumentType));
|
|
|
|
input = conversion(from, argument, variable);
|
|
|
|
argPointer = contentPointer(argument, u"arg"_s);
|
|
|
|
}
|
|
|
|
|
|
|
|
return u"[&](){ auto arg = " + input
|
|
|
|
+ u"; return aotContext->constructValueType("_s + metaType(containedTo)
|
|
|
|
+ u", "_s + metaObject(
|
|
|
|
isExtension ? containedTo->extensionType().scope : containedTo)
|
|
|
|
+ u", "_s + QString::number(int(ctor.constructorIndex()))
|
|
|
|
+ u", "_s + argPointer + u"); }()"_s;
|
|
|
|
}
|
|
|
|
|
|
|
|
reject(u"internal conversion with incompatible or ambiguous types"_s);
|
|
|
|
return QString();
|
|
|
|
}
|
|
|
|
|
2021-11-16 15:49:49 +00:00
|
|
|
void QQmlJSCodeGenerator::reject(const QString &thing)
|
|
|
|
{
|
2022-03-21 09:21:18 +00:00
|
|
|
setError(u"Cannot generate efficient code for %1"_s.arg(thing));
|
2021-11-16 15:49:49 +00:00
|
|
|
}
|
|
|
|
|
2022-02-16 13:01:52 +00:00
|
|
|
QQmlJSCodeGenerator::AccumulatorConverter::AccumulatorConverter(QQmlJSCodeGenerator *generator)
|
|
|
|
: accumulatorOut(generator->m_state.accumulatorOut())
|
|
|
|
, accumulatorVariableIn(generator->m_state.accumulatorVariableIn)
|
|
|
|
, accumulatorVariableOut(generator->m_state.accumulatorVariableOut)
|
|
|
|
, generator(generator)
|
|
|
|
{
|
2022-02-16 15:34:56 +00:00
|
|
|
if (accumulatorVariableOut.isEmpty())
|
|
|
|
return;
|
|
|
|
|
2022-02-16 13:01:52 +00:00
|
|
|
const QQmlJSTypeResolver *resolver = generator->m_typeResolver;
|
|
|
|
const QQmlJSScope::ConstPtr origContained = resolver->originalContainedType(accumulatorOut);
|
2022-05-19 13:32:22 +00:00
|
|
|
const QQmlJSScope::ConstPtr stored = accumulatorOut.storedType();
|
|
|
|
const QQmlJSScope::ConstPtr origStored = resolver->originalType(stored);
|
|
|
|
|
|
|
|
// If the stored type differs or if we store in QVariant and the contained type differs,
|
2022-06-27 10:54:47 +00:00
|
|
|
// then we have to use a temporary ...
|
2022-05-19 13:32:22 +00:00
|
|
|
if (!resolver->equals(origStored, stored)
|
|
|
|
|| (!resolver->equals(origContained, resolver->containedType(accumulatorOut))
|
|
|
|
&& resolver->equals(stored, resolver->varType()))) {
|
2022-06-27 10:54:47 +00:00
|
|
|
|
|
|
|
const bool storable = isTypeStorable(resolver, origStored);
|
|
|
|
generator->m_state.accumulatorVariableOut = storable ? u"retrieved"_s : QString();
|
2022-02-16 13:01:52 +00:00
|
|
|
generator->m_state.setRegister(Accumulator, resolver->original(accumulatorOut));
|
2022-03-21 09:21:18 +00:00
|
|
|
generator->m_body += u"{\n"_s;
|
2022-06-27 10:54:47 +00:00
|
|
|
if (storable) {
|
|
|
|
generator->m_body += origStored->augmentedInternalName() + u' '
|
|
|
|
+ generator->m_state.accumulatorVariableOut + u";\n";
|
|
|
|
}
|
2022-02-16 13:01:52 +00:00
|
|
|
} else if (generator->m_state.accumulatorVariableIn == generator->m_state.accumulatorVariableOut
|
|
|
|
&& generator->m_state.readsRegister(Accumulator)
|
|
|
|
&& resolver->registerIsStoredIn(
|
|
|
|
generator->m_state.accumulatorOut(), resolver->varType())) {
|
|
|
|
// If both m_state.accumulatorIn and m_state.accumulatorOut are QVariant, we will need to
|
|
|
|
// prepare the output QVariant, and afterwards use the input variant. Therefore we need to
|
|
|
|
// move the input out of the way first.
|
2022-02-17 12:04:35 +00:00
|
|
|
generator->m_state.accumulatorVariableIn
|
2022-03-21 09:21:18 +00:00
|
|
|
= generator->m_state.accumulatorVariableIn + u"_moved"_s;
|
|
|
|
generator->m_body += u"{\n"_s;
|
|
|
|
generator->m_body += u"QVariant "_s + generator->m_state.accumulatorVariableIn
|
|
|
|
+ u" = std::move("_s + generator->m_state.accumulatorVariableOut + u");\n"_s;
|
2022-02-16 13:01:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QQmlJSCodeGenerator::AccumulatorConverter::~AccumulatorConverter()
|
|
|
|
{
|
|
|
|
if (accumulatorVariableOut != generator->m_state.accumulatorVariableOut) {
|
2022-03-21 09:21:18 +00:00
|
|
|
generator->m_body += accumulatorVariableOut + u" = "_s + generator->conversion(
|
2022-02-16 13:01:52 +00:00
|
|
|
generator->m_state.accumulatorOut(), accumulatorOut,
|
2022-03-21 09:21:18 +00:00
|
|
|
generator->m_state.accumulatorVariableOut) + u";\n"_s;
|
|
|
|
generator->m_body += u"}\n"_s;
|
2022-02-16 13:01:52 +00:00
|
|
|
generator->m_state.setRegister(Accumulator, accumulatorOut);
|
|
|
|
generator->m_state.accumulatorVariableOut = accumulatorVariableOut;
|
|
|
|
} else if (accumulatorVariableIn != generator->m_state.accumulatorVariableIn) {
|
2022-03-21 09:21:18 +00:00
|
|
|
generator->m_body += u"}\n"_s;
|
2022-02-16 13:01:52 +00:00
|
|
|
generator->m_state.accumulatorVariableIn = accumulatorVariableIn;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-11-16 15:49:49 +00:00
|
|
|
QT_END_NAMESPACE
|