251QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(GeneratorOption option)
253 const auto registerTypeStrings = [
this](QQmlJS::AST::Type *type) {
257 if (type->typeArgument) {
258 registerString(type->typeArgument->toString());
259 registerString(type->typeId->toString());
261 registerString(type->toString());
264 registerString(module->fileName);
265 registerString(module->finalUrl);
266 for (Context *f : std::as_const(module->functions)) {
267 registerString(f->name);
268 registerTypeStrings(f->returnType);
269 for (
int i = 0; i < f->arguments.size(); ++i) {
270 registerString(f->arguments.at(i).id);
271 if (
const QQmlJS::AST::TypeAnnotation *annotation
272 = f->arguments.at(i).typeAnnotation.data()) {
273 registerTypeStrings(annotation->type);
276 for (
int i = 0; i < f->locals.size(); ++i)
277 registerString(f->locals.at(i));
279 for (Context *c : std::as_const(module->blocks)) {
280 for (
int i = 0; i < c->locals.size(); ++i)
281 registerString(c->locals.at(i));
284 const auto registerExportEntry = [
this](
const Compiler::ExportEntry &entry) {
285 registerString(entry.exportName);
286 registerString(entry.moduleRequest);
287 registerString(entry.importName);
288 registerString(entry.localName);
290 std::for_each(module->localExportEntries.constBegin(), module->localExportEntries.constEnd(), registerExportEntry);
291 std::for_each(module->indirectExportEntries.constBegin(), module->indirectExportEntries.constEnd(), registerExportEntry);
292 std::for_each(module->starExportEntries.constBegin(), module->starExportEntries.constEnd(), registerExportEntry);
295 for (
const auto &entry: module->importEntries) {
296 registerString(entry.moduleRequest);
297 registerString(entry.importName);
298 registerString(entry.localName);
301 for (
const QString &request: module->moduleRequests)
302 registerString(request);
305 Q_ALLOCA_VAR(quint32_le, blockClassAndFunctionOffsets, (module->functions.size() + module->classes.size() + module->templateObjects.size() + module->blocks.size()) *
sizeof(quint32_le));
306 uint jsClassDataOffset = 0;
309 CompiledData::Unit *unit;
311 QV4::CompiledData::Unit tempHeader = generateHeader(option, blockClassAndFunctionOffsets, &jsClassDataOffset);
312 dataPtr =
reinterpret_cast<
char *>(malloc(tempHeader.unitSize));
313 memset(dataPtr, 0, tempHeader.unitSize);
314 memcpy(&unit, &dataPtr,
sizeof(CompiledData::Unit*));
315 memcpy(unit, &tempHeader,
sizeof(tempHeader));
318 memcpy(dataPtr + unit->offsetToFunctionTable, blockClassAndFunctionOffsets, unit->functionTableSize *
sizeof(quint32_le));
319 memcpy(dataPtr + unit->offsetToClassTable, blockClassAndFunctionOffsets + unit->functionTableSize, unit->classTableSize *
sizeof(quint32_le));
320 memcpy(dataPtr + unit->offsetToTemplateObjectTable, blockClassAndFunctionOffsets + unit->functionTableSize + unit->classTableSize, unit->templateObjectTableSize *
sizeof(quint32_le));
321 memcpy(dataPtr + unit->offsetToBlockTable, blockClassAndFunctionOffsets + unit->functionTableSize + unit->classTableSize + unit->templateObjectTableSize, unit->blockTableSize *
sizeof(quint32_le));
323 for (
int i = 0; i < module->functions.size(); ++i) {
324 Context *function = module->functions.at(i);
325 if (function == module->rootContext)
326 unit->indexOfRootFunction = i;
328 writeFunction(dataPtr + blockClassAndFunctionOffsets[i], function);
331 for (
int i = 0; i < module->classes.size(); ++i) {
332 const Class &c = module->classes.at(i);
334 writeClass(dataPtr + blockClassAndFunctionOffsets[i + module->functions.size()], c);
337 for (
int i = 0; i < module->templateObjects.size(); ++i) {
338 const TemplateObject &t = module->templateObjects.at(i);
340 writeTemplateObject(dataPtr + blockClassAndFunctionOffsets[i + module->functions.size() + module->classes.size()], t);
343 for (
int i = 0; i < module->blocks.size(); ++i) {
344 Context *block = module->blocks.at(i);
346 writeBlock(dataPtr + blockClassAndFunctionOffsets[i + module->classes.size() + module->templateObjects.size() + module->functions.size()], block);
349 CompiledData::Lookup *lookupsToWrite =
reinterpret_cast<CompiledData::Lookup*>(dataPtr + unit->offsetToLookupTable);
350 for (
const CompiledData::Lookup &l : std::as_const(lookups))
351 *lookupsToWrite++ = l;
353 CompiledData::RegExp *regexpTable =
reinterpret_cast<CompiledData::RegExp *>(dataPtr + unit->offsetToRegexpTable);
355 memcpy(regexpTable, regexps.constData(), regexps.size() *
sizeof(*regexpTable));
357#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
358 ReturnedValue *constantTable =
reinterpret_cast<ReturnedValue *>(dataPtr + unit->offsetToConstantTable);
359 if (constants.size())
360 memcpy(constantTable, constants.constData(), constants.size() *
sizeof(ReturnedValue));
362 quint64_le *constantTable =
reinterpret_cast<quint64_le *>(dataPtr + unit->offsetToConstantTable);
363 for (
int i = 0; i < constants.count(); ++i)
364 constantTable[i] = constants.at(i);
368 if (jsClassData.size())
369 memcpy(dataPtr + jsClassDataOffset, jsClassData.constData(), jsClassData.size());
372 quint32_le *jsClassOffsetTable =
reinterpret_cast<quint32_le *>(dataPtr + unit->offsetToJSClassTable);
373 for (
int i = 0; i < jsClassOffsets.size(); ++i)
374 jsClassOffsetTable[i] = jsClassDataOffset + jsClassOffsets.at(i);
377 if (translations.size()) {
378 memcpy(dataPtr + unit->offsetToTranslationTable, translations.constData(), translations.size() *
sizeof(CompiledData::TranslationData));
382 const auto populateExportEntryTable = [
this, dataPtr](
const QVector<Compiler::ExportEntry> &table, quint32_le offset) {
383 CompiledData::ExportEntry *entryToWrite =
reinterpret_cast<CompiledData::ExportEntry *>(dataPtr + offset);
384 for (
const Compiler::ExportEntry &entry: table) {
385 entryToWrite->exportName = getStringId(entry.exportName);
386 entryToWrite->moduleRequest = getStringId(entry.moduleRequest);
387 entryToWrite->importName = getStringId(entry.importName);
388 entryToWrite->localName = getStringId(entry.localName);
389 entryToWrite->location = entry.location;
393 populateExportEntryTable(module->localExportEntries, unit->offsetToLocalExportEntryTable);
394 populateExportEntryTable(module->indirectExportEntries, unit->offsetToIndirectExportEntryTable);
395 populateExportEntryTable(module->starExportEntries, unit->offsetToStarExportEntryTable);
399 CompiledData::ImportEntry *entryToWrite =
reinterpret_cast<CompiledData::ImportEntry *>(dataPtr + unit->offsetToImportEntryTable);
400 for (
const Compiler::ImportEntry &entry: module->importEntries) {
401 entryToWrite->moduleRequest = getStringId(entry.moduleRequest);
402 entryToWrite->importName = getStringId(entry.importName);
403 entryToWrite->localName = getStringId(entry.localName);
404 entryToWrite->location = entry.location;
410 quint32_le *moduleRequestEntryToWrite =
reinterpret_cast<quint32_le *>(dataPtr + unit->offsetToModuleRequestTable);
411 for (
const QString &moduleRequest: module->moduleRequests) {
412 *moduleRequestEntryToWrite = getStringId(moduleRequest);
413 moduleRequestEntryToWrite++;
418 if (option == GenerateWithStringTable)
419 stringTable.serialize(unit);
421 generateUnitChecksum(unit);
426void QV4::Compiler::JSUnitGenerator::writeFunction(
char *f, QV4::Compiler::Context *irFunction)
const
428 QV4::CompiledData::Function *function = (QV4::CompiledData::Function *)f;
430 quint32 currentOffset =
static_cast<quint32>(QtPrivate::roundUpToMultipleOf(8,
sizeof(*function)));
432 function->nameIndex = getStringId(irFunction->name);
434 if (irFunction->isStrict)
435 function->flags |= CompiledData::Function::IsStrict;
436 if (irFunction->isArrowFunction)
437 function->flags |= CompiledData::Function::IsArrowFunction;
438 if (irFunction->isGenerator)
439 function->flags |= CompiledData::Function::IsGenerator;
440 if (irFunction->returnsClosure)
441 function->flags |= CompiledData::Function::IsClosureWrapper;
443 if (!irFunction->returnsClosure
444 || (irFunction->usesArgumentsObject == Context::UsesArgumentsObject::Used)
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());
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;