252QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(GeneratorOption option)
255 const auto registerTypeStrings = [
this](QQmlJS::AST::Type *type) {
259 if (type->typeArgument) {
260 registerString(type->typeArgument->toString());
261 registerString(type->typeId->toString());
263 registerString(type->toString());
266 registerString(module->fileName);
267 registerString(module->finalUrl);
268 for (Context *f : std::as_const(module->functions)) {
269 registerString(f->name);
270 registerTypeStrings(f->returnType);
271 for (
int i = 0; i < f->arguments.size(); ++i) {
272 registerString(f->arguments.at(i).id);
273 if (
const QQmlJS::AST::TypeAnnotation *annotation
274 = f->arguments.at(i).typeAnnotation.data()) {
275 registerTypeStrings(annotation->type);
278 for (
int i = 0; i < f->locals.size(); ++i)
279 registerString(f->locals.at(i));
281 for (Context *c : std::as_const(module->blocks)) {
282 for (
int i = 0; i < c->locals.size(); ++i)
283 registerString(c->locals.at(i));
286 const auto registerExportEntry = [
this](
const Compiler::ExportEntry &entry) {
287 registerString(entry.exportName);
288 registerString(entry.moduleRequest);
289 registerString(entry.importName);
290 registerString(entry.localName);
292 std::for_each(module->localExportEntries.constBegin(), module->localExportEntries.constEnd(), registerExportEntry);
293 std::for_each(module->indirectExportEntries.constBegin(), module->indirectExportEntries.constEnd(), registerExportEntry);
294 std::for_each(module->starExportEntries.constBegin(), module->starExportEntries.constEnd(), registerExportEntry);
297 for (
const auto &entry: std::as_const(module->importEntries)) {
298 registerString(entry.moduleRequest);
299 registerString(entry.importName);
300 registerString(entry.localName);
303 for (
const QString &request: std::as_const(module->moduleRequests))
304 registerString(request);
307 Q_ALLOCA_VAR(quint32_le, blockClassAndFunctionOffsets, (module->functions.size() + module->classes.size() + module->templateObjects.size() + module->blocks.size()) *
sizeof(quint32_le));
308 uint jsClassDataOffset = 0;
311 CompiledData::Unit *unit;
313 QV4::CompiledData::Unit tempHeader = generateHeader(option, blockClassAndFunctionOffsets, &jsClassDataOffset);
314 dataPtr =
reinterpret_cast<
char *>(malloc(tempHeader.unitSize));
315 memset(dataPtr, 0, tempHeader.unitSize);
316 memcpy(&unit, &dataPtr,
sizeof(CompiledData::Unit*));
317 memcpy(unit, &tempHeader,
sizeof(tempHeader));
320 memcpy(dataPtr + unit->offsetToFunctionTable, blockClassAndFunctionOffsets, unit->functionTableSize *
sizeof(quint32_le));
321 memcpy(dataPtr + unit->offsetToClassTable, blockClassAndFunctionOffsets + unit->functionTableSize, unit->classTableSize *
sizeof(quint32_le));
322 memcpy(dataPtr + unit->offsetToTemplateObjectTable, blockClassAndFunctionOffsets + unit->functionTableSize + unit->classTableSize, unit->templateObjectTableSize *
sizeof(quint32_le));
323 memcpy(dataPtr + unit->offsetToBlockTable, blockClassAndFunctionOffsets + unit->functionTableSize + unit->classTableSize + unit->templateObjectTableSize, unit->blockTableSize *
sizeof(quint32_le));
325 for (
int i = 0; i < module->functions.size(); ++i) {
326 Context *function = module->functions.at(i);
327 if (function == module->rootContext)
328 unit->indexOfRootFunction = i;
330 writeFunction(dataPtr + blockClassAndFunctionOffsets[i], function);
333 for (
int i = 0; i < module->classes.size(); ++i) {
334 const Class &c = module->classes.at(i);
336 writeClass(dataPtr + blockClassAndFunctionOffsets[i + module->functions.size()], c);
339 for (
int i = 0; i < module->templateObjects.size(); ++i) {
340 const TemplateObject &t = module->templateObjects.at(i);
342 writeTemplateObject(dataPtr + blockClassAndFunctionOffsets[i + module->functions.size() + module->classes.size()], t);
345 for (
int i = 0; i < module->blocks.size(); ++i) {
346 Context *block = module->blocks.at(i);
348 writeBlock(dataPtr + blockClassAndFunctionOffsets[i + module->classes.size() + module->templateObjects.size() + module->functions.size()], block);
351 CompiledData::Lookup *lookupsToWrite =
reinterpret_cast<CompiledData::Lookup*>(dataPtr + unit->offsetToLookupTable);
352 for (
const CompiledData::Lookup &l : std::as_const(lookups))
353 *lookupsToWrite++ = l;
355 CompiledData::RegExp *regexpTable =
reinterpret_cast<CompiledData::RegExp *>(dataPtr + unit->offsetToRegexpTable);
357 memcpy(regexpTable, regexps.constData(), regexps.size() *
sizeof(*regexpTable));
359#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
360 ReturnedValue *constantTable =
reinterpret_cast<ReturnedValue *>(dataPtr + unit->offsetToConstantTable);
361 if (constants.size())
362 memcpy(constantTable, constants.constData(), constants.size() *
sizeof(ReturnedValue));
364 quint64_le *constantTable =
reinterpret_cast<quint64_le *>(dataPtr + unit->offsetToConstantTable);
365 for (
int i = 0; i < constants.count(); ++i)
366 constantTable[i] = constants.at(i);
370 if (jsClassData.size())
371 memcpy(dataPtr + jsClassDataOffset, jsClassData.constData(), jsClassData.size());
374 quint32_le *jsClassOffsetTable =
reinterpret_cast<quint32_le *>(dataPtr + unit->offsetToJSClassTable);
375 for (
int i = 0; i < jsClassOffsets.size(); ++i)
376 jsClassOffsetTable[i] = jsClassDataOffset + jsClassOffsets.at(i);
379 if (translations.size()) {
380 memcpy(dataPtr + unit->offsetToTranslationTable, translations.constData(), translations.size() *
sizeof(CompiledData::TranslationData));
384 const auto populateExportEntryTable = [
this, dataPtr](
const QList<Compiler::ExportEntry> &table, quint32_le offset) {
385 CompiledData::ExportEntry *entryToWrite =
reinterpret_cast<CompiledData::ExportEntry *>(dataPtr + offset);
386 for (
const Compiler::ExportEntry &entry: table) {
387 entryToWrite->exportName = getStringId(entry.exportName);
388 entryToWrite->moduleRequest = getStringId(entry.moduleRequest);
389 entryToWrite->importName = getStringId(entry.importName);
390 entryToWrite->localName = getStringId(entry.localName);
391 entryToWrite->location = entry.location;
395 populateExportEntryTable(module->localExportEntries, unit->offsetToLocalExportEntryTable);
396 populateExportEntryTable(module->indirectExportEntries, unit->offsetToIndirectExportEntryTable);
397 populateExportEntryTable(module->starExportEntries, unit->offsetToStarExportEntryTable);
401 CompiledData::ImportEntry *entryToWrite =
reinterpret_cast<CompiledData::ImportEntry *>(dataPtr + unit->offsetToImportEntryTable);
402 for (
const Compiler::ImportEntry &entry: std::as_const(module->importEntries)) {
403 entryToWrite->moduleRequest = getStringId(entry.moduleRequest);
404 entryToWrite->importName = getStringId(entry.importName);
405 entryToWrite->localName = getStringId(entry.localName);
406 entryToWrite->location = entry.location;
412 quint32_le *moduleRequestEntryToWrite =
reinterpret_cast<quint32_le *>(dataPtr + unit->offsetToModuleRequestTable);
413 for (
const QString &moduleRequest: std::as_const(module->moduleRequests)) {
414 *moduleRequestEntryToWrite = getStringId(moduleRequest);
415 moduleRequestEntryToWrite++;
420 if (option == GenerateWithStringTable)
421 stringTable.serialize(unit);
423 generateUnitChecksum(unit);
428void QV4::Compiler::JSUnitGenerator::writeFunction(
char *f, QV4::Compiler::Context *irFunction)
const
430 QV4::CompiledData::Function *function = (QV4::CompiledData::Function *)f;
432 quint32 currentOffset =
static_cast<quint32>(QtPrivate::roundUpToMultipleOf(8,
sizeof(*function)));
434 function->nameIndex = getStringId(irFunction->name);
436 if (irFunction->isStrict)
437 function->flags |= CompiledData::Function::IsStrict;
438 if (irFunction->isArrowFunction)
439 function->flags |= CompiledData::Function::IsArrowFunction;
440 if (irFunction->isGenerator)
441 function->flags |= CompiledData::Function::IsGenerator;
442 if (irFunction->returnsClosure)
443 function->flags |= CompiledData::Function::IsClosureWrapper;
445 if (!irFunction->returnsClosure
446 || (irFunction->usesArgumentsObject == Context::UsesArgumentsObject::Used)
447 || irFunction->innerFunctionAccessesThis
448 || irFunction->innerFunctionAccessesNewTarget) {
451 function->nestedFunctionIndex = std::numeric_limits<uint32_t>::max();
454 function->nestedFunctionIndex
455 = quint32(module->functions.indexOf(irFunction->nestedContexts.first()));
458 function->length = irFunction->formals ? irFunction->formals->length() : 0;
459 function->nFormals = irFunction->arguments.size();
460 function->formalsOffset = currentOffset;
461 currentOffset += function->nFormals *
sizeof(CompiledData::Parameter);
463 const auto idGenerator = [
this](
const QString &str) {
return getStringId(str); };
465 QmlIR::Parameter::initType(&function->returnType, idGenerator, irFunction->returnType);
467 function->sizeOfLocalTemporalDeadZone = irFunction->sizeOfLocalTemporalDeadZone;
468 function->sizeOfRegisterTemporalDeadZone = irFunction->sizeOfRegisterTemporalDeadZone;
469 function->firstTemporalDeadZoneRegister = irFunction->firstTemporalDeadZoneRegister;
471 function->nLocals = irFunction->locals.size();
472 function->localsOffset = currentOffset;
473 currentOffset += function->nLocals *
sizeof(quint32);
475 function->nLineAndStatementNumbers
476 = irFunction->lineAndStatementNumberMapping.size();
477 Q_ASSERT(function->lineAndStatementNumberOffset() == currentOffset);
478 currentOffset += function->nLineAndStatementNumbers
479 *
sizeof(CompiledData::CodeOffsetToLineAndStatement);
481 function->nRegisters = irFunction->registerCountInFunction;
483 if (!irFunction->labelInfo.empty()) {
484 function->nLabelInfos = quint32(irFunction->labelInfo.size());
485 Q_ASSERT(function->labelInfosOffset() == currentOffset);
486 currentOffset += function->nLabelInfos *
sizeof(quint32);
489 function->location.set(irFunction->line, irFunction->column);
491 function->codeOffset = currentOffset;
492 function->codeSize = irFunction->code.size();
495 CompiledData::Parameter *formals = (CompiledData::Parameter *)(f + function->formalsOffset);
496 for (
int i = 0; i < irFunction->arguments.size(); ++i) {
497 auto *formal = &formals[i];
498 formal->nameIndex = getStringId(irFunction->arguments.at(i).id);
499 if (QQmlJS::AST::TypeAnnotation *annotation = irFunction->arguments.at(i).typeAnnotation.data())
500 QmlIR::Parameter::initType(&formal->type, idGenerator, annotation->type);
504 quint32_le *locals = (quint32_le *)(f + function->localsOffset);
505 for (
int i = 0; i < irFunction->locals.size(); ++i)
506 locals[i] = getStringId(irFunction->locals.at(i));
509 memcpy(f + function->lineAndStatementNumberOffset(),
510 irFunction->lineAndStatementNumberMapping.constData(),
511 irFunction->lineAndStatementNumberMapping.size()
512 *
sizeof(CompiledData::CodeOffsetToLineAndStatement));
514 quint32_le *labels = (quint32_le *)(f + function->labelInfosOffset());
515 for (
unsigned u : irFunction->labelInfo) {
520 memcpy(f + function->codeOffset, irFunction->code.constData(), irFunction->code.size());
527void QV4::Compiler::JSUnitGenerator::writeClass(
char *b,
const QV4::Compiler::Class &c)
529 QV4::CompiledData::Class *cls =
reinterpret_cast<QV4::CompiledData::Class *>(b);
531 quint32 currentOffset =
sizeof(QV4::CompiledData::Class);
533 QList<Class::Method> allMethods = c.staticMethods;
534 allMethods += c.methods;
536 cls->constructorFunction = c.constructorIndex;
537 cls->nameIndex = c.nameIndex;
538 cls->nMethods = c.methods.size();
539 cls->nStaticMethods = c.staticMethods.size();
540 cls->methodTableOffset = currentOffset;
541 CompiledData::Method *method =
reinterpret_cast<CompiledData::Method *>(b + currentOffset);
544 for (
int i = 0; i < allMethods.size(); ++i) {
545 method->name = allMethods.at(i).nameIndex;
546 method->type = allMethods.at(i).type;
547 method->function = allMethods.at(i).functionIndex;
551 static const bool showCode = qEnvironmentVariableIsSet(
"QV4_SHOW_BYTECODE");
553 qDebug() <<
"=== Class" << stringForIndex(cls->nameIndex) <<
"static methods"
554 << cls->nStaticMethods <<
"methods" << cls->nMethods;
555 qDebug() <<
" constructor:" << cls->constructorFunction;
556 for (uint i = 0; i < cls->nStaticMethods + cls->nMethods; ++i) {
557 QDebug output = qDebug().nospace();
558 output <<
" " << i <<
": ";
559 if (i < cls->nStaticMethods)
561 switch (cls->methodTable()[i].type) {
562 case CompiledData::Method::Getter:
563 output <<
"get ";
break;
564 case CompiledData::Method::Setter:
565 output <<
"set ";
break;
569 output << stringForIndex(cls->methodTable()[i].name) <<
" "
570 << cls->methodTable()[i].function;