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{
344 }
347}
348
351{
356 return result;
357}
358
360{
362
363 if (isESModule() && module())
364 return module();
365
366 if (data->indexOfRootFunction < 0)
367 return nullptr;
368
370 if (!runtimeStrings)
371 populate();
372
375
376 if (isESModule())
377 setModule(module->d());
378
379 for (uint i = 0, end = data->moduleRequestTableSize; i < end; ++i) {
381 if (engine->hasException)
382 return nullptr;
385 }
386
388
390 if (importCount > 0) {
391 imports = new const StaticValue *[importCount];
392 memset(imports, 0, importCount * sizeof(StaticValue *));
393 }
394 for (uint i = 0; i < importCount; ++i) {
397
398 if (const auto module = dependentModule(urlAt(entry.moduleRequest))) {
400 if (!valuePtr) {
401 QString referenceErrorMessage = QStringLiteral("Unable to resolve import reference ");
407 return nullptr;
408 }
409 imports[i] = valuePtr;
410 }
411 }
412
413 const auto throwReferenceError = [&](const CompiledData::ExportEntry &entry, const QString &importName) {
414 QString referenceErrorMessage = QStringLiteral("Unable to resolve re-export reference ");
419 };
420
421 for (uint i = 0; i < data->indirectExportEntryTableSize; ++i) {
427 return nullptr;
428 }
429 }
430 }
431
432 return module->d();
433}
434
437{
438 if (!module())
439 return nullptr;
440
441 for (const auto &entry: std::as_const(*resolveSet)) {
443 return nullptr;
444 }
445
447
448 if (exportName->toQString() == QLatin1String("*"))
449 return &module()->self;
450
452
453 Q_ASSERT(data);
455
457
462 if (index == UINT_MAX)
463 return nullptr;
464 if (index >= module()->scope->locals.size)
465 return &(imports[index - module()->scope->locals.size]->asValue<Value>());
466 return &module()->scope->locals[index];
467 }
468
474 }
475 return nullptr;
476 }
477
478 if (exportName->toQString() == QLatin1String("default"))
479 return nullptr;
480
481 const Value *starResolution = nullptr;
482
483 for (uint i = 0; i < data->starExportEntryTableSize; ++i) {
485 const Value *resolution = nullptr;
488
489 // ### handle ambiguous
490 if (resolution) {
491 if (!starResolution) {
493 continue;
494 }
496 return nullptr;
497 }
498 }
499
500 return starResolution;
501}
502
505{
508 return stringAt(lhs.exportName) < name->toQString();
509 });
511 return nullptr;
512 return matchingExport;
513}
514
517 bool includeDefaultExport) const
518{
519 if (exportNameSet->contains(this))
520 return;
521 exportNameSet->append(this);
522
523 const auto append = [names, includeDefaultExport](const QString &name) {
524 if (!includeDefaultExport && name == QLatin1String("default"))
525 return;
526 names->append(name);
527 };
528
530
531 Q_ASSERT(data);
533
534 for (uint i = 0; i < data->localExportEntryTableSize; ++i) {
537 }
538
539 for (uint i = 0; i < data->indirectExportEntryTableSize; ++i) {
542 }
543
544 for (uint i = 0; i < data->starExportEntryTableSize; ++i) {
548 names, exportNameSet, /*includeDefaultExport*/false);
549 }
550 }
551}
552
561
563{
565
566 const CompiledData::Unit *data = unitData();
567 for (uint i = 0, end = data->moduleRequestTableSize; i < end; ++i) {
569
570 if (engine->hasException)
571 return;
572
574 module->evaluate();
575 if (engine->hasException)
576 return;
577 }
578}
579
581{
582#if QT_CONFIG(translation)
583 using namespace CompiledData;
584 bool byId = false;
585 switch (binding->type()) {
587 byId = true;
591 }
592 default:
593 break;
594 }
595#endif
597}
598
600{
601#if !QT_CONFIG(translation)
602 return QString();
603#else
605
606 if (index.byId) {
609 }
610
611 const auto fileContext = [this]() {
612 // This code must match that in the qsTr() implementation
613 const QString &path = fileName();
615
617 ? QStringView{ path }.mid(lastSlash + 1, path.size() - lastSlash - 5)
618 : QStringView();
619 return context.toUtf8();
620 };
621
622 const bool hasContext
625 if (hasContext) {
627 } else {
631 }
632
636#endif
637}
638
640{
641 if (const Module *m = m_valueOrModule.as<QV4::Module>())
642 return m->d();
643 return nullptr;
644}
645
647{
648 // We don't necessarily hold any other references to ES modules. So, if the GC
649 // is running right now, we need to mark it. Otherwise it might collect it even
650 // though it's still reachable via the engine's list of compilation units.
652 if constexpr (QV4::WriteBarrier::isInsertionBarrier) {
653 module->mark(stack);
654 }
655 });
657}
658
659} // namespace QV4
660
661QT_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)