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 scopde 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->getter = QV4::Lookup::getterGeneric;
116 else if (type == CompiledData::Lookup::Type_Setter)
117 l->setter = QV4::Lookup::setterGeneric;
118 else if (type == CompiledData::Lookup::Type_GlobalGetter)
119 l->globalGetter = QV4::Lookup::globalGetterGeneric;
120 else if (type == CompiledData::Lookup::Type_QmlContextPropertyGetter)
121 l->qmlContextPropertyGetter = QQmlContextWrapper::resolveQmlContextPropertyLookupGetter;
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
268void ExecutableCompilationUnit::markObjects(QV4::MarkStack *markStack) const
269{
270 const CompiledData::Unit *data = m_compilationUnit->data;
271
272 if (runtimeStrings) {
273 for (uint i = 0, end = totalStringCount(); i < end; ++i)
274 if (runtimeStrings[i])
275 runtimeStrings[i]->mark(markStack);
276 }
277 if (runtimeRegularExpressions) {
278 for (uint i = 0; i < data->regexpTableSize; ++i)
279 Value::fromStaticValue(staticValue: runtimeRegularExpressions[i]).mark(markStack);
280 }
281 if (runtimeClasses) {
282 for (uint i = 0; i < data->jsClassTableSize; ++i)
283 if (runtimeClasses[i])
284 runtimeClasses[i]->mark(markStack);
285 }
286 for (QV4::Function *f : std::as_const(t: runtimeFunctions))
287 if (f && f->internalClass)
288 f->internalClass->mark(markStack);
289 for (QV4::Heap::InternalClass *c : std::as_const(t: runtimeBlocks))
290 if (c)
291 c->mark(markStack);
292
293 for (QV4::Heap::Object *o : std::as_const(t&: templateObjects))
294 if (o)
295 o->mark(markStack);
296
297 if (runtimeLookups) {
298 for (uint i = 0; i < data->lookupTableSize; ++i)
299 runtimeLookups[i].markObjects(stack: markStack);
300 }
301
302 if (Heap::Base *v = m_valueOrModule.heapObject())
303 v->mark(markStack);
304}
305
306IdentifierHash ExecutableCompilationUnit::createNamedObjectsPerComponent(int componentObjectIndex)
307{
308 IdentifierHash namedObjectCache(engine);
309 const CompiledData::Object *component = objectAt(index: componentObjectIndex);
310 const quint32_le *namedObjectIndexPtr = component->namedObjectsInComponentTable();
311 for (quint32 i = 0; i < component->nNamedObjectsInComponent; ++i, ++namedObjectIndexPtr) {
312 const CompiledData::Object *namedObject = objectAt(index: *namedObjectIndexPtr);
313 namedObjectCache.add(str: runtimeStrings[namedObject->idNameIndex], value: namedObject->objectId());
314 }
315 Q_ASSERT(!namedObjectCache.isEmpty());
316 return *namedObjectsPerComponentCache.insert(key: componentObjectIndex, value: namedObjectCache);
317}
318
319QQmlRefPointer<ExecutableCompilationUnit> ExecutableCompilationUnit::create(
320 QQmlRefPointer<CompiledData::CompilationUnit> &&compilationUnit, ExecutionEngine *engine)
321{
322 auto result = QQmlRefPointer<ExecutableCompilationUnit>(
323 new ExecutableCompilationUnit(std::move(compilationUnit)),
324 QQmlRefPointer<ExecutableCompilationUnit>::Adopt);
325 result->engine = engine;
326 return result;
327}
328
329Heap::Module *ExecutableCompilationUnit::instantiate()
330{
331 const CompiledData::Unit *data = m_compilationUnit->data;
332
333 if (isESModule() && module())
334 return module();
335
336 if (data->indexOfRootFunction < 0)
337 return nullptr;
338
339 Q_ASSERT(engine);
340 if (!runtimeStrings)
341 populate();
342
343 Scope scope(engine);
344 Scoped<Module> module(scope, engine->memoryManager->allocate<Module>(args&: engine, args: this));
345
346 if (isESModule())
347 setModule(module->d());
348
349 const QStringList moduleRequests = m_compilationUnit->moduleRequests();
350 for (const QString &request: moduleRequests) {
351 const QUrl url(request);
352 const auto dependentModuleUnit = engine->loadModule(url: url, referrer: this);
353 if (engine->hasException)
354 return nullptr;
355 if (dependentModuleUnit)
356 dependentModuleUnit->instantiate();
357 }
358
359 ScopedString importName(scope);
360
361 const uint importCount = data->importEntryTableSize;
362 if (importCount > 0) {
363 imports = new const StaticValue *[importCount];
364 memset(s: imports, c: 0, n: importCount * sizeof(StaticValue *));
365 }
366 for (uint i = 0; i < importCount; ++i) {
367 const CompiledData::ImportEntry &entry = data->importEntryTable()[i];
368 QUrl url = urlAt(index: entry.moduleRequest);
369 importName = runtimeStrings[entry.importName];
370
371 if (const auto module = engine->loadModule(url: url, referrer: this)) {
372 const Value *valuePtr = module->resolveExport(exportName: importName);
373 if (!valuePtr) {
374 QString referenceErrorMessage = QStringLiteral("Unable to resolve import reference ");
375 referenceErrorMessage += importName->toQString();
376 QV4::ScopedValue compiledValue(scope, module->value());
377 engine->throwReferenceError(
378 value: referenceErrorMessage, fileName: fileName(),
379 lineNumber: entry.location.line(), column: entry.location.column());
380 return nullptr;
381 }
382 imports[i] = valuePtr;
383 }
384 }
385
386 const auto throwReferenceError = [&](const CompiledData::ExportEntry &entry, const QString &importName) {
387 QString referenceErrorMessage = QStringLiteral("Unable to resolve re-export reference ");
388 referenceErrorMessage += importName;
389 engine->throwReferenceError(
390 value: referenceErrorMessage, fileName: fileName(),
391 lineNumber: entry.location.line(), column: entry.location.column());
392 };
393
394 for (uint i = 0; i < data->indirectExportEntryTableSize; ++i) {
395 const CompiledData::ExportEntry &entry = data->indirectExportEntryTable()[i];
396 if (auto dependentModule = engine->loadModule(url: urlAt(index: entry.moduleRequest), referrer: this)) {
397 ScopedString importName(scope, runtimeStrings[entry.importName]);
398 if (!dependentModule->resolveExport(exportName: importName)) {
399 throwReferenceError(entry, importName->toQString());
400 return nullptr;
401 }
402 }
403 }
404
405 return module->d();
406}
407
408const Value *ExecutableCompilationUnit::resolveExportRecursively(
409 QV4::String *exportName, QVector<ResolveSetEntry> *resolveSet)
410{
411 if (!module())
412 return nullptr;
413
414 for (const auto &entry: *resolveSet)
415 if (entry.module == this && entry.exportName->isEqualTo(other: exportName))
416 return nullptr;
417
418 (*resolveSet) << ResolveSetEntry(this, exportName);
419
420 if (exportName->toQString() == QLatin1String("*"))
421 return &module()->self;
422
423 const CompiledData::Unit *data = m_compilationUnit->data;
424
425 Q_ASSERT(data);
426 Q_ASSERT(engine);
427
428 Scope scope(engine);
429
430 if (auto localExport = lookupNameInExportTable(
431 firstExportEntry: data->localExportEntryTable(), tableSize: data->localExportEntryTableSize, name: exportName)) {
432 ScopedString localName(scope, runtimeStrings[localExport->localName]);
433 uint index = module()->scope->internalClass->indexOfValueOrGetter(id: localName->toPropertyKey());
434 if (index == UINT_MAX)
435 return nullptr;
436 if (index >= module()->scope->locals.size)
437 return &(imports[index - module()->scope->locals.size]->asValue<Value>());
438 return &module()->scope->locals[index];
439 }
440
441 if (auto indirectExport = lookupNameInExportTable(
442 firstExportEntry: data->indirectExportEntryTable(), tableSize: data->indirectExportEntryTableSize, name: exportName)) {
443 QUrl request = urlAt(index: indirectExport->moduleRequest);
444 if (auto dependentModule = engine->loadModule(url: request, referrer: this)) {
445 ScopedString importName(scope, runtimeStrings[indirectExport->importName]);
446 return dependentModule->resolveExportRecursively(exportName: importName, resolveSet);
447 }
448 return nullptr;
449 }
450
451 if (exportName->toQString() == QLatin1String("default"))
452 return nullptr;
453
454 const Value *starResolution = nullptr;
455
456 for (uint i = 0; i < data->starExportEntryTableSize; ++i) {
457 const CompiledData::ExportEntry &entry = data->starExportEntryTable()[i];
458 QUrl request = urlAt(index: entry.moduleRequest);
459 const Value *resolution = nullptr;
460 if (auto dependentModule = engine->loadModule(url: request, referrer: this))
461 resolution = dependentModule->resolveExportRecursively(exportName, resolveSet);
462
463 // ### handle ambiguous
464 if (resolution) {
465 if (!starResolution) {
466 starResolution = resolution;
467 continue;
468 }
469 if (resolution != starResolution)
470 return nullptr;
471 }
472 }
473
474 return starResolution;
475}
476
477const CompiledData::ExportEntry *ExecutableCompilationUnit::lookupNameInExportTable(
478 const CompiledData::ExportEntry *firstExportEntry, int tableSize, QV4::String *name) const
479{
480 const CompiledData::ExportEntry *lastExportEntry = firstExportEntry + tableSize;
481 auto matchingExport = std::lower_bound(first: firstExportEntry, last: lastExportEntry, val: name, comp: [this](const CompiledData::ExportEntry &lhs, QV4::String *name) {
482 return stringAt(index: lhs.exportName) < name->toQString();
483 });
484 if (matchingExport == lastExportEntry || stringAt(index: matchingExport->exportName) != name->toQString())
485 return nullptr;
486 return matchingExport;
487}
488
489void ExecutableCompilationUnit::getExportedNamesRecursively(
490 QStringList *names, QVector<const ExecutableCompilationUnit*> *exportNameSet,
491 bool includeDefaultExport) const
492{
493 if (exportNameSet->contains(t: this))
494 return;
495 exportNameSet->append(t: this);
496
497 const auto append = [names, includeDefaultExport](const QString &name) {
498 if (!includeDefaultExport && name == QLatin1String("default"))
499 return;
500 names->append(t: name);
501 };
502
503 const CompiledData::Unit *data = m_compilationUnit->data;
504
505 Q_ASSERT(data);
506 Q_ASSERT(engine);
507
508 for (uint i = 0; i < data->localExportEntryTableSize; ++i) {
509 const CompiledData::ExportEntry &entry = data->localExportEntryTable()[i];
510 append(stringAt(index: entry.exportName));
511 }
512
513 for (uint i = 0; i < data->indirectExportEntryTableSize; ++i) {
514 const CompiledData::ExportEntry &entry = data->indirectExportEntryTable()[i];
515 append(stringAt(index: entry.exportName));
516 }
517
518 for (uint i = 0; i < data->starExportEntryTableSize; ++i) {
519 const CompiledData::ExportEntry &entry = data->starExportEntryTable()[i];
520 if (auto dependentModule = engine->loadModule(url: urlAt(index: entry.moduleRequest), referrer: this)) {
521 dependentModule->getExportedNamesRecursively(
522 names, exportNameSet, /*includeDefaultExport*/false);
523 }
524 }
525}
526
527void ExecutableCompilationUnit::evaluate()
528{
529 Q_ASSERT(engine);
530
531 QV4::Scope scope(engine);
532 QV4::Scoped<Module> mod(scope, module());
533 mod->evaluate();
534}
535
536void ExecutableCompilationUnit::evaluateModuleRequests()
537{
538 Q_ASSERT(engine);
539
540 const QStringList moduleRequests = m_compilationUnit->moduleRequests();
541 for (const QString &request: moduleRequests) {
542 auto dependentModule = engine->loadModule(url: QUrl(request), referrer: this);
543
544 if (engine->hasException)
545 return;
546
547 Q_ASSERT(dependentModule);
548 dependentModule->evaluate();
549 if (engine->hasException)
550 return;
551 }
552}
553
554QString ExecutableCompilationUnit::bindingValueAsString(const CompiledData::Binding *binding) const
555{
556#if QT_CONFIG(translation)
557 using namespace CompiledData;
558 bool byId = false;
559 switch (binding->type()) {
560 case Binding::Type_TranslationById:
561 byId = true;
562 Q_FALLTHROUGH();
563 case Binding::Type_Translation: {
564 return translateFrom(index: { .index: binding->value.translationDataIndex, .byId: byId });
565 }
566 default:
567 break;
568 }
569#endif
570 return m_compilationUnit->bindingValueAsString(binding);
571}
572
573QString ExecutableCompilationUnit::translateFrom(TranslationDataIndex index) const
574{
575#if !QT_CONFIG(translation)
576 return QString();
577#else
578 const CompiledData::TranslationData &translation = unitData()->translations()[index.index];
579
580 if (index.byId) {
581 QByteArray id = stringAt(index: translation.stringIndex).toUtf8();
582 return qtTrId(id: id.constData(), n: translation.number);
583 }
584
585 const auto fileContext = [this]() {
586 // This code must match that in the qsTr() implementation
587 const QString &path = fileName();
588 int lastSlash = path.lastIndexOf(c: QLatin1Char('/'));
589
590 QStringView context = (lastSlash > -1)
591 ? QStringView{ path }.mid(pos: lastSlash + 1, n: path.size() - lastSlash - 5)
592 : QStringView();
593 return context.toUtf8();
594 };
595
596 const bool hasContext
597 = translation.contextIndex != QV4::CompiledData::TranslationData::NoContextIndex;
598 QByteArray context;
599 if (hasContext) {
600 context = stringAt(index: translation.contextIndex).toUtf8();
601 } else {
602 auto pragmaTranslationContext = unitData()->translationContextIndex();
603 context = stringAt(index: *pragmaTranslationContext).toUtf8();
604 context = context.isEmpty() ? fileContext() : context;
605 }
606
607 QByteArray comment = stringAt(index: translation.commentIndex).toUtf8();
608 QByteArray text = stringAt(index: translation.stringIndex).toUtf8();
609 return QCoreApplication::translate(context, key: text, disambiguation: comment, n: translation.number);
610#endif
611}
612
613Heap::Module *ExecutableCompilationUnit::module() const
614{
615 if (const Module *m = m_valueOrModule.as<QV4::Module>())
616 return m->d();
617 return nullptr;
618}
619
620void ExecutableCompilationUnit::setModule(Heap::Module *module)
621{
622 m_valueOrModule = module;
623}
624
625} // namespace QV4
626
627QT_END_NAMESPACE
628

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