1445void IRBuilder::setBindingValue(QV4::CompiledData::Binding *binding, QQmlJS::AST::Statement *statement, QQmlJS::AST::Node *parentNode)
1447 QQmlJS::SourceLocation loc = statement->firstSourceLocation();
1448 binding->valueLocation.set(loc.startLine, loc.startColumn);
1449 binding->setType(QV4::CompiledData::Binding::Type_Invalid);
1450 if (_propertyDeclaration && _propertyDeclaration->isReadOnly())
1451 binding->setFlag(QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration);
1453 QQmlJS::AST::ExpressionStatement *exprStmt = QQmlJS::AST::cast<QQmlJS::AST::ExpressionStatement *>(statement);
1455 QQmlJS::AST::ExpressionNode *
const expr = exprStmt->expression;
1456 if (QQmlJS::AST::StringLiteral *lit = QQmlJS::AST::cast<QQmlJS::AST::StringLiteral *>(expr)) {
1457 binding->setType(QV4::CompiledData::Binding::Type_String);
1458 binding->stringIndex = registerString(lit->value.toString());
1459 }
else if (QQmlJS::AST::TemplateLiteral *templateLit = QQmlJS::AST::cast<QQmlJS::AST::TemplateLiteral *>(expr);
1460 templateLit && templateLit->hasNoSubstitution) {
1463 binding->setType(QV4::CompiledData::Binding::Type_String);
1464 binding->stringIndex = registerString(templateLit->value.toString());
1465 }
else if (expr->kind == QQmlJS::AST::Node::Kind_TrueLiteral) {
1466 binding->setType(QV4::CompiledData::Binding::Type_Boolean);
1467 binding->value.b =
true;
1468 }
else if (expr->kind == QQmlJS::AST::Node::Kind_FalseLiteral) {
1469 binding->setType(QV4::CompiledData::Binding::Type_Boolean);
1470 binding->value.b =
false;
1471 }
else if (QQmlJS::AST::NumericLiteral *lit = QQmlJS::AST::cast<QQmlJS::AST::NumericLiteral *>(expr)) {
1472 binding->setType(QV4::CompiledData::Binding::Type_Number);
1473 binding->value.constantValueIndex = jsGenerator->registerConstant(QV4::Encode(lit->value));
1474 }
else if (QQmlJS::AST::CallExpression *call = QQmlJS::AST::cast<QQmlJS::AST::CallExpression *>(expr)) {
1475 if (QQmlJS::AST::IdentifierExpression *base = QQmlJS::AST::cast<QQmlJS::AST::IdentifierExpression *>(call->base)) {
1476 tryGeneratingTranslationBinding(base->name, call->arguments, binding);
1480 }
else if (QQmlJS::AST::cast<QQmlJS::AST::FunctionExpression *>(expr)) {
1481 binding->setFlag(QV4::CompiledData::Binding::IsFunctionExpression);
1482 }
else if (QQmlJS::AST::UnaryMinusExpression *unaryMinus = QQmlJS::AST::cast<QQmlJS::AST::UnaryMinusExpression *>(expr)) {
1483 if (QQmlJS::AST::NumericLiteral *lit = QQmlJS::AST::cast<QQmlJS::AST::NumericLiteral *>(unaryMinus->expression)) {
1484 binding->setType(QV4::CompiledData::Binding::Type_Number);
1485 binding->value.constantValueIndex = jsGenerator->registerConstant(QV4::Encode(-lit->value));
1487 }
else if (QQmlJS::AST::cast<QQmlJS::AST::NullExpression *>(expr)) {
1488 binding->setType(QV4::CompiledData::Binding::Type_Null);
1489 binding->value.nullMarker = 0;
1494 if (binding->type() == QV4::CompiledData::Binding::Type_Invalid) {
1495 binding->setType(QV4::CompiledData::Binding::Type_Script);
1497 CompiledFunctionOrExpression *expr = New<CompiledFunctionOrExpression>();
1498 expr->node = statement;
1499 expr->parentNode = parentNode;
1500 expr->nameIndex = registerString(QLatin1String(
"expression for ")
1501 + stringAt(binding->propertyNameIndex));
1502 const int index = bindingsTarget()->functionsAndExpressions->append(expr);
1503 binding->value.compiledScriptIndex = index;
1509 QQmlJS::AST::Node *nodeForString = statement;
1511 nodeForString = exprStmt->expression;
1512 const QStringView source = asStringRef(nodeForString);
1513 if (source == u"undefined") {
1514 binding->stringIndex = registerString(u"undefined"_s);
1515 }
else if (qualifiedEnumDot(source) != -1) {
1516 binding->stringIndex = registerString(source.toString());
1517 }
else if (
const auto *arrayPattern =
1518 QQmlJS::AST::cast<QQmlJS::AST::ArrayPattern *>(nodeForString);
1519 arrayPattern && !arrayPattern->elements) {
1520 binding->stringIndex = registerString(u"[]"_s);
1522 binding->stringIndex = emptyStringIndex;
1800bool IRBuilder::resolveQualifiedId(QQmlJS::AST::UiQualifiedId **nameToResolve, Object **object,
bool onAssignment)
1802 QQmlJS::AST::UiQualifiedId *qualifiedIdElement = *nameToResolve;
1804 if (qualifiedIdElement->name == QLatin1String(
"id") && qualifiedIdElement->next)
1805 COMPILE_EXCEPTION(qualifiedIdElement->identifierToken, tr(
"Invalid use of id property"));
1808 QString currentName = qualifiedIdElement->name.toString();
1809 if (qualifiedIdElement->next) {
1810 for (
const QV4::CompiledData::Import* import : std::as_const(_imports))
1811 if (import->qualifierIndex != emptyStringIndex
1812 && stringAt(import->qualifierIndex) == currentName) {
1813 qualifiedIdElement = qualifiedIdElement->next;
1814 currentName += QLatin1Char(
'.') + qualifiedIdElement->name;
1816 if (!qualifiedIdElement->name.data()->isUpper())
1817 COMPILE_EXCEPTION(qualifiedIdElement->firstSourceLocation(), tr(
"Expected type name"));
1824 while (qualifiedIdElement->next) {
1825 const quint32 propertyNameIndex = registerString(currentName);
1826 const bool isAttachedProperty = qualifiedIdElement->name.data()->isUpper();
1828 Binding *binding = (*object)->findBinding(propertyNameIndex);
1830 if (isAttachedProperty) {
1831 if (!binding->isAttachedProperty())
1833 }
else if (!binding->isGroupedProperty()) {
1838 binding = New<Binding>();
1839 binding->propertyNameIndex = propertyNameIndex;
1840 binding->offset = qualifiedIdElement->identifierToken.offset;
1841 binding->location.set(qualifiedIdElement->identifierToken.startLine,
1842 qualifiedIdElement->identifierToken.startColumn);
1843 binding->valueLocation.set(qualifiedIdElement->next->identifierToken.startLine,
1844 qualifiedIdElement->next->identifierToken.startColumn);
1845 binding->clearFlags();
1848 binding->setFlag(QV4::CompiledData::Binding::IsOnAssignment);
1850 if (isAttachedProperty)
1851 binding->setType(QV4::CompiledData::Binding::Type_AttachedProperty);
1853 binding->setType(QV4::CompiledData::Binding::Type_GroupedProperty);
1856 if (!defineQMLObject(&objIndex,
nullptr, binding->location,
nullptr,
nullptr))
1858 binding->value.objectIndex = objIndex;
1860 QString error = (*object)->appendBinding(binding,
false);
1861 if (!error.isEmpty()) {
1862 recordError(qualifiedIdElement->identifierToken,
1863 error.arg(stringAt(propertyNameIndex)),
1864 QQmlJS::DiagnosticCategory::DuplicatePropertyBinding);
1865 if (!shouldContinue())
1868 *object = _objects.at(objIndex);
1870 Q_ASSERT(binding->isAttachedProperty() || binding->isGroupedProperty());
1871 *object = _objects.at(binding->value.objectIndex);
1874 qualifiedIdElement = qualifiedIdElement->next;
1875 if (qualifiedIdElement)
1876 currentName = qualifiedIdElement->name.toString();
1878 *nameToResolve = qualifiedIdElement;
1936void QmlUnitGenerator::generate(Document &output,
const QV4::CompiledData::DependentTypesHasher &dependencyHasher)
1938 using namespace QV4::CompiledData;
1940 output.jsGenerator.stringTable.registerString(output.jsModule.fileName);
1941 output.jsGenerator.stringTable.registerString(output.jsModule.finalUrl);
1943 Unit *jsUnit =
nullptr;
1945 if (!output.javaScriptCompilationUnit)
1946 output.javaScriptCompilationUnit.adopt(
new QV4::CompiledData::CompilationUnit);
1949 if (output.javaScriptCompilationUnit->unitData()) {
1950 jsUnit =
const_cast<Unit *>(output.javaScriptCompilationUnit->unitData());
1951 output.javaScriptCompilationUnit->dynamicStrings
1952 = output.jsGenerator.stringTable.allStrings();
1955 jsUnit = createdUnit = output.jsGenerator.generateUnit();
1958 for (Pragma *p : std::as_const(output.pragmas)) {
1960 case Pragma::Singleton:
1961 createdUnit->flags |= Unit::IsSingleton;
1963 case Pragma::Strict:
1964 createdUnit->flags |= Unit::IsStrict;
1966 case Pragma::ComponentBehavior:
1968 switch (p->componentBehavior) {
1970 createdUnit->flags |= Unit::ComponentsBound;
1972 case Pragma::Unbound:
1977 case Pragma::ListPropertyAssignBehavior:
1978 switch (p->listPropertyAssignBehavior) {
1979 case Pragma::Replace:
1980 createdUnit->flags |= Unit::ListPropertyAssignReplace;
1982 case Pragma::ReplaceIfNotDefault:
1983 createdUnit->flags |= Unit::ListPropertyAssignReplaceIfNotDefault;
1985 case Pragma::Append:
1990 case Pragma::FunctionSignatureBehavior:
1991 switch (p->functionSignatureBehavior) {
1992 case Pragma::Enforced:
1994 case Pragma::Ignored:
1995 createdUnit->flags |= Unit::FunctionSignaturesIgnored;
1999 case Pragma::NativeMethodBehavior:
2000 switch (p->nativeMethodBehavior) {
2001 case Pragma::AcceptThisObject:
2002 createdUnit->flags |= Unit::NativeMethodsAcceptThisObject;
2004 case Pragma::RejectThisObject:
2009 case Pragma::ValueTypeBehavior:
2010 if (Pragma::ValueTypeBehaviorValues(p->valueTypeBehavior)
2011 .testFlag(Pragma::Copy)) {
2012 createdUnit->flags |= Unit::ValueTypesCopied;
2014 if (Pragma::ValueTypeBehaviorValues(p->valueTypeBehavior)
2015 .testFlag(Pragma::Addressable)) {
2016 createdUnit->flags |= Unit::ValueTypesAddressable;
2018 if (Pragma::ValueTypeBehaviorValues(p->valueTypeBehavior)
2019 .testFlag(Pragma::Assertable)) {
2020 createdUnit->flags |= Unit::ValueTypesAssertable;
2023 case Pragma::Translator:
2024 if (createdUnit->translationTableSize)
2025 if (quint32_le *index = createdUnit->translationContextIndex())
2026 *index = p->translationContextIndex;
2031 if (dependencyHasher) {
2032 const QByteArray checksum = dependencyHasher();
2033 if (checksum.size() ==
sizeof(createdUnit->dependencyMD5Checksum)) {
2034 memcpy(createdUnit->dependencyMD5Checksum, checksum.constData(),
2035 sizeof(createdUnit->dependencyMD5Checksum));
2039 createdUnit->sourceFileIndex = output.jsGenerator.stringTable.getStringId(output.jsModule.fileName);
2040 createdUnit->finalUrlIndex = output.jsGenerator.stringTable.getStringId(output.jsModule.finalUrl);
2044 output.jsGenerator.stringTable.freeze();
2046 const uint importSize = uint(
sizeof(QV4::CompiledData::Import)) * output.imports.size();
2047 const uint objectOffsetTableSize = output.objects.size() * uint(
sizeof(quint32));
2049 QHash<
const Object*, quint32> objectOffsets;
2051 const unsigned int objectOffset =
sizeof(QV4::CompiledData::QmlUnit) + importSize;
2052 uint nextOffset = objectOffset + objectOffsetTableSize;
2053 for (Object *o : std::as_const(output.objects)) {
2054 objectOffsets.insert(o, nextOffset);
2055 nextOffset += QV4::CompiledData::Object::calculateSizeExcludingSignalsAndEnums(o->functionCount(), o->propertyCount(), o->aliasCount(), o->enumCount(), o->signalCount(), o->bindingCount(), o->inlineComponentCount(), o->requiredPropertyExtraDataCount());
2057 int signalTableSize = 0;
2058 for (
const Signal *s = o->firstSignal(); s; s = s->next)
2059 signalTableSize += QV4::CompiledData::Signal::calculateSize(s->parameters->count);
2061 nextOffset += signalTableSize;
2063 int enumTableSize = 0;
2064 for (
const Enum *e = o->firstEnum(); e; e = e->next)
2065 enumTableSize += QV4::CompiledData::Enum::calculateSize(e->enumValues->count);
2067 nextOffset += enumTableSize;
2070 const uint totalSize = nextOffset;
2071 char *data = (
char*)malloc(totalSize);
2072 memset(data, 0, totalSize);
2073 QV4::CompiledData::QmlUnit *qmlUnit =
reinterpret_cast<QV4::CompiledData::QmlUnit *>(data);
2074 qmlUnit->offsetToImports =
sizeof(*qmlUnit);
2075 qmlUnit->nImports = output.imports.size();
2076 qmlUnit->offsetToObjects = objectOffset;
2077 qmlUnit->nObjects = output.objects.size();
2080 char *importPtr = data + qmlUnit->offsetToImports;
2081 for (
const QV4::CompiledData::Import *imp : std::as_const(output.imports)) {
2082 QV4::CompiledData::Import *importToWrite =
reinterpret_cast<QV4::CompiledData::Import*>(importPtr);
2083 *importToWrite = *imp;
2084 importPtr +=
sizeof(QV4::CompiledData::Import);
2088 quint32_le *objectTable =
reinterpret_cast<quint32_le*>(data + qmlUnit->offsetToObjects);
2089 for (
int i = 0; i < output.objects.size(); ++i) {
2090 const Object *o = output.objects.at(i);
2091 char *
const objectPtr = data + objectOffsets.value(o);
2092 *objectTable++ = objectOffsets.value(o);
2094 QV4::CompiledData::Object *objectToWrite =
reinterpret_cast<QV4::CompiledData::Object*>(objectPtr);
2095 objectToWrite->inheritedTypeNameIndex = o->inheritedTypeNameIndex;
2096 objectToWrite->indexOfDefaultPropertyOrAlias = o->indexOfDefaultPropertyOrAlias;
2097 objectToWrite->setHasAliasAsDefaultProperty(o->defaultPropertyIsAlias);
2098 objectToWrite->setFlags(QV4::CompiledData::Object::Flags(o->flags));
2099 objectToWrite->idNameIndex = o->idNameIndex;
2100 objectToWrite->location = o->location;
2101 objectToWrite->locationOfIdProperty = o->locationOfIdProperty;
2103 quint32 nextOffset =
sizeof(QV4::CompiledData::Object);
2105 objectToWrite->nFunctions = o->functionCount();
2106 objectToWrite->offsetToFunctions = nextOffset;
2107 nextOffset += objectToWrite->nFunctions *
sizeof(quint32);
2109 objectToWrite->nProperties = o->propertyCount();
2110 objectToWrite->offsetToProperties = nextOffset;
2111 nextOffset += objectToWrite->nProperties *
sizeof(QV4::CompiledData::Property);
2113 objectToWrite->nAliases = o->aliasCount();
2114 objectToWrite->offsetToAliases = nextOffset;
2115 nextOffset += objectToWrite->nAliases *
sizeof(QV4::CompiledData::Alias);
2117 objectToWrite->nEnums = o->enumCount();
2118 objectToWrite->offsetToEnums = nextOffset;
2119 nextOffset += objectToWrite->nEnums *
sizeof(quint32);
2121 objectToWrite->nSignals = o->signalCount();
2122 objectToWrite->offsetToSignals = nextOffset;
2123 nextOffset += objectToWrite->nSignals *
sizeof(quint32);
2125 objectToWrite->nBindings = o->bindingCount();
2126 objectToWrite->offsetToBindings = nextOffset;
2127 nextOffset += objectToWrite->nBindings *
sizeof(QV4::CompiledData::Binding);
2129 objectToWrite->nInlineComponents = o->inlineComponentCount();
2130 objectToWrite->offsetToInlineComponents = nextOffset;
2131 nextOffset += objectToWrite->nInlineComponents *
sizeof (QV4::CompiledData::InlineComponent);
2133 objectToWrite->nRequiredPropertyExtraData = o->requiredPropertyExtraDataCount();
2134 objectToWrite->offsetToRequiredPropertyExtraData = nextOffset;
2135 nextOffset += objectToWrite->nRequiredPropertyExtraData *
sizeof(QV4::CompiledData::RequiredPropertyExtraData);
2137 quint32_le *functionsTable =
reinterpret_cast<quint32_le *>(objectPtr + objectToWrite->offsetToFunctions);
2138 for (
const Function *f = o->firstFunction(); f; f = f->next)
2139 *functionsTable++ = o->runtimeFunctionIndices.at(f->index);
2141 char *propertiesPtr = objectPtr + objectToWrite->offsetToProperties;
2142 for (
const Property *p = o->firstProperty(); p; p = p->next) {
2143 QV4::CompiledData::Property *propertyToWrite =
reinterpret_cast<QV4::CompiledData::Property*>(propertiesPtr);
2144 *propertyToWrite = *p;
2145 propertiesPtr +=
sizeof(QV4::CompiledData::Property);
2148 char *aliasesPtr = objectPtr + objectToWrite->offsetToAliases;
2149 for (
const Alias *a = o->firstAlias(); a; a = a->next) {
2150 QV4::CompiledData::Alias *aliasToWrite =
reinterpret_cast<QV4::CompiledData::Alias*>(aliasesPtr);
2152 aliasesPtr +=
sizeof(QV4::CompiledData::Alias);
2155 char *bindingPtr = objectPtr + objectToWrite->offsetToBindings;
2156 bindingPtr = writeBindings(bindingPtr, o);
2157 Q_ASSERT((bindingPtr - objectToWrite->offsetToBindings - objectPtr) /
sizeof(QV4::CompiledData::Binding) ==
unsigned(o->bindingCount()));
2159 quint32_le *signalOffsetTable =
reinterpret_cast<quint32_le *>(objectPtr + objectToWrite->offsetToSignals);
2160 quint32 signalTableSize = 0;
2161 char *signalPtr = objectPtr + nextOffset;
2162 for (
const Signal *s = o->firstSignal(); s; s = s->next) {
2163 *signalOffsetTable++ = signalPtr - objectPtr;
2164 QV4::CompiledData::Signal *signalToWrite =
reinterpret_cast<QV4::CompiledData::Signal*>(signalPtr);
2166 signalToWrite->nameIndex = s->nameIndex;
2167 signalToWrite->location = s->location;
2168 signalToWrite->nParameters = s->parameters->count;
2170 QV4::CompiledData::Parameter *parameterToWrite =
reinterpret_cast<QV4::CompiledData::Parameter*>(signalPtr +
sizeof(*signalToWrite));
2171 for (Parameter *param = s->parameters->first; param; param = param->next, ++parameterToWrite)
2172 *parameterToWrite = *param;
2174 int size = QV4::CompiledData::Signal::calculateSize(s->parameters->count);
2175 signalTableSize += size;
2178 nextOffset += signalTableSize;
2180 quint32_le *enumOffsetTable =
reinterpret_cast<quint32_le*>(objectPtr + objectToWrite->offsetToEnums);
2181 char *enumPtr = objectPtr + nextOffset;
2182 for (
const Enum *e = o->firstEnum(); e; e = e->next) {
2183 *enumOffsetTable++ = enumPtr - objectPtr;
2184 QV4::CompiledData::Enum *enumToWrite =
reinterpret_cast<QV4::CompiledData::Enum*>(enumPtr);
2186 enumToWrite->nameIndex = e->nameIndex;
2187 enumToWrite->location = e->location;
2188 enumToWrite->nEnumValues = e->enumValues->count;
2190 QV4::CompiledData::EnumValue *enumValueToWrite =
reinterpret_cast<QV4::CompiledData::EnumValue*>(enumPtr +
sizeof(*enumToWrite));
2191 for (EnumValue *enumValue = e->enumValues->first; enumValue; enumValue = enumValue->next, ++enumValueToWrite)
2192 *enumValueToWrite = *enumValue;
2194 int size = QV4::CompiledData::Enum::calculateSize(e->enumValues->count);
2198 char *inlineComponentPtr = objectPtr + objectToWrite->offsetToInlineComponents;
2199 for (
auto it = o->inlineComponentsBegin(); it != o->inlineComponentsEnd(); ++it) {
2200 const InlineComponent *ic = it.ptr;
2201 QV4::CompiledData::InlineComponent *icToWrite =
reinterpret_cast<QV4::CompiledData::InlineComponent*>(inlineComponentPtr);
2203 inlineComponentPtr +=
sizeof(QV4::CompiledData::InlineComponent);
2206 char *requiredPropertyExtraDataPtr = objectPtr + objectToWrite->offsetToRequiredPropertyExtraData;
2207 for (
auto it = o->requiredPropertyExtraDataBegin(); it != o->requiredPropertyExtraDataEnd(); ++it) {
2208 const RequiredPropertyExtraData *extraData = it.ptr;
2209 QV4::CompiledData::RequiredPropertyExtraData *extraDataToWrite =
reinterpret_cast<QV4::CompiledData::RequiredPropertyExtraData*>(requiredPropertyExtraDataPtr);
2210 *extraDataToWrite = *extraData;
2211 requiredPropertyExtraDataPtr +=
sizeof(QV4::CompiledData::RequiredPropertyExtraData);
2215 if (!output.javaScriptCompilationUnit->unitData()) {
2217 jsUnit =
static_cast<QV4::CompiledData::Unit *>(realloc(jsUnit, jsUnit->unitSize + totalSize));
2218 jsUnit->offsetToQmlUnit = jsUnit->unitSize;
2219 jsUnit->unitSize += totalSize;
2220 memcpy(jsUnit->qmlUnit(), qmlUnit, totalSize);
2222 QV4::Compiler::JSUnitGenerator::generateUnitChecksum(jsUnit);
2223 qmlUnit = jsUnit->qmlUnit();
2226 static const bool showStats = qEnvironmentVariableIsSet(
"QML_SHOW_UNIT_STATS");
2228 qDebug() <<
"Generated QML unit that is" << totalSize <<
"bytes big contains:";
2229 qDebug() <<
" " << jsUnit->functionTableSize <<
"functions";
2230 qDebug() <<
" " << jsUnit->unitSize <<
"for JS unit";
2231 qDebug() <<
" " << importSize <<
"for imports";
2232 qDebug() <<
" " << nextOffset - objectOffset - objectOffsetTableSize <<
"for" << qmlUnit->nObjects <<
"objects";
2233 quint32 totalBindingCount = 0;
2234 for (quint32 i = 0; i < qmlUnit->nObjects; ++i)
2235 totalBindingCount += qmlUnit->objectAt(i)->nBindings;
2236 qDebug() <<
" " << totalBindingCount <<
"bindings";
2237 quint32 totalCodeSize = 0;
2238 for (quint32 i = 0; i < jsUnit->functionTableSize; ++i)
2239 totalCodeSize += jsUnit->functionAt(i)->codeSize;
2240 qDebug() <<
" " << totalCodeSize <<
"bytes total byte code";
2241 qDebug() <<
" " << jsUnit->stringTableSize <<
"strings";
2242 quint32 totalStringSize = 0;
2243 for (quint32 i = 0; i < jsUnit->stringTableSize; ++i)
2244 totalStringSize += QV4::CompiledData::String::calculateSize(jsUnit->stringAtInternal(i));
2245 qDebug() <<
" " << totalStringSize <<
"bytes total strings";
2248 output.javaScriptCompilationUnit->setUnitData(
2249 jsUnit, qmlUnit, output.jsModule.fileName, output.jsModule.finalUrl);