1// Copyright (C) 2019 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qml/qqmlprivate.h"
5#include "qv4engine_p.h"
6#include "qv4executablecompilationunit_p.h"
7
8#include <private/qv4engine_p.h>
9#include <private/qv4regexp_p.h>
10#include <private/qv4lookup_p.h>
11#include <private/qv4qmlcontext_p.h>
12#include <private/qv4identifiertable_p.h>
13#include <private/qv4objectproto_p.h>
14#include <private/qqmlengine_p.h>
15#include <private/qv4qobjectwrapper_p.h>
16#include <private/qqmlvaluetypewrapper_p.h>
17#include <private/qqmlscriptdata_p.h>
18#include <private/qv4module_p.h>
19#include <private/qv4compilationunitmapper_p.h>
20#include <private/qqmltypewrapper_p.h>
21#include <private/qv4resolvedtypereference_p.h>
22#include <private/qv4objectiterator_p.h>
23
24#include <QtQml/qqmlpropertymap.h>
25
26#include <QtCore/qfileinfo.h>
27#include <QtCore/qcryptographichash.h>
28
29QT_BEGIN_NAMESPACE
30
31namespace QV4 {
32
33ExecutableCompilationUnit::ExecutableCompilationUnit() = default;
34
35ExecutableCompilationUnit::ExecutableCompilationUnit(
36 QQmlRefPointer<CompiledData::CompilationUnit> &&compilationUnit)
37 : m_compilationUnit(std::move(compilationUnit))
38{
39 constants = m_compilationUnit->constants;
40}
41
42ExecutableCompilationUnit::~ExecutableCompilationUnit()
43{
44 if (engine)
45 clear();
46}
47
48static QString toString(QV4::ReturnedValue v)
49{
50 Value val = Value::fromReturnedValue(val: v);
51 QString result;
52 if (val.isInt32())
53 result = QLatin1String("int ");
54 else if (val.isDouble())
55 result = QLatin1String("double ");
56 if (val.isEmpty())
57 result += QLatin1String("empty");
58 else
59 result += val.toQStringNoThrow();
60 return result;
61}
62
63static void dumpConstantTable(const StaticValue *constants, uint count)
64{
65 QDebug d = qDebug();
66 d.nospace() << Qt::right;
67 for (uint i = 0; i < count; ++i) {
68 d << qSetFieldWidth(width: 8) << i << qSetFieldWidth(width: 0) << ": "
69 << toString(v: constants[i].asReturnedValue()).toUtf8().constData() << "\n";
70 }
71}
72
73void ExecutableCompilationUnit::populate()
74{
75 /* In general, we should use QV4::Scope whenever we allocate heap objects, and employ write barriers
76 for member variables pointing to heap objects. However, ExecutableCompilationUnit is special, as it
77 is always part of the root set. So instead of using scoped allocations and write barriers, we use a
78 slightly different approach: We temporarily block the gc from running. Afterwards, at the end of the
79 function we check whether the gc was already running, and mark the ExecutableCompilationUnit. This
80 ensures that all the newly allocated objects of the compilation unit will be marked in turn.
81 If the gc was not running, we don't have to do anything, because everything will be marked when the
82 gc starts marking the root set at the start of a run.
83 */
84 const CompiledData::Unit *data = m_compilationUnit->data;
85 GCCriticalSection<ExecutableCompilationUnit> criticalSection(engine, this);
86
87 Q_ASSERT(!runtimeStrings);
88 Q_ASSERT(engine);
89 Q_ASSERT(data);
90 const quint32 stringCount = totalStringCount();
91 runtimeStrings = (QV4::Heap::String **)calloc(nmemb: stringCount, size: sizeof(QV4::Heap::String*));
92 for (uint i = 0; i < stringCount; ++i)
93 runtimeStrings[i] = engine->newString(s: stringAt(index: i));
94
95 runtimeRegularExpressions
96 = new QV4::Value[data->regexpTableSize];
97 for (uint i = 0; i < data->regexpTableSize; ++i) {
98 const CompiledData::RegExp *re = data->regexpAt(index: i);
99 uint f = re->flags();
100 const CompiledData::RegExp::Flags flags = static_cast<CompiledData::RegExp::Flags>(f);
101 runtimeRegularExpressions[i] = QV4::RegExp::create(
102 engine, pattern: stringAt(index: re->stringIndex()), flags);
103 }
104
105 if (data->lookupTableSize) {
106 runtimeLookups = new QV4::Lookup[data->lookupTableSize];
107 memset(s: runtimeLookups, c: 0, n: data->lookupTableSize * sizeof(QV4::Lookup));
108 const CompiledData::Lookup *compiledLookups = data->lookupTable();
109 for (uint i = 0; i < data->lookupTableSize; ++i) {
110 QV4::Lookup *l = runtimeLookups + i;
111
112 CompiledData::Lookup::Type type
113 = CompiledData::Lookup::Type(uint(compiledLookups[i].type()));
114 if (type == CompiledData::Lookup::Type_Getter)
115 l->call = Lookup::Call::GetterGeneric;
116 else if (type == CompiledData::Lookup::Type_Setter)
117 l->call = Lookup::Call::SetterGeneric;
118 else if (type == CompiledData::Lookup::Type_GlobalGetter)
119 l->call = Lookup::Call::GlobalGetterGeneric;
120 else if (type == CompiledData::Lookup::Type_QmlContextPropertyGetter)
121 l->call = Lookup::Call::ContextGetterGeneric;
122 l->forCall = compiledLookups[i].mode() == CompiledData::Lookup::Mode_ForCall;
123 l->nameIndex = compiledLookups[i].nameIndex();
124 }
125 }
126
127 if (data->jsClassTableSize) {
128 runtimeClasses
129 = (QV4::Heap::InternalClass **)calloc(nmemb: data->jsClassTableSize,
130 size: sizeof(QV4::Heap::InternalClass *));
131
132 for (uint i = 0; i < data->jsClassTableSize; ++i) {
133 int memberCount = 0;
134 const CompiledData::JSClassMember *member
135 = data->jsClassAt(idx: i, nMembers: &memberCount);
136 runtimeClasses[i]
137 = engine->internalClasses(icType: QV4::ExecutionEngine::Class_Object);
138 for (int j = 0; j < memberCount; ++j, ++member)
139 runtimeClasses[i]
140 = runtimeClasses[i]->addMember(
141 identifier: engine->identifierTable->asPropertyKey(
142 str: runtimeStrings[member->nameOffset()]),
143 data: member->isAccessor()
144 ? QV4::Attr_Accessor
145 : QV4::Attr_Data);
146 }
147 }
148
149 runtimeFunctions.resize(size: data->functionTableSize);
150 static bool ignoreAotCompiledFunctions
151 = qEnvironmentVariableIsSet(varName: "QV4_FORCE_INTERPRETER")
152 || !(engine->diskCacheOptions() & ExecutionEngine::DiskCache::AotNative);
153
154 const QQmlPrivate::AOTCompiledFunction *aotFunction
155 = ignoreAotCompiledFunctions ? nullptr : m_compilationUnit->aotCompiledFunctions;
156
157 auto advanceAotFunction = [&](int i) -> const QQmlPrivate::AOTCompiledFunction * {
158 if (aotFunction) {
159 if (aotFunction->functionPtr) {
160 if (aotFunction->functionIndex == i)
161 return aotFunction++;
162 } else {
163 aotFunction = nullptr;
164 }
165 }
166 return nullptr;
167 };
168
169 for (int i = 0 ;i < runtimeFunctions.size(); ++i) {
170 const QV4::CompiledData::Function *compiledFunction = data->functionAt(idx: i);
171 runtimeFunctions[i] = QV4::Function::create(engine, unit: this, function: compiledFunction,
172 aotFunction: advanceAotFunction(i));
173 }
174
175 Scope scope(engine);
176 Scoped<InternalClass> ic(scope);
177
178 runtimeBlocks.resize(size: data->blockTableSize);
179 for (int i = 0 ;i < runtimeBlocks.size(); ++i) {
180 const QV4::CompiledData::Block *compiledBlock = data->blockAt(idx: i);
181 ic = engine->internalClasses(icType: EngineBase::Class_CallContext);
182
183 // first locals
184 const quint32_le *localsIndices = compiledBlock->localsTable();
185 for (quint32 j = 0; j < compiledBlock->nLocals; ++j)
186 ic = ic->addMember(
187 identifier: engine->identifierTable->asPropertyKey(str: runtimeStrings[localsIndices[j]]),
188 data: Attr_NotConfigurable);
189 runtimeBlocks[i] = ic->d();
190 }
191
192 static const bool showCode = qEnvironmentVariableIsSet(varName: "QV4_SHOW_BYTECODE");
193 if (showCode) {
194 qDebug() << "=== Constant table";
195 dumpConstantTable(constants, count: data->constantTableSize);
196 qDebug() << "=== String table";
197 for (uint i = 0, end = totalStringCount(); i < end; ++i)
198 qDebug() << " " << i << ":" << runtimeStrings[i]->toQString();
199 qDebug() << "=== Closure table";
200 for (uint i = 0; i < data->functionTableSize; ++i)
201 qDebug() << " " << i << ":" << runtimeFunctions[i]->name()->toQString();
202 qDebug() << "root function at index "
203 << (data->indexOfRootFunction != -1
204 ? data->indexOfRootFunction : 0);
205 }
206}
207
208Heap::Object *ExecutableCompilationUnit::templateObjectAt(int index) const
209{
210 const CompiledData::Unit *data = m_compilationUnit->data;
211 Q_ASSERT(data);
212 Q_ASSERT(engine);
213
214 Q_ASSERT(index < int(data->templateObjectTableSize));
215 if (!templateObjects.size())
216 templateObjects.resize(size: data->templateObjectTableSize);
217 Heap::Object *o = templateObjects.at(i: index);
218 if (o)
219 return o;
220
221 // create the template object
222 Scope scope(engine);
223 const CompiledData::TemplateObject *t = data->templateObjectAt(idx: index);
224 Scoped<ArrayObject> a(scope, engine->newArrayObject(count: t->size));
225 Scoped<ArrayObject> raw(scope, engine->newArrayObject(count: t->size));
226 ScopedValue s(scope);
227 for (uint i = 0; i < t->size; ++i) {
228 s = runtimeStrings[t->stringIndexAt(i)];
229 a->arraySet(index: i, value: s);
230 s = runtimeStrings[t->rawStringIndexAt(i)];
231 raw->arraySet(index: i, value: s);
232 }
233
234 ObjectPrototype::method_freeze(engine->functionCtor(), thisObject: nullptr, argv: raw, argc: 1);
235 a->defineReadonlyProperty(QStringLiteral("raw"), value: raw);
236 ObjectPrototype::method_freeze(engine->functionCtor(), thisObject: nullptr, argv: a, argc: 1);
237
238 templateObjects[index] = a->objectValue()->d();
239 return templateObjects.at(i: index);
240}
241
242void ExecutableCompilationUnit::clear()
243{
244 delete [] imports;
245 imports = nullptr;
246
247 if (runtimeLookups) {
248 const uint lookupTableSize = unitData()->lookupTableSize;
249 for (uint i = 0; i < lookupTableSize; ++i)
250 runtimeLookups[i].releasePropertyCache();
251 }
252
253 delete [] runtimeLookups;
254 runtimeLookups = nullptr;
255
256 for (QV4::Function *f : std::as_const(t&: runtimeFunctions))
257 f->destroy();
258 runtimeFunctions.clear();
259
260 free(ptr: runtimeStrings);
261 runtimeStrings = nullptr;
262 delete [] runtimeRegularExpressions;
263 runtimeRegularExpressions = nullptr;
264 free(ptr: runtimeClasses);
265 runtimeClasses = nullptr;
266
267 static QQmlRefPointer<CompiledData::CompilationUnit> nullUnit
268 = QQml::makeRefPointer<CompiledData::CompilationUnit>();
269 m_compilationUnit = nullUnit;
270}
271
272void ExecutableCompilationUnit::markObjects(QV4::MarkStack *markStack) const
273{
274 const CompiledData::Unit *data = m_compilationUnit->data;
275
276 if (runtimeStrings) {
277 for (uint i = 0, end = totalStringCount(); i < end; ++i)
278 if (runtimeStrings[i])
279 runtimeStrings[i]->mark(markStack);
280 }
281 if (runtimeRegularExpressions) {
282 for (uint i = 0; i < data->regexpTableSize; ++i)
283 Value::fromStaticValue(staticValue: runtimeRegularExpressions[i]).mark(markStack);
284 }
285 if (runtimeClasses) {
286 for (uint i = 0; i < data->jsClassTableSize; ++i)
287 if (runtimeClasses[i])
288 runtimeClasses[i]->mark(markStack);
289 }
290 for (QV4::Function *f : std::as_const(t: runtimeFunctions))
291 if (f && f->internalClass)
292 f->internalClass->mark(markStack);
293 for (QV4::Heap::InternalClass *c : std::as_const(t: runtimeBlocks))
294 if (c)
295 c->mark(markStack);
296
297 for (QV4::Heap::Object *o : std::as_const(t&: templateObjects))
298 if (o)
299 o->mark(markStack);
300
301 if (runtimeLookups) {
302 for (uint i = 0; i < data->lookupTableSize; ++i)
303 runtimeLookups[i].markObjects(stack: markStack);
304 }
305
306 if (Heap::Base *v = m_valueOrModule.heapObject())
307 v->mark(markStack);
308}
309
310IdentifierHash ExecutableCompilationUnit::createNamedObjectsPerComponent(int componentObjectIndex)
311{
312 IdentifierHash namedObjectCache(engine);
313 const CompiledData::Object *component = objectAt(index: componentObjectIndex);
314 const quint32_le *namedObjectIndexPtr = component->namedObjectsInComponentTable();
315 for (quint32 i = 0; i < component->nNamedObjectsInComponent; ++i, ++namedObjectIndexPtr) {
316 const CompiledData::Object *namedObject = objectAt(index: *namedObjectIndexPtr);
317 namedObjectCache.add(str: runtimeStrings[namedObject->idNameIndex], value: namedObject->objectId());
318 }
319 Q_ASSERT(!namedObjectCache.isEmpty());
320 return *namedObjectsPerComponentCache.insert(key: componentObjectIndex, value: namedObjectCache);
321}
322
323QQmlRefPointer<ExecutableCompilationUnit> ExecutableCompilationUnit::create(
324 QQmlRefPointer<CompiledData::CompilationUnit> &&compilationUnit, ExecutionEngine *engine)
325{
326 auto result = QQmlRefPointer<ExecutableCompilationUnit>(
327 new ExecutableCompilationUnit(std::move(compilationUnit)),
328 QQmlRefPointer<ExecutableCompilationUnit>::Adopt);
329 result->engine = engine;
330 return result;
331}
332
333Heap::Module *ExecutableCompilationUnit::instantiate()
334{
335 const CompiledData::Unit *data = m_compilationUnit->data;
336
337 if (isESModule() && module())
338 return module();
339
340 if (data->indexOfRootFunction < 0)
341 return nullptr;
342
343 Q_ASSERT(engine);
344 if (!runtimeStrings)
345 populate();
346
347 Scope scope(engine);
348 Scoped<Module> module(scope, engine->memoryManager->allocate<Module>(args&: engine, args: this));
349
350 if (isESModule())
351 setModule(module->d());
352
353 const QStringList moduleRequests = m_compilationUnit->moduleRequests();
354 for (const QString &request: moduleRequests) {
355 const QUrl url(request);
356 const auto dependentModuleUnit = engine->loadModule(url: url, referrer: this);
357 if (engine->hasException)
358 return nullptr;
359 if (dependentModuleUnit)
360 dependentModuleUnit->instantiate();
361 }
362
363 ScopedString importName(scope);
364
365 const uint importCount = data->importEntryTableSize;
366 if (importCount > 0) {
367 imports = new const StaticValue *[importCount];
368 memset(s: imports, c: 0, n: importCount * sizeof(StaticValue *));
369 }
370 for (uint i = 0; i < importCount; ++i) {
371 const CompiledData::ImportEntry &entry = data->importEntryTable()[i];
372 QUrl url = urlAt(index: entry.moduleRequest);
373 importName = runtimeStrings[entry.importName];
374
375 if (const auto module = engine->loadModule(url: url, referrer: this)) {
376 const Value *valuePtr = module->resolveExport(exportName: importName);
377 if (!valuePtr) {
378 QString referenceErrorMessage = QStringLiteral("Unable to resolve import reference ");
379 referenceErrorMessage += importName->toQString();
380 QV4::ScopedValue compiledValue(scope, module->value());
381 engine->throwReferenceError(
382 value: referenceErrorMessage, fileName: fileName(),
383 lineNumber: entry.location.line(), column: entry.location.column());
384 return nullptr;
385 }
386 imports[i] = valuePtr;
387 }
388 }
389
390 const auto throwReferenceError = [&](const CompiledData::ExportEntry &entry, const QString &importName) {
391 QString referenceErrorMessage = QStringLiteral("Unable to resolve re-export reference ");
392 referenceErrorMessage += importName;
393 engine->throwReferenceError(
394 value: referenceErrorMessage, fileName: fileName(),
395 lineNumber: entry.location.line(), column: entry.location.column());
396 };
397
398 for (uint i = 0; i < data->indirectExportEntryTableSize; ++i) {
399 const CompiledData::ExportEntry &entry = data->indirectExportEntryTable()[i];
400 if (auto dependentModule = engine->loadModule(url: urlAt(index: entry.moduleRequest), referrer: this)) {
401 ScopedString importName(scope, runtimeStrings[entry.importName]);
402 if (!dependentModule->resolveExport(exportName: importName)) {
403 throwReferenceError(entry, importName->toQString());
404 return nullptr;
405 }
406 }
407 }
408
409 return module->d();
410}
411
412const Value *ExecutableCompilationUnit::resolveExportRecursively(
413 QV4::String *exportName, QVector<ResolveSetEntry> *resolveSet)
414{
415 if (!module())
416 return nullptr;
417
418 for (const auto &entry: *resolveSet)
419 if (entry.module == this && entry.exportName->isEqualTo(other: exportName))
420 return nullptr;
421
422 (*resolveSet) << ResolveSetEntry(this, exportName);
423
424 if (exportName->toQString() == QLatin1String("*"))
425 return &module()->self;
426
427 const CompiledData::Unit *data = m_compilationUnit->data;
428
429 Q_ASSERT(data);
430 Q_ASSERT(engine);
431
432 Scope scope(engine);
433
434 if (auto localExport = lookupNameInExportTable(
435 firstExportEntry: data->localExportEntryTable(), tableSize: data->localExportEntryTableSize, name: exportName)) {
436 ScopedString localName(scope, runtimeStrings[localExport->localName]);
437 uint index = module()->scope->internalClass->indexOfValueOrGetter(id: localName->toPropertyKey());
438 if (index == UINT_MAX)
439 return nullptr;
440 if (index >= module()->scope->locals.size)
441 return &(imports[index - module()->scope->locals.size]->asValue<Value>());
442 return &module()->scope->locals[index];
443 }
444
445 if (auto indirectExport = lookupNameInExportTable(
446 firstExportEntry: data->indirectExportEntryTable(), tableSize: data->indirectExportEntryTableSize, name: exportName)) {
447 QUrl request = urlAt(index: indirectExport->moduleRequest);
448 if (auto dependentModule = engine->loadModule(url: request, referrer: this)) {
449 ScopedString importName(scope, runtimeStrings[indirectExport->importName]);
450 return dependentModule->resolveExportRecursively(exportName: importName, resolveSet);
451 }
452 return nullptr;
453 }
454
455 if (exportName->toQString() == QLatin1String("default"))
456 return nullptr;
457
458 const Value *starResolution = nullptr;
459
460 for (uint i = 0; i < data->starExportEntryTableSize; ++i) {
461 const CompiledData::ExportEntry &entry = data->starExportEntryTable()[i];
462 QUrl request = urlAt(index: entry.moduleRequest);
463 const Value *resolution = nullptr;
464 if (auto dependentModule = engine->loadModule(url: request, referrer: this))
465 resolution = dependentModule->resolveExportRecursively(exportName, resolveSet);
466
467 // ### handle ambiguous
468 if (resolution) {
469 if (!starResolution) {
470 starResolution = resolution;
471 continue;
472 }
473 if (resolution != starResolution)
474 return nullptr;
475 }
476 }
477
478 return starResolution;
479}
480
481const CompiledData::ExportEntry *ExecutableCompilationUnit::lookupNameInExportTable(
482 const CompiledData::ExportEntry *firstExportEntry, int tableSize, QV4::String *name) const
483{
484 const CompiledData::ExportEntry *lastExportEntry = firstExportEntry + tableSize;
485 auto matchingExport = std::lower_bound(first: firstExportEntry, last: lastExportEntry, val: name, comp: [this](const CompiledData::ExportEntry &lhs, QV4::String *name) {
486 return stringAt(index: lhs.exportName) < name->toQString();
487 });
488 if (matchingExport == lastExportEntry || stringAt(index: matchingExport->exportName) != name->toQString())
489 return nullptr;
490 return matchingExport;
491}
492
493void ExecutableCompilationUnit::getExportedNamesRecursively(
494 QStringList *names, QVector<const ExecutableCompilationUnit*> *exportNameSet,
495 bool includeDefaultExport) const
496{
497 if (exportNameSet->contains(t: this))
498 return;
499 exportNameSet->append(t: this);
500
501 const auto append = [names, includeDefaultExport](const QString &name) {
502 if (!includeDefaultExport && name == QLatin1String("default"))
503 return;
504 names->append(t: name);
505 };
506
507 const CompiledData::Unit *data = m_compilationUnit->data;
508
509 Q_ASSERT(data);
510 Q_ASSERT(engine);
511
512 for (uint i = 0; i < data->localExportEntryTableSize; ++i) {
513 const CompiledData::ExportEntry &entry = data->localExportEntryTable()[i];
514 append(stringAt(index: entry.exportName));
515 }
516
517 for (uint i = 0; i < data->indirectExportEntryTableSize; ++i) {
518 const CompiledData::ExportEntry &entry = data->indirectExportEntryTable()[i];
519 append(stringAt(index: entry.exportName));
520 }
521
522 for (uint i = 0; i < data->starExportEntryTableSize; ++i) {
523 const CompiledData::ExportEntry &entry = data->starExportEntryTable()[i];
524 if (auto dependentModule = engine->loadModule(url: urlAt(index: entry.moduleRequest), referrer: this)) {
525 dependentModule->getExportedNamesRecursively(
526 names, exportNameSet, /*includeDefaultExport*/false);
527 }
528 }
529}
530
531void ExecutableCompilationUnit::evaluate()
532{
533 Q_ASSERT(engine);
534
535 QV4::Scope scope(engine);
536 QV4::Scoped<Module> mod(scope, module());
537 mod->evaluate();
538}
539
540void ExecutableCompilationUnit::evaluateModuleRequests()
541{
542 Q_ASSERT(engine);
543
544 const QStringList moduleRequests = m_compilationUnit->moduleRequests();
545 for (const QString &request: moduleRequests) {
546 auto dependentModule = engine->loadModule(url: QUrl(request), referrer: this);
547
548 if (engine->hasException)
549 return;
550
551 Q_ASSERT(dependentModule);
552 dependentModule->evaluate();
553 if (engine->hasException)
554 return;
555 }
556}
557
558QString ExecutableCompilationUnit::bindingValueAsString(const CompiledData::Binding *binding) const
559{
560#if QT_CONFIG(translation)
561 using namespace CompiledData;
562 bool byId = false;
563 switch (binding->type()) {
564 case Binding::Type_TranslationById:
565 byId = true;
566 Q_FALLTHROUGH();
567 case Binding::Type_Translation: {
568 return translateFrom(index: { .index: binding->value.translationDataIndex, .byId: byId });
569 }
570 default:
571 break;
572 }
573#endif
574 return m_compilationUnit->bindingValueAsString(binding);
575}
576
577QString ExecutableCompilationUnit::translateFrom(TranslationDataIndex index) const
578{
579#if !QT_CONFIG(translation)
580 return QString();
581#else
582 const CompiledData::TranslationData &translation = unitData()->translations()[index.index];
583
584 if (index.byId) {
585 QByteArray id = stringAt(index: translation.stringIndex).toUtf8();
586 return qtTrId(id: id.constData(), n: translation.number);
587 }
588
589 const auto fileContext = [this]() {
590 // This code must match that in the qsTr() implementation
591 const QString &path = fileName();
592 int lastSlash = path.lastIndexOf(c: QLatin1Char('/'));
593
594 QStringView context = (lastSlash > -1)
595 ? QStringView{ path }.mid(pos: lastSlash + 1, n: path.size() - lastSlash - 5)
596 : QStringView();
597 return context.toUtf8();
598 };
599
600 const bool hasContext
601 = translation.contextIndex != QV4::CompiledData::TranslationData::NoContextIndex;
602 QByteArray context;
603 if (hasContext) {
604 context = stringAt(index: translation.contextIndex).toUtf8();
605 } else {
606 auto pragmaTranslationContext = unitData()->translationContextIndex();
607 context = stringAt(index: *pragmaTranslationContext).toUtf8();
608 context = context.isEmpty() ? fileContext() : context;
609 }
610
611 QByteArray comment = stringAt(index: translation.commentIndex).toUtf8();
612 QByteArray text = stringAt(index: translation.stringIndex).toUtf8();
613 return QCoreApplication::translate(context, key: text, disambiguation: comment, n: translation.number);
614#endif
615}
616
617Heap::Module *ExecutableCompilationUnit::module() const
618{
619 if (const Module *m = m_valueOrModule.as<QV4::Module>())
620 return m->d();
621 return nullptr;
622}
623
624void ExecutableCompilationUnit::setModule(Heap::Module *module)
625{
626 m_valueOrModule = module;
627}
628
629} // namespace QV4
630
631QT_END_NAMESPACE
632

source code of qtdeclarative/src/qml/jsruntime/qv4executablecompilationunit.cpp