Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qv4compiler.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// Copyright (C) 2018 Intel Corporation.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#include <qv4compiler_p.h>
6#include <qv4codegen_p.h>
7#include <private/qv4compileddata_p.h>
8#include <private/qv4staticvalue_p.h>
9#include <private/qv4alloca_p.h>
10#include <private/qqmljslexer_p.h>
11#include <private/qqmljsast_p.h>
12#include <private/qml_compile_hash_p.h>
13#include <private/qqmlirbuilder_p.h>
14#include <QCryptographicHash>
15#include <QtEndian>
16
17// Efficient implementation that takes advantage of powers of two.
18
20namespace QtPrivate { // Disambiguate from WTF::roundUpToMultipleOf
21static inline size_t roundUpToMultipleOf(size_t divisor, size_t x)
22{
23 Q_ASSERT(divisor && !(divisor & (divisor - 1)));
24 const size_t remainderMask = divisor - 1;
25 return (x + remainderMask) & ~remainderMask;
26}
27}
29
31{
32 clear();
33}
34
36{
37 Q_ASSERT(!frozen);
39 if (it != stringToId.cend())
40 return *it;
41 stringToId.insert(str, strings.size());
42 strings.append(str);
44 return strings.size() - 1;
45}
46
48{
49 Q_ASSERT(stringToId.contains(string));
50 return stringToId.value(string);
51}
52
54{
55 strings.clear();
56 stringToId.clear();
57 stringDataSize = 0;
58 frozen = false;
59}
60
62{
63 clear();
64 for (uint i = 0; i < unit->stringTableSize; ++i)
65 registerString(unit->stringAtInternal(i));
66 backingUnitTableSize = unit->stringTableSize;
67 stringDataSize = 0;
68}
69
71{
72 char *dataStart = reinterpret_cast<char *>(unit);
73 quint32_le *stringTable = reinterpret_cast<quint32_le *>(dataStart + unit->offsetToStringTable);
74 char *stringData = reinterpret_cast<char *>(stringTable)
76 for (int i = backingUnitTableSize ; i < strings.size(); ++i) {
77 const int index = i - backingUnitTableSize;
78 stringTable[index] = stringData - dataStart;
79 const QString &qstr = strings.at(i);
80
82 Q_ASSERT(reinterpret_cast<uintptr_t>(s) % alignof(QV4::CompiledData::String) == 0);
83 Q_ASSERT(qstr.size() >= 0);
84 s->size = qstr.size();
85
86 ushort *uc = reinterpret_cast<ushort *>(reinterpret_cast<char *>(s) + sizeof(*s));
87 qToLittleEndian<ushort>(qstr.constData(), s->size, uc);
88 uc[s->size] = 0;
89
91 }
92}
93
95{
96#ifndef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
98
99 const int checksummableDataOffset
100 = offsetof(QV4::CompiledData::Unit, md5Checksum) + sizeof(unit->md5Checksum);
101
102 const char *dataPtr = reinterpret_cast<const char *>(unit) + checksummableDataOffset;
103 hash.addData({dataPtr, qsizetype(unit->unitSize - checksummableDataOffset)});
104
105 QByteArray checksum = hash.result();
106 Q_ASSERT(checksum.size() == sizeof(unit->md5Checksum));
107 memcpy(unit->md5Checksum, checksum.constData(), sizeof(unit->md5Checksum));
108#else
109 memset(unit->md5Checksum, 0, sizeof(unit->md5Checksum));
110#endif
111}
112
114 : module(module)
115{
116 // Make sure the empty string always gets index 0
118}
119
121{
122 return registerGetterLookup(registerString(name), mode);
123}
124
126{
130}
131
133{
134 lookups << CompiledData::Lookup(
136 return lookups.size() - 1;
137}
138
140{
141 return registerSetterLookup(registerString(name));
142}
143
145{
146 lookups << CompiledData::Lookup(
149 return lookups.size() - 1;
150}
151
153{
154 lookups << CompiledData::Lookup(
156 return lookups.size() - 1;
157}
158
160 int nameIndex, LookupMode mode)
161{
162 lookups << CompiledData::Lookup(
164 nameIndex);
165 return lookups.size() - 1;
166}
167
169{
170 quint32 flags = 0;
181
182 regexps.append(CompiledData::RegExp(flags, registerString(regexp->pattern.toString())));
183 return regexps.size() - 1;
184}
185
187{
188 int idx = constants.indexOf(v);
189 if (idx >= 0)
190 return idx;
191 constants.append(v);
192 return constants.size() - 1;
193}
194
196{
197 return constants.at(idx);
198}
199
200// The JSClass object and its members are stored contiguously in the jsClassData.
201// In order to get to the members you have to skip over the JSClass, therefore +1.
202static constexpr qsizetype jsClassMembersOffset = 1;
203
205{
206 // ### re-use existing class definitions.
207
209 jsClassOffsets.append(jsClassData.size());
210 const int oldSize = jsClassData.size();
211 jsClassData.resize(jsClassData.size() + size);
212 memset(jsClassData.data() + oldSize, 0, size);
213
214 CompiledData::JSClass *jsClass = reinterpret_cast<CompiledData::JSClass*>(jsClassData.data() + oldSize);
215 jsClass->nMembers = members.size();
217 = reinterpret_cast<CompiledData::JSClassMember*>(jsClass + jsClassMembersOffset);
218
219 for (const auto &name : members) {
220 member->set(registerString(name), false);
221 ++member;
222 }
223
224 return jsClassOffsets.size() - 1;
225}
226
228{
229 const CompiledData::JSClass *jsClass
230 = reinterpret_cast<const CompiledData::JSClass*>(
231 jsClassData.data() + jsClassOffsets[jsClassId]);
232 return jsClass->nMembers;
233}
234
236{
237 const CompiledData::JSClass *jsClass = reinterpret_cast<const CompiledData::JSClass*>(
238 jsClassData.data() + jsClassOffsets[jsClassId]);
239 Q_ASSERT(member >= 0);
240 Q_ASSERT(uint(member) < jsClass->nMembers);
242 = reinterpret_cast<const CompiledData::JSClassMember*>(jsClass + jsClassMembersOffset);
243 return stringForIndex(members[member].nameOffset());
244}
245
247{
248 translations.append(translation);
249 return translations.size() - 1;
250}
251
253{
254 const auto registerTypeStrings = [this](QQmlJS::AST::Type *type) {
255 if (!type)
256 return;
257
258 if (type->typeArgument) {
259 registerString(type->typeArgument->toString());
260 registerString(type->typeId->toString());
261 }
262 registerString(type->toString());
263 };
264
265 registerString(module->fileName);
266 registerString(module->finalUrl);
267 for (Context *f : std::as_const(module->functions)) {
268 registerString(f->name);
269 registerTypeStrings(f->returnType);
270 for (int i = 0; i < f->arguments.size(); ++i) {
271 registerString(f->arguments.at(i).id);
272 if (const QQmlJS::AST::TypeAnnotation *annotation
273 = f->arguments.at(i).typeAnnotation.data()) {
274 registerTypeStrings(annotation->type);
275 }
276 }
277 for (int i = 0; i < f->locals.size(); ++i)
278 registerString(f->locals.at(i));
279 }
280 for (Context *c : std::as_const(module->blocks)) {
281 for (int i = 0; i < c->locals.size(); ++i)
282 registerString(c->locals.at(i));
283 }
284 {
285 const auto registerExportEntry = [this](const Compiler::ExportEntry &entry) {
286 registerString(entry.exportName);
287 registerString(entry.moduleRequest);
288 registerString(entry.importName);
289 registerString(entry.localName);
290 };
291 std::for_each(module->localExportEntries.constBegin(), module->localExportEntries.constEnd(), registerExportEntry);
292 std::for_each(module->indirectExportEntries.constBegin(), module->indirectExportEntries.constEnd(), registerExportEntry);
293 std::for_each(module->starExportEntries.constBegin(), module->starExportEntries.constEnd(), registerExportEntry);
294 }
295 {
296 for (const auto &entry: module->importEntries) {
297 registerString(entry.moduleRequest);
298 registerString(entry.importName);
299 registerString(entry.localName);
300 }
301
302 for (const QString &request: module->moduleRequests)
303 registerString(request);
304 }
305
306 Q_ALLOCA_VAR(quint32_le, blockClassAndFunctionOffsets, (module->functions.size() + module->classes.size() + module->templateObjects.size() + module->blocks.size()) * sizeof(quint32_le));
307 uint jsClassDataOffset = 0;
308
309 char *dataPtr;
310 CompiledData::Unit *unit;
311 {
312 QV4::CompiledData::Unit tempHeader = generateHeader(option, blockClassAndFunctionOffsets, &jsClassDataOffset);
313 dataPtr = reinterpret_cast<char *>(malloc(tempHeader.unitSize));
314 memset(dataPtr, 0, tempHeader.unitSize);
315 memcpy(&unit, &dataPtr, sizeof(CompiledData::Unit*));
316 memcpy(unit, &tempHeader, sizeof(tempHeader));
317 }
318
319 memcpy(dataPtr + unit->offsetToFunctionTable, blockClassAndFunctionOffsets, unit->functionTableSize * sizeof(quint32_le));
320 memcpy(dataPtr + unit->offsetToClassTable, blockClassAndFunctionOffsets + unit->functionTableSize, unit->classTableSize * sizeof(quint32_le));
321 memcpy(dataPtr + unit->offsetToTemplateObjectTable, blockClassAndFunctionOffsets + unit->functionTableSize + unit->classTableSize, unit->templateObjectTableSize * sizeof(quint32_le));
322 memcpy(dataPtr + unit->offsetToBlockTable, blockClassAndFunctionOffsets + unit->functionTableSize + unit->classTableSize + unit->templateObjectTableSize, unit->blockTableSize * sizeof(quint32_le));
323
324 for (int i = 0; i < module->functions.size(); ++i) {
325 Context *function = module->functions.at(i);
326 if (function == module->rootContext)
327 unit->indexOfRootFunction = i;
328
329 writeFunction(dataPtr + blockClassAndFunctionOffsets[i], function);
330 }
331
332 for (int i = 0; i < module->classes.size(); ++i) {
333 const Class &c = module->classes.at(i);
334
335 writeClass(dataPtr + blockClassAndFunctionOffsets[i + module->functions.size()], c);
336 }
337
338 for (int i = 0; i < module->templateObjects.size(); ++i) {
339 const TemplateObject &t = module->templateObjects.at(i);
340
341 writeTemplateObject(dataPtr + blockClassAndFunctionOffsets[i + module->functions.size() + module->classes.size()], t);
342 }
343
344 for (int i = 0; i < module->blocks.size(); ++i) {
345 Context *block = module->blocks.at(i);
346
347 writeBlock(dataPtr + blockClassAndFunctionOffsets[i + module->classes.size() + module->templateObjects.size() + module->functions.size()], block);
348 }
349
350 CompiledData::Lookup *lookupsToWrite = reinterpret_cast<CompiledData::Lookup*>(dataPtr + unit->offsetToLookupTable);
351 for (const CompiledData::Lookup &l : std::as_const(lookups))
352 *lookupsToWrite++ = l;
353
354 CompiledData::RegExp *regexpTable = reinterpret_cast<CompiledData::RegExp *>(dataPtr + unit->offsetToRegexpTable);
355 if (regexps.size())
356 memcpy(regexpTable, regexps.constData(), regexps.size() * sizeof(*regexpTable));
357
358#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
359 ReturnedValue *constantTable = reinterpret_cast<ReturnedValue *>(dataPtr + unit->offsetToConstantTable);
360 if (constants.size())
361 memcpy(constantTable, constants.constData(), constants.size() * sizeof(ReturnedValue));
362#else
363 quint64_le *constantTable = reinterpret_cast<quint64_le *>(dataPtr + unit->offsetToConstantTable);
364 for (int i = 0; i < constants.count(); ++i)
365 constantTable[i] = constants.at(i);
366#endif
367
368 {
369 if (jsClassData.size())
370 memcpy(dataPtr + jsClassDataOffset, jsClassData.constData(), jsClassData.size());
371
372 // write js classes and js class lookup table
373 quint32_le *jsClassOffsetTable = reinterpret_cast<quint32_le *>(dataPtr + unit->offsetToJSClassTable);
374 for (int i = 0; i < jsClassOffsets.size(); ++i)
375 jsClassOffsetTable[i] = jsClassDataOffset + jsClassOffsets.at(i);
376 }
377
378 if (translations.size()) {
379 memcpy(dataPtr + unit->offsetToTranslationTable, translations.constData(), translations.size() * sizeof(CompiledData::TranslationData));
380 }
381
382 {
383 const auto populateExportEntryTable = [this, dataPtr](const QVector<Compiler::ExportEntry> &table, quint32_le offset) {
384 CompiledData::ExportEntry *entryToWrite = reinterpret_cast<CompiledData::ExportEntry *>(dataPtr + offset);
385 for (const Compiler::ExportEntry &entry: table) {
386 entryToWrite->exportName = getStringId(entry.exportName);
387 entryToWrite->moduleRequest = getStringId(entry.moduleRequest);
388 entryToWrite->importName = getStringId(entry.importName);
389 entryToWrite->localName = getStringId(entry.localName);
390 entryToWrite->location = entry.location;
391 entryToWrite++;
392 }
393 };
394 populateExportEntryTable(module->localExportEntries, unit->offsetToLocalExportEntryTable);
395 populateExportEntryTable(module->indirectExportEntries, unit->offsetToIndirectExportEntryTable);
396 populateExportEntryTable(module->starExportEntries, unit->offsetToStarExportEntryTable);
397 }
398
399 {
400 CompiledData::ImportEntry *entryToWrite = reinterpret_cast<CompiledData::ImportEntry *>(dataPtr + unit->offsetToImportEntryTable);
401 for (const Compiler::ImportEntry &entry: module->importEntries) {
402 entryToWrite->moduleRequest = getStringId(entry.moduleRequest);
403 entryToWrite->importName = getStringId(entry.importName);
404 entryToWrite->localName = getStringId(entry.localName);
405 entryToWrite->location = entry.location;
406 entryToWrite++;
407 }
408 }
409
410 {
411 quint32_le *moduleRequestEntryToWrite = reinterpret_cast<quint32_le *>(dataPtr + unit->offsetToModuleRequestTable);
412 for (const QString &moduleRequest: module->moduleRequests) {
413 *moduleRequestEntryToWrite = getStringId(moduleRequest);
414 moduleRequestEntryToWrite++;
415 }
416 }
417
418 // write strings and string table
419 if (option == GenerateWithStringTable)
420 stringTable.serialize(unit);
421
422 generateUnitChecksum(unit);
423
424 return unit;
425}
426
428{
430
431 quint32 currentOffset = static_cast<quint32>(QtPrivate::roundUpToMultipleOf(8, sizeof(*function)));
432
433 function->nameIndex = getStringId(irFunction->name);
434 function->flags = 0;
435 if (irFunction->isStrict)
437 if (irFunction->isArrowFunction)
439 if (irFunction->isGenerator)
441 if (irFunction->returnsClosure)
443
444 if (!irFunction->returnsClosure
445 || irFunction->innerFunctionAccessesThis
446 || irFunction->innerFunctionAccessesNewTarget) {
447 // If the inner function does things with this and new.target we need to do some work in
448 // the outer function. Then we shouldn't directly access the nested function.
449 function->nestedFunctionIndex = std::numeric_limits<uint32_t>::max();
450 } else {
451 // Otherwise we can directly use the nested function.
452 function->nestedFunctionIndex
453 = quint32(module->functions.indexOf(irFunction->nestedContexts.first()));
454 }
455
456 function->length = irFunction->formals ? irFunction->formals->length() : 0;
457 function->nFormals = irFunction->arguments.size();
458 function->formalsOffset = currentOffset;
459 currentOffset += function->nFormals * sizeof(CompiledData::Parameter);
460
461 const auto idGenerator = [this](const QString &str) { return getStringId(str); };
462
463 QmlIR::Parameter::initType(&function->returnType, idGenerator, irFunction->returnType);
464
465 function->sizeOfLocalTemporalDeadZone = irFunction->sizeOfLocalTemporalDeadZone;
466 function->sizeOfRegisterTemporalDeadZone = irFunction->sizeOfRegisterTemporalDeadZone;
467 function->firstTemporalDeadZoneRegister = irFunction->firstTemporalDeadZoneRegister;
468
469 function->nLocals = irFunction->locals.size();
470 function->localsOffset = currentOffset;
471 currentOffset += function->nLocals * sizeof(quint32);
472
473 function->nLineAndStatementNumbers
474 = irFunction->lineAndStatementNumberMapping.size();
475 Q_ASSERT(function->lineAndStatementNumberOffset() == currentOffset);
476 currentOffset += function->nLineAndStatementNumbers
478
479 function->nRegisters = irFunction->registerCountInFunction;
480
481 if (!irFunction->labelInfo.empty()) {
482 function->nLabelInfos = quint32(irFunction->labelInfo.size());
483 Q_ASSERT(function->labelInfosOffset() == currentOffset);
484 currentOffset += function->nLabelInfos * sizeof(quint32);
485 }
486
487 function->location.set(irFunction->line, irFunction->column);
488
489 function->codeOffset = currentOffset;
490 function->codeSize = irFunction->code.size();
491
492 // write formals
493 CompiledData::Parameter *formals = (CompiledData::Parameter *)(f + function->formalsOffset);
494 for (int i = 0; i < irFunction->arguments.size(); ++i) {
495 auto *formal = &formals[i];
496 formal->nameIndex = getStringId(irFunction->arguments.at(i).id);
497 if (QQmlJS::AST::TypeAnnotation *annotation = irFunction->arguments.at(i).typeAnnotation.data())
498 QmlIR::Parameter::initType(&formal->type, idGenerator, annotation->type);
499 }
500
501 // write locals
502 quint32_le *locals = (quint32_le *)(f + function->localsOffset);
503 for (int i = 0; i < irFunction->locals.size(); ++i)
504 locals[i] = getStringId(irFunction->locals.at(i));
505
506 // write line and statement numbers
507 memcpy(f + function->lineAndStatementNumberOffset(),
508 irFunction->lineAndStatementNumberMapping.constData(),
509 irFunction->lineAndStatementNumberMapping.size()
511
512 quint32_le *labels = (quint32_le *)(f + function->labelInfosOffset());
513 for (unsigned u : irFunction->labelInfo) {
514 *labels++ = u;
515 }
516
517 // write byte code
518 memcpy(f + function->codeOffset, irFunction->code.constData(), irFunction->code.size());
519}
520
521static_assert(int(QV4::Compiler::Class::Method::Regular) == int(QV4::CompiledData::Method::Regular), "Incompatible layout");
522static_assert(int(QV4::Compiler::Class::Method::Getter) == int(QV4::CompiledData::Method::Getter), "Incompatible layout");
523static_assert(int(QV4::Compiler::Class::Method::Setter) == int(QV4::CompiledData::Method::Setter), "Incompatible layout");
524
526{
527 QV4::CompiledData::Class *cls = reinterpret_cast<QV4::CompiledData::Class *>(b);
528
529 quint32 currentOffset = sizeof(QV4::CompiledData::Class);
530
531 QVector<Class::Method> allMethods = c.staticMethods;
532 allMethods += c.methods;
533
534 cls->constructorFunction = c.constructorIndex;
535 cls->nameIndex = c.nameIndex;
536 cls->nMethods = c.methods.size();
537 cls->nStaticMethods = c.staticMethods.size();
538 cls->methodTableOffset = currentOffset;
539 CompiledData::Method *method = reinterpret_cast<CompiledData::Method *>(b + currentOffset);
540
541 // write methods
542 for (int i = 0; i < allMethods.size(); ++i) {
543 method->name = allMethods.at(i).nameIndex;
544 method->type = allMethods.at(i).type;
545 method->function = allMethods.at(i).functionIndex;
546 ++method;
547 }
548
549 static const bool showCode = qEnvironmentVariableIsSet("QV4_SHOW_BYTECODE");
550 if (showCode) {
551 qDebug() << "=== Class" << stringForIndex(cls->nameIndex) << "static methods"
552 << cls->nStaticMethods << "methods" << cls->nMethods;
553 qDebug() << " constructor:" << cls->constructorFunction;
554 for (uint i = 0; i < cls->nStaticMethods + cls->nMethods; ++i) {
555 QDebug output = qDebug().nospace();
556 output << " " << i << ": ";
557 if (i < cls->nStaticMethods)
558 output << "static ";
559 switch (cls->methodTable()[i].type) {
561 output << "get "; break;
563 output << "set "; break;
564 default:
565 break;
566 }
567 output << stringForIndex(cls->methodTable()[i].name) << " "
568 << cls->methodTable()[i].function;
569 }
570 qDebug().space();
571 }
572}
573
575{
577 tmpl->size = t.strings.size();
578
579 quint32 currentOffset = sizeof(QV4::CompiledData::TemplateObject);
580
581 quint32_le *strings = reinterpret_cast<quint32_le *>(b + currentOffset);
582
583 // write methods
584 for (int i = 0; i < t.strings.size(); ++i)
585 strings[i] = t.strings.at(i);
586 strings += t.strings.size();
587
588 for (int i = 0; i < t.rawStrings.size(); ++i)
589 strings[i] = t.rawStrings.at(i);
590
591 static const bool showCode = qEnvironmentVariableIsSet("QV4_SHOW_BYTECODE");
592 if (showCode) {
593 qDebug() << "=== TemplateObject size" << tmpl->size;
594 for (uint i = 0; i < tmpl->size; ++i) {
595 qDebug() << " " << i << stringForIndex(tmpl->stringIndexAt(i));
596 qDebug() << " raw: " << stringForIndex(tmpl->rawStringIndexAt(i));
597 }
598 qDebug();
599 }
600}
601
603{
604 QV4::CompiledData::Block *block = reinterpret_cast<QV4::CompiledData::Block *>(b);
605
606 quint32 currentOffset = static_cast<quint32>(QtPrivate::roundUpToMultipleOf(8, sizeof(*block)));
607
609 block->nLocals = irBlock->locals.size();
610 block->localsOffset = currentOffset;
611 currentOffset += block->nLocals * sizeof(quint32);
612
613 // write locals
614 quint32_le *locals = (quint32_le *)(b + block->localsOffset);
615 for (int i = 0; i < irBlock->locals.size(); ++i)
616 locals[i] = getStringId(irBlock->locals.at(i));
617
618 static const bool showCode = qEnvironmentVariableIsSet("QV4_SHOW_BYTECODE");
619 if (showCode) {
620 qDebug() << "=== Variables for block" << irBlock->blockIndex;
621 for (int i = 0; i < irBlock->locals.size(); ++i)
622 qDebug() << " " << i << ":" << locals[i];
623 qDebug();
624 }
625}
626
627QV4::CompiledData::Unit QV4::Compiler::JSUnitGenerator::generateHeader(QV4::Compiler::JSUnitGenerator::GeneratorOption option, quint32_le *blockAndFunctionOffsets, uint *jsClassDataOffset)
628{
630 memset(&unit, 0, sizeof(unit));
631 memcpy(unit.magic, CompiledData::magic_str, sizeof(unit.magic));
633 unit.flags |= module->unitFlags;
635 unit.qtVersion = QT_VERSION;
636 qstrcpy(unit.libraryVersionHash, QML_COMPILE_HASH);
637 memset(unit.md5Checksum, 0, sizeof(unit.md5Checksum));
638 memset(unit.dependencyMD5Checksum, 0, sizeof(unit.dependencyMD5Checksum));
639
640 quint32 nextOffset = sizeof(CompiledData::Unit);
641
642 unit.functionTableSize = module->functions.size();
643 unit.offsetToFunctionTable = nextOffset;
644 nextOffset += unit.functionTableSize * sizeof(uint);
645
646 unit.classTableSize = module->classes.size();
647 unit.offsetToClassTable = nextOffset;
648 nextOffset += unit.classTableSize * sizeof(uint);
649
650 unit.templateObjectTableSize = module->templateObjects.size();
651 unit.offsetToTemplateObjectTable = nextOffset;
652 nextOffset += unit.templateObjectTableSize * sizeof(uint);
653
654 unit.blockTableSize = module->blocks.size();
655 unit.offsetToBlockTable = nextOffset;
656 nextOffset += unit.blockTableSize * sizeof(uint);
657
658 unit.lookupTableSize = lookups.size();
659 unit.offsetToLookupTable = nextOffset;
660 nextOffset += unit.lookupTableSize * sizeof(CompiledData::Lookup);
661
662 unit.regexpTableSize = regexps.size();
663 unit.offsetToRegexpTable = nextOffset;
664 nextOffset += unit.regexpTableSize * sizeof(CompiledData::RegExp);
665
666 unit.constantTableSize = constants.size();
667
668 // Ensure we load constants from well-aligned addresses into for example SSE registers.
669 nextOffset = static_cast<quint32>(QtPrivate::roundUpToMultipleOf(16, nextOffset));
670 unit.offsetToConstantTable = nextOffset;
671 nextOffset += unit.constantTableSize * sizeof(ReturnedValue);
672
673 unit.jsClassTableSize = jsClassOffsets.size();
674 unit.offsetToJSClassTable = nextOffset;
675 nextOffset += unit.jsClassTableSize * sizeof(uint);
676
677 *jsClassDataOffset = nextOffset;
678 nextOffset += jsClassData.size();
679
680 nextOffset = static_cast<quint32>(QtPrivate::roundUpToMultipleOf(8, nextOffset));
681
682 unit.translationTableSize = translations.size();
683 unit.offsetToTranslationTable = nextOffset;
684 nextOffset += unit.translationTableSize * sizeof(CompiledData::TranslationData);
685
686 nextOffset = static_cast<quint32>(QtPrivate::roundUpToMultipleOf(8, nextOffset));
687
688 const auto reserveExportTable = [&nextOffset](int count, quint32_le *tableSizePtr, quint32_le *offsetPtr) {
689 *tableSizePtr = count;
690 *offsetPtr = nextOffset;
691 nextOffset += count * sizeof(CompiledData::ExportEntry);
692 nextOffset = static_cast<quint32>(QtPrivate::roundUpToMultipleOf(8, nextOffset));
693 };
694
695 reserveExportTable(module->localExportEntries.size(), &unit.localExportEntryTableSize, &unit.offsetToLocalExportEntryTable);
696 reserveExportTable(module->indirectExportEntries.size(), &unit.indirectExportEntryTableSize, &unit.offsetToIndirectExportEntryTable);
697 reserveExportTable(module->starExportEntries.size(), &unit.starExportEntryTableSize, &unit.offsetToStarExportEntryTable);
698
699 unit.importEntryTableSize = module->importEntries.size();
700 unit.offsetToImportEntryTable = nextOffset;
701 nextOffset += unit.importEntryTableSize * sizeof(CompiledData::ImportEntry);
702 nextOffset = static_cast<quint32>(QtPrivate::roundUpToMultipleOf(8, nextOffset));
703
704 unit.moduleRequestTableSize = module->moduleRequests.size();
705 unit.offsetToModuleRequestTable = nextOffset;
706 nextOffset += unit.moduleRequestTableSize * sizeof(uint);
707 nextOffset = static_cast<quint32>(QtPrivate::roundUpToMultipleOf(8, nextOffset));
708
709 quint32 functionSize = 0;
710 for (int i = 0; i < module->functions.size(); ++i) {
711 Context *f = module->functions.at(i);
712 blockAndFunctionOffsets[i] = nextOffset;
713
715 f->arguments.size(), f->locals.size(), f->lineAndStatementNumberMapping.size(),
716 f->nestedContexts.size(), int(f->labelInfo.size()), f->code.size());
717 functionSize += size - f->code.size();
718 nextOffset += size;
719 }
720
721 blockAndFunctionOffsets += module->functions.size();
722
723 for (int i = 0; i < module->classes.size(); ++i) {
724 const Class &c = module->classes.at(i);
725 blockAndFunctionOffsets[i] = nextOffset;
726
727 nextOffset += QV4::CompiledData::Class::calculateSize(c.staticMethods.size(), c.methods.size());
728 }
729 blockAndFunctionOffsets += module->classes.size();
730
731 for (int i = 0; i < module->templateObjects.size(); ++i) {
732 const TemplateObject &t = module->templateObjects.at(i);
733 blockAndFunctionOffsets[i] = nextOffset;
734
735 nextOffset += QV4::CompiledData::TemplateObject::calculateSize(t.strings.size());
736 }
737 blockAndFunctionOffsets += module->templateObjects.size();
738
739 for (int i = 0; i < module->blocks.size(); ++i) {
740 Context *c = module->blocks.at(i);
741 blockAndFunctionOffsets[i] = nextOffset;
742
743 nextOffset += QV4::CompiledData::Block::calculateSize(c->locals.size());
744 }
745
746 if (option == GenerateWithStringTable) {
747 unit.stringTableSize = stringTable.stringCount();
748 nextOffset = static_cast<quint32>(QtPrivate::roundUpToMultipleOf(8, nextOffset));
749 unit.offsetToStringTable = nextOffset;
750 nextOffset += stringTable.sizeOfTableAndData();
751 } else {
752 unit.stringTableSize = 0;
753 unit.offsetToStringTable = 0;
754 }
755 unit.indexOfRootFunction = -1;
756 unit.sourceFileIndex = getStringId(module->fileName);
757 unit.finalUrlIndex = getStringId(module->finalUrl);
758 unit.sourceTimeStamp = module->sourceTimeStamp.isValid() ? module->sourceTimeStamp.toMSecsSinceEpoch() : 0;
759 unit.offsetToQmlUnit = 0;
760
761 unit.unitSize = nextOffset;
762
763 static const bool showStats = qEnvironmentVariableIsSet("QML_SHOW_UNIT_STATS");
764 if (showStats) {
765 qDebug() << "Generated JS unit that is" << unit.unitSize << "bytes contains:";
766 qDebug() << " " << functionSize << "bytes for non-code function data for" << unit.functionTableSize << "functions";
767 qDebug() << " " << translations.size() * sizeof(CompiledData::TranslationData) << "bytes for" << translations.size() << "translations";
768 }
769
770 return unit;
771}
\inmodule QtCore
Definition qbytearray.h:57
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
Definition qbytearray.h:474
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
Definition qbytearray.h:122
qsizetype size() const noexcept
Returns the size of this array.
\inmodule QtCore
\inmodule QtCore
Definition qhash.h:1135
Definition qlist.h:74
qsizetype size() const noexcept
Definition qlist.h:386
const_reference at(qsizetype i) const noexcept
Definition qlist.h:429
const_iterator cend() const noexcept
Definition qset.h:142
const_iterator constFind(const T &value) const
Definition qset.h:161
iterator insert(const T &value)
Definition qset.h:155
\inmodule QtCore
QString toString() const
Returns a deep copy of this string view's data as a QString.
Definition qstring.h:1014
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
const QChar * constData() const
Returns a pointer to the data stored in the QString.
Definition qstring.h:1101
qsizetype size() const
Returns the number of characters in this string.
Definition qstring.h:182
const QChar at(qsizetype i) const
Returns the character at the given index position in the string.
Definition qstring.h:1079
QHash< int, QWidget * > hash
[35multi]
QString str
[2]
b clear()
QSet< QString >::iterator it
Combined button and popup list for selecting options.
static const char magic_str[]
quint64 ReturnedValue
\macro QT_NAMESPACE
static size_t roundUpToMultipleOf(size_t divisor, size_t x)
Q_CORE_EXPORT char * qstrcpy(char *dst, const char *src)
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction function
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char * method
static quint32 checksum(const QByteArray &table)
#define qDebug
[1]
Definition qlogging.h:160
static QByteArray stringData(const QMetaObject *mo, int index)
GLboolean GLboolean GLboolean b
GLsizei const GLfloat * v
[13]
GLint GLint GLint GLint GLint x
[0]
GLenum mode
GLuint divisor
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint index
[2]
GLsizei const GLchar ** strings
[1]
GLenum GLenum GLsizei count
GLfloat GLfloat f
GLenum type
GLbitfield flags
GLenum GLuint GLintptr offset
GLuint name
const GLubyte * c
GLuint entry
GLdouble GLdouble t
Definition qopenglext.h:243
GLdouble s
[6]
Definition qopenglext.h:235
GLuint GLenum option
GLenum GLenum GLsizei void * table
QCborArray members(const QCborMap *classDef, QLatin1StringView key, QTypeRevision maxMajorVersion, Postprocess &&process)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
Q_CORE_EXPORT bool qEnvironmentVariableIsSet(const char *varName) noexcept
#define QT_VERSION
unsigned int quint32
Definition qtypes.h:45
ptrdiff_t qsizetype
Definition qtypes.h:70
unsigned int uint
Definition qtypes.h:29
unsigned short ushort
Definition qtypes.h:28
#define Q_ALLOCA_VAR(type, name, size)
Definition qv4alloca_p.h:36
#define QV4_DATA_STRUCTURE_VERSION
static constexpr qsizetype jsClassMembersOffset
static QV4::CompiledData::Lookup::Mode lookupMode(QV4::Compiler::JSUnitGenerator::LookupMode mode)
QT_BEGIN_NAMESPACE typedef uchar * output
QNetworkRequest request(url)
static int calculateSize(int nLocals)
static int calculateSize(int nStaticMethods, int nMethods)
const Method * methodTable() const
static int calculateSize(int nFormals, int nLocals, int nLinesAndStatements, int nInnerfunctions, int labelInfoSize, int codeSize)
void set(quint32 nameOffset, bool isAccessor)
static int calculateSize(int nMembers)
static int calculateSize(const QString &str)
quint32_le offsetToIndirectExportEntryTable
QString stringAtInternal(uint idx) const
char libraryVersionHash[QmlCompileHashSpace]
QQmlJS::AST::FormalParameterList * formals
QQmlJS::AST::BoundNames arguments
QVector< Context * > nestedContexts
QQmlJS::AST::Type * returnType
QVector< CompiledData::CodeOffsetToLineAndStatement > lineAndStatementNumberMapping
std::vector< unsigned > labelInfo
int registerJSClass(const QStringList &members)
QString jsClassMember(int jsClassId, int member) const
int registerGlobalGetterLookup(int nameIndex, LookupMode mode)
void writeTemplateObject(char *f, const TemplateObject &o)
static void generateUnitChecksum(CompiledData::Unit *unit)
ReturnedValue constant(int idx) const
int registerTranslation(const CompiledData::TranslationData &translation)
void writeBlock(char *f, Context *irBlock) const
void writeClass(char *f, const Class &c)
int registerRegExp(QQmlJS::AST::RegExpLiteral *regexp)
QV4::CompiledData::Unit * generateUnit(GeneratorOption option=GenerateWithStringTable)
int registerSetterLookup(const QString &name)
int registerQmlContextPropertyGetterLookup(int nameIndex, LookupMode mode)
void writeFunction(char *f, Context *irFunction) const
int jsClassSize(int jsClassId) const
int registerConstant(ReturnedValue v)
int registerGetterLookup(const QString &name, LookupMode mode)
int registerString(const QString &str)
int getStringId(const QString &string) const
int registerString(const QString &str)
void serialize(CompiledData::Unit *unit)
void initializeFromBackingUnit(const CompiledData::Unit *unit)
static bool initType(QV4::CompiledData::ParameterType *type, const IdGenerator &idGenerator, const QQmlJS::AST::Type *annotation)