Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qv4executablecompilationunit.cpp
Go to the documentation of this file.
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// Qt-Security score:significant
4
5#include "qml/qqmlprivate.h"
6#include "qv4engine_p.h"
8
9#include <private/qv4engine_p.h>
10#include <private/qv4regexp_p.h>
11#include <private/qv4lookup_p.h>
12#include <private/qv4qmlcontext_p.h>
13#include <private/qv4identifiertable_p.h>
14#include <private/qv4objectproto_p.h>
15#include <private/qqmlengine_p.h>
16#include <private/qv4qobjectwrapper_p.h>
17#include <private/qqmlvaluetypewrapper_p.h>
18#include <private/qqmlscriptdata_p.h>
19#include <private/qv4module_p.h>
20#include <private/qv4compilationunitmapper_p.h>
21#include <private/qqmltypewrapper_p.h>
22#include <private/qv4resolvedtypereference_p.h>
23#include <private/qv4objectiterator_p.h>
24
25#include <QtQml/qqmlpropertymap.h>
26
27#include <QtCore/qfileinfo.h>
28#include <QtCore/qcryptographichash.h>
29
31
32DEFINE_BOOL_CONFIG_OPTION(qv4FailOnInvalidAot, QV4_FAIL_ON_INVALID_AOT)
33DEFINE_BOOL_CONFIG_OPTION(qv4SkipAotValidation, QV4_SKIP_AOT_VALIDATION)
34
35namespace QV4 {
36
38
42{
44}
45
47{
48 if (engine)
49 clear();
50}
51
52static QString toString(QV4::ReturnedValue v)
53{
54 Value val = Value::fromReturnedValue(v);
55 QString result;
56 if (val.isInt32())
57 result = QLatin1String("int ");
58 else if (val.isDouble())
59 result = QLatin1String("double ");
60 if (val.isEmpty())
61 result += QLatin1String("empty");
62 else
63 result += val.toQStringNoThrow();
64 return result;
65}
66
67static void dumpConstantTable(const StaticValue *constants, uint count)
68{
69 QDebug d = qDebug();
70 d.nospace() << Qt::right;
71 for (uint i = 0; i < count; ++i) {
72 d << qSetFieldWidth(8) << i << qSetFieldWidth(0) << ": "
73 << toString(constants[i].asReturnedValue()).toUtf8().constData() << "\n";
74 }
75}
76
78{
79 /* In general, we should use QV4::Scope whenever we allocate heap objects, and employ write barriers
80 for member variables pointing to heap objects. However, ExecutableCompilationUnit is special, as it
81 is always part of the root set. So instead of using scoped allocations and write barriers, we use a
82 slightly different approach: We temporarily block the gc from running. Afterwards, at the end of the
83 function we check whether the gc was already running, and mark the ExecutableCompilationUnit. This
84 ensures that all the newly allocated objects of the compilation unit will be marked in turn.
85 If the gc was not running, we don't have to do anything, because everything will be marked when the
86 gc starts marking the root set at the start of a run.
87 */
90
96 for (uint i = 0; i < stringCount; ++i)
98
100 = new QV4::Value[data->regexpTableSize];
101 for (uint i = 0; i < data->regexpTableSize; ++i) {
102 const CompiledData::RegExp *re = data->regexpAt(i);
103 uint f = re->flags();
104 const CompiledData::RegExp::Flags flags = static_cast<CompiledData::RegExp::Flags>(f);
107 }
108
109 if (data->lookupTableSize) {
113 for (uint i = 0; i < data->lookupTableSize; ++i) {
115
120 else if (type == CompiledData::Lookup::Type_Setter)
128 }
129 }
130
131 if (data->jsClassTableSize) {
134 sizeof(QV4::Heap::InternalClass *));
135
136 for (uint i = 0; i < data->jsClassTableSize; ++i) {
137 int memberCount = 0;
142 for (int j = 0; j < memberCount; ++j, ++member)
149 : QV4::Attr_Data);
150 }
151 }
152
153 const auto validateCULookupSignatures = [&]() -> bool {
155 return true;
157 return true; // Non-existent code can't be invalid
158
159 Q_ASSERT(data->version >= 0x4d); // Otherwise validateLookupSignatures is uninitialized
161 bool valid = v && v(engine->qmlEngine(), m_compilationUnit.data());
162
163 if (!valid && qv4FailOnInvalidAot()) {
164 // The compile time and run time AOT lookup signatures don't match. A rebuild is needed.
165 qFatal("AOT lookup signatures validation failed for file %s. A rebuild is needed. %s",
166 fileName().toUtf8().constData(), "[QV4_FAIL_ON_INVALID_AOT]");
167 }
168 return valid;
169 };
170
172 static const bool staticIgnoreAotCompiledFunctions
173 = qEnvironmentVariableIsSet("QV4_FORCE_INTERPRETER")
175
178
181
182 auto advanceAotFunction = [&](int i) -> const QQmlPrivate::AOTCompiledFunction * {
183 if (aotFunction) {
186 return aotFunction++;
187 } else {
188 aotFunction = nullptr;
189 }
190 }
191 return nullptr;
192 };
193
194 for (int i = 0 ;i < runtimeFunctions.size(); ++i) {
198 }
199
202
204 for (int i = 0 ;i < runtimeBlocks.size(); ++i) {
207
208 // first locals
210 for (quint32 j = 0; j < compiledBlock->nLocals; ++j)
211 ic = ic->addMember(
214 runtimeBlocks[i] = ic->d();
215 }
216
217 static const bool showCode = qEnvironmentVariableIsSet("QV4_SHOW_BYTECODE");
218 if (showCode) {
219 qDebug() << "=== Constant table";
221 qDebug() << "=== String table";
222 for (uint i = 0, end = totalStringCount(); i < end; ++i)
223 qDebug() << " " << i << ":" << runtimeStrings[i]->toQString();
224 qDebug() << "=== Closure table";
225 for (uint i = 0; i < data->functionTableSize; ++i)
226 qDebug() << " " << i << ":" << runtimeFunctions[i]->name()->toQString();
227 qDebug() << "root function at index "
228 << (data->indexOfRootFunction != -1
230 }
231}
232
266
268{
269 delete [] imports;
270 imports = nullptr;
271
272 if (runtimeLookups) {
274 for (uint i = 0; i < lookupTableSize; ++i)
276 }
277
278 delete [] runtimeLookups;
279 runtimeLookups = nullptr;
280
282 f->destroy();
284
286 runtimeStrings = nullptr;
290 runtimeClasses = nullptr;
291
295}
296
298{
300
301 if (runtimeStrings) {
302 for (uint i = 0, end = totalStringCount(); i < end; ++i)
303 if (runtimeStrings[i])
305 }
307 for (uint i = 0; i < data->regexpTableSize; ++i)
309 }
310 if (runtimeClasses) {
311 for (uint i = 0; i < data->jsClassTableSize; ++i)
312 if (runtimeClasses[i])
314 }
316 if (f && f->internalClass)
319 if (c)
320 c->mark(markStack);
321
323 if (o)
324 o->mark(markStack);
325
326 if (runtimeLookups) {
327 for (uint i = 0; i < data->lookupTableSize; ++i)
329 }
330
332 v->mark(markStack);
333}
334
336{
343 }
346}
347
350{
355 return result;
356}
357
359{
361
362 if (isESModule() && module())
363 return module();
364
365 if (data->indexOfRootFunction < 0)
366 return nullptr;
367
369 if (!runtimeStrings)
370 populate();
371
374
375 if (isESModule())
376 setModule(module->d());
377
378 for (uint i = 0, end = data->moduleRequestTableSize; i < end; ++i) {
380 if (engine->hasException)
381 return nullptr;
384 }
385
387
389 if (importCount > 0) {
390 imports = new const StaticValue *[importCount];
391 memset(imports, 0, importCount * sizeof(StaticValue *));
392 }
393 for (uint i = 0; i < importCount; ++i) {
396
397 if (const auto module = dependentModule(urlAt(entry.moduleRequest))) {
399 if (!valuePtr) {
400 QString referenceErrorMessage = QStringLiteral("Unable to resolve import reference ");
406 return nullptr;
407 }
408 imports[i] = valuePtr;
409 }
410 }
411
412 const auto throwReferenceError = [&](const CompiledData::ExportEntry &entry, const QString &importName) {
413 QString referenceErrorMessage = QStringLiteral("Unable to resolve re-export reference ");
418 };
419
420 for (uint i = 0; i < data->indirectExportEntryTableSize; ++i) {
426 return nullptr;
427 }
428 }
429 }
430
431 return module->d();
432}
433
436{
437 if (!module())
438 return nullptr;
439
440 for (const auto &entry: std::as_const(*resolveSet)) {
442 return nullptr;
443 }
444
446
447 if (exportName->toQString() == QLatin1String("*"))
448 return &module()->self;
449
451
452 Q_ASSERT(data);
454
456
461 if (index == UINT_MAX)
462 return nullptr;
463 if (index >= module()->scope->locals.size)
464 return &(imports[index - module()->scope->locals.size]->asValue<Value>());
465 return &module()->scope->locals[index];
466 }
467
473 }
474 return nullptr;
475 }
476
477 if (exportName->toQString() == QLatin1String("default"))
478 return nullptr;
479
480 const Value *starResolution = nullptr;
481
482 for (uint i = 0; i < data->starExportEntryTableSize; ++i) {
484 const Value *resolution = nullptr;
487
488 // ### handle ambiguous
489 if (resolution) {
490 if (!starResolution) {
492 continue;
493 }
495 return nullptr;
496 }
497 }
498
499 return starResolution;
500}
501
504{
507 return stringAt(lhs.exportName) < name->toQString();
508 });
510 return nullptr;
511 return matchingExport;
512}
513
516 bool includeDefaultExport) const
517{
518 if (exportNameSet->contains(this))
519 return;
520 exportNameSet->append(this);
521
522 const auto append = [names, includeDefaultExport](const QString &name) {
523 if (!includeDefaultExport && name == QLatin1String("default"))
524 return;
525 names->append(name);
526 };
527
529
530 Q_ASSERT(data);
532
533 for (uint i = 0; i < data->localExportEntryTableSize; ++i) {
536 }
537
538 for (uint i = 0; i < data->indirectExportEntryTableSize; ++i) {
541 }
542
543 for (uint i = 0; i < data->starExportEntryTableSize; ++i) {
547 names, exportNameSet, /*includeDefaultExport*/false);
548 }
549 }
550}
551
560
562{
564
565 const CompiledData::Unit *data = unitData();
566 for (uint i = 0, end = data->moduleRequestTableSize; i < end; ++i) {
568
569 if (engine->hasException)
570 return;
571
573 module->evaluate();
574 if (engine->hasException)
575 return;
576 }
577}
578
580{
581#if QT_CONFIG(translation)
582 using namespace CompiledData;
583 bool byId = false;
584 switch (binding->type()) {
586 byId = true;
590 }
591 default:
592 break;
593 }
594#endif
596}
597
599{
600#if !QT_CONFIG(translation)
601 return QString();
602#else
604
605 if (index.byId) {
608 }
609
610 const auto fileContext = [this]() {
611 // This code must match that in the qsTr() implementation
612 const QString &path = fileName();
614
616 ? QStringView{ path }.mid(lastSlash + 1, path.size() - lastSlash - 5)
617 : QStringView();
618 return context.toUtf8();
619 };
620
621 const bool hasContext
624 if (hasContext) {
626 } else {
630 }
631
635#endif
636}
637
639{
640 if (const Module *m = m_valueOrModule.as<QV4::Module>())
641 return m->d();
642 return nullptr;
643}
644
646{
647 // We don't necessarily hold any other references to ES modules. So, if the GC
648 // is running right now, we need to mark it. Otherwise it might collect it even
649 // though it's still reachable via the engine's list of compilation units.
651 if constexpr (QV4::WriteBarrier::isInsertionBarrier) {
652 module->mark(stack);
653 }
654 });
656}
657
658} // namespace QV4
659
660QT_END_NAMESPACE
Combined button and popup list for selecting options.
Definition qjsvalue.h:24
static void dumpConstantTable(const StaticValue *constants, uint count)
static QString toString(QV4::ReturnedValue v)