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>
23 Q_ASSERT(divisor && !(divisor & (divisor - 1)));
24 const size_t remainderMask = divisor - 1;
25 return (x + remainderMask) & ~remainderMask;
30QV4::Compiler::StringTableGenerator::StringTableGenerator()
35int QV4::Compiler::StringTableGenerator::registerString(
const QString &str)
38 QHash<QString,
int>::ConstIterator it = stringToId.constFind(str);
39 if (it != stringToId.cend())
41 stringToId.insert(str, strings.size());
43 stringDataSize += QV4::CompiledData::String::calculateSize(str);
44 return strings.size() - 1;
47int QV4::Compiler::StringTableGenerator::getStringId(
const QString &string)
const
49 Q_ASSERT(stringToId.contains(string));
50 return stringToId.value(string);
53void QV4::Compiler::StringTableGenerator::clear()
61void QV4::Compiler::StringTableGenerator::initializeFromBackingUnit(
const QV4::CompiledData::Unit *unit)
64 for (uint i = 0; i < unit->stringTableSize; ++i)
65 registerString(unit->stringAtInternal(i));
66 backingUnitTableSize = unit->stringTableSize;
70void QV4::Compiler::StringTableGenerator::serialize(CompiledData::Unit *unit)
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)
75 + QtPrivate::roundUpToMultipleOf(8, unit->stringTableSize *
sizeof(uint));
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);
81 QV4::CompiledData::String *s =
reinterpret_cast<QV4::CompiledData::String *>(stringData);
82 Q_ASSERT(
reinterpret_cast<uintptr_t>(s) %
alignof(QV4::CompiledData::String) == 0);
83 Q_ASSERT(qstr.size() >= 0);
84 s->size = qstr.size();
86 ushort *uc =
reinterpret_cast<ushort *>(
reinterpret_cast<
char *>(s) +
sizeof(*s));
87 qToLittleEndian<ushort>(qstr.constData(), s->size, uc);
90 stringData += QV4::CompiledData::String::calculateSize(qstr);
94void QV4::Compiler::JSUnitGenerator::generateUnitChecksum(QV4::CompiledData::Unit *unit)
96#ifndef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
97 QCryptographicHash hash(QCryptographicHash::Md5);
99 const int checksummableDataOffset
100 = offsetof(QV4::CompiledData::Unit, md5Checksum) +
sizeof(unit->md5Checksum);
102 const char *dataPtr =
reinterpret_cast<
const char *>(unit) + checksummableDataOffset;
103 hash.addData({dataPtr, qsizetype(unit->unitSize - checksummableDataOffset)});
105 QByteArray checksum = hash.result();
106 Q_ASSERT(checksum.size() ==
sizeof(unit->md5Checksum));
107 memcpy(unit->md5Checksum, checksum.constData(),
sizeof(unit->md5Checksum));
109 memset(unit->md5Checksum, 0,
sizeof(unit->md5Checksum));
113QV4::Compiler::JSUnitGenerator::JSUnitGenerator(QV4::Compiler::Module *module)
117 registerString(QString());
120int QV4::Compiler::JSUnitGenerator::registerGetterLookup(
const QString &name, LookupMode mode)
122 return registerGetterLookup(registerString(name), mode);
127 return mode == QV4::Compiler::JSUnitGenerator::LookupForCall
128 ? QV4::CompiledData::Lookup::Mode_ForCall
129 : QV4::CompiledData::Lookup::Mode_ForStorage;
132int QV4::Compiler::JSUnitGenerator::registerGetterLookup(
int nameIndex, LookupMode mode)
134 lookups << CompiledData::Lookup(
135 CompiledData::Lookup::Type_Getter, lookupMode(mode), nameIndex);
136 return lookups.size() - 1;
139int QV4::Compiler::JSUnitGenerator::registerSetterLookup(
const QString &name)
141 return registerSetterLookup(registerString(name));
144int QV4::Compiler::JSUnitGenerator::registerSetterLookup(
int nameIndex)
146 lookups << CompiledData::Lookup(
147 CompiledData::Lookup::Type_Setter,
148 CompiledData::Lookup::Mode_ForStorage, nameIndex);
149 return lookups.size() - 1;
152int QV4::Compiler::JSUnitGenerator::registerGlobalGetterLookup(
int nameIndex, LookupMode mode)
154 lookups << CompiledData::Lookup(
155 CompiledData::Lookup::Type_GlobalGetter, lookupMode(mode), nameIndex);
156 return lookups.size() - 1;
159int QV4::Compiler::JSUnitGenerator::registerQmlContextPropertyGetterLookup(
160 int nameIndex, LookupMode mode)
162 lookups << CompiledData::Lookup(
163 CompiledData::Lookup::Type_QmlContextPropertyGetter, lookupMode(mode),
165 return lookups.size() - 1;
168int QV4::Compiler::JSUnitGenerator::registerRegExp(QQmlJS::AST::RegExpLiteral *regexp)
171 if (regexp->flags & QQmlJS::Lexer::RegExp_Global)
172 flags |= CompiledData::RegExp::RegExp_Global;
173 if (regexp->flags & QQmlJS::Lexer::RegExp_IgnoreCase)
174 flags |= CompiledData::RegExp::RegExp_IgnoreCase;
175 if (regexp->flags & QQmlJS::Lexer::RegExp_Multiline)
176 flags |= CompiledData::RegExp::RegExp_Multiline;
177 if (regexp->flags & QQmlJS::Lexer::RegExp_Unicode)
178 flags |= CompiledData::RegExp::RegExp_Unicode;
179 if (regexp->flags & QQmlJS::Lexer::RegExp_Sticky)
180 flags |= CompiledData::RegExp::RegExp_Sticky;
182 regexps.append(CompiledData::RegExp(flags, registerString(regexp->pattern.toString())));
183 return regexps.size() - 1;
186int QV4::Compiler::JSUnitGenerator::registerConstant(QV4::ReturnedValue v)
188 int idx = constants.indexOf(v);
192 return constants.size() - 1;
195QV4::ReturnedValue QV4::Compiler::JSUnitGenerator::constant(
int idx)
const
197 return constants.at(idx);
204int QV4::Compiler::JSUnitGenerator::registerJSClass(
const QStringList &members)
208 const int size = CompiledData::JSClass::calculateSize(members.size());
209 jsClassOffsets.append(jsClassData.size());
210 const int oldSize = jsClassData.size();
211 jsClassData.resize(jsClassData.size() + size);
212 memset(jsClassData.data() + oldSize, 0, size);
214 CompiledData::JSClass *jsClass =
reinterpret_cast<CompiledData::JSClass*>(jsClassData.data() + oldSize);
215 jsClass->nMembers = members.size();
216 CompiledData::JSClassMember *member
217 =
reinterpret_cast<CompiledData::JSClassMember*>(jsClass + jsClassMembersOffset);
219 for (
const auto &name : members) {
220 member->set(registerString(name),
false);
224 return jsClassOffsets.size() - 1;
227int QV4::Compiler::JSUnitGenerator::jsClassSize(
int jsClassId)
const
229 const CompiledData::JSClass *jsClass
230 =
reinterpret_cast<
const CompiledData::JSClass*>(
231 jsClassData.data() + jsClassOffsets[jsClassId]);
232 return jsClass->nMembers;
235QString QV4::Compiler::JSUnitGenerator::jsClassMember(
int jsClassId,
int member)
const
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);
241 const CompiledData::JSClassMember *members
242 =
reinterpret_cast<
const CompiledData::JSClassMember*>(jsClass + jsClassMembersOffset);
243 return stringForIndex(members[member].nameOffset());
246int QV4::Compiler::JSUnitGenerator::registerTranslation(
const QV4::CompiledData::TranslationData &translation)
248 translations.append(translation);
249 return translations.size() - 1;
252QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(GeneratorOption option)
254 const auto registerTypeStrings = [
this](QQmlJS::AST::Type *type) {
258 if (type->typeArgument) {
259 registerString(type->typeArgument->toString());
260 registerString(type->typeId->toString());
262 registerString(type->toString());
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);
277 for (
int i = 0; i < f->locals.size(); ++i)
278 registerString(f->locals.at(i));
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));
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);
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);
296 for (
const auto &entry: module->importEntries) {
297 registerString(entry.moduleRequest);
298 registerString(entry.importName);
299 registerString(entry.localName);
302 for (
const QString &request: module->moduleRequests)
303 registerString(request);
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;
310 CompiledData::Unit *unit;
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));
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));
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;
329 writeFunction(dataPtr + blockClassAndFunctionOffsets[i], function);
332 for (
int i = 0; i < module->classes.size(); ++i) {
333 const Class &c = module->classes.at(i);
335 writeClass(dataPtr + blockClassAndFunctionOffsets[i + module->functions.size()], c);
338 for (
int i = 0; i < module->templateObjects.size(); ++i) {
339 const TemplateObject &t = module->templateObjects.at(i);
341 writeTemplateObject(dataPtr + blockClassAndFunctionOffsets[i + module->functions.size() + module->classes.size()], t);
344 for (
int i = 0; i < module->blocks.size(); ++i) {
345 Context *block = module->blocks.at(i);
347 writeBlock(dataPtr + blockClassAndFunctionOffsets[i + module->classes.size() + module->templateObjects.size() + module->functions.size()], block);
350 CompiledData::Lookup *lookupsToWrite =
reinterpret_cast<CompiledData::Lookup*>(dataPtr + unit->offsetToLookupTable);
351 for (
const CompiledData::Lookup &l : std::as_const(lookups))
352 *lookupsToWrite++ = l;
354 CompiledData::RegExp *regexpTable =
reinterpret_cast<CompiledData::RegExp *>(dataPtr + unit->offsetToRegexpTable);
356 memcpy(regexpTable, regexps.constData(), regexps.size() *
sizeof(*regexpTable));
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));
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);
369 if (jsClassData.size())
370 memcpy(dataPtr + jsClassDataOffset, jsClassData.constData(), jsClassData.size());
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);
378 if (translations.size()) {
379 memcpy(dataPtr + unit->offsetToTranslationTable, translations.constData(), translations.size() *
sizeof(CompiledData::TranslationData));
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;
394 populateExportEntryTable(module->localExportEntries, unit->offsetToLocalExportEntryTable);
395 populateExportEntryTable(module->indirectExportEntries, unit->offsetToIndirectExportEntryTable);
396 populateExportEntryTable(module->starExportEntries, unit->offsetToStarExportEntryTable);
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;
411 quint32_le *moduleRequestEntryToWrite =
reinterpret_cast<quint32_le *>(dataPtr + unit->offsetToModuleRequestTable);
412 for (
const QString &moduleRequest: module->moduleRequests) {
413 *moduleRequestEntryToWrite = getStringId(moduleRequest);
414 moduleRequestEntryToWrite++;
419 if (option == GenerateWithStringTable)
420 stringTable.serialize(unit);
422 generateUnitChecksum(unit);
427void QV4::Compiler::JSUnitGenerator::writeFunction(
char *f, QV4::Compiler::Context *irFunction)
const
429 QV4::CompiledData::Function *function = (QV4::CompiledData::Function *)f;
431 quint32 currentOffset =
static_cast<quint32>(QtPrivate::roundUpToMultipleOf(8,
sizeof(*function)));
433 function->nameIndex = getStringId(irFunction->name);
435 if (irFunction->isStrict)
436 function->flags |= CompiledData::Function::IsStrict;
437 if (irFunction->isArrowFunction)
438 function->flags |= CompiledData::Function::IsArrowFunction;
439 if (irFunction->isGenerator)
440 function->flags |= CompiledData::Function::IsGenerator;
441 if (irFunction->returnsClosure)
442 function->flags |= CompiledData::Function::IsClosureWrapper;
444 if (!irFunction->returnsClosure
445 || irFunction->innerFunctionAccessesThis
446 || irFunction->innerFunctionAccessesNewTarget) {
449 function->nestedFunctionIndex = std::numeric_limits<uint32_t>::max();
452 function->nestedFunctionIndex
453 = quint32(module->functions.indexOf(irFunction->nestedContexts.first()));
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);
461 const auto idGenerator = [
this](
const QString &str) {
return getStringId(str); };
463 QmlIR::Parameter::initType(&function->returnType, idGenerator, irFunction->returnType);
465 function->sizeOfLocalTemporalDeadZone = irFunction->sizeOfLocalTemporalDeadZone;
466 function->sizeOfRegisterTemporalDeadZone = irFunction->sizeOfRegisterTemporalDeadZone;
467 function->firstTemporalDeadZoneRegister = irFunction->firstTemporalDeadZoneRegister;
469 function->nLocals = irFunction->locals.size();
470 function->localsOffset = currentOffset;
471 currentOffset += function->nLocals *
sizeof(quint32);
473 function->nLineAndStatementNumbers
474 = irFunction->lineAndStatementNumberMapping.size();
475 Q_ASSERT(function->lineAndStatementNumberOffset() == currentOffset);
476 currentOffset += function->nLineAndStatementNumbers
477 *
sizeof(CompiledData::CodeOffsetToLineAndStatement);
479 function->nRegisters = irFunction->registerCountInFunction;
481 if (!irFunction->labelInfo.empty()) {
482 function->nLabelInfos = quint32(irFunction->labelInfo.size());
483 Q_ASSERT(function->labelInfosOffset() == currentOffset);
484 currentOffset += function->nLabelInfos *
sizeof(quint32);
487 function->location.set(irFunction->line, irFunction->column);
489 function->codeOffset = currentOffset;
490 function->codeSize = irFunction->code.size();
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);
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));
507 memcpy(f + function->lineAndStatementNumberOffset(),
508 irFunction->lineAndStatementNumberMapping.constData(),
509 irFunction->lineAndStatementNumberMapping.size()
510 *
sizeof(CompiledData::CodeOffsetToLineAndStatement));
512 quint32_le *labels = (quint32_le *)(f + function->labelInfosOffset());
513 for (
unsigned u : irFunction->labelInfo) {
518 memcpy(f + function->codeOffset, irFunction->code.constData(), irFunction->code.size());
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");
525void QV4::Compiler::JSUnitGenerator::writeClass(
char *b,
const QV4::Compiler::Class &c)
527 QV4::CompiledData::Class *cls =
reinterpret_cast<QV4::CompiledData::Class *>(b);
529 quint32 currentOffset =
sizeof(QV4::CompiledData::Class);
531 QVector<Class::Method> allMethods = c.staticMethods;
532 allMethods += c.methods;
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);
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;
549 static const bool showCode = qEnvironmentVariableIsSet(
"QV4_SHOW_BYTECODE");
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)
559 switch (cls->methodTable()[i].type) {
560 case CompiledData::Method::Getter:
561 output <<
"get ";
break;
562 case CompiledData::Method::Setter:
563 output <<
"set ";
break;
567 output << stringForIndex(cls->methodTable()[i].name) <<
" "
568 << cls->methodTable()[i].function;
574void QV4::Compiler::JSUnitGenerator::writeTemplateObject(
char *b,
const QV4::Compiler::TemplateObject &t)
576 QV4::CompiledData::TemplateObject *tmpl =
reinterpret_cast<QV4::CompiledData::TemplateObject *>(b);
577 tmpl->size = t.strings.size();
579 quint32 currentOffset =
sizeof(QV4::CompiledData::TemplateObject);
581 quint32_le *strings =
reinterpret_cast<quint32_le *>(b + currentOffset);
584 for (
int i = 0; i < t.strings.size(); ++i)
585 strings[i] = t.strings.at(i);
586 strings += t.strings.size();
588 for (
int i = 0; i < t.rawStrings.size(); ++i)
589 strings[i] = t.rawStrings.at(i);
591 static const bool showCode = qEnvironmentVariableIsSet(
"QV4_SHOW_BYTECODE");
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));
602void QV4::Compiler::JSUnitGenerator::writeBlock(
char *b, QV4::Compiler::Context *irBlock)
const
604 QV4::CompiledData::Block *block =
reinterpret_cast<QV4::CompiledData::Block *>(b);
606 quint32 currentOffset =
static_cast<quint32>(QtPrivate::roundUpToMultipleOf(8,
sizeof(*block)));
608 block->sizeOfLocalTemporalDeadZone = irBlock->sizeOfLocalTemporalDeadZone;
609 block->nLocals = irBlock->locals.size();
610 block->localsOffset = currentOffset;
611 currentOffset += block->nLocals *
sizeof(quint32);
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));
618 static const bool showCode = qEnvironmentVariableIsSet(
"QV4_SHOW_BYTECODE");
620 qDebug() <<
"=== Variables for block" << irBlock->blockIndex;
621 for (
int i = 0; i < irBlock->locals.size(); ++i)
622 qDebug() <<
" " << i <<
":" << locals[i];
627QV4::CompiledData::Unit QV4::Compiler::JSUnitGenerator::generateHeader(QV4::Compiler::JSUnitGenerator::GeneratorOption option, quint32_le *blockAndFunctionOffsets, uint *jsClassDataOffset)
629 CompiledData::Unit unit;
630 memset(&unit, 0,
sizeof(unit));
631 memcpy(unit.magic, CompiledData::magic_str,
sizeof(unit.magic));
632 unit.flags = QV4::CompiledData::Unit::IsJavascript;
633 unit.flags |= module->unitFlags;
634 unit.version = QV4_DATA_STRUCTURE_VERSION;
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));
640 quint32 nextOffset =
sizeof(CompiledData::Unit);
642 unit.functionTableSize = module->functions.size();
643 unit.offsetToFunctionTable = nextOffset;
644 nextOffset += unit.functionTableSize *
sizeof(uint);
646 unit.classTableSize = module->classes.size();
647 unit.offsetToClassTable = nextOffset;
648 nextOffset += unit.classTableSize *
sizeof(uint);
650 unit.templateObjectTableSize = module->templateObjects.size();
651 unit.offsetToTemplateObjectTable = nextOffset;
652 nextOffset += unit.templateObjectTableSize *
sizeof(uint);
654 unit.blockTableSize = module->blocks.size();
655 unit.offsetToBlockTable = nextOffset;
656 nextOffset += unit.blockTableSize *
sizeof(uint);
658 unit.lookupTableSize = lookups.size();
659 unit.offsetToLookupTable = nextOffset;
660 nextOffset += unit.lookupTableSize *
sizeof(CompiledData::Lookup);
662 unit.regexpTableSize = regexps.size();
663 unit.offsetToRegexpTable = nextOffset;
664 nextOffset += unit.regexpTableSize *
sizeof(CompiledData::RegExp);
666 unit.constantTableSize = constants.size();
669 nextOffset =
static_cast<quint32>(QtPrivate::roundUpToMultipleOf(16, nextOffset));
670 unit.offsetToConstantTable = nextOffset;
671 nextOffset += unit.constantTableSize *
sizeof(ReturnedValue);
673 unit.jsClassTableSize = jsClassOffsets.size();
674 unit.offsetToJSClassTable = nextOffset;
675 nextOffset += unit.jsClassTableSize *
sizeof(uint);
677 *jsClassDataOffset = nextOffset;
678 nextOffset += jsClassData.size();
680 nextOffset =
static_cast<quint32>(QtPrivate::roundUpToMultipleOf(8, nextOffset));
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;
690 nextOffset =
static_cast<quint32>(QtPrivate::roundUpToMultipleOf(8, nextOffset));
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));
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);
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));
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));
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;
718 quint32 size = QV4::CompiledData::Function::calculateSize(
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();
725 blockAndFunctionOffsets += module->functions.size();
727 for (
int i = 0; i < module->classes.size(); ++i) {
728 const Class &c = module->classes.at(i);
729 blockAndFunctionOffsets[i] = nextOffset;
731 nextOffset += QV4::CompiledData::Class::calculateSize(c.staticMethods.size(), c.methods.size());
733 blockAndFunctionOffsets += module->classes.size();
735 for (
int i = 0; i < module->templateObjects.size(); ++i) {
736 const TemplateObject &t = module->templateObjects.at(i);
737 blockAndFunctionOffsets[i] = nextOffset;
739 nextOffset += QV4::CompiledData::TemplateObject::calculateSize(t.strings.size());
741 blockAndFunctionOffsets += module->templateObjects.size();
743 for (
int i = 0; i < module->blocks.size(); ++i) {
744 Context *c = module->blocks.at(i);
745 blockAndFunctionOffsets[i] = nextOffset;
747 nextOffset += QV4::CompiledData::Block::calculateSize(c->locals.size());
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();
756 unit.stringTableSize = 0;
757 unit.offsetToStringTable = 0;
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;
765 unit.unitSize = nextOffset;
767 static const bool showStats = qEnvironmentVariableIsSet(
"QML_SHOW_UNIT_STATS");
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";
Combined button and popup list for selecting options.
static size_t roundUpToMultipleOf(size_t divisor, size_t x)
static constexpr qsizetype jsClassMembersOffset
static QV4::CompiledData::Lookup::Mode lookupMode(QV4::Compiler::JSUnitGenerator::LookupMode mode)