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
32namespace QV4 {
33
35
39{
41}
42
44{
45 if (engine)
46 clear();
47}
48
49static QString toString(QV4::ReturnedValue v)
50{
51 Value val = Value::fromReturnedValue(v);
52 QString result;
53 if (val.isInt32())
54 result = QLatin1String("int ");
55 else if (val.isDouble())
56 result = QLatin1String("double ");
57 if (val.isEmpty())
58 result += QLatin1String("empty");
59 else
60 result += val.toQStringNoThrow();
61 return result;
62}
63
64static void dumpConstantTable(const StaticValue *constants, uint count)
65{
66 QDebug d = qDebug();
67 d.nospace() << Qt::right;
68 for (uint i = 0; i < count; ++i) {
69 d << qSetFieldWidth(8) << i << qSetFieldWidth(0) << ": "
70 << toString(constants[i].asReturnedValue()).toUtf8().constData() << "\n";
71 }
72}
73
75{
76 /* In general, we should use QV4::Scope whenever we allocate heap objects, and employ write barriers
77 for member variables pointing to heap objects. However, ExecutableCompilationUnit is special, as it
78 is always part of the root set. So instead of using scoped allocations and write barriers, we use a
79 slightly different approach: We temporarily block the gc from running. Afterwards, at the end of the
80 function we check whether the gc was already running, and mark the ExecutableCompilationUnit. This
81 ensures that all the newly allocated objects of the compilation unit will be marked in turn.
82 If the gc was not running, we don't have to do anything, because everything will be marked when the
83 gc starts marking the root set at the start of a run.
84 */
87
93 for (uint i = 0; i < stringCount; ++i)
95
98 for (uint i = 0; i < data->regexpTableSize; ++i) {
99 const CompiledData::RegExp *re = data->regexpAt(i);
100 uint f = re->flags();
101 const CompiledData::RegExp::Flags flags = static_cast<CompiledData::RegExp::Flags>(f);
104 }
105
106 if (data->lookupTableSize) {
110 for (uint i = 0; i < data->lookupTableSize; ++i) {
112
117 else if (type == CompiledData::Lookup::Type_Setter)
125 }
126 }
127
128 if (data->jsClassTableSize) {
131 sizeof(QV4::Heap::InternalClass *));
132
133 for (uint i = 0; i < data->jsClassTableSize; ++i) {
134 int memberCount = 0;
139 for (int j = 0; j < memberCount; ++j, ++member)
146 : QV4::Attr_Data);
147 }
148 }
149
152 = qEnvironmentVariableIsSet("QV4_FORCE_INTERPRETER")
154
157
158 auto advanceAotFunction = [&](int i) -> const QQmlPrivate::AOTCompiledFunction * {
159 if (aotFunction) {
162 return aotFunction++;
163 } else {
164 aotFunction = nullptr;
165 }
166 }
167 return nullptr;
168 };
169
170 for (int i = 0 ;i < runtimeFunctions.size(); ++i) {
174 }
175
178
180 for (int i = 0 ;i < runtimeBlocks.size(); ++i) {
183
184 // first locals
186 for (quint32 j = 0; j < compiledBlock->nLocals; ++j)
187 ic = ic->addMember(
190 runtimeBlocks[i] = ic->d();
191 }
192
193 static const bool showCode = qEnvironmentVariableIsSet("QV4_SHOW_BYTECODE");
194 if (showCode) {
195 qDebug() << "=== Constant table";
197 qDebug() << "=== String table";
198 for (uint i = 0, end = totalStringCount(); i < end; ++i)
199 qDebug() << " " << i << ":" << runtimeStrings[i]->toQString();
200 qDebug() << "=== Closure table";
201 for (uint i = 0; i < data->functionTableSize; ++i)
202 qDebug() << " " << i << ":" << runtimeFunctions[i]->name()->toQString();
203 qDebug() << "root function at index "
204 << (data->indexOfRootFunction != -1
206 }
207}
208
242
244{
245 delete [] imports;
246 imports = nullptr;
247
248 if (runtimeLookups) {
250 for (uint i = 0; i < lookupTableSize; ++i)
252 }
253
254 delete [] runtimeLookups;
255 runtimeLookups = nullptr;
256
258 f->destroy();
260
262 runtimeStrings = nullptr;
266 runtimeClasses = nullptr;
267
271}
272
274{
276
277 if (runtimeStrings) {
278 for (uint i = 0, end = totalStringCount(); i < end; ++i)
279 if (runtimeStrings[i])
281 }
283 for (uint i = 0; i < data->regexpTableSize; ++i)
285 }
286 if (runtimeClasses) {
287 for (uint i = 0; i < data->jsClassTableSize; ++i)
288 if (runtimeClasses[i])
290 }
292 if (f && f->internalClass)
295 if (c)
296 c->mark(markStack);
297
299 if (o)
300 o->mark(markStack);
301
302 if (runtimeLookups) {
303 for (uint i = 0; i < data->lookupTableSize; ++i)
305 }
306
308 v->mark(markStack);
309}
310
312{
319 }
322}
323
326{
331 return result;
332}
333
335{
337
338 if (isESModule() && module())
339 return module();
340
341 if (data->indexOfRootFunction < 0)
342 return nullptr;
343
345 if (!runtimeStrings)
346 populate();
347
350
351 if (isESModule())
352 setModule(module->d());
353
354 for (uint i = 0, end = data->moduleRequestTableSize; i < end; ++i) {
356 if (engine->hasException)
357 return nullptr;
360 }
361
363
365 if (importCount > 0) {
366 imports = new const StaticValue *[importCount];
367 memset(imports, 0, importCount * sizeof(StaticValue *));
368 }
369 for (uint i = 0; i < importCount; ++i) {
372
373 if (const auto module = dependentModule(urlAt(entry.moduleRequest))) {
375 if (!valuePtr) {
376 QString referenceErrorMessage = QStringLiteral("Unable to resolve import reference ");
382 return nullptr;
383 }
384 imports[i] = valuePtr;
385 }
386 }
387
388 const auto throwReferenceError = [&](const CompiledData::ExportEntry &entry, const QString &importName) {
389 QString referenceErrorMessage = QStringLiteral("Unable to resolve re-export reference ");
394 };
395
396 for (uint i = 0; i < data->indirectExportEntryTableSize; ++i) {
402 return nullptr;
403 }
404 }
405 }
406
407 return module->d();
408}
409
412{
413 if (!module())
414 return nullptr;
415
416 for (const auto &entry: std::as_const(*resolveSet)) {
418 return nullptr;
419 }
420
422
423 if (exportName->toQString() == QLatin1String("*"))
424 return &module()->self;
425
427
428 Q_ASSERT(data);
430
432
437 if (index == UINT_MAX)
438 return nullptr;
439 if (index >= module()->scope->locals.size)
440 return &(imports[index - module()->scope->locals.size]->asValue<Value>());
441 return &module()->scope->locals[index];
442 }
443
449 }
450 return nullptr;
451 }
452
453 if (exportName->toQString() == QLatin1String("default"))
454 return nullptr;
455
456 const Value *starResolution = nullptr;
457
458 for (uint i = 0; i < data->starExportEntryTableSize; ++i) {
460 const Value *resolution = nullptr;
463
464 // ### handle ambiguous
465 if (resolution) {
466 if (!starResolution) {
468 continue;
469 }
471 return nullptr;
472 }
473 }
474
475 return starResolution;
476}
477
480{
483 return stringAt(lhs.exportName) < name->toQString();
484 });
486 return nullptr;
487 return matchingExport;
488}
489
492 bool includeDefaultExport) const
493{
494 if (exportNameSet->contains(this))
495 return;
496 exportNameSet->append(this);
497
498 const auto append = [names, includeDefaultExport](const QString &name) {
499 if (!includeDefaultExport && name == QLatin1String("default"))
500 return;
501 names->append(name);
502 };
503
505
506 Q_ASSERT(data);
508
509 for (uint i = 0; i < data->localExportEntryTableSize; ++i) {
512 }
513
514 for (uint i = 0; i < data->indirectExportEntryTableSize; ++i) {
517 }
518
519 for (uint i = 0; i < data->starExportEntryTableSize; ++i) {
523 names, exportNameSet, /*includeDefaultExport*/false);
524 }
525 }
526}
527
536
538{
540
541 const CompiledData::Unit *data = unitData();
542 for (uint i = 0, end = data->moduleRequestTableSize; i < end; ++i) {
544
545 if (engine->hasException)
546 return;
547
549 module->evaluate();
550 if (engine->hasException)
551 return;
552 }
553}
554
556{
557#if QT_CONFIG(translation)
558 using namespace CompiledData;
559 bool byId = false;
560 switch (binding->type()) {
562 byId = true;
566 }
567 default:
568 break;
569 }
570#endif
572}
573
575{
576#if !QT_CONFIG(translation)
577 return QString();
578#else
580
581 if (index.byId) {
584 }
585
586 const auto fileContext = [this]() {
587 // This code must match that in the qsTr() implementation
588 const QString &path = fileName();
590
592 ? QStringView{ path }.mid(lastSlash + 1, path.size() - lastSlash - 5)
593 : QStringView();
594 return context.toUtf8();
595 };
596
597 const bool hasContext
600 if (hasContext) {
602 } else {
606 }
607
611#endif
612}
613
615{
616 if (const Module *m = m_valueOrModule.as<QV4::Module>())
617 return m->d();
618 return nullptr;
619}
620
622{
623 // We don't necessarily hold any other references to ES modules. So, if the GC
624 // is running right now, we need to mark it. Otherwise it might collect it even
625 // though it's still reachable via the engine's list of compilation units.
627 if constexpr (QV4::WriteBarrier::isInsertionBarrier) {
628 module->mark(stack);
629 }
630 });
632}
633
634} // namespace QV4
635
636QT_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)