Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
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
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
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
167
169{
170 quint32 flags = 0;
171 if (regexp->flags & QQmlJS::Lexer::RegExp_Global)
173 if (regexp->flags & QQmlJS::Lexer::RegExp_IgnoreCase)
175 if (regexp->flags & QQmlJS::Lexer::RegExp_Multiline)
177 if (regexp->flags & QQmlJS::Lexer::RegExp_Unicode)
179 if (regexp->flags & QQmlJS::Lexer::RegExp_Sticky)
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)
436 function->flags |= CompiledData::Function::IsStrict;
437 if (irFunction->isArrowFunction)
439 if (irFunction->isGenerator)
440 function->flags |= CompiledData::Function::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
608 block->sizeOfLocalTemporalDeadZone = irBlock->sizeOfLocalTemporalDeadZone;
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 if (unit.translationTableSize != 0) {
686 constexpr auto spaceForTranslationContextId = sizeof(quint32_le);
687 nextOffset += spaceForTranslationContextId;
688 }
689
690 nextOffset = static_cast<quint32>(QtPrivate::roundUpToMultipleOf(8, nextOffset));
691
692 const auto reserveExportTable = [&nextOffset](int count, quint32_le *tableSizePtr, quint32_le *offsetPtr) {
693 *tableSizePtr = count;
694 *offsetPtr = nextOffset;
695 nextOffset += count * sizeof(CompiledData::ExportEntry);
696 nextOffset = static_cast<quint32>(QtPrivate::roundUpToMultipleOf(8, nextOffset));
697 };
698
699 reserveExportTable(module->localExportEntries.size(), &unit.localExportEntryTableSize, &unit.offsetToLocalExportEntryTable);
700 reserveExportTable(module->indirectExportEntries.size(), &unit.indirectExportEntryTableSize, &unit.offsetToIndirectExportEntryTable);
701 reserveExportTable(module->starExportEntries.size(), &unit.starExportEntryTableSize, &unit.offsetToStarExportEntryTable);
702
703 unit.importEntryTableSize = module->importEntries.size();
704 unit.offsetToImportEntryTable = nextOffset;
705 nextOffset += unit.importEntryTableSize * sizeof(CompiledData::ImportEntry);
706 nextOffset = static_cast<quint32>(QtPrivate::roundUpToMultipleOf(8, nextOffset));
707
708 unit.moduleRequestTableSize = module->moduleRequests.size();
709 unit.offsetToModuleRequestTable = nextOffset;
710 nextOffset += unit.moduleRequestTableSize * sizeof(uint);
711 nextOffset = static_cast<quint32>(QtPrivate::roundUpToMultipleOf(8, nextOffset));
712
713 quint32 functionSize = 0;
714 for (int i = 0; i < module->functions.size(); ++i) {
715 Context *f = module->functions.at(i);
716 blockAndFunctionOffsets[i] = nextOffset;
717
719 f->arguments.size(), f->locals.size(), f->lineAndStatementNumberMapping.size(),
720 f->nestedContexts.size(), int(f->labelInfo.size()), f->code.size());
721 functionSize += size - f->code.size();
722 nextOffset += size;
723 }
724
725 blockAndFunctionOffsets += module->functions.size();
726
727 for (int i = 0; i < module->classes.size(); ++i) {
728 const Class &c = module->classes.at(i);
729 blockAndFunctionOffsets[i] = nextOffset;
730
731 nextOffset += QV4::CompiledData::Class::calculateSize(c.staticMethods.size(), c.methods.size());
732 }
733 blockAndFunctionOffsets += module->classes.size();
734
735 for (int i = 0; i < module->templateObjects.size(); ++i) {
736 const TemplateObject &t = module->templateObjects.at(i);
737 blockAndFunctionOffsets[i] = nextOffset;
738
739 nextOffset += QV4::CompiledData::TemplateObject::calculateSize(t.strings.size());
740 }
741 blockAndFunctionOffsets += module->templateObjects.size();
742
743 for (int i = 0; i < module->blocks.size(); ++i) {
744 Context *c = module->blocks.at(i);
745 blockAndFunctionOffsets[i] = nextOffset;
746
747 nextOffset += QV4::CompiledData::Block::calculateSize(c->locals.size());
748 }
749
750 if (option == GenerateWithStringTable) {
751 unit.stringTableSize = stringTable.stringCount();
752 nextOffset = static_cast<quint32>(QtPrivate::roundUpToMultipleOf(8, nextOffset));
753 unit.offsetToStringTable = nextOffset;
754 nextOffset += stringTable.sizeOfTableAndData();
755 } else {
756 unit.stringTableSize = 0;
757 unit.offsetToStringTable = 0;
758 }
759 unit.indexOfRootFunction = -1;
760 unit.sourceFileIndex = getStringId(module->fileName);
761 unit.finalUrlIndex = getStringId(module->finalUrl);
762 unit.sourceTimeStamp = module->sourceTimeStamp.isValid() ? module->sourceTimeStamp.toMSecsSinceEpoch() : 0;
763 unit.offsetToQmlUnit = 0;
764
765 unit.unitSize = nextOffset;
766
767 static const bool showStats = qEnvironmentVariableIsSet("QML_SHOW_UNIT_STATS");
768 if (showStats) {
769 qDebug() << "Generated JS unit that is" << unit.unitSize << "bytes contains:";
770 qDebug() << " " << functionSize << "bytes for non-code function data for" << unit.functionTableSize << "functions";
771 qDebug() << " " << translations.size() * sizeof(CompiledData::TranslationData) << "bytes for" << translations.size() << "translations";
772 }
773
774 return unit;
775}
\inmodule QtCore
Definition qbytearray.h:57
\inmodule QtCore
\inmodule QtCore
Definition qhash.h:1145
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
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
qsizetype size() const noexcept
Returns the number of characters in this string.
Definition qstring.h:186
const QChar at(qsizetype i) const
Returns the character at the given index position in the string.
Definition qstring.h:1226
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_NO_KEYWORDS >
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 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
QLEInteger< quint32 > quint32_le
Definition qendian.h:396
QLEInteger< quint64 > quint64_le
Definition qendian.h:397
static quint32 checksum(const QByteArray &table)
#define qDebug
[1]
Definition qlogging.h:164
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
GLdouble s
[6]
Definition qopenglext.h:235
const GLubyte * c
GLuint entry
GLdouble GLdouble t
Definition qopenglext.h:243
GLuint GLenum option
GLenum GLenum GLsizei void * table
Members members(const Members &candidates, 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:50
ptrdiff_t qsizetype
Definition qtypes.h:165
unsigned int uint
Definition qtypes.h:34
unsigned short ushort
Definition qtypes.h:33
#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)
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]
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)