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
qv4engine.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 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 "qv4engine_p.h"
6
7#include <wtf/BumpPointerAllocator.h>
8#include <wtf/OSAllocator.h>
9#include <wtf/PageAllocation.h>
10
11#include <private/qjsvalue_p.h>
12#include <private/qqmlbuiltinfunctions_p.h>
13#include <private/qqmlengine_p.h>
14#include <private/qqmljsdiagnosticmessage_p.h>
15#include <private/qqmllist_p.h>
16#include <private/qqmllistwrapper_p.h>
17#include <private/qqmlscriptblob_p.h>
18#include <private/qqmlscriptdata_p.h>
19#include <private/qqmltypeloader_p.h>
20#include <private/qqmltypewrapper_p.h>
21#include <private/qqmlvaluetype_p.h>
22#include <private/qqmlvaluetypewrapper_p.h>
23#include <private/qv4argumentsobject_p.h>
24#include <private/qv4arraybuffer_p.h>
25#include <private/qv4arrayiterator_p.h>
26#include <private/qv4arrayobject_p.h>
27#include <private/qv4atomics_p.h>
28#include <private/qv4booleanobject_p.h>
29#include <private/qv4codegen_p.h>
30#include <private/qv4compileddata_p.h>
31#include <private/qv4dataview_p.h>
32#include <private/qv4dateobject_p.h>
33#include <private/qv4debugging_p.h>
34#include <private/qv4errorobject_p.h>
35#include <private/qv4executableallocator_p.h>
36#include <private/qv4function_p.h>
37#include <private/qv4functionobject_p.h>
38#include <private/qv4generatorobject_p.h>
39#include <private/qv4globalobject_p.h>
40#include <private/qv4identifiertable_p.h>
41#include <private/qv4iterator_p.h>
42#include <private/qv4jsonobject_p.h>
43#include <private/qv4mapiterator_p.h>
44#include <private/qv4mapobject_p.h>
45#include <private/qv4mathobject_p.h>
46#include <private/qv4memberdata_p.h>
47#include <private/qv4mm_p.h>
48#include <private/qv4module_p.h>
49#include <private/qv4numberobject_p.h>
50#include <private/qv4object_p.h>
51#include <private/qv4objectiterator_p.h>
52#include <private/qv4objectproto_p.h>
53#include <private/qv4profiling_p.h>
54#include <private/qv4promiseobject_p.h>
55#include <private/qv4proxy_p.h>
56#include <private/qv4qmetaobjectwrapper_p.h>
57#include <private/qv4qmlcontext_p.h>
58#include <private/qv4qobjectwrapper_p.h>
59#include <private/qv4reflect_p.h>
60#include <private/qv4regexp_p.h>
61#include <private/qv4regexpobject_p.h>
62#include <private/qv4runtime_p.h>
63#include <private/qv4sequenceobject_p.h>
64#include <private/qv4setiterator_p.h>
65#include <private/qv4setobject_p.h>
66#include <private/qv4sqlerrors_p.h>
67#include <private/qv4stackframe_p.h>
68#include <private/qv4stacklimits_p.h>
69#include <private/qv4stringiterator_p.h>
70#include <private/qv4stringobject_p.h>
71#include <private/qv4symbol_p.h>
72#include <private/qv4typedarray_p.h>
73#include <private/qv4urlobject_p.h>
74#include <private/qv4value_p.h>
75#include <private/qv4variantassociationobject_p.h>
76#include <private/qv4variantobject_p.h>
77
78#include <QtQml/qqmlfile.h>
79
80#include <QtCore/qdatetime.h>
81#include <QtCore/qdir.h>
82#include <QtCore/qfileinfo.h>
83#include <QtCore/qiterable.h>
84#include <QtCore/qloggingcategory.h>
85#include <QtCore/qmetatype.h>
86#include <QtCore/qmetasequence.h>
87#include <QtCore/qtextstream.h>
88#include <QtCore/qtimezone.h>
89
90#if QT_CONFIG(regularexpression)
91#include <QtCore/qregularexpression.h>
92#endif
93#if QT_CONFIG(qml_locale)
94#include <private/qqmllocale_p.h>
95#endif
96#if QT_CONFIG(qml_xml_http_request)
97#include <private/qv4domerrors_p.h>
98#include <private/qqmlxmlhttprequest_p.h>
99#endif
100#ifdef V4_USE_VALGRIND
101#include <valgrind/memcheck.h>
102#endif
103
105
106DEFINE_BOOL_CONFIG_OPTION(disableDiskCache, QML_DISABLE_DISK_CACHE);
108
109using namespace QV4;
110
111// While engineSerial is odd the statics haven't been initialized. The engine that receives ID 1
112// initializes the statics and sets engineSerial to 2 afterwards.
113// Each engine does engineSerial.fetchAndAddOrdered(2) on creation. Therefore engineSerial stays
114// odd while the statics are being initialized, and stays even afterwards.
115// Any further engines created while the statics are being initialized busy-wait until engineSerial
116// is even.
117Q_CONSTINIT static QBasicAtomicInt engineSerial = Q_BASIC_ATOMIC_INITIALIZER(1);
118Q_CONSTINIT static QBasicAtomicInt hasPreview = Q_BASIC_ATOMIC_INITIALIZER(0);
119int ExecutionEngine::s_maxCallDepth = -1;
120int ExecutionEngine::s_jitCallCountThreshold = 3;
121int ExecutionEngine::s_maxJSStackSize = 4 * 1024 * 1024;
122int ExecutionEngine::s_maxGCStackSize = 2 * 1024 * 1024;
123int ExecutionEngine::s_stackSizeSoftLimit = -1;
124
125ReturnedValue throwTypeError(const FunctionObject *b, const QV4::Value *, const QV4::Value *, int)
126{
127 return b->engine()->throwTypeError();
128}
129
130
131template <typename ReturnType>
132ReturnType convertJSValueToVariantType(const QJSValue &value)
133{
134 const QVariant variant = value.toVariant();
135 return variant.metaType() == QMetaType::fromType<QJSValue>()
136 ? ReturnType()
137 : variant.value<ReturnType>();
138}
139
144
145namespace {
146void createNewIteratorIfNonExisting(void **iterator) {
147 if (*iterator == nullptr)
148 *iterator = new JSArrayIterator;
149}
150}
151
153{
154 // set up some functions so that non-array QMetaSequence::Iterables do not crash
155 // but instead appear as an empty sequence
156
157 using namespace QtMetaContainerPrivate;
158 QMetaSequenceInterface iface;
159 iface.sizeFn = [](const void *) { return qsizetype(0); };
160 iface.valueAtIndexFn = [](const void *, qsizetype, void *) {};
161 iface.createIteratorFn = [](void *, QMetaSequenceInterface::Position) -> void * {
162 return nullptr;
163 };
164 iface.advanceIteratorFn = [](void *, qsizetype) {};
165 iface.compareIteratorFn = [](const void *, const void *) {
166 return true; /*all iterators are nullptr*/
167 };
168 iface.destroyIteratorFn = [](const void *) {};
169 iface.copyIteratorFn = [](void *, const void *) {};
170 iface.diffIteratorFn = [](const void *, const void *) { return qsizetype(0); };
171
172 iface.createConstIteratorFn = [](const void *, QMetaSequenceInterface::Position) -> void * {
173 return nullptr;
174 };
175 iface.advanceConstIteratorFn = [](void *, qsizetype) {};
176 iface.compareConstIteratorFn = [](const void *, const void *) {
177 return true; /*all iterators are nullptr*/
178 };
179 iface.destroyConstIteratorFn = [](const void *) {};
180 iface.copyConstIteratorFn = [](void *, const void *) {};
181 iface.diffConstIteratorFn = [](const void *, const void *) { return qsizetype(0); };
182 return iface;
183}
184
186{
187 using namespace QtMetaContainerPrivate;
188 QMetaSequenceInterface iface;
189 iface.valueMetaType = QtPrivate::qMetaTypeInterfaceForType<QVariant>();
190 iface.iteratorCapabilities = RandomAccessCapability | BiDirectionalCapability | ForwardCapability;
191 iface.addRemoveCapabilities = CanAddAtEnd;
192 iface.sizeFn = [](const void *p) -> qsizetype {
193 return static_cast<QJSValue const *>(p)->property(QString::fromLatin1("length")).toInt();
194 };
195
196 /* Lifetime management notes:
197 * valueAtIndexFn and valueAtIteratorFn return a pointer to a JSValue allocated via
198 * QMetaType::create Because we set QVariantConstructionFlags::ShouldDeleteVariantData,
199 * QMetaSequence::Iterable::at and QMetaSequence::Iterable::operator*() will free that memory
200 */
201
202 iface.valueAtIndexFn = [](const void *iterable, qsizetype index, void *dataPtr) -> void {
203 auto *data = static_cast<QVariant *>(dataPtr);
204 *data = static_cast<QJSValue const *>(iterable)->property(quint32(index)).toVariant();
205 };
206 iface.createIteratorFn = [](void *iterable, QMetaSequenceInterface::Position pos) {
207 void *iterator = nullptr;
208 createNewIteratorIfNonExisting(&iterator);
209 auto jsArrayIterator = static_cast<JSArrayIterator *>(iterator);
210 jsArrayIterator->index = 0;
211 jsArrayIterator->data = reinterpret_cast<QJSValue const*>(iterable);
212 if (pos == QMetaSequenceInterface::AtEnd) {
213 auto length = static_cast<QJSValue const *>(iterable)->property(
214 QString::fromLatin1("length")).toInt();
215 jsArrayIterator->index = quint32(length);
216 }
217 return iterator;
218 };
219 iface.createConstIteratorFn = [](const void *iterable, QMetaSequenceInterface::Position pos) {
220 void *iterator = nullptr;
221 createNewIteratorIfNonExisting(&iterator);
222 auto jsArrayIterator = static_cast<JSArrayIterator *>(iterator);
223 jsArrayIterator->index = 0;
224 jsArrayIterator->data = reinterpret_cast<QJSValue const*>(iterable);
225 if (pos == QMetaSequenceInterface::AtEnd) {
226 auto length = static_cast<QJSValue const *>(iterable)->property(
227 QString::fromLatin1("length")).toInt();
228 jsArrayIterator->index = quint32(length);
229 }
230 return iterator;
231 };
232 iface.advanceIteratorFn = [](void *iterator, qsizetype advanceBy) {
233 static_cast<JSArrayIterator *>(iterator)->index += quint32(advanceBy);
234 };
235 iface.advanceConstIteratorFn = [](void *iterator, qsizetype advanceBy) {
236 static_cast<JSArrayIterator *>(iterator)->index += quint32(advanceBy);
237 };
238 iface.valueAtIteratorFn = [](const void *iterator, void *dataPtr) -> void {
239 const auto *arrayIterator = static_cast<const JSArrayIterator *>(iterator);
240 const QJSValue *jsArray = arrayIterator->data;
241 auto *data = static_cast<QVariant *>(dataPtr);
242 *data = jsArray->property(arrayIterator->index).toVariant();
243 };
244 iface.valueAtConstIteratorFn = [](const void *iterator, void *dataPtr) -> void {
245 const auto *arrayIterator = static_cast<const JSArrayIterator *>(iterator);
246 const QJSValue *jsArray = arrayIterator->data;
247 auto *data = static_cast<QVariant *>(dataPtr);
248 *data = jsArray->property(arrayIterator->index).toVariant();
249 };
250 iface.destroyIteratorFn = [](const void *iterator) {
251 delete static_cast<const JSArrayIterator *>(iterator);
252 };
253 iface.destroyConstIteratorFn = [](const void *iterator) {
254 delete static_cast<const JSArrayIterator *>(iterator);
255 };
256 iface.compareIteratorFn = [](const void *p, const void *other) {
257 auto this_ = static_cast<const JSArrayIterator *>(p);
258 auto that_ = static_cast<const JSArrayIterator *>(other);
259 return this_->index == that_->index && this_->data == that_->data;
260 };
261 iface.compareConstIteratorFn = [](const void *p, const void *other) {
262 auto this_ = static_cast<const JSArrayIterator *>(p);
263 auto that_ = static_cast<const JSArrayIterator *>(other);
264 return this_->index == that_->index && this_->data == that_->data;
265 };
266 iface.copyIteratorFn = [](void *iterator, const void *otherIterator) {
267 auto *otherIter = (static_cast<JSArrayIterator const *>(otherIterator));
268 static_cast<JSArrayIterator *>(iterator)->index = otherIter->index;
269 static_cast<JSArrayIterator *>(iterator)->data = otherIter->data;
270 };
271 iface.copyConstIteratorFn = [](void *iterator, const void *otherIterator) {
272 auto *otherIter = (static_cast<JSArrayIterator const *>(otherIterator));
273 static_cast<JSArrayIterator *>(iterator)->index = otherIter->index;
274 static_cast<JSArrayIterator *>(iterator)->data = otherIter->data;
275 };
276 iface.diffIteratorFn = [](const void *iterator, const void *otherIterator) -> qsizetype {
277 const auto *self = static_cast<const JSArrayIterator *>(iterator);
278 const auto *other = static_cast<const JSArrayIterator *>(otherIterator);
279 return self->index - other->index;
280 };
281 iface.diffConstIteratorFn = [](const void *iterator, const void *otherIterator) -> qsizetype {
282 const auto *self = static_cast<const JSArrayIterator *>(iterator);
283 const auto *other = static_cast<const JSArrayIterator *>(otherIterator);
284 return self->index - other->index;
285 };
286 iface.addValueFn = [](void *iterable, const void *data, QMetaSequenceInterface::Position) {
287 auto *jsvalue = static_cast<QJSValue *>(iterable);
288 QV4::Scope scope(QJSValuePrivate::engine(jsvalue));
289 QV4::ScopedArrayObject a(scope, QJSValuePrivate::asManagedType<QV4::ArrayObject>(jsvalue));
290 QV4::ScopedValue v(scope, scope.engine->fromVariant(*static_cast<const QVariant *>(data)));
291 if (!a)
292 return;
293 int len = a->getLength();
294 a->setIndexed(len, v, QV4::Object::DoNotThrow);
295 };
296 return iface;
297}
298
299static QMetaSequence::Iterable jsvalueToSequence (const QJSValue& value) {
300 using namespace QtMetaTypePrivate;
301 using namespace QtMetaContainerPrivate;
302
303
304 if (!value.isArray()) {
305 static QMetaSequenceInterface emptySequence = emptySequenceInterface();
306 return QMetaSequence::Iterable(QMetaSequence(&emptySequence), nullptr);
307 }
308
309 static QMetaSequenceInterface sequence = sequenceInterface();
310 return QMetaSequence::Iterable(QMetaSequence(&sequence), &value);
311}
312
313void ExecutionEngine::initializeStaticMembers()
314{
315 bool ok = false;
316
317 const int envMaxJSStackSize = qEnvironmentVariableIntValue("QV4_JS_MAX_STACK_SIZE", &ok);
318 if (ok && envMaxJSStackSize > 0)
319 s_maxJSStackSize = envMaxJSStackSize;
320
321 const int envMaxGCStackSize = qEnvironmentVariableIntValue("QV4_GC_MAX_STACK_SIZE", &ok);
322 if (ok && envMaxGCStackSize > 0)
323 s_maxGCStackSize = envMaxGCStackSize;
324
325 const int envStackSizeSoftLimit = qEnvironmentVariableIntValue("QV4_STACK_SOFT_LIMIT", &ok);
326 if (ok && envStackSizeSoftLimit > -1)
327 s_stackSizeSoftLimit = envStackSizeSoftLimit;
328 else
329 s_stackSizeSoftLimit = -1;
330
331 if (qEnvironmentVariableIsSet("QV4_CRASH_ON_STACKOVERFLOW")) {
332 s_maxCallDepth = std::numeric_limits<qint32>::max();
333 } else {
334 ok = false;
335 s_maxCallDepth = qEnvironmentVariableIntValue("QV4_MAX_CALL_DEPTH", &ok);
336 if (!ok || s_maxCallDepth <= 0)
337 s_maxCallDepth = -1;
338 }
339
340 ok = false;
341 s_jitCallCountThreshold = qEnvironmentVariableIntValue("QV4_JIT_CALL_THRESHOLD", &ok);
342 if (!ok)
343 s_jitCallCountThreshold = 3;
344 if (qEnvironmentVariableIsSet("QV4_FORCE_INTERPRETER"))
345 s_jitCallCountThreshold = std::numeric_limits<int>::max();
346
347 qMetaTypeId<QJSValue>();
348 qMetaTypeId<QList<int> >();
349
350 if (!QMetaType::hasRegisteredConverterFunction<QJSValue, QVariantMap>())
351 QMetaType::registerConverter<QJSValue, QVariantMap>(convertJSValueToVariantType<QVariantMap>);
352 if (!QMetaType::hasRegisteredConverterFunction<QJSValue, QVariantHash>())
353 QMetaType::registerConverter<QJSValue, QVariantHash>(convertJSValueToVariantType<QVariantHash>);
354 if (!QMetaType::hasRegisteredConverterFunction<QJSValue, QVariantList>())
355 QMetaType::registerConverter<QJSValue, QVariantList>(convertJSValueToVariantType<QVariantList>);
356 if (!QMetaType::hasRegisteredConverterFunction<QJSValue, QStringList>())
357 QMetaType::registerConverter<QJSValue, QStringList>(convertJSValueToVariantType<QStringList>);
358 if (!QMetaType::hasRegisteredConverterFunction<QJSValue, QMetaSequence::Iterable>())
359 QMetaType::registerConverter<QJSValue, QMetaSequence::Iterable>(jsvalueToSequence);
360}
361
362/*!
363 \class QV4::ExecutionEngine
364 \inmodule QtQml
365 \internal
366*/
367ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
368 : executableAllocator(new QV4::ExecutableAllocator)
369 , regExpAllocator(new QV4::ExecutableAllocator)
370 , bumperPointerAllocator(new WTF::BumpPointerAllocator)
371 , jsStack(new WTF::PageAllocation)
372 , gcStack(new WTF::PageAllocation)
373 , publicEngine(jsEngine)
374 , m_engineId(engineSerial.fetchAndAddOrdered(2))
375#if QT_CONFIG(qml_jit)
376 , m_canAllocateExecutableMemory(OSAllocator::canAllocateExecutableMemory())
377#endif
378{
379 if (m_engineId == 1) {
380 initializeStaticMembers();
381 engineSerial.storeRelease(2); // make it even
382 } else if (Q_UNLIKELY(m_engineId & 1)) {
383 // This should be rare. You usually don't create lots of engines at the same time.
384 while (engineSerial.loadAcquire() & 1) {
385 QThread::yieldCurrentThread();
386 }
387 }
388
389 if (s_maxCallDepth < 0)
390 setCppStackProperties();
391 else
392 callDepth = 0;
393
394 // We allocate guard pages around our stacks.
395 const size_t guardPages = 2 * WTF::pageSize();
396
397 memoryManager = new QV4::MemoryManager(this);
398 // we don't want to run the gc while the initial setup is not done; not even in aggressive mode
399 GCCriticalSection gcCriticalSection(this);
400 // reserve space for the JS stack
401 // we allow it to grow to a bit more than m_maxJSStackSize, as we can overshoot due to ScopedValues
402 // allocated outside of JIT'ed methods.
403 *jsStack = WTF::PageAllocation::allocate(
404 s_maxJSStackSize + 256*1024 + guardPages, WTF::OSAllocator::JSVMStackPages,
405 /* writable */ true, /* executable */ false, /* includesGuardPages */ true);
406 jsStackBase = (Value *)jsStack->base();
407#ifdef V4_USE_VALGRIND
408 VALGRIND_MAKE_MEM_UNDEFINED(jsStackBase, s_maxJSStackSize + 256*1024);
409#endif
410
411 jsStackTop = jsStackBase;
412
413 *gcStack = WTF::PageAllocation::allocate(
414 s_maxGCStackSize + guardPages, WTF::OSAllocator::JSVMStackPages,
415 /* writable */ true, /* executable */ false, /* includesGuardPages */ true);
416
417 exceptionValue = jsAlloca(1);
418 *exceptionValue = Encode::undefined();
419 globalObject = static_cast<Object *>(jsAlloca(1));
420 jsObjects = jsAlloca(NJSObjects);
421 typedArrayPrototype = static_cast<Object *>(jsAlloca(NTypedArrayTypes));
422 typedArrayCtors = static_cast<FunctionObject *>(jsAlloca(NTypedArrayTypes));
423 jsStrings = jsAlloca(NJSStrings);
424 jsSymbols = jsAlloca(NJSSymbols);
425
426 // set up stack limits
427 jsStackLimit = jsStackBase + s_maxJSStackSize/sizeof(Value);
428
429 identifierTable = new IdentifierTable(this);
430
431 memset(classes, 0, sizeof(classes));
432 classes[Class_Empty] = memoryManager->allocIC<InternalClass>();
433 classes[Class_Empty]->init(this);
434
435 classes[Class_MemberData] = classes[Class_Empty]->changeVTable(QV4::MemberData::staticVTable());
436 classes[Class_SimpleArrayData] = classes[Class_Empty]->changeVTable(QV4::SimpleArrayData::staticVTable());
437 classes[Class_SparseArrayData] = classes[Class_Empty]->changeVTable(QV4::SparseArrayData::staticVTable());
438 classes[Class_ExecutionContext] = classes[Class_Empty]->changeVTable(QV4::ExecutionContext::staticVTable());
439 classes[Class_CallContext] = classes[Class_Empty]->changeVTable(QV4::CallContext::staticVTable());
440 classes[Class_QmlContext] = classes[Class_Empty]->changeVTable(QV4::QmlContext::staticVTable());
441
442 Scope scope(this);
443 Scoped<InternalClass> ic(scope);
444 ic = classes[Class_Empty]->changeVTable(QV4::Object::staticVTable());
445 jsObjects[ObjectProto] = memoryManager->allocObject<ObjectPrototype>(ic->d());
446 classes[Class_Object] = ic->changePrototype(objectPrototype()->d());
447 classes[Class_QmlContextWrapper] = classes[Class_Object]->changeVTable(QV4::QQmlContextWrapper::staticVTable());
448
449 ic = newInternalClass(QV4::StringObject::staticVTable(), objectPrototype());
450 jsObjects[StringProto] = memoryManager->allocObject<StringPrototype>(ic->d(), /*init =*/ false);
451 classes[Class_String] = classes[Class_Empty]->changeVTable(QV4::String::staticVTable())->changePrototype(stringPrototype()->d());
452 Q_ASSERT(stringPrototype()->d() && classes[Class_String]->prototype);
453
454 jsObjects[SymbolProto] = memoryManager->allocate<SymbolPrototype>();
455 classes[Class_Symbol] = classes[EngineBase::Class_Empty]->changeVTable(QV4::Symbol::staticVTable())->changePrototype(symbolPrototype()->d());
456
457 jsStrings[String_Empty] = newIdentifier(QString());
458 jsStrings[String_undefined] = newIdentifier(QStringLiteral("undefined"));
459 jsStrings[String_null] = newIdentifier(QStringLiteral("null"));
460 jsStrings[String_true] = newIdentifier(QStringLiteral("true"));
461 jsStrings[String_false] = newIdentifier(QStringLiteral("false"));
462 jsStrings[String_boolean] = newIdentifier(QStringLiteral("boolean"));
463 jsStrings[String_number] = newIdentifier(QStringLiteral("number"));
464 jsStrings[String_string] = newIdentifier(QStringLiteral("string"));
465 jsStrings[String_default] = newIdentifier(QStringLiteral("default"));
466 jsStrings[String_symbol] = newIdentifier(QStringLiteral("symbol"));
467 jsStrings[String_object] = newIdentifier(QStringLiteral("object"));
468 jsStrings[String_function] = newIdentifier(QStringLiteral("function"));
469 jsStrings[String_length] = newIdentifier(QStringLiteral("length"));
470 jsStrings[String_prototype] = newIdentifier(QStringLiteral("prototype"));
471 jsStrings[String_constructor] = newIdentifier(QStringLiteral("constructor"));
472 jsStrings[String_arguments] = newIdentifier(QStringLiteral("arguments"));
473 jsStrings[String_caller] = newIdentifier(QStringLiteral("caller"));
474 jsStrings[String_callee] = newIdentifier(QStringLiteral("callee"));
475 jsStrings[String_this] = newIdentifier(QStringLiteral("this"));
476 jsStrings[String___proto__] = newIdentifier(QStringLiteral("__proto__"));
477 jsStrings[String_enumerable] = newIdentifier(QStringLiteral("enumerable"));
478 jsStrings[String_configurable] = newIdentifier(QStringLiteral("configurable"));
479 jsStrings[String_writable] = newIdentifier(QStringLiteral("writable"));
480 jsStrings[String_value] = newIdentifier(QStringLiteral("value"));
481 jsStrings[String_get] = newIdentifier(QStringLiteral("get"));
482 jsStrings[String_set] = newIdentifier(QStringLiteral("set"));
483 jsStrings[String_eval] = newIdentifier(QStringLiteral("eval"));
484 jsStrings[String_uintMax] = newIdentifier(QStringLiteral("4294967295"));
485 jsStrings[String_name] = newIdentifier(QStringLiteral("name"));
486 jsStrings[String_index] = newIdentifier(QStringLiteral("index"));
487 jsStrings[String_input] = newIdentifier(QStringLiteral("input"));
488 jsStrings[String_toString] = newIdentifier(QStringLiteral("toString"));
489 jsStrings[String_toLocaleString] = newIdentifier(QStringLiteral("toLocaleString"));
490 jsStrings[String_destroy] = newIdentifier(QStringLiteral("destroy"));
491 jsStrings[String_valueOf] = newIdentifier(QStringLiteral("valueOf"));
492 jsStrings[String_byteLength] = newIdentifier(QStringLiteral("byteLength"));
493 jsStrings[String_byteOffset] = newIdentifier(QStringLiteral("byteOffset"));
494 jsStrings[String_buffer] = newIdentifier(QStringLiteral("buffer"));
495 jsStrings[String_lastIndex] = newIdentifier(QStringLiteral("lastIndex"));
496 jsStrings[String_next] = newIdentifier(QStringLiteral("next"));
497 jsStrings[String_done] = newIdentifier(QStringLiteral("done"));
498 jsStrings[String_return] = newIdentifier(QStringLiteral("return"));
499 jsStrings[String_throw] = newIdentifier(QStringLiteral("throw"));
500 jsStrings[String_global] = newIdentifier(QStringLiteral("global"));
501 jsStrings[String_ignoreCase] = newIdentifier(QStringLiteral("ignoreCase"));
502 jsStrings[String_multiline] = newIdentifier(QStringLiteral("multiline"));
503 jsStrings[String_unicode] = newIdentifier(QStringLiteral("unicode"));
504 jsStrings[String_sticky] = newIdentifier(QStringLiteral("sticky"));
505 jsStrings[String_source] = newIdentifier(QStringLiteral("source"));
506 jsStrings[String_flags] = newIdentifier(QStringLiteral("flags"));
507
508 jsSymbols[Symbol_hasInstance] = Symbol::create(this, QStringLiteral("@Symbol.hasInstance"));
509 jsSymbols[Symbol_isConcatSpreadable] = Symbol::create(this, QStringLiteral("@Symbol.isConcatSpreadable"));
510 jsSymbols[Symbol_iterator] = Symbol::create(this, QStringLiteral("@Symbol.iterator"));
511 jsSymbols[Symbol_match] = Symbol::create(this, QStringLiteral("@Symbol.match"));
512 jsSymbols[Symbol_replace] = Symbol::create(this, QStringLiteral("@Symbol.replace"));
513 jsSymbols[Symbol_search] = Symbol::create(this, QStringLiteral("@Symbol.search"));
514 jsSymbols[Symbol_species] = Symbol::create(this, QStringLiteral("@Symbol.species"));
515 jsSymbols[Symbol_split] = Symbol::create(this, QStringLiteral("@Symbol.split"));
516 jsSymbols[Symbol_toPrimitive] = Symbol::create(this, QStringLiteral("@Symbol.toPrimitive"));
517 jsSymbols[Symbol_toStringTag] = Symbol::create(this, QStringLiteral("@Symbol.toStringTag"));
518 jsSymbols[Symbol_unscopables] = Symbol::create(this, QStringLiteral("@Symbol.unscopables"));
519 jsSymbols[Symbol_revokableProxy] = Symbol::create(this, QStringLiteral("@Proxy.revokableProxy"));
520
521 ic = newInternalClass(ArrayPrototype::staticVTable(), objectPrototype());
522 Q_ASSERT(ic->d()->prototype);
523 ic = ic->addMember(id_length()->propertyKey(), Attr_NotConfigurable|Attr_NotEnumerable);
524 Q_ASSERT(ic->d()->prototype);
525 jsObjects[ArrayProto] = memoryManager->allocObject<ArrayPrototype>(ic->d());
526 classes[Class_ArrayObject] = ic->changePrototype(arrayPrototype()->d());
527 jsObjects[PropertyListProto] = memoryManager->allocate<PropertyListPrototype>();
528
529 Scoped<InternalClass> argsClass(scope);
530 argsClass = newInternalClass(ArgumentsObject::staticVTable(), objectPrototype());
531 argsClass = argsClass->addMember(id_length()->propertyKey(), Attr_NotEnumerable);
532 argsClass = argsClass->addMember(symbol_iterator()->propertyKey(), Attr_Data|Attr_NotEnumerable);
533 classes[Class_ArgumentsObject] = argsClass->addMember(id_callee()->propertyKey(), Attr_Data|Attr_NotEnumerable);
534 argsClass = newInternalClass(StrictArgumentsObject::staticVTable(), objectPrototype());
535 argsClass = argsClass->addMember(id_length()->propertyKey(), Attr_NotEnumerable);
536 argsClass = argsClass->addMember(symbol_iterator()->propertyKey(), Attr_Data|Attr_NotEnumerable);
537 classes[Class_StrictArgumentsObject] = argsClass->addMember(id_callee()->propertyKey(), Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
538
539 *static_cast<Value *>(globalObject) = newObject();
540 Q_ASSERT(globalObject->d()->vtable());
541 initRootContext();
542
543 ic = newInternalClass(QV4::StringObject::staticVTable(), objectPrototype());
544 ic = ic->addMember(id_length()->propertyKey(), Attr_ReadOnly);
545 classes[Class_StringObject] = ic->changePrototype(stringPrototype()->d());
546 Q_ASSERT(classes[Class_StringObject]->verifyIndex(id_length()->propertyKey(), Heap::StringObject::LengthPropertyIndex));
547
548 classes[Class_SymbolObject] = newInternalClass(QV4::SymbolObject::staticVTable(), symbolPrototype());
549
550 jsObjects[NumberProto] = memoryManager->allocate<NumberPrototype>();
551 jsObjects[BooleanProto] = memoryManager->allocate<BooleanPrototype>();
552 jsObjects[DateProto] = memoryManager->allocate<DatePrototype>();
553
554#if defined(QT_NO_DEBUG) && !defined(QT_FORCE_ASSERTS)
555 InternalClassEntry *index = nullptr;
556#else
557 InternalClassEntry _index;
558 auto *index = &_index;
559#endif
560 ic = newInternalClass(QV4::FunctionPrototype::staticVTable(), objectPrototype());
561 auto addProtoHasInstance = [&] {
562 // Add an invalid prototype slot, so that all function objects have the same layout
563 // This helps speed up instanceof operations and other things where we need to query
564 // prototype property (as we always know it's location)
565 ic = ic->addMember(id_prototype()->propertyKey(), Attr_Invalid, index);
566 Q_ASSERT(index->index == Heap::FunctionObject::Index_Prototype);
567 // add an invalid @hasInstance slot, so that we can quickly track whether the
568 // hasInstance method has been reimplemented. This is required for a fast
569 // instanceof implementation
570 ic = ic->addMember(symbol_hasInstance()->propertyKey(), Attr_Invalid, index);
571 Q_ASSERT(index->index == Heap::FunctionObject::Index_HasInstance);
572 };
573 addProtoHasInstance();
574 jsObjects[FunctionProto] = memoryManager->allocObject<FunctionPrototype>(ic->d());
575 ic = newInternalClass(FunctionObject::staticVTable(), functionPrototype());
576 addProtoHasInstance();
577 classes[Class_FunctionObject] = ic->d();
578 ic = ic->addMember(id_name()->propertyKey(), Attr_ReadOnly, index);
579 Q_ASSERT(index->index == Heap::ArrowFunction::Index_Name);
580 ic = ic->addMember(id_length()->propertyKey(), Attr_ReadOnly_ButConfigurable, index);
581 Q_ASSERT(index->index == Heap::ArrowFunction::Index_Length);
582 classes[Class_ArrowFunction] = ic->changeVTable(ArrowFunction::staticVTable());
583 ic = ic->changeVTable(MemberFunction::staticVTable());
584 classes[Class_MemberFunction] = ic->d();
585 ic = ic->changeVTable(GeneratorFunction::staticVTable());
586 classes[Class_GeneratorFunction] = ic->d();
587 ic = ic->changeVTable(MemberGeneratorFunction::staticVTable());
588 classes[Class_MemberGeneratorFunction] = ic->d();
589
590 ic = ic->changeMember(id_prototype()->propertyKey(), Attr_NotConfigurable|Attr_NotEnumerable);
591 ic = ic->changeVTable(ScriptFunction::staticVTable());
592 classes[Class_ScriptFunction] = ic->d();
593 ic = ic->changeVTable(ConstructorFunction::staticVTable());
594 classes[Class_ConstructorFunction] = ic->d();
595
596 classes[Class_ObjectProto] = classes[Class_Object]->addMember(id_constructor()->propertyKey(), Attr_NotEnumerable, index);
597 Q_ASSERT(index->index == Heap::FunctionObject::Index_ProtoConstructor);
598
599 jsObjects[GeneratorProto] = memoryManager->allocObject<GeneratorPrototype>(classes[Class_Object]);
600 classes[Class_GeneratorObject] = newInternalClass(QV4::GeneratorObject::staticVTable(), generatorPrototype());
601
602 ScopedString str(scope);
603 classes[Class_RegExp] = classes[Class_Empty]->changeVTable(QV4::RegExp::staticVTable());
604 ic = newInternalClass(QV4::RegExpObject::staticVTable(), objectPrototype());
605 ic = ic->addMember(id_lastIndex()->propertyKey(), Attr_NotEnumerable|Attr_NotConfigurable, index);
606 Q_ASSERT(index->index == RegExpObject::Index_LastIndex);
607 jsObjects[RegExpProto] = memoryManager->allocObject<RegExpPrototype>(classes[Class_Object]);
608 classes[Class_RegExpObject] = ic->changePrototype(regExpPrototype()->d());
609
610 ic = classes[Class_ArrayObject]->addMember(id_index()->propertyKey(), Attr_Data, index);
611 Q_ASSERT(index->index == RegExpObject::Index_ArrayIndex);
612 classes[Class_RegExpExecArray] = ic->addMember(id_input()->propertyKey(), Attr_Data, index);
613 Q_ASSERT(index->index == RegExpObject::Index_ArrayInput);
614
615 ic = newInternalClass(ErrorObject::staticVTable(), nullptr);
616 ic = ic->addMember((str = newIdentifier(QStringLiteral("stack")))->propertyKey(), Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable, index);
617 Q_ASSERT(index->index == ErrorObject::Index_Stack);
618 Q_ASSERT(index->setterIndex == ErrorObject::Index_StackSetter);
619 ic = ic->addMember((str = newIdentifier(QStringLiteral("fileName")))->propertyKey(), Attr_Data|Attr_NotEnumerable, index);
620 Q_ASSERT(index->index == ErrorObject::Index_FileName);
621 ic = ic->addMember((str = newIdentifier(QStringLiteral("lineNumber")))->propertyKey(), Attr_Data|Attr_NotEnumerable, index);
622 classes[Class_ErrorObject] = ic->d();
623 Q_ASSERT(index->index == ErrorObject::Index_LineNumber);
624 classes[Class_ErrorObjectWithMessage] = ic->addMember((str = newIdentifier(QStringLiteral("message")))->propertyKey(), Attr_Data|Attr_NotEnumerable, index);
625 Q_ASSERT(index->index == ErrorObject::Index_Message);
626 ic = newInternalClass(Object::staticVTable(), objectPrototype());
627 ic = ic->addMember(id_constructor()->propertyKey(), Attr_Data|Attr_NotEnumerable, index);
628 Q_ASSERT(index->index == ErrorPrototype::Index_Constructor);
629 ic = ic->addMember((str = newIdentifier(QStringLiteral("message")))->propertyKey(), Attr_Data|Attr_NotEnumerable, index);
630 Q_ASSERT(index->index == ErrorPrototype::Index_Message);
631 classes[Class_ErrorProto] = ic->addMember(id_name()->propertyKey(), Attr_Data|Attr_NotEnumerable, index);
632 Q_ASSERT(index->index == ErrorPrototype::Index_Name);
633
634 classes[Class_ProxyObject] = classes[Class_Empty]->changeVTable(ProxyObject::staticVTable());
635 classes[Class_ProxyFunctionObject] = classes[Class_Empty]->changeVTable(ProxyFunctionObject::staticVTable());
636
637 jsObjects[GetStack_Function] = FunctionObject::createBuiltinFunction(this, str = newIdentifier(QStringLiteral("stack")), ErrorObject::method_get_stack, 0);
638
639 jsObjects[ErrorProto] = memoryManager->allocObject<ErrorPrototype>(classes[Class_ErrorProto]);
640 ic = classes[Class_ErrorProto]->changePrototype(errorPrototype()->d());
641 jsObjects[EvalErrorProto] = memoryManager->allocObject<EvalErrorPrototype>(ic->d());
642 jsObjects[RangeErrorProto] = memoryManager->allocObject<RangeErrorPrototype>(ic->d());
643 jsObjects[ReferenceErrorProto] = memoryManager->allocObject<ReferenceErrorPrototype>(ic->d());
644 jsObjects[SyntaxErrorProto] = memoryManager->allocObject<SyntaxErrorPrototype>(ic->d());
645 jsObjects[TypeErrorProto] = memoryManager->allocObject<TypeErrorPrototype>(ic->d());
646 jsObjects[URIErrorProto] = memoryManager->allocObject<URIErrorPrototype>(ic->d());
647
648 jsObjects[VariantProto] = memoryManager->allocate<VariantPrototype>();
649 Q_ASSERT(variantPrototype()->getPrototypeOf() == objectPrototype()->d());
650
651 jsObjects[VariantAssociationProto] = memoryManager->allocate<VariantAssociationPrototype>();
652 Q_ASSERT(variantAssociationPrototype()->getPrototypeOf() == objectPrototype()->d());
653
654 ic = newInternalClass(SequencePrototype::staticVTable(), SequencePrototype::defaultPrototype(this));
655 jsObjects[SequenceProto] = ScopedValue(scope, memoryManager->allocObject<SequencePrototype>(ic->d()));
656
657 jsObjects[Object_Ctor] = memoryManager->allocate<ObjectCtor>(this);
658 jsObjects[String_Ctor] = memoryManager->allocate<StringCtor>(this);
659 jsObjects[Symbol_Ctor] = memoryManager->allocate<SymbolCtor>(this);
660 jsObjects[Number_Ctor] = memoryManager->allocate<NumberCtor>(this);
661 jsObjects[Boolean_Ctor] = memoryManager->allocate<BooleanCtor>(this);
662 jsObjects[Array_Ctor] = memoryManager->allocate<ArrayCtor>(this);
663 jsObjects[Function_Ctor] = memoryManager->allocate<FunctionCtor>(this);
664 jsObjects[GeneratorFunction_Ctor] = memoryManager->allocate<GeneratorFunctionCtor>(this);
665 jsObjects[Date_Ctor] = memoryManager->allocate<DateCtor>(this);
666 jsObjects[RegExp_Ctor] = memoryManager->allocate<RegExpCtor>(this);
667 jsObjects[Error_Ctor] = memoryManager->allocate<ErrorCtor>(this);
668 jsObjects[EvalError_Ctor] = memoryManager->allocate<EvalErrorCtor>(this);
669 jsObjects[RangeError_Ctor] = memoryManager->allocate<RangeErrorCtor>(this);
670 jsObjects[ReferenceError_Ctor] = memoryManager->allocate<ReferenceErrorCtor>(this);
671 jsObjects[SyntaxError_Ctor] = memoryManager->allocate<SyntaxErrorCtor>(this);
672 jsObjects[TypeError_Ctor] = memoryManager->allocate<TypeErrorCtor>(this);
673 jsObjects[URIError_Ctor] = memoryManager->allocate<URIErrorCtor>(this);
674 jsObjects[IteratorProto] = memoryManager->allocate<IteratorPrototype>();
675
676 ic = newInternalClass(ForInIteratorPrototype::staticVTable(), iteratorPrototype());
677 jsObjects[ForInIteratorProto] = memoryManager->allocObject<ForInIteratorPrototype>(ic);
678 ic = newInternalClass(SetIteratorPrototype::staticVTable(), iteratorPrototype());
679 jsObjects[MapIteratorProto] = memoryManager->allocObject<MapIteratorPrototype>(ic);
680 ic = newInternalClass(SetIteratorPrototype::staticVTable(), iteratorPrototype());
681 jsObjects[SetIteratorProto] = memoryManager->allocObject<SetIteratorPrototype>(ic);
682 ic = newInternalClass(ArrayIteratorPrototype::staticVTable(), iteratorPrototype());
683 jsObjects[ArrayIteratorProto] = memoryManager->allocObject<ArrayIteratorPrototype>(ic);
684 ic = newInternalClass(StringIteratorPrototype::staticVTable(), iteratorPrototype());
685 jsObjects[StringIteratorProto] = memoryManager->allocObject<StringIteratorPrototype>(ic);
686
687 //
688 // url
689 //
690
691 jsObjects[Url_Ctor] = memoryManager->allocate<UrlCtor>(this);
692 jsObjects[UrlProto] = memoryManager->allocate<UrlPrototype>();
693 jsObjects[UrlSearchParams_Ctor] = memoryManager->allocate<UrlSearchParamsCtor>(this);
694 jsObjects[UrlSearchParamsProto] = memoryManager->allocate<UrlSearchParamsPrototype>();
695
696 str = newString(QStringLiteral("get [Symbol.species]"));
697 jsObjects[GetSymbolSpecies] = FunctionObject::createBuiltinFunction(this, str, ArrayPrototype::method_get_species, 0);
698
699 static_cast<ObjectPrototype *>(objectPrototype())->init(this, objectCtor());
700 static_cast<StringPrototype *>(stringPrototype())->init(this, stringCtor());
701 static_cast<SymbolPrototype *>(symbolPrototype())->init(this, symbolCtor());
702 static_cast<NumberPrototype *>(numberPrototype())->init(this, numberCtor());
703 static_cast<BooleanPrototype *>(booleanPrototype())->init(this, booleanCtor());
704 static_cast<ArrayPrototype *>(arrayPrototype())->init(this, arrayCtor());
705 static_cast<PropertyListPrototype *>(propertyListPrototype())->init();
706 static_cast<DatePrototype *>(datePrototype())->init(this, dateCtor());
707 static_cast<FunctionPrototype *>(functionPrototype())->init(this, functionCtor());
708 static_cast<GeneratorPrototype *>(generatorPrototype())->init(this, generatorFunctionCtor());
709 static_cast<RegExpPrototype *>(regExpPrototype())->init(this, regExpCtor());
710 static_cast<ErrorPrototype *>(errorPrototype())->init(this, errorCtor());
711 static_cast<EvalErrorPrototype *>(evalErrorPrototype())->init(this, evalErrorCtor());
712 static_cast<RangeErrorPrototype *>(rangeErrorPrototype())->init(this, rangeErrorCtor());
713 static_cast<ReferenceErrorPrototype *>(referenceErrorPrototype())->init(this, referenceErrorCtor());
714 static_cast<SyntaxErrorPrototype *>(syntaxErrorPrototype())->init(this, syntaxErrorCtor());
715 static_cast<TypeErrorPrototype *>(typeErrorPrototype())->init(this, typeErrorCtor());
716 static_cast<URIErrorPrototype *>(uRIErrorPrototype())->init(this, uRIErrorCtor());
717 static_cast<UrlPrototype *>(urlPrototype())->init(this, urlCtor());
718 static_cast<UrlSearchParamsPrototype *>(urlSearchParamsPrototype())->init(this, urlSearchParamsCtor());
719
720 static_cast<IteratorPrototype *>(iteratorPrototype())->init(this);
721 static_cast<ForInIteratorPrototype *>(forInIteratorPrototype())->init(this);
722 static_cast<MapIteratorPrototype *>(mapIteratorPrototype())->init(this);
723 static_cast<SetIteratorPrototype *>(setIteratorPrototype())->init(this);
724 static_cast<ArrayIteratorPrototype *>(arrayIteratorPrototype())->init(this);
725 static_cast<StringIteratorPrototype *>(stringIteratorPrototype())->init(this);
726
727 static_cast<VariantPrototype *>(variantPrototype())->init();
728
729 sequencePrototype()->cast<SequencePrototype>()->init();
730
731 jsObjects[WeakMap_Ctor] = memoryManager->allocate<WeakMapCtor>(this);
732 jsObjects[WeakMapProto] = memoryManager->allocate<WeakMapPrototype>();
733 static_cast<WeakMapPrototype *>(weakMapPrototype())->init(this, weakMapCtor());
734
735 jsObjects[Map_Ctor] = memoryManager->allocate<MapCtor>(this);
736 jsObjects[MapProto] = memoryManager->allocate<MapPrototype>();
737 static_cast<MapPrototype *>(mapPrototype())->init(this, mapCtor());
738
739 jsObjects[WeakSet_Ctor] = memoryManager->allocate<WeakSetCtor>(this);
740 jsObjects[WeakSetProto] = memoryManager->allocate<WeakSetPrototype>();
741 static_cast<WeakSetPrototype *>(weakSetPrototype())->init(this, weakSetCtor());
742
743 jsObjects[Set_Ctor] = memoryManager->allocate<SetCtor>(this);
744 jsObjects[SetProto] = memoryManager->allocate<SetPrototype>();
745 static_cast<SetPrototype *>(setPrototype())->init(this, setCtor());
746
747 //
748 // promises
749 //
750
751 jsObjects[Promise_Ctor] = memoryManager->allocate<PromiseCtor>(this);
752 jsObjects[PromiseProto] = memoryManager->allocate<PromisePrototype>();
753 static_cast<PromisePrototype *>(promisePrototype())->init(this, promiseCtor());
754
755 // typed arrays
756
757 jsObjects[SharedArrayBuffer_Ctor] = memoryManager->allocate<SharedArrayBufferCtor>(this);
758 jsObjects[SharedArrayBufferProto] = memoryManager->allocate<SharedArrayBufferPrototype>();
759 static_cast<SharedArrayBufferPrototype *>(sharedArrayBufferPrototype())->init(this, sharedArrayBufferCtor());
760
761 jsObjects[ArrayBuffer_Ctor] = memoryManager->allocate<ArrayBufferCtor>(this);
762 jsObjects[ArrayBufferProto] = memoryManager->allocate<ArrayBufferPrototype>();
763 static_cast<ArrayBufferPrototype *>(arrayBufferPrototype())->init(this, arrayBufferCtor());
764
765 jsObjects[DataView_Ctor] = memoryManager->allocate<DataViewCtor>(this);
766 jsObjects[DataViewProto] = memoryManager->allocate<DataViewPrototype>();
767 static_cast<DataViewPrototype *>(dataViewPrototype())->init(this, dataViewCtor());
768 jsObjects[ValueTypeProto] = (Heap::Base *) nullptr;
769 jsObjects[SignalHandlerProto] = (Heap::Base *) nullptr;
770 jsObjects[TypeWrapperProto] = (Heap::Base *) nullptr;
771
772 jsObjects[IntrinsicTypedArray_Ctor] = memoryManager->allocate<IntrinsicTypedArrayCtor>(this);
773 jsObjects[IntrinsicTypedArrayProto] = memoryManager->allocate<IntrinsicTypedArrayPrototype>();
774 static_cast<IntrinsicTypedArrayPrototype *>(intrinsicTypedArrayPrototype())
775 ->init(this, static_cast<IntrinsicTypedArrayCtor *>(intrinsicTypedArrayCtor()));
776
777 for (int i = 0; i < NTypedArrayTypes; ++i) {
778 static_cast<Value &>(typedArrayCtors[i]) = memoryManager->allocate<TypedArrayCtor>(this, Heap::TypedArray::Type(i));
779 static_cast<Value &>(typedArrayPrototype[i]) = memoryManager->allocate<TypedArrayPrototype>(Heap::TypedArray::Type(i));
780 typedArrayPrototype[i].as<TypedArrayPrototype>()->init(this, static_cast<TypedArrayCtor *>(typedArrayCtors[i].as<Object>()));
781 }
782
783 //
784 // set up the global object
785 //
786 rootContext()->d()->activation.set(scope.engine, globalObject->d());
787 Q_ASSERT(globalObject->d()->vtable());
788
789 globalObject->defineDefaultProperty(QStringLiteral("Object"), *objectCtor());
790 globalObject->defineDefaultProperty(QStringLiteral("String"), *stringCtor());
791 globalObject->defineDefaultProperty(QStringLiteral("Symbol"), *symbolCtor());
792 FunctionObject *numberObject = numberCtor();
793 globalObject->defineDefaultProperty(QStringLiteral("Number"), *numberObject);
794 globalObject->defineDefaultProperty(QStringLiteral("Boolean"), *booleanCtor());
795 globalObject->defineDefaultProperty(QStringLiteral("Array"), *arrayCtor());
796 globalObject->defineDefaultProperty(QStringLiteral("Function"), *functionCtor());
797 globalObject->defineDefaultProperty(QStringLiteral("Date"), *dateCtor());
798 globalObject->defineDefaultProperty(QStringLiteral("RegExp"), *regExpCtor());
799 globalObject->defineDefaultProperty(QStringLiteral("Error"), *errorCtor());
800 globalObject->defineDefaultProperty(QStringLiteral("EvalError"), *evalErrorCtor());
801 globalObject->defineDefaultProperty(QStringLiteral("RangeError"), *rangeErrorCtor());
802 globalObject->defineDefaultProperty(QStringLiteral("ReferenceError"), *referenceErrorCtor());
803 globalObject->defineDefaultProperty(QStringLiteral("SyntaxError"), *syntaxErrorCtor());
804 globalObject->defineDefaultProperty(QStringLiteral("TypeError"), *typeErrorCtor());
805 globalObject->defineDefaultProperty(QStringLiteral("URIError"), *uRIErrorCtor());
806 globalObject->defineDefaultProperty(QStringLiteral("Promise"), *promiseCtor());
807 globalObject->defineDefaultProperty(QStringLiteral("URL"), *urlCtor());
808 globalObject->defineDefaultProperty(QStringLiteral("URLSearchParams"), *urlSearchParamsCtor());
809
810 globalObject->defineDefaultProperty(QStringLiteral("SharedArrayBuffer"), *sharedArrayBufferCtor());
811 globalObject->defineDefaultProperty(QStringLiteral("ArrayBuffer"), *arrayBufferCtor());
812 globalObject->defineDefaultProperty(QStringLiteral("DataView"), *dataViewCtor());
813 globalObject->defineDefaultProperty(QStringLiteral("WeakSet"), *weakSetCtor());
814 globalObject->defineDefaultProperty(QStringLiteral("Set"), *setCtor());
815 globalObject->defineDefaultProperty(QStringLiteral("WeakMap"), *weakMapCtor());
816 globalObject->defineDefaultProperty(QStringLiteral("Map"), *mapCtor());
817
818 for (int i = 0; i < NTypedArrayTypes; ++i)
819 globalObject->defineDefaultProperty((str = typedArrayCtors[i].as<FunctionObject>()->name()), typedArrayCtors[i]);
820 ScopedObject o(scope);
821 globalObject->defineDefaultProperty(QStringLiteral("Atomics"), (o = memoryManager->allocate<Atomics>()));
822 globalObject->defineDefaultProperty(QStringLiteral("Math"), (o = memoryManager->allocate<MathObject>()));
823 globalObject->defineDefaultProperty(QStringLiteral("JSON"), (o = memoryManager->allocate<JsonObject>()));
824 globalObject->defineDefaultProperty(QStringLiteral("Reflect"), (o = memoryManager->allocate<Reflect>()));
825 globalObject->defineDefaultProperty(QStringLiteral("Proxy"), (o = memoryManager->allocate<Proxy>(this)));
826
827 globalObject->defineReadonlyProperty(QStringLiteral("undefined"), Value::undefinedValue());
828 globalObject->defineReadonlyProperty(QStringLiteral("NaN"), Value::fromDouble(std::numeric_limits<double>::quiet_NaN()));
829 globalObject->defineReadonlyProperty(QStringLiteral("Infinity"), Value::fromDouble(Q_INFINITY));
830
831
832 jsObjects[Eval_Function] = memoryManager->allocate<EvalFunction>(this);
833 globalObject->defineDefaultProperty(QStringLiteral("eval"), *evalFunction());
834
835 // ES6: 20.1.2.12 & 20.1.2.13:
836 // parseInt and parseFloat must be the same FunctionObject on the global &
837 // Number object.
838 {
839 QString piString(QStringLiteral("parseInt"));
840 QString pfString(QStringLiteral("parseFloat"));
841 Scope scope(this);
842 ScopedString pi(scope, newIdentifier(piString));
843 ScopedString pf(scope, newIdentifier(pfString));
844 ScopedFunctionObject parseIntFn(scope, FunctionObject::createBuiltinFunction(this, pi, GlobalFunctions::method_parseInt, 2));
845 ScopedFunctionObject parseFloatFn(scope, FunctionObject::createBuiltinFunction(this, pf, GlobalFunctions::method_parseFloat, 1));
846 globalObject->defineDefaultProperty(piString, parseIntFn);
847 globalObject->defineDefaultProperty(pfString, parseFloatFn);
848 numberObject->defineDefaultProperty(piString, parseIntFn);
849 numberObject->defineDefaultProperty(pfString, parseFloatFn);
850 }
851
852 globalObject->defineDefaultProperty(QStringLiteral("isNaN"), GlobalFunctions::method_isNaN, 1);
853 globalObject->defineDefaultProperty(QStringLiteral("isFinite"), GlobalFunctions::method_isFinite, 1);
854 globalObject->defineDefaultProperty(QStringLiteral("decodeURI"), GlobalFunctions::method_decodeURI, 1);
855 globalObject->defineDefaultProperty(QStringLiteral("decodeURIComponent"), GlobalFunctions::method_decodeURIComponent, 1);
856 globalObject->defineDefaultProperty(QStringLiteral("encodeURI"), GlobalFunctions::method_encodeURI, 1);
857 globalObject->defineDefaultProperty(QStringLiteral("encodeURIComponent"), GlobalFunctions::method_encodeURIComponent, 1);
858 globalObject->defineDefaultProperty(QStringLiteral("escape"), GlobalFunctions::method_escape, 1);
859 globalObject->defineDefaultProperty(QStringLiteral("unescape"), GlobalFunctions::method_unescape, 1);
860
861 ScopedFunctionObject t(
862 scope,
863 memoryManager->allocate<DynamicFunctionObject>(this, nullptr, ::throwTypeError));
864 t->defineReadonlyProperty(id_length(), Value::fromInt32(0));
865 t->setInternalClass(t->internalClass()->cryopreserved());
866 jsObjects[ThrowerObject] = t;
867
868 ScopedProperty pd(scope);
869 pd->value = thrower();
870 pd->set = thrower();
871 functionPrototype()->insertMember(id_caller(), pd, Attr_Accessor|Attr_ReadOnly_ButConfigurable);
872 functionPrototype()->insertMember(id_arguments(), pd, Attr_Accessor|Attr_ReadOnly_ButConfigurable);
873
874 QV4::QObjectWrapper::initializeBindings(this);
875
876 m_delayedCallQueue.init(this);
877 isInitialized = true;
878}
879
880ExecutionEngine::~ExecutionEngine()
881{
882 // The public engine destructors set this before they get here, but an
883 // ExecutionEngine can also be used on its own. Everything below - the final sweep
884 // in ~MemoryManager in particular - runs destruction handlers against an engine
885 // that is already losing its parts, and those must not start a gc.
886 inShutdown = true;
887
888#if QT_CONFIG(qml_network)
889 delete networkAccessManager;
890#endif
891 m_typeLoader.reset();
892 qDeleteAll(m_extensionData);
893 delete m_multiplyWrappedQObjects;
894 m_multiplyWrappedQObjects = nullptr;
895 delete identifierTable;
896 delete memoryManager;
897
898 for (const auto &cu : std::as_const(m_compilationUnits)) {
899 Q_ASSERT(cu->engine == this);
900 cu->clear();
901 cu->engine = nullptr;
902 }
903 m_compilationUnits.clear();
904
905 delete bumperPointerAllocator;
906 delete regExpCache;
907 delete regExpAllocator;
908 delete executableAllocator;
909 jsStack->deallocate();
910 delete jsStack;
911 gcStack->deallocate();
912 delete gcStack;
913
914#if QT_CONFIG(qml_xml_http_request)
915 qt_rem_qmlxmlhttprequest(this, m_xmlHttpRequestData);
916 m_xmlHttpRequestData = nullptr;
917#endif
918
919 QQmlMetaType::freeUnusedTypesAndCaches();
920}
921
922#if QT_CONFIG(qml_network)
923QNetworkAccessManager *ExecutionEngine::getNetworkAccessManager()
924{
925 if (!networkAccessManager)
926 networkAccessManager = typeLoader()->createNetworkAccessManager(nullptr);
927 return networkAccessManager;
928}
929#endif
930
931#if QT_CONFIG(qml_debug)
932void ExecutionEngine::setDebugger(Debugging::Debugger *debugger)
933{
934 Q_ASSERT(!m_debugger);
935 m_debugger.reset(debugger);
936}
937
938void ExecutionEngine::setProfiler(Profiling::Profiler *profiler)
939{
940 Q_ASSERT(!m_profiler);
941 m_profiler.reset(profiler);
942}
943
944void ExecutionEngine::setPreviewing(bool enabled)
945{
946 hasPreview.storeRelease(enabled);
947}
948
949bool ExecutionEngine::isPreviewing()
950{
951 return hasPreview.loadAcquire();
952}
953
954#endif // QT_CONFIG(qml_debug)
955
956void ExecutionEngine::initRootContext()
957{
958 Scope scope(this);
959 Scoped<ExecutionContext> r(scope, memoryManager->allocManaged<ExecutionContext>());
960 r->d()->init(Heap::ExecutionContext::Type_GlobalContext);
961 r->d()->activation.set(this, globalObject->d());
962 jsObjects[RootContext] = r;
963 jsObjects[ScriptContext] = r;
964 jsObjects[IntegerNull] = Encode((int)0);
965}
966
967Heap::InternalClass *ExecutionEngine::newClass(Heap::InternalClass *other)
968{
969 Heap::InternalClass *ic = memoryManager->allocIC<InternalClass>();
970 ic->init(other);
971 return ic;
972}
973
974Heap::InternalClass *ExecutionEngine::newInternalClass(const VTable *vtable, Object *prototype)
975{
976 Scope scope(this);
977 Scoped<InternalClass> ic(scope, internalClasses(Class_Empty)->changeVTable(vtable));
978 return ic->changePrototype(prototype ? prototype->d() : nullptr);
979}
980
981Heap::Object *ExecutionEngine::newObject()
982{
983 return memoryManager->allocate<Object>();
984}
985
986Heap::Object *ExecutionEngine::newObject(Heap::InternalClass *internalClass)
987{
988 return memoryManager->allocObject<Object>(internalClass);
989}
990
991Heap::String *ExecutionEngine::newString(const QString &s)
992{
993 return memoryManager->allocWithStringData<String>(s.size() * sizeof(QChar), s);
994}
995
996Heap::String *ExecutionEngine::newIdentifier(const QString &text)
997{
998 Scope scope(this);
999 ScopedString s(scope, memoryManager->allocWithStringData<String>(text.size() * sizeof(QChar), text));
1000 s->toPropertyKey();
1001 return s->d();
1002}
1003
1004Heap::Object *ExecutionEngine::newStringObject(const String *string)
1005{
1006 return memoryManager->allocate<StringObject>(string);
1007}
1008
1009Heap::Object *ExecutionEngine::newSymbolObject(const Symbol *symbol)
1010{
1011 return memoryManager->allocObject<SymbolObject>(classes[Class_SymbolObject], symbol);
1012}
1013
1014Heap::Object *ExecutionEngine::newNumberObject(double value)
1015{
1016 return memoryManager->allocate<NumberObject>(value);
1017}
1018
1019Heap::Object *ExecutionEngine::newBooleanObject(bool b)
1020{
1021 return memoryManager->allocate<BooleanObject>(b);
1022}
1023
1024Heap::ArrayObject *ExecutionEngine::newArrayObject(int count)
1025{
1026 Scope scope(this);
1027 ScopedArrayObject object(scope, memoryManager->allocate<ArrayObject>());
1028
1029 if (count) {
1030 if (count < 0x1000)
1031 object->arrayReserve(count);
1032 object->setArrayLengthUnchecked(count);
1033 }
1034 return object->d();
1035}
1036
1037Heap::ArrayObject *ExecutionEngine::newArrayObject(const Value *values, int length)
1038{
1039 Scope scope(this);
1040 ScopedArrayObject a(scope, memoryManager->allocate<ArrayObject>());
1041
1042 if (length) {
1043 size_t size = sizeof(Heap::ArrayData) + (length-1)*sizeof(Value);
1044 Heap::SimpleArrayData *d = scope.engine->memoryManager->allocManaged<SimpleArrayData>(size);
1045 d->init();
1046 d->type = Heap::ArrayData::Simple;
1047 d->offset = 0;
1048 d->values.alloc = length;
1049 d->values.size = length;
1050 // this doesn't require a write barrier, things will be ok, when the new array data gets inserted into
1051 // the parent object
1052 memcpy(&d->values.values, values, length*sizeof(Value));
1053 a->d()->arrayData.set(this, d);
1054 a->setArrayLengthUnchecked(length);
1055 }
1056 return a->d();
1057}
1058
1059Heap::ArrayObject *ExecutionEngine::newArrayObject(const QStringList &list)
1060{
1061 return memoryManager->allocate<ArrayObject>(list);
1062}
1063
1064Heap::ArrayObject *ExecutionEngine::newArrayObject(Heap::InternalClass *internalClass)
1065{
1066 return memoryManager->allocObject<ArrayObject>(internalClass);
1067}
1068
1069Heap::ArrayBuffer *ExecutionEngine::newArrayBuffer(const QByteArray &array)
1070{
1071 return memoryManager->allocate<ArrayBuffer>(array);
1072}
1073
1074Heap::ArrayBuffer *ExecutionEngine::newArrayBuffer(size_t length)
1075{
1076 return memoryManager->allocate<ArrayBuffer>(length);
1077}
1078
1079Heap::DateObject *ExecutionEngine::newDateObject(double dateTime)
1080{
1081 return memoryManager->allocate<DateObject>(dateTime);
1082}
1083
1084Heap::DateObject *ExecutionEngine::newDateObject(const QDateTime &dateTime)
1085{
1086 return memoryManager->allocate<DateObject>(dateTime);
1087}
1088
1089Heap::DateObject *ExecutionEngine::newDateObject(
1090 QDate date, Heap::Object *parent, int index, uint flags)
1091{
1092 return memoryManager->allocate<DateObject>(
1093 date, parent, index, Heap::ReferenceObject::Flags(flags));
1094}
1095
1096Heap::DateObject *ExecutionEngine::newDateObject(
1097 QTime time, Heap::Object *parent, int index, uint flags)
1098{
1099 return memoryManager->allocate<DateObject>(
1100 time, parent, index, Heap::ReferenceObject::Flags(flags));
1101}
1102
1103Heap::DateObject *ExecutionEngine::newDateObject(
1104 QDateTime dateTime, Heap::Object *parent, int index, uint flags)
1105{
1106 return memoryManager->allocate<DateObject>(
1107 dateTime, parent, index, Heap::ReferenceObject::Flags(flags));
1108}
1109
1110Heap::RegExpObject *ExecutionEngine::newRegExpObject(const QString &pattern, int flags)
1111{
1112 Scope scope(this);
1113 Scoped<RegExp> re(scope, RegExp::create(this, pattern, static_cast<CompiledData::RegExp::Flags>(flags)));
1114 return newRegExpObject(re);
1115}
1116
1117Heap::RegExpObject *ExecutionEngine::newRegExpObject(RegExp *re)
1118{
1119 return memoryManager->allocate<RegExpObject>(re);
1120}
1121
1122#if QT_CONFIG(regularexpression)
1123Heap::RegExpObject *ExecutionEngine::newRegExpObject(const QRegularExpression &re)
1124{
1125 return memoryManager->allocate<RegExpObject>(re);
1126}
1127#endif
1128
1129Heap::UrlObject *ExecutionEngine::newUrlObject()
1130{
1131 return memoryManager->allocate<UrlObject>();
1132}
1133
1134Heap::UrlObject *ExecutionEngine::newUrlObject(const QUrl &url)
1135{
1136 Scope scope(this);
1137 Scoped<UrlObject> urlObject(scope, newUrlObject());
1138 urlObject->setUrl(url);
1139 return urlObject->d();
1140}
1141
1142Heap::UrlSearchParamsObject *ExecutionEngine::newUrlSearchParamsObject()
1143{
1144 return memoryManager->allocate<UrlSearchParamsObject>();
1145}
1146
1147Heap::Object *ExecutionEngine::newErrorObject(const Value &value)
1148{
1149 return ErrorObject::create<ErrorObject>(this, value, errorCtor());
1150}
1151
1152Heap::Object *ExecutionEngine::newErrorObject(const QString &message)
1153{
1154 return ErrorObject::create<ErrorObject>(this, message);
1155}
1156
1157Heap::Object *ExecutionEngine::newSyntaxErrorObject(const QString &message)
1158{
1159 return ErrorObject::create<SyntaxErrorObject>(this, message);
1160}
1161
1162Heap::Object *ExecutionEngine::newSyntaxErrorObject(const QString &message, const QString &fileName, int line, int column)
1163{
1164 return ErrorObject::create<SyntaxErrorObject>(this, message, fileName, line, column);
1165}
1166
1167
1168Heap::Object *ExecutionEngine::newReferenceErrorObject(const QString &message)
1169{
1170 return ErrorObject::create<ReferenceErrorObject>(this, message);
1171}
1172
1173Heap::Object *ExecutionEngine::newReferenceErrorObject(const QString &message, const QString &fileName, int line, int column)
1174{
1175 return ErrorObject::create<ReferenceErrorObject>(this, message, fileName, line, column);
1176}
1177
1178
1179Heap::Object *ExecutionEngine::newTypeErrorObject(const QString &message)
1180{
1181 return ErrorObject::create<TypeErrorObject>(this, message);
1182}
1183
1184Heap::Object *ExecutionEngine::newRangeErrorObject(const QString &message)
1185{
1186 return ErrorObject::create<RangeErrorObject>(this, message);
1187}
1188
1189Heap::Object *ExecutionEngine::newURIErrorObject(const Value &message)
1190{
1191 return ErrorObject::create<URIErrorObject>(this, message, uRIErrorCtor());
1192}
1193
1194Heap::PromiseObject *ExecutionEngine::newPromiseObject()
1195{
1196 if (!m_reactionHandler) {
1197 m_reactionHandler.reset(new Promise::ReactionHandler);
1198 }
1199
1200 Scope scope(this);
1201 Scoped<PromiseObject> object(scope, memoryManager->allocate<PromiseObject>(this));
1202 return object->d();
1203}
1204
1205Heap::Object *ExecutionEngine::newPromiseObject(const QV4::FunctionObject *thisObject, const QV4::PromiseCapability *capability)
1206{
1207 if (!m_reactionHandler) {
1208 m_reactionHandler.reset(new Promise::ReactionHandler);
1209 }
1210
1211 Scope scope(this);
1212 Scoped<CapabilitiesExecutorWrapper> executor(scope, memoryManager->allocate<CapabilitiesExecutorWrapper>());
1213 executor->d()->capabilities.set(this, capability->d());
1214 executor->insertMember(id_length(), Primitive::fromInt32(2), Attr_NotWritable|Attr_NotEnumerable);
1215
1216 ScopedObject object(scope, thisObject->callAsConstructor(executor, 1));
1217 return object->d();
1218}
1219
1220Promise::ReactionHandler *ExecutionEngine::getPromiseReactionHandler()
1221{
1222 Q_ASSERT(m_reactionHandler);
1223 return m_reactionHandler.data();
1224}
1225
1226Heap::Object *ExecutionEngine::newURIErrorObject(const QString &message)
1227{
1228 return ErrorObject::create<URIErrorObject>(this, message);
1229}
1230
1231Heap::Object *ExecutionEngine::newEvalErrorObject(const QString &message)
1232{
1233 return ErrorObject::create<EvalErrorObject>(this, message);
1234}
1235
1236Heap::Object *ExecutionEngine::newVariantObject(const QMetaType type, const void *data)
1237{
1238 return memoryManager->allocate<VariantObject>(type, data);
1239}
1240
1241Heap::Object *ExecutionEngine::newForInIteratorObject(Object *o)
1242{
1243 Scope scope(this);
1244 ScopedObject obj(scope, memoryManager->allocate<ForInIteratorObject>(o));
1245 return obj->d();
1246}
1247
1248Heap::Object *ExecutionEngine::newMapIteratorObject(Object *o)
1249{
1250 return memoryManager->allocate<MapIteratorObject>(o->d(), this);
1251}
1252
1253Heap::Object *ExecutionEngine::newSetIteratorObject(Object *o)
1254{
1255 return memoryManager->allocate<SetIteratorObject>(o->d(), this);
1256}
1257
1258Heap::Object *ExecutionEngine::newArrayIteratorObject(Object *o)
1259{
1260 return memoryManager->allocate<ArrayIteratorObject>(o->d(), this);
1261}
1262
1263Heap::QmlContext *ExecutionEngine::qmlContext() const
1264{
1265 return currentStackFrame
1266 ? static_cast<Heap::QmlContext *>(qmlContext(currentContext()->d()))
1267 : nullptr;
1268}
1269
1270QObject *ExecutionEngine::qmlScopeObject() const
1271{
1272 Heap::QmlContext *ctx = qmlContext();
1273 if (!ctx)
1274 return nullptr;
1275
1276 return ctx->qml()->scopeObject;
1277}
1278
1279QQmlRefPointer<QQmlContextData> ExecutionEngine::callingQmlContext() const
1280{
1281 Heap::QmlContext *ctx = qmlContext();
1282 if (!ctx)
1283 return nullptr;
1284
1285 return ctx->qml()->context;
1286}
1287
1288StackTrace ExecutionEngine::stackTrace(int frameLimit) const
1289{
1290 StackTrace stack;
1291
1292 CppStackFrame *f = currentStackFrame;
1293 while (f && frameLimit) {
1294 QV4::StackFrame frame;
1295 frame.source = f->source();
1296 frame.function = f->function();
1297 frame.line = f->lineNumber();
1298
1299 stack.append(frame);
1300 if (f->isJSTypesFrame()) {
1301 if (static_cast<JSTypesStackFrame *>(f)->isTailCalling()) {
1302 QV4::StackFrame frame;
1303 frame.function = QStringLiteral("[elided tail calls]");
1304 stack.append(frame);
1305 }
1306 }
1307 --frameLimit;
1308 f = f->parentFrame();
1309 }
1310
1311 return stack;
1312}
1313
1314/* Helper and "C" linkage exported function to format a GDBMI stacktrace for
1315 * invocation by a debugger.
1316 * Sample GDB invocation: print qt_v4StackTrace((void*)0x7fffffffb290)
1317 * Sample CDB invocation: .call Qt5Qmld!qt_v4StackTrace(0x7fffffffb290) ; gh
1318 * Note: The helper is there to suppress MSVC warning 4190 about anything
1319 * with UDT return types in a "C" linkage function. */
1320
1321static inline char *v4StackTrace(const ExecutionContext *context)
1322{
1323 QString result;
1324 QTextStream str(&result);
1325 str << "stack=[";
1326 if (context && context->engine()) {
1327 const QList<StackFrame> stackTrace = context->engine()->stackTrace(20);
1328 for (int i = 0; i < stackTrace.size(); ++i) {
1329 if (i)
1330 str << ',';
1331 const QUrl url(stackTrace.at(i).source);
1332 const QString fileName = url.isLocalFile() ? url.toLocalFile() : url.toString();
1333 str << "frame={level=\"" << i << "\",func=\"" << stackTrace.at(i).function
1334 << "\",file=\"" << fileName << "\",fullname=\"" << fileName
1335 << "\",line=\"" << qAbs(stackTrace.at(i).line) << "\",language=\"js\"}";
1336 }
1337 }
1338 str << ']';
1339 return qstrdup(result.toLocal8Bit().constData());
1340}
1341
1342extern "C" Q_QML_EXPORT char *qt_v4StackTrace(void *executionContext)
1343{
1344 return v4StackTrace(reinterpret_cast<const ExecutionContext *>(executionContext));
1345}
1346
1347extern "C" Q_QML_EXPORT char *qt_v4StackTraceForEngine(void *executionEngine)
1348{
1349 auto engine = (reinterpret_cast<const ExecutionEngine *>(executionEngine));
1350 return v4StackTrace(engine->currentContext());
1351}
1352
1353QUrl ExecutionEngine::resolvedUrl(const QString &file)
1354{
1355 QUrl src(file);
1356 if (!src.isRelative())
1357 return src;
1358
1359 QUrl base;
1360 CppStackFrame *f = currentStackFrame;
1361 while (f) {
1362 if (f->v4Function) {
1363 base = f->v4Function->finalUrl();
1364 break;
1365 }
1366 f = f->parentFrame();
1367 }
1368
1369 if (base.isEmpty() && globalCode)
1370 base = globalCode->finalUrl();
1371
1372 if (base.isEmpty())
1373 return src;
1374
1375 return base.resolved(src);
1376}
1377
1378void ExecutionEngine::markObjects(MarkStack *markStack)
1379{
1380 for (int i = 0; i < NClasses; ++i) {
1381 if (Heap::InternalClass *c = classes[i])
1382 c->mark(markStack);
1383 }
1384
1385 identifierTable->markObjects(markStack);
1386
1387 for (const auto &compilationUnit : std::as_const(m_compilationUnits))
1388 compilationUnit->markObjects(markStack);
1389}
1390
1391ReturnedValue ExecutionEngine::throwError(const Value &value)
1392{
1393 // we can get in here with an exception already set, as the runtime
1394 // doesn't check after every operation that can throw.
1395 // in this case preserve the first exception to give correct error
1396 // information
1397 if (hasException)
1398 return Encode::undefined();
1399
1400 hasException = true;
1401 *exceptionValue = value;
1402 QV4::Scope scope(this);
1403 QV4::Scoped<ErrorObject> error(scope, value);
1404 if (!!error)
1405 exceptionStackTrace = *error->d()->stackTrace;
1406 else
1407 exceptionStackTrace = stackTrace();
1408
1409 if (QV4::Debugging::Debugger *debug = debugger())
1410 debug->aboutToThrow();
1411
1412 return Encode::undefined();
1413}
1414
1415ReturnedValue ExecutionEngine::catchException(StackTrace *trace)
1416{
1417 Q_ASSERT(hasException);
1418 if (trace)
1419 *trace = exceptionStackTrace;
1420 exceptionStackTrace.clear();
1421 hasException = false;
1422 ReturnedValue res = exceptionValue->asReturnedValue();
1423 *exceptionValue = Value::emptyValue();
1424 return res;
1425}
1426
1427ReturnedValue ExecutionEngine::throwError(const QString &message)
1428{
1429 Scope scope(this);
1430 ScopedValue v(scope, newString(message));
1431 v = newErrorObject(v);
1432 return throwError(v);
1433}
1434
1435ReturnedValue ExecutionEngine::throwSyntaxError(const QString &message, const QString &fileName, int line, int column)
1436{
1437 Scope scope(this);
1438 ScopedObject error(scope, newSyntaxErrorObject(message, fileName, line, column));
1439 return throwError(error);
1440}
1441
1442ReturnedValue ExecutionEngine::throwSyntaxError(const QString &message)
1443{
1444 Scope scope(this);
1445 ScopedObject error(scope, newSyntaxErrorObject(message));
1446 return throwError(error);
1447}
1448
1449
1450ReturnedValue ExecutionEngine::throwTypeError()
1451{
1452 Scope scope(this);
1453 ScopedObject error(scope, newTypeErrorObject(QStringLiteral("Type error")));
1454 return throwError(error);
1455}
1456
1457ReturnedValue ExecutionEngine::throwTypeError(const QString &message)
1458{
1459 Scope scope(this);
1460 ScopedObject error(scope, newTypeErrorObject(message));
1461 return throwError(error);
1462}
1463
1464ReturnedValue ExecutionEngine::throwReferenceError(const QString &name)
1465{
1466 Scope scope(this);
1467 QString msg = name + QLatin1String(" is not defined");
1468 ScopedObject error(scope, newReferenceErrorObject(msg));
1469 return throwError(error);
1470}
1471
1472ReturnedValue ExecutionEngine::throwReferenceError(const Value &value)
1473{
1474 Scope scope(this);
1475 ScopedString s(scope, value.toString(this));
1476 QString msg = s->toQString() + QLatin1String(" is not defined");
1477 ScopedObject error(scope, newReferenceErrorObject(msg));
1478 return throwError(error);
1479}
1480
1481ReturnedValue ExecutionEngine::throwReferenceError(const QString &message, const QString &fileName, int line, int column)
1482{
1483 Scope scope(this);
1484 QString msg = message;
1485 ScopedObject error(scope, newReferenceErrorObject(msg, fileName, line, column));
1486 return throwError(error);
1487}
1488
1489ReturnedValue ExecutionEngine::throwRangeError(const QString &message)
1490{
1491 Scope scope(this);
1492 ScopedObject error(scope, newRangeErrorObject(message));
1493 return throwError(error);
1494}
1495
1496ReturnedValue ExecutionEngine::throwRangeError(const Value &value)
1497{
1498 Scope scope(this);
1499 ScopedString s(scope, value.toString(this));
1500 QString msg = s->toQString() + QLatin1String(" out of range");
1501 ScopedObject error(scope, newRangeErrorObject(msg));
1502 return throwError(error);
1503}
1504
1505ReturnedValue ExecutionEngine::throwURIError(const Value &msg)
1506{
1507 Scope scope(this);
1508 ScopedObject error(scope, newURIErrorObject(msg));
1509 return throwError(error);
1510}
1511
1512ReturnedValue ExecutionEngine::throwUnimplemented(const QString &message)
1513{
1514 Scope scope(this);
1515 ScopedValue v(scope, newString(QLatin1String("Unimplemented ") + message));
1516 v = newErrorObject(v);
1517 return throwError(v);
1518}
1519
1520
1521QQmlError ExecutionEngine::catchExceptionAsQmlError()
1522{
1523 QV4::StackTrace trace;
1524 QV4::Scope scope(this);
1525 QV4::ScopedValue exception(scope, catchException(&trace));
1526 QQmlError error;
1527 if (!trace.isEmpty()) {
1528 QV4::StackFrame frame = trace.constFirst();
1529 error.setUrl(QUrl(frame.source));
1530 error.setLine(qAbs(frame.line));
1531 error.setColumn(frame.column);
1532 }
1533 QV4::Scoped<QV4::ErrorObject> errorObj(scope, exception);
1534 error.setDescription(exception->toQStringNoThrow());
1535 return error;
1536}
1537
1538void ExecutionEngine::amendException()
1539{
1540 const int missingLineNumber = currentStackFrame->missingLineNumber();
1541 const int lineNumber = currentStackFrame->lineNumber();
1542 Q_ASSERT(missingLineNumber != lineNumber);
1543
1544 auto amendStackTrace = [&](QV4::StackTrace *stackTrace) {
1545 for (auto it = stackTrace->begin(), end = stackTrace->end(); it != end; ++it) {
1546 if (it->line == missingLineNumber) {
1547 it->line = lineNumber;
1548 break;
1549 }
1550 }
1551 };
1552
1553 amendStackTrace(&exceptionStackTrace);
1554
1555 QV4::Scope scope(this);
1556 QV4::Scoped<QV4::ErrorObject> error(scope, *exceptionValue);
1557 if (error) // else some other value was thrown
1558 amendStackTrace(error->d()->stackTrace);
1559}
1560
1561// Variant conversion code
1562
1565static QVariant toVariant(
1566 const QV4::Value &value, QMetaType typeHint, JSToQVariantConversionBehavior conversionBehavior,
1567 V4ObjectSet *visitedObjects);
1568static QObject *qtObjectFromJS(const QV4::Value &value);
1569static QVariant objectToVariant(const QV4::Object *o, V4ObjectSet *visitedObjects = nullptr,
1571static bool convertToNativeQObject(const QV4::Value &value, QMetaType targetType, void **result);
1572
1573static QVariant toVariant(const QV4::Value &value, QMetaType metaType, JSToQVariantConversionBehavior conversionBehavior,
1574 V4ObjectSet *visitedObjects)
1575{
1576 Q_ASSERT (!value.isEmpty());
1577
1578 if (const QV4::VariantObject *v = value.as<QV4::VariantObject>())
1579 return v->d()->data();
1580
1581 if (metaType == QMetaType::fromType<bool>())
1582 return QVariant(value.toBoolean());
1583
1584 if (metaType == QMetaType::fromType<double>())
1585 return QVariant(value.toNumber());
1586
1587 if (metaType == QMetaType::fromType<float>())
1588 return QVariant(float(value.toNumber()));
1589
1590 if (metaType == QMetaType::fromType<QJsonValue>())
1591 return QVariant::fromValue(QV4::JsonObject::toJsonValue(value));
1592
1593 if (metaType == QMetaType::fromType<QJSValue>())
1594 return QVariant::fromValue(QJSValuePrivate::fromReturnedValue(value.asReturnedValue()));
1595
1596 if (const QV4::Object *o = value.as<QV4::Object>()) {
1597 QV4::Scope scope(o->engine());
1598 QV4::ScopedObject object(scope, o);
1599 if (metaType == QMetaType::fromType<QJsonObject>()
1600 && !value.as<ArrayObject>() && !value.as<FunctionObject>()) {
1601 return QVariant::fromValue(QV4::JsonObject::toJsonObject(object));
1602 } else if (QV4::QObjectWrapper *wrapper = object->as<QV4::QObjectWrapper>()) {
1603 return QVariant::fromValue<QObject *>(wrapper->object());
1604 } else if (object->as<QV4::QQmlContextWrapper>()) {
1605 return QVariant();
1606 } else if (QV4::QQmlTypeWrapper *w = object->as<QV4::QQmlTypeWrapper>()) {
1607 return w->toVariant();
1608 } else if (QV4::QQmlValueTypeWrapper *v = object->as<QV4::QQmlValueTypeWrapper>()) {
1609 return v->toVariant();
1610 } else if (QV4::QmlListWrapper *l = object->as<QV4::QmlListWrapper>()) {
1611 return l->toVariant();
1612 } else if (QV4::Sequence *s = object->as<QV4::Sequence>()) {
1613 if (metaType.isValid()
1614 && metaType != QMetaType::fromType<QVariant>()
1615 && metaType != s->d()->listType()) {
1616 // If we can, produce an accurate result.
1617 const QVariant result = QV4::SequencePrototype::toVariant(value, metaType);
1618 if (result.isValid())
1619 return result;
1620 }
1621
1622 // Otherwise produce the "natural" type of the sequence.
1623 return QV4::SequencePrototype::toVariant(s);
1624 } else if (auto association = object->as<QV4::VariantAssociationObject>()) {
1625 return association->d()->toVariant();
1626 }
1627 }
1628
1629 if (const QV4::ArrayObject *o = value.as<ArrayObject>()) {
1630 QV4::Scope scope(o->engine());
1631 QV4::ScopedArrayObject a(scope, o);
1632 if (metaType == QMetaType::fromType<QList<QObject *>>()) {
1633 QList<QObject *> list;
1634 uint length = a->getLength();
1635 QV4::Scoped<QV4::Object> qobjectLike(scope);
1636 for (uint ii = 0; ii < length; ++ii) {
1637 qobjectLike = a->get(ii);
1638 list << qtObjectFromJS(qobjectLike);
1639 }
1640
1641 return QVariant::fromValue<QList<QObject*> >(list);
1642 } else if (metaType == QMetaType::fromType<QJsonArray>()) {
1643 return QVariant::fromValue(QV4::JsonObject::toJsonArray(a));
1644 }
1645
1646 QVariant retn = QV4::SequencePrototype::toVariant(value, metaType);
1647 if (retn.isValid())
1648 return retn;
1649 }
1650
1651 if (value.isUndefined())
1652 return QVariant();
1653 if (value.isNull())
1654 return QVariant::fromValue(nullptr);
1655 if (value.isBoolean())
1656 return value.booleanValue();
1657 if (value.isInteger())
1658 return value.integerValue();
1659 if (value.isNumber())
1660 return value.asDouble();
1661 if (String *s = value.stringValue()) {
1662 const QString &str = s->toQString();
1663 // QChars are stored as a strings
1664 if (metaType == QMetaType::fromType<QChar>() && str.size() == 1)
1665 return str.at(0);
1666 return str;
1667 }
1668 if (const QV4::DateObject *d = value.as<DateObject>()) {
1669 // NOTE: since we convert QTime to JS Date,
1670 // round trip will change the variant type (to QDateTime)!
1671
1672 if (metaType == QMetaType::fromType<QDate>())
1673 return DateObject::dateTimeToDate(d->toQDateTime());
1674
1675 if (metaType == QMetaType::fromType<QTime>())
1676 return d->toQDateTime().time();
1677
1678 if (metaType == QMetaType::fromType<QString>())
1679 return d->toString();
1680
1681 return d->toQDateTime();
1682 }
1683 if (const QV4::UrlObject *d = value.as<UrlObject>())
1684 return d->toQUrl();
1685 if (const ArrayBuffer *d = value.as<ArrayBuffer>())
1686 return d->asByteArray();
1687 if (const Symbol *symbol = value.as<Symbol>()) {
1688 return conversionBehavior == JSToQVariantConversionBehavior::Never
1689 ? QVariant::fromValue(QJSValuePrivate::fromReturnedValue(symbol->asReturnedValue()))
1690 : symbol->descriptiveString();
1691 }
1692
1693 const QV4::Object *object = value.as<QV4::Object>();
1694 Q_ASSERT(object);
1695 QV4::Scope scope(object->engine());
1696 QV4::ScopedObject o(scope, object);
1697
1698#if QT_CONFIG(regularexpression)
1699 if (QV4::RegExpObject *re = o->as<QV4::RegExpObject>())
1700 return re->toQRegularExpression();
1701#endif
1702
1703 if (metaType.isValid() && !(metaType.flags() & QMetaType::PointerToQObject)) {
1704 const QVariant result
1705 = QQmlValueTypeProvider::createValueType(value, metaType, scope.engine);
1706 if (result.isValid())
1707 return result;
1708 }
1709
1710 if (conversionBehavior == JSToQVariantConversionBehavior::Never)
1711 return QVariant::fromValue(QJSValuePrivate::fromReturnedValue(o->asReturnedValue()));
1712
1713 return objectToVariant(o, visitedObjects, conversionBehavior);
1714}
1715
1716QVariant ExecutionEngine::toVariantLossy(const Value &value)
1717{
1718 return ::toVariant(value, QMetaType(), JSToQVariantConversionBehavior::Aggressive, nullptr);
1719}
1720
1721QVariant ExecutionEngine::toVariant(
1722 const Value &value, QMetaType typeHint, bool createJSValueForObjectsAndSymbols)
1723{
1724 auto behavior = createJSValueForObjectsAndSymbols ? JSToQVariantConversionBehavior::Never
1725 : JSToQVariantConversionBehavior::Safish;
1726 return ::toVariant(value, typeHint, behavior, nullptr);
1727}
1728
1729template<typename Association>
1731 const QV4::Object *o, V4ObjectSet *visitedObjects,
1732 JSToQVariantConversionBehavior conversionBehvior)
1733{
1734 Association association;
1735 QV4::Scope scope(o->engine());
1736 QV4::ObjectIterator it(scope, o, QV4::ObjectIterator::EnumerableOnly);
1737 QV4::ScopedValue name(scope);
1738 QV4::ScopedValue val(scope);
1739 while (1) {
1740 name = it.nextPropertyNameAsString(val);
1741 if (name->isNull())
1742 break;
1743
1744 QString key = name->toQStringNoThrow();
1745 association.insert(key, ::toVariant(
1746 val, /*type hint*/ QMetaType {},
1747 conversionBehvior, visitedObjects));
1748 }
1749 return association;
1750}
1751
1752static QVariant objectToVariant(const QV4::Object *o, V4ObjectSet *visitedObjects,
1753 JSToQVariantConversionBehavior conversionBehvior)
1754{
1755 Q_ASSERT(o);
1756
1757 QV4::ExecutionEngine *engine = o->engine();
1758 if (Q_UNLIKELY(engine->checkStackLimits())) {
1759 if (o->as<ArrayObject>())
1760 return QVariantList();
1761 return QVariantMap();
1762 }
1763
1764 V4ObjectSet recursionGuardSet;
1765 if (!visitedObjects) {
1766 visitedObjects = &recursionGuardSet;
1767 } else if (visitedObjects->contains(o->d())) {
1768 // Avoid recursion.
1769 // For compatibility with QVariant{List,Map} conversion, we return an
1770 // empty object (and no error is thrown).
1771 if (o->as<ArrayObject>())
1772 return QVariantList();
1773 return QVariantMap();
1774 }
1775 visitedObjects->insert(o->d());
1776
1777 QVariant result;
1778
1779 if (o->as<ArrayObject>()) {
1780 QV4::Scope scope(engine);
1781 QV4::ScopedArrayObject a(scope, o->asReturnedValue());
1782 QV4::ScopedValue v(scope);
1783 QVariantList list;
1784
1785 int length = a->getLength();
1786 for (int ii = 0; ii < length; ++ii) {
1787 v = a->get(ii);
1788 list << ::toVariant(v, QMetaType {}, conversionBehvior,
1789 visitedObjects);
1790 }
1791
1792 result = list;
1793 } else if (o->getPrototypeOf() == engine->objectPrototype()->d()
1794 || (conversionBehvior == JSToQVariantConversionBehavior::Aggressive &&
1795 !o->as<QV4::FunctionObject>())) {
1796 /* FunctionObject is excluded for historical reasons, even though
1797 objects with a custom prototype risk losing information
1798 But the Aggressive path is used only in QJSValue::toVariant
1799 which is documented to be lossy
1800 */
1801 result = objectToVariantAssociation<QVariantMap>(o, visitedObjects, conversionBehvior);
1802 } else {
1803 // If it's not a plain object, we can only save it as QJSValue.
1804 result = QVariant::fromValue(QJSValuePrivate::fromReturnedValue(o->asReturnedValue()));
1805 }
1806
1807 visitedObjects->remove(o->d());
1808 return result;
1809}
1810
1811/*!
1812 \internal
1813
1814 Transform the given \a metaType and \a ptr into a JavaScript representation.
1815 */
1816QV4::ReturnedValue ExecutionEngine::fromData(
1817 QMetaType metaType, const void *ptr,
1818 QV4::Heap::Object *container, int property, uint flags)
1819{
1820 const auto createSequence = [&](const QMetaSequence metaSequence) {
1821 QV4::Scope scope(this);
1822 QV4::Scoped<Sequence> sequence(scope);
1823 if (container) {
1824 return QV4::SequencePrototype::newSequence(
1825 this, metaType, metaSequence, ptr,
1826 container, property, Heap::ReferenceObject::Flags(flags));
1827 } else {
1828 return QV4::SequencePrototype::fromData(this, metaType, metaSequence, ptr);
1829 }
1830 };
1831
1832 const int type = metaType.id();
1833 if (type < QMetaType::User) {
1834 switch (QMetaType::Type(type)) {
1835 case QMetaType::UnknownType:
1836 case QMetaType::Void:
1837 return QV4::Encode::undefined();
1838 case QMetaType::Nullptr:
1839 case QMetaType::VoidStar:
1840 return QV4::Encode::null();
1841 case QMetaType::Bool:
1842 return QV4::Encode(*reinterpret_cast<const bool*>(ptr));
1843 case QMetaType::Int:
1844 return QV4::Encode(*reinterpret_cast<const int*>(ptr));
1845 case QMetaType::UInt:
1846 return QV4::Encode(*reinterpret_cast<const uint*>(ptr));
1847 case QMetaType::Long:
1848 return QV4::Encode((double)*reinterpret_cast<const long *>(ptr));
1849 case QMetaType::ULong:
1850 return QV4::Encode((double)*reinterpret_cast<const ulong *>(ptr));
1851 case QMetaType::LongLong:
1852 return QV4::Encode((double)*reinterpret_cast<const qlonglong*>(ptr));
1853 case QMetaType::ULongLong:
1854 return QV4::Encode((double)*reinterpret_cast<const qulonglong*>(ptr));
1855 case QMetaType::Double:
1856 return QV4::Encode(*reinterpret_cast<const double*>(ptr));
1857 case QMetaType::QString:
1858 return newString(*reinterpret_cast<const QString*>(ptr))->asReturnedValue();
1859 case QMetaType::QByteArray:
1860 return newArrayBuffer(*reinterpret_cast<const QByteArray*>(ptr))->asReturnedValue();
1861 case QMetaType::Float:
1862 return QV4::Encode(*reinterpret_cast<const float*>(ptr));
1863 case QMetaType::Short:
1864 return QV4::Encode((int)*reinterpret_cast<const short*>(ptr));
1865 case QMetaType::UShort:
1866 return QV4::Encode((int)*reinterpret_cast<const unsigned short*>(ptr));
1867 case QMetaType::Char:
1868 return QV4::Encode((int)*reinterpret_cast<const char*>(ptr));
1869 case QMetaType::UChar:
1870 return QV4::Encode((int)*reinterpret_cast<const unsigned char*>(ptr));
1871 case QMetaType::SChar:
1872 return QV4::Encode((int)*reinterpret_cast<const signed char*>(ptr));
1873 case QMetaType::QChar:
1874 return newString(*reinterpret_cast<const QChar *>(ptr))->asReturnedValue();
1875 case QMetaType::Char16:
1876 return newString(QChar(*reinterpret_cast<const char16_t *>(ptr)))->asReturnedValue();
1877 case QMetaType::QDateTime:
1878 return QV4::Encode(newDateObject(
1879 *reinterpret_cast<const QDateTime *>(ptr),
1880 container, property, flags));
1881 case QMetaType::QDate:
1882 return QV4::Encode(newDateObject(
1883 *reinterpret_cast<const QDate *>(ptr),
1884 container, property, flags));
1885 case QMetaType::QTime:
1886 return QV4::Encode(newDateObject(
1887 *reinterpret_cast<const QTime *>(ptr),
1888 container, property, flags));
1889#if QT_CONFIG(regularexpression)
1890 case QMetaType::QRegularExpression:
1891 return QV4::Encode(newRegExpObject(*reinterpret_cast<const QRegularExpression *>(ptr)));
1892#endif
1893 case QMetaType::QObjectStar:
1894 return QV4::QObjectWrapper::wrap(this, *reinterpret_cast<QObject* const *>(ptr));
1895 case QMetaType::QStringList:
1896 return createSequence(QMetaSequence::fromContainer<QStringList>());
1897 case QMetaType::QVariantList:
1898 return createSequence(QMetaSequence::fromContainer<QVariantList>());
1899 case QMetaType::QVariantMap:
1900 return VariantAssociationPrototype::fromQVariantMap(
1901 this,
1902 *reinterpret_cast<const QVariantMap *>(ptr),
1903 container, property, Heap::ReferenceObject::Flags(flags));
1904 case QMetaType::QVariantHash:
1905 return VariantAssociationPrototype::fromQVariantHash(
1906 this,
1907 *reinterpret_cast<const QVariantHash *>(ptr),
1908 container, property, Heap::ReferenceObject::Flags(flags));
1909 case QMetaType::QJsonValue:
1910 return QV4::JsonObject::fromJsonValue(this, *reinterpret_cast<const QJsonValue *>(ptr));
1911 case QMetaType::QJsonObject:
1912 return QV4::JsonObject::fromJsonObject(this, *reinterpret_cast<const QJsonObject *>(ptr));
1913 case QMetaType::QJsonArray:
1914 return QV4::JsonObject::fromJsonArray(this, *reinterpret_cast<const QJsonArray *>(ptr));
1915 case QMetaType::QPixmap:
1916 case QMetaType::QImage:
1917 // Scarce value types
1918 return QV4::Encode(newVariantObject(metaType, ptr));
1919 default:
1920 break;
1921 }
1922 }
1923
1924 if (metaType.flags() & QMetaType::IsEnumeration)
1925 return fromData(metaType.underlyingType(), ptr, container, property, flags);
1926
1927 QV4::Scope scope(this);
1928 if (metaType == QMetaType::fromType<QQmlListReference>()) {
1929 typedef QQmlListReferencePrivate QDLRP;
1930 QDLRP *p = QDLRP::get((QQmlListReference*)const_cast<void *>(ptr));
1931 if (p->object)
1932 return QV4::QmlListWrapper::create(scope.engine, p->property, p->propertyType);
1933 else
1934 return QV4::Encode::null();
1935 } else if (auto flags = metaType.flags(); flags & QMetaType::IsQmlList) {
1936 // casting to QQmlListProperty<QObject> is slightly nasty, but it's the
1937 // same QQmlListReference does.
1938 const auto *p = static_cast<const QQmlListProperty<QObject> *>(ptr);
1939 if (p->object)
1940 return QV4::QmlListWrapper::create(scope.engine, *p, metaType);
1941 else
1942 return QV4::Encode::null();
1943 } else if (metaType == QMetaType::fromType<QJSValue>()) {
1944 return QJSValuePrivate::convertToReturnedValue(
1945 this, *reinterpret_cast<const QJSValue *>(ptr));
1946 } else if (metaType == QMetaType::fromType<QList<QObject *> >()) {
1947 // XXX Can this be made more by using Array as a prototype and implementing
1948 // directly against QList<QObject*>?
1949 const QList<QObject *> &list = *(const QList<QObject *>*)ptr;
1950 QV4::ScopedArrayObject a(scope, newArrayObject());
1951 a->arrayReserve(list.size());
1952 QV4::ScopedValue v(scope);
1953 for (int ii = 0; ii < list.size(); ++ii)
1954 a->arrayPut(ii, (v = QV4::QObjectWrapper::wrap(this, list.at(ii))));
1955 a->setArrayLengthUnchecked(list.size());
1956 return a.asReturnedValue();
1957 } else if (auto flags = metaType.flags(); flags & QMetaType::PointerToQObject) {
1958 if (flags.testFlag(QMetaType::IsConst))
1959 return QV4::QObjectWrapper::wrapConst(this, *reinterpret_cast<QObject* const *>(ptr));
1960 else
1961 return QV4::QObjectWrapper::wrap(this, *reinterpret_cast<QObject* const *>(ptr));
1962 } else if (metaType == QMetaType::fromType<QJSPrimitiveValue>()) {
1963 const QJSPrimitiveValue *primitive = static_cast<const QJSPrimitiveValue *>(ptr);
1964 switch (primitive->type()) {
1965 case QJSPrimitiveValue::Boolean:
1966 return Encode(primitive->asBoolean());
1967 case QJSPrimitiveValue::Integer:
1968 return Encode(primitive->asInteger());
1969 case QJSPrimitiveValue::String:
1970 return newString(primitive->asString())->asReturnedValue();
1971 case QJSPrimitiveValue::Undefined:
1972 return Encode::undefined();
1973 case QJSPrimitiveValue::Null:
1974 return Encode::null();
1975 case QJSPrimitiveValue::Double:
1976 return Encode(primitive->asDouble());
1977 }
1978 }
1979
1980 if (const QMetaObject *vtmo = QQmlMetaType::metaObjectForValueType(metaType)) {
1981 if (container) {
1982 return QV4::QQmlValueTypeWrapper::create(
1983 this, ptr, vtmo, metaType,
1984 container, property, Heap::ReferenceObject::Flags(flags));
1985 } else {
1986 return QV4::QQmlValueTypeWrapper::create(this, ptr, vtmo, metaType);
1987 }
1988 }
1989
1990 const QQmlType listType = QQmlMetaType::qmlListType(metaType);
1991 if (listType.isSequentialContainer())
1992 return createSequence(listType.listMetaSequence());
1993
1994 QMetaSequence::Iterable iterable;
1995 if (QMetaType::convert(metaType, ptr, QMetaType::fromType<QMetaSequence::Iterable>(), &iterable)) {
1996
1997 // If the resulting iterable is useful for anything, turn it into a QV4::Sequence.
1998 const QMetaSequence sequence = iterable.metaContainer();
1999 if (sequence.hasSize() && sequence.canGetValueAtIndex())
2000 return createSequence(sequence);
2001
2002 // As a last resort, try to read the contents of the container via an iterator
2003 // and build a JS array from them.
2004 if (sequence.hasConstIterator() && sequence.canGetValueAtConstIterator()) {
2005 QV4::ScopedArrayObject a(scope, newArrayObject());
2006 QV4::ScopedValue v(scope);
2007 for (auto it = iterable.constBegin(), end = iterable.constEnd(); it != end; ++it) {
2008 v = fromVariant(*it);
2009 a->push_back(v);
2010 }
2011 return a.asReturnedValue();
2012 }
2013 }
2014
2015 return QV4::Encode(newVariantObject(metaType, ptr));
2016}
2017
2018QV4::ReturnedValue QV4::ExecutionEngine::fromVariant(const QVariant &variant)
2019{
2020 return fromData(variant.metaType(), variant.constData());
2021}
2022
2023ReturnedValue ExecutionEngine::fromVariant(
2024 const QVariant &variant, Heap::Object *parent, int property, uint flags)
2025{
2026 return fromData(variant.metaType(), variant.constData(), parent, property, flags);
2027}
2028
2029// Returns true if fromVariant() would produce undefined for the given variant.
2030bool ExecutionEngine::isUndefinedVariant(const QVariant &variant)
2031{
2032 const QMetaType metaType = variant.metaType();
2033 return isEquivalentToUndefinedData(metaType, variant.constData());
2034}
2035
2036// Assumes that data points to data of type metaType
2037// Returns true if it would convert to undefined in QML
2038bool ExecutionEngine::isEquivalentToUndefinedData(QMetaType metaType, const void *data)
2039{
2040 switch (metaType.id()) {
2041 case QMetaType::UnknownType:
2042 case QMetaType::Void:
2043 return true;
2044 case QMetaType::QJsonValue:
2045 return static_cast<const QJsonValue *>(data)->isUndefined();
2046 default:
2047 break;
2048 }
2049
2050 if (metaType == QMetaType::fromType<QJSValue>())
2051 return static_cast<const QJSValue *>(data)->isUndefined();
2052 if (metaType == QMetaType::fromType<QJSPrimitiveValue>()) {
2053 return static_cast<const QJSPrimitiveValue *>(data)->type()
2054 == QJSPrimitiveValue::Undefined;
2055 }
2056 if (metaType == QMetaType::fromType<QJSManagedValue>())
2057 return static_cast<const QJSManagedValue *>(data)->isUndefined();
2058 return false;
2059}
2060
2061QVariantMap ExecutionEngine::variantMapFromJS(const Object *o)
2062{
2063 Q_ASSERT(o);
2064 V4ObjectSet visitedObjects;
2065 visitedObjects.insert(o->d());
2066 return objectToVariantAssociation<QVariantMap>(
2067 o, &visitedObjects, JSToQVariantConversionBehavior::Safish);
2068}
2069
2070QVariantHash ExecutionEngine::variantHashFromJS(const Object *o)
2071{
2072 Q_ASSERT(o);
2073 V4ObjectSet visitedObjects;
2074 visitedObjects.insert(o->d());
2075 return objectToVariantAssociation<QVariantHash>(
2076 o, &visitedObjects, JSToQVariantConversionBehavior::Safish);
2077}
2078
2079// Converts the meta-type defined by the given type and data to JS.
2080// Returns the value if conversion succeeded, an empty handle otherwise.
2081QV4::ReturnedValue ExecutionEngine::metaTypeToJS(QMetaType type, const void *data)
2082{
2083 Q_ASSERT(data != nullptr);
2084
2085 if (type == QMetaType::fromType<QVariant>()) {
2086 // unwrap it: this is tested in QJSEngine, and makes the most sense for
2087 // end-user code too.
2088 return fromVariant(*reinterpret_cast<const QVariant*>(data));
2089 } else if (type == QMetaType::fromType<QUrl>()) {
2090 // Create a proper URL object here, rather than a variant.
2091 return newUrlObject(*reinterpret_cast<const QUrl *>(data))->asReturnedValue();
2092 }
2093
2094 return fromData(type, data);
2095}
2096
2097int ExecutionEngine::maxJSStackSize() const
2098{
2099 return s_maxJSStackSize;
2100}
2101
2102int ExecutionEngine::maxGCStackSize() const
2103{
2104 return s_maxGCStackSize;
2105}
2106
2107/*!
2108 \internal
2109 Returns \a length converted to int if its safe to
2110 pass to \c Scope::alloc.
2111 Otherwise it throws a RangeError, and returns 0.
2112 */
2113int ExecutionEngine::safeForAllocLength(qint64 len64)
2114{
2115 if (len64 < 0ll || len64 > qint64(std::numeric_limits<int>::max())) {
2116 throwRangeError(QStringLiteral("Invalid array length."));
2117 return 0;
2118 }
2119 if (len64 > qint64(this->jsStackLimit - this->jsStackTop)) {
2120 throwRangeError(QStringLiteral("Array too large for apply()."));
2121 return 0;
2122 }
2123 return len64;
2124}
2125
2126ReturnedValue ExecutionEngine::global()
2127{
2128 return globalObject->asReturnedValue();
2129}
2130
2131QQmlRefPointer<ExecutableCompilationUnit> ExecutionEngine::compilationUnitForUrl(const QUrl &url) const
2132{
2133 // Gives the _most recently inserted_ CU of that URL. That's what we want.
2134 return m_compilationUnits.value(url);
2135}
2136
2137QQmlRefPointer<ExecutableCompilationUnit> ExecutionEngine::executableCompilationUnit(
2138 QQmlRefPointer<CompiledData::CompilationUnit> &&unit)
2139{
2140 const QUrl url = unit->finalUrl();
2141 auto [begin, end] = std::as_const(m_compilationUnits).equal_range(url);
2142
2143 for (auto it = begin; it != end; ++it) {
2144 if ((*it)->baseCompilationUnit() == unit)
2145 return *it;
2146 }
2147
2148 auto executableUnit = m_compilationUnits.insert(
2149 url, ExecutableCompilationUnit::create(std::move(unit), this));
2150 // runtime data should not be initialized yet, so we don't need to mark the CU
2151 Q_ASSERT(!(*executableUnit)->runtimeStrings);
2152 return *executableUnit;
2153}
2154
2155QQmlRefPointer<ExecutableCompilationUnit> ExecutionEngine::insertCompilationUnit(QQmlRefPointer<CompiledData::CompilationUnit> &&unit) {
2156 QUrl url = unit->finalUrl();
2157 auto executableUnit = ExecutableCompilationUnit::create(std::move(unit), this);
2158 /* Compilation Units stored in the engine are part of the gc roots,
2159 so we don't trigger any write-barrier when they are added. Use
2160 markCustom to make sure they are still marked when we insert them */
2161 QV4::WriteBarrier::markCustom(this, [&executableUnit](QV4::MarkStack *ms) {
2162 executableUnit->markObjects(ms);
2163 });
2164 return *m_compilationUnits.insert(std::move(url), std::move(executableUnit));
2165}
2166
2167void ExecutionEngine::trimCompilationUnits()
2168{
2169 for (auto it = m_compilationUnits.begin(); it != m_compilationUnits.end();) {
2170 if ((*it)->count() == 1)
2171 it = m_compilationUnits.erase(it);
2172 else
2173 ++it;
2174 }
2175}
2176
2177void ExecutionEngine::trimCompilationUnitsForUrl(const QUrl &url)
2178{
2179 auto it = m_compilationUnits.find(url);
2180 while (it != m_compilationUnits.end() && it.key() == url) {
2181 if ((*it)->count() == 1)
2182 it = m_compilationUnits.erase(it);
2183 else
2184 ++it;
2185 }
2186}
2187
2188/*!
2189 * Returns any _existing_ module for the given \a url and \a referrer. This
2190 * does not actually load anything. You must guarantee the existence of the
2191 * module by keeping a (direct or indirect) reference to it somewhere, or you
2192 * must live with a possible nullptr being returned.
2193 */
2194ExecutionEngine::Module ExecutionEngine::moduleForUrl(
2195 const QUrl &url, const ExecutableCompilationUnit *referrer)
2196{
2197 QUrl resolved = referrer
2198 ? referrer->finalUrl().resolved(QQmlMetaType::normalizedUrl(url))
2199 : QQmlMetaType::normalizedUrl(url);
2200 if (!resolved.path().endsWith(QLatin1String(".mjs")))
2201 resolved.setFragment(QLatin1String("module"));
2202
2203 // Executable compilation unit already present in engine
2204 auto existingModule = m_compilationUnits.constFind(resolved);
2205 if (existingModule != m_compilationUnits.constEnd())
2206 return *existingModule;
2207
2208 // Also try with the relative url, to support native modules.
2209 if (resolved != url) {
2210 existingModule = m_compilationUnits.constFind(url);
2211 if (existingModule != m_compilationUnits.constEnd())
2212 return *existingModule;
2213 }
2214
2215 if (const auto blob = m_typeLoader->getScript(resolved, QQmlTypeLoader::Synchronous))
2216 return executableCompilationUnit(blob->scriptData()->compilationUnit());
2217
2218 // Unavailable
2219 return Module();
2220}
2221
2222ExecutionEngine::Module ExecutionEngine::registerNativeModule(
2223 const QUrl &url, const QV4::Value &value)
2224{
2225 Q_ASSERT(!m_compilationUnits.contains(url));
2226
2227 const QV4::CompiledData::Unit *unit = Compiler::Codegen::generateNativeModuleUnitData(
2228 /*debugMode*/debugger() != nullptr, url.toString(), value);
2229 if (!unit)
2230 return Module();
2231
2232 QQmlRefPointer<CompiledData::CompilationUnit> cu;
2233
2234 // Make sure the type loader doesn't try to resolve the module anymore.
2235 // If some other code requests that same module, we need to produce the same CU.
2236 cu = typeLoader()->injectModule(url, unit);
2237
2238 QQmlRefPointer<ExecutableCompilationUnit> newModule = insertCompilationUnit(std::move(cu));
2239
2240 Q_ASSERT(m_compilationUnits.contains(url, newModule));
2241
2242 Scope scope(this);
2243 Scoped<QV4::Module> instance(scope, newModule->instantiate());
2244 Scoped<CallContext> context(scope, instance->d()->scope);
2245
2246 const CompiledData::Unit *unitData = newModule->baseCompilationUnit()->data;
2247 const CompiledData::ExportEntry *exportEntries = unitData->localExportEntryTable();
2248
2249 ScopedObject object(scope, value);
2250 for (uint i = 0, end = unitData->localExportEntryTableSize; i < end; ++i) {
2251 const CompiledData::ExportEntry *localExport = exportEntries + i;
2252 ScopedString localName(scope, newModule->runtimeStrings[localExport->localName]);
2253 const uint index
2254 = context->internalClass()->indexOfValueOrGetter(localName->toPropertyKey());
2255 QV4::Heap::CallContext *cc = context->d();
2256 Q_ASSERT(index < cc->locals.size);
2257 if (localName->toQString() == QLatin1String("default")) {
2258 cc->locals.set(this, index, value);
2259 continue;
2260 }
2261
2262 Q_ASSERT(object);
2263
2264 ScopedValue localValue(scope, object->get(localName));
2265 cc->locals.set(this, index, localValue);
2266 }
2267
2268 instance->d()->evaluated = true;
2269 return newModule;
2270}
2271
2273{
2274 using DiskCache = ExecutionEngine::DiskCache;
2275
2276 if (v == nullptr)
2277 return DiskCache::Enabled;
2278
2279 ExecutionEngine::DiskCacheOptions result = DiskCache::Disabled;
2280 const QList<QByteArray> options = QByteArray(v).split(',');
2281 for (const QByteArray &option : options) {
2282 if (option == "aot-bytecode")
2283 result |= DiskCache::AotByteCode;
2284 else if (option == "aot-native")
2285 result |= DiskCache::AotNative;
2286 else if (option == "aot")
2287 result |= DiskCache::Aot;
2288 else if (option == "qmlc-read")
2289 result |= DiskCache::QmlcRead;
2290 else if (option == "qmlc-write")
2291 result |= DiskCache::QmlcWrite;
2292 else if (option == "qmlc")
2293 result |= DiskCache::Qmlc;
2294 else
2295 qWarning() << "Ignoring unknown option to QML_DISK_CACHE:" << option;
2296 }
2297
2298 return result;
2299}
2300
2301ExecutionEngine::DiskCacheOptions ExecutionEngine::diskCacheOptions() const
2302{
2303 if (forceDiskCache())
2304 return DiskCache::Enabled;
2305 if (disableDiskCache() || debugger())
2306 return DiskCache::Disabled;
2307 static const DiskCacheOptions options = qmlGetConfigOption<
2308 DiskCacheOptions, transFormDiskCache>("QML_DISK_CACHE");
2309 return hasPreview.loadAcquire()
2310 ? (options & ~DiskCacheOptions(DiskCache::Aot)) // Disable AOT if preview enabled
2311 : options;
2312}
2313
2314void ExecutionEngine::callInContext(QV4::Function *function, QObject *self,
2315 QV4::ExecutionContext *context, int argc, void **args,
2316 QMetaType *types)
2317{
2318 if (!args) {
2319 Q_ASSERT(argc == 0);
2320 void *dummyArgs[] = { nullptr };
2321 QMetaType dummyTypes[] = { QMetaType::fromType<void>() };
2322 function->call(self, dummyArgs, dummyTypes, argc, context);
2323 return;
2324 }
2325 Q_ASSERT(types); // both args and types must be present
2326 // implicitly sets the return value, which is args[0]
2327 function->call(self, args, types, argc, context);
2328}
2329
2330QV4::ReturnedValue ExecutionEngine::callInContext(QV4::Function *function, QObject *self,
2331 QV4::ExecutionContext *context, int argc,
2332 const QV4::Value *argv)
2333{
2334 QV4::Scope scope(this);
2335 QV4::ScopedObject jsSelf(scope, QV4::QObjectWrapper::wrap(this, self));
2336 Q_ASSERT(jsSelf);
2337 return function->call(jsSelf, argv, argc, context);
2338}
2339
2340void ExecutionEngine::initQmlGlobalObject()
2341{
2342 initializeGlobal();
2343 lockObject(*globalObject);
2344}
2345
2346static bool globalNamesAreStaticallyKnown(QV4::Object *globalObject)
2347{
2348 const Heap::InternalClass *ic = globalObject->internalClass();
2349 const SharedInternalClassData<PropertyKey> &nameMap = ic->nameMap;
2350 bool clean = true;
2351 for (uint i = 0, end = ic->size; i < end; ++i) {
2352 const QV4::PropertyKey id = nameMap.at(i);
2353 if (id.isString()) {
2354 if (!Compiler::Codegen::isNameGlobal(id.toQString())) {
2355 qCritical() << id.toQString()
2356 << "is part of the JavaScript global object "
2357 "but not statically known to be global";
2358 clean = false;
2359 }
2360 }
2361 }
2362 return clean;
2363}
2364
2365#if QT_CONFIG(qml_xml_http_request)
2366void ExecutionEngine::setupXmlHttpRequestExtension()
2367{
2368 qt_add_domexceptions(this);
2369 m_xmlHttpRequestData = qt_add_qmlxmlhttprequest(this);
2370}
2371#endif
2372
2373void ExecutionEngine::initializeGlobal()
2374{
2375 createQtObject();
2376
2377 QV4::GlobalExtensions::init(globalObject, QJSEngine::AllExtensions);
2378
2379#if QT_CONFIG(qml_locale)
2380 QQmlLocale::registerStringLocaleCompare(this);
2381 QQmlDateExtension::registerExtension(this);
2382 QQmlNumberExtension::registerExtension(this);
2383#endif
2384
2385#if QT_CONFIG(qml_xml_http_request)
2386 setupXmlHttpRequestExtension();
2387#endif
2388
2389 qt_add_sqlexceptions(this);
2390
2391 Q_ASSERT(globalNamesAreStaticallyKnown(globalObject));
2392}
2393
2394void ExecutionEngine::createQtObject()
2395{
2396 QV4::Scope scope(this);
2397 QtObject *qtObject = new QtObject(this);
2398
2399 if (publicEngine) {
2400 // If we have a public engine, parent to that one so that we don't delete
2401 // the instance on QQmlEngine::clearSingletons() we still need it as property
2402 // of the global object after all.
2403 QJSEngine::setObjectOwnership(qtObject, QJSEngine::CppOwnership);
2404 qtObject->setParent(publicEngine);
2405 } else {
2406 // If we don't have a public engine, the object isn't exposed as a singleton.
2407 // We can use JavaScript ownership to have it deleted by the last GC run.
2408 QJSEngine::setObjectOwnership(qtObject, QJSEngine::JavaScriptOwnership);
2409 }
2410
2411 QV4::ScopedObject qtObjectWrapper(
2412 scope, QV4::QObjectWrapper::wrap(this, qtObject));
2413 QV4::ScopedObject qtNamespaceWrapper(
2414 scope, QV4::QMetaObjectWrapper::create(this, &Qt::staticMetaObject));
2415 QV4::ScopedObject qtObjectProtoWrapper(
2416 scope, qtObjectWrapper->getPrototypeOf());
2417
2418 qtNamespaceWrapper->setPrototypeOf(qtObjectProtoWrapper);
2419 qtObjectWrapper->setPrototypeOf(qtNamespaceWrapper);
2420
2421 globalObject->defineDefaultProperty(QStringLiteral("Qt"), qtObjectWrapper);
2422}
2423
2424void ExecutionEngine::setQmlEngine(QQmlEngine *engine)
2425{
2426 // Second stage of initialization. We're updating some more prototypes here.
2427 isInitialized = false;
2428 m_qmlEngine = engine;
2429 initQmlGlobalObject();
2430 isInitialized = true;
2431}
2432
2433static void freeze_recursive(QV4::ExecutionEngine *v4, QV4::Object *object)
2434{
2435 if (object->as<QV4::QObjectWrapper>() || object->internalClass()->isFrozen())
2436 return;
2437
2438 QV4::Scope scope(v4);
2439
2440 bool instanceOfObject = false;
2441 QV4::ScopedObject p(scope, object->getPrototypeOf());
2442 while (p) {
2443 if (p->d() == v4->objectPrototype()->d()) {
2444 instanceOfObject = true;
2445 break;
2446 }
2447 p = p->getPrototypeOf();
2448 }
2449 if (!instanceOfObject)
2450 return;
2451
2452 Heap::InternalClass *frozen = object->internalClass()->frozen();
2453 object->setInternalClass(frozen); // Immediately assign frozen to prevent it from getting GC'd
2454
2455 QV4::ScopedObject o(scope);
2456 for (uint i = 0; i < frozen->size; ++i) {
2457 if (!frozen->nameMap.at(i).isStringOrSymbol())
2458 continue;
2459 o = *object->propertyData(i);
2460 if (o)
2461 freeze_recursive(v4, o);
2462 }
2463}
2464
2465void ExecutionEngine::freezeObject(const QV4::Value &value)
2466{
2467 QV4::Scope scope(this);
2468 QV4::ScopedObject o(scope, value);
2469 freeze_recursive(this, o);
2470}
2471
2472void ExecutionEngine::lockObject(const QV4::Value &value)
2473{
2474 QV4::Scope scope(this);
2475 ScopedObject object(scope, value);
2476 if (!object)
2477 return;
2478
2479 std::vector<Heap::Object *> stack { object->d() };
2480
2481 // Methods meant to be overridden
2482 const PropertyKey writableMembers[] = {
2483 id_toString()->propertyKey(),
2484 id_toLocaleString()->propertyKey(),
2485 id_valueOf()->propertyKey(),
2486 id_constructor()->propertyKey()
2487 };
2488 const auto writableBegin = std::begin(writableMembers);
2489 const auto writableEnd = std::end(writableMembers);
2490
2491 while (!stack.empty()) {
2492 object = stack.back();
2493 stack.pop_back();
2494
2495 if (object->as<QV4::QObjectWrapper>() || object->internalClass()->isLocked())
2496 continue;
2497
2498 Scoped<InternalClass> locked(scope, object->internalClass()->locked());
2499 QV4::ScopedObject member(scope);
2500
2501 // Taking this copy is cheap. It's refcounted. This avoids keeping a reference
2502 // to the original IC.
2503 const SharedInternalClassData<PropertyKey> nameMap = locked->d()->nameMap;
2504
2505 for (uint i = 0, end = locked->d()->size; i < end; ++i) {
2506 const PropertyKey key = nameMap.at(i);
2507 if (!key.isStringOrSymbol())
2508 continue;
2509 if ((member = *object->propertyData(i))) {
2510 stack.push_back(member->d());
2511 if (std::find(writableBegin, writableEnd, key) == writableEnd) {
2512 PropertyAttributes attributes = locked->d()->find(key).attributes;
2513 attributes.setConfigurable(false);
2514 attributes.setWritable(false);
2515 locked = locked->changeMember(key, attributes);
2516 }
2517 }
2518 }
2519
2520 object->setInternalClass(locked->d());
2521 }
2522}
2523
2524void ExecutionEngine::startTimer(const QString &timerName)
2525{
2526 if (!m_time.isValid())
2527 m_time.start();
2528 m_startedTimers[timerName] = m_time.elapsed();
2529}
2530
2531qint64 ExecutionEngine::stopTimer(const QString &timerName, bool *wasRunning)
2532{
2533 if (!m_startedTimers.contains(timerName)) {
2534 *wasRunning = false;
2535 return 0;
2536 }
2537 *wasRunning = true;
2538 qint64 startedAt = m_startedTimers.take(timerName);
2539 return m_time.elapsed() - startedAt;
2540}
2541
2542int ExecutionEngine::consoleCountHelper(const QString &file, quint16 line, quint16 column)
2543{
2544 const QString key = file + QString::number(line) + QString::number(column);
2545 int number = m_consoleCount.value(key, 0);
2546 number++;
2547 m_consoleCount.insert(key, number);
2548 return number;
2549}
2550
2551void ExecutionEngine::setExtensionData(int index, Deletable *data)
2552{
2553 if (m_extensionData.size() <= index)
2554 m_extensionData.resize(index + 1);
2555
2556 if (m_extensionData.at(index))
2557 delete m_extensionData.at(index);
2558
2559 m_extensionData[index] = data;
2560}
2561
2562template<typename Source>
2563bool convertToIterable(QMetaType metaType, void *data, Source *sequence)
2564{
2565 QMetaSequence::Iterable iterable;
2566 if (!QMetaType::view(metaType, data, QMetaType::fromType<QMetaSequence::Iterable>(), &iterable))
2567 return false;
2568
2569 // Clear the sequence before appending. There may be stale data in there.
2570 metaType.destruct(data);
2571 metaType.construct(data);
2572
2573 QV4::Scope scope(sequence->engine());
2574 QV4::ScopedValue v(scope);
2575
2576 const QMetaType elementMetaType = iterable.metaContainer().valueMetaType();
2577 QVariant element;
2578 void *elementData = nullptr;
2579 if (elementMetaType == QMetaType::fromType<QVariant>()) {
2580 elementData = &element;
2581 } else {
2582 element = QVariant(elementMetaType);
2583 elementData = element.data();
2584 }
2585
2586 for (qsizetype i = 0, end = sequence->getLength(); i < end; ++i) {
2587 v = sequence->get(i);
2588 ExecutionEngine::metaTypeFromJS(v, elementMetaType, elementData);
2589 iterable.append(element);
2590 }
2591
2592 return true;
2593}
2594
2595/*!
2596 * \internal
2597 *
2598 * Converts a JS value to a meta-type.
2599 * \a data must point to a default-constructed instance of \a metaType.
2600 * Returns \c true if conversion succeeded, \c false otherwise. In the latter case,
2601 * \a data is not modified.
2602 */
2603bool ExecutionEngine::metaTypeFromJS(const Value &value, QMetaType metaType, void *data)
2604{
2605 // check if it's one of the types we know
2606 switch (metaType.id()) {
2607 case QMetaType::Bool:
2608 *reinterpret_cast<bool*>(data) = value.toBoolean();
2609 return true;
2610 case QMetaType::Int:
2611 *reinterpret_cast<int*>(data) = value.toInt32();
2612 return true;
2613 case QMetaType::UInt:
2614 *reinterpret_cast<uint*>(data) = value.toUInt32();
2615 return true;
2616 case QMetaType::Long:
2617 *reinterpret_cast<long*>(data) = long(value.toInteger());
2618 return true;
2619 case QMetaType::ULong:
2620 *reinterpret_cast<ulong*>(data) = ulong(value.toInteger());
2621 return true;
2622 case QMetaType::LongLong:
2623 *reinterpret_cast<qlonglong*>(data) = qlonglong(value.toInteger());
2624 return true;
2625 case QMetaType::ULongLong:
2626 *reinterpret_cast<qulonglong*>(data) = qulonglong(value.toInteger());
2627 return true;
2628 case QMetaType::Double:
2629 *reinterpret_cast<double*>(data) = value.toNumber();
2630 return true;
2631 case QMetaType::QString:
2632 if (value.isUndefined())
2633 *reinterpret_cast<QString*>(data) = QStringLiteral("undefined");
2634 else if (value.isNull())
2635 *reinterpret_cast<QString*>(data) = QStringLiteral("null");
2636 else
2637 *reinterpret_cast<QString*>(data) = value.toQString();
2638 return true;
2639 case QMetaType::QByteArray:
2640 if (const ArrayBuffer *ab = value.as<ArrayBuffer>()) {
2641 *reinterpret_cast<QByteArray*>(data) = ab->asByteArray();
2642 } else if (const String *string = value.as<String>()) {
2643 *reinterpret_cast<QByteArray*>(data) = string->toQString().toUtf8();
2644 } else if (const ArrayObject *ao = value.as<ArrayObject>()) {
2645 // Since QByteArray is sequentially iterable, we have to construct it from a JS Array.
2646 QByteArray result;
2647 const qint64 length = ao->getLength();
2648 result.reserve(length);
2649 QV4::Scope scope(ao->engine());
2650 QV4::ScopedValue v(scope);
2651 for (qint64 i = 0; i < length; ++i) {
2652 char value = 0;
2653 v = ao->get(i);
2654 ExecutionEngine::metaTypeFromJS(v, QMetaType::fromType<char>(), &value);
2655 result.push_back(value);
2656 }
2657 *reinterpret_cast<QByteArray*>(data) = std::move(result);
2658 } else {
2659 *reinterpret_cast<QByteArray*>(data) = QByteArray();
2660 }
2661 return true;
2662 case QMetaType::Float:
2663 *reinterpret_cast<float*>(data) = value.toNumber();
2664 return true;
2665 case QMetaType::Short:
2666 *reinterpret_cast<short*>(data) = short(value.toInt32());
2667 return true;
2668 case QMetaType::UShort:
2669 *reinterpret_cast<unsigned short*>(data) = value.toUInt16();
2670 return true;
2671 case QMetaType::Char:
2672 *reinterpret_cast<char*>(data) = char(value.toInt32());
2673 return true;
2674 case QMetaType::UChar:
2675 *reinterpret_cast<unsigned char*>(data) = (unsigned char)(value.toInt32());
2676 return true;
2677 case QMetaType::SChar:
2678 *reinterpret_cast<signed char*>(data) = (signed char)(value.toInt32());
2679 return true;
2680 case QMetaType::QChar:
2681 if (String *s = value.stringValue()) {
2682 QString str = s->toQString();
2683 *reinterpret_cast<QChar*>(data) = str.isEmpty() ? QChar() : str.at(0);
2684 } else {
2685 *reinterpret_cast<QChar*>(data) = QChar(ushort(value.toUInt16()));
2686 }
2687 return true;
2688 case QMetaType::QDateTime:
2689 if (const QV4::DateObject *d = value.as<DateObject>()) {
2690 *reinterpret_cast<QDateTime *>(data) = d->toQDateTime();
2691 return true;
2692 } break;
2693 case QMetaType::QDate:
2694 if (const QV4::DateObject *d = value.as<DateObject>()) {
2695 *reinterpret_cast<QDate *>(data) = DateObject::dateTimeToDate(d->toQDateTime());
2696 return true;
2697 } break;
2698 case QMetaType::QTime:
2699 if (const QV4::DateObject *d = value.as<DateObject>()) {
2700 *reinterpret_cast<QTime *>(data) = d->toQDateTime().time();
2701 return true;
2702 } break;
2703 case QMetaType::QUrl:
2704 if (String *s = value.stringValue()) {
2705 *reinterpret_cast<QUrl *>(data) = QUrl(s->toQString());
2706 return true;
2707 } else if (const QV4::UrlObject *d = value.as<UrlObject>()) {
2708 *reinterpret_cast<QUrl *>(data) = d->toQUrl();
2709 return true;
2710 } else if (const QV4::VariantObject *d = value.as<VariantObject>()) {
2711 const QVariant *variant = &d->d()->data();
2712 if (variant->metaType() == QMetaType::fromType<QUrl>()) {
2713 *reinterpret_cast<QUrl *>(data)
2714 = *reinterpret_cast<const QUrl *>(variant->constData());
2715 return true;
2716 }
2717 }
2718 break;
2719#if QT_CONFIG(regularexpression)
2720 case QMetaType::QRegularExpression:
2721 if (const QV4::RegExpObject *r = value.as<QV4::RegExpObject>()) {
2722 *reinterpret_cast<QRegularExpression *>(data) = r->toQRegularExpression();
2723 return true;
2724 } break;
2725#endif
2726 case QMetaType::QObjectStar: {
2727 if (value.isNull()) {
2728 *reinterpret_cast<QObject* *>(data) = nullptr;
2729 return true;
2730 }
2731 if (value.as<QV4::QObjectWrapper>()) {
2732 *reinterpret_cast<QObject* *>(data) = qtObjectFromJS(value);
2733 return true;
2734 }
2735 break;
2736 }
2737 case QMetaType::QStringList: {
2738 const QV4::ArrayObject *a = value.as<QV4::ArrayObject>();
2739 if (a) {
2740 *reinterpret_cast<QStringList *>(data) = a->toQStringList();
2741 return true;
2742 }
2743 break;
2744 }
2745 case QMetaType::QVariantList: {
2746 const QV4::ArrayObject *a = value.as<QV4::ArrayObject>();
2747 if (a) {
2748 *reinterpret_cast<QVariantList *>(data) = ExecutionEngine::toVariant(
2749 *a, /*typeHint*/QMetaType{}, /*createJSValueForObjectsAndSymbols*/false)
2750 .toList();
2751 return true;
2752 }
2753 break;
2754 }
2755 case QMetaType::QVariantMap: {
2756 const QV4::Object *o = value.as<QV4::Object>();
2757 if (o) {
2758 *reinterpret_cast<QVariantMap *>(data) = o->engine()->variantMapFromJS(o);
2759 return true;
2760 }
2761 break;
2762 }
2763 case QMetaType::QVariant:
2764 if (value.as<QV4::Managed>()) {
2765 *reinterpret_cast<QVariant*>(data) = ExecutionEngine::toVariant(
2766 value, /*typeHint*/QMetaType{}, /*createJSValueForObjectsAndSymbols*/false);
2767 } else if (value.isNull()) {
2768 *reinterpret_cast<QVariant*>(data) = QVariant::fromValue(nullptr);
2769 } else if (value.isUndefined()) {
2770 *reinterpret_cast<QVariant*>(data) = QVariant();
2771 } else if (value.isBoolean()) {
2772 *reinterpret_cast<QVariant*>(data) = QVariant(value.booleanValue());
2773 } else if (value.isInteger()) {
2774 *reinterpret_cast<QVariant*>(data) = QVariant(value.integerValue());
2775 } else if (value.isDouble()) {
2776 *reinterpret_cast<QVariant*>(data) = QVariant(value.doubleValue());
2777 }
2778 return true;
2779 case QMetaType::QJsonValue:
2780 *reinterpret_cast<QJsonValue *>(data) = QV4::JsonObject::toJsonValue(value);
2781 return true;
2782 case QMetaType::QJsonObject: {
2783 *reinterpret_cast<QJsonObject *>(data) = QV4::JsonObject::toJsonObject(value.as<Object>());
2784 return true;
2785 }
2786 case QMetaType::QJsonArray: {
2787 *reinterpret_cast<QJsonArray *>(data) = QV4::JsonObject::toJsonArray(value.as<Object>());
2788 return true;
2789 }
2790 default:
2791 break;
2792 }
2793
2794 if (metaType.flags() & QMetaType::IsEnumeration) {
2795 *reinterpret_cast<int *>(data) = value.toInt32();
2796 return true;
2797 }
2798
2799 if (const QV4::QmlListWrapper *wrapper = value.as<QV4::QmlListWrapper>()) {
2800 if (metaType == QMetaType::fromType<QQmlListReference>()) {
2801 *reinterpret_cast<QQmlListReference *>(data) = wrapper->toListReference();
2802 return true;
2803 }
2804
2805 const auto wrapperPrivate = wrapper->d();
2806 if (metaType == QMetaType::fromType<QQmlListProperty<QObject> *>()
2807 || metaType == wrapperPrivate->propertyType()) {
2808 *reinterpret_cast<QQmlListProperty<QObject> *>(data) = *wrapperPrivate->property();
2809 return true;
2810 }
2811
2812 if (metaType == QMetaType::fromType<QObjectList>()) {
2813 *reinterpret_cast<QObjectList *>(data)
2814 = wrapperPrivate->property()->toList<QObjectList>();
2815 return true;
2816 }
2817
2818 if (convertToIterable(metaType, data, wrapper))
2819 return true;
2820 }
2821
2822 if (const QQmlValueTypeWrapper *vtw = value.as<QQmlValueTypeWrapper>()) {
2823 const QMetaType valueType = vtw->type();
2824 if (valueType == metaType)
2825 return vtw->toGadget(data);
2826
2827 Heap::QQmlValueTypeWrapper *d = vtw->d();
2828 if (d->isReference())
2829 d->readReference();
2830
2831 if (void *gadgetPtr = d->gadgetPtr()) {
2832 if (QQmlValueTypeProvider::populateValueType(
2833 metaType, data, valueType, gadgetPtr, vtw->engine())) {
2834 return true;
2835 }
2836 if (QMetaType::canConvert(valueType, metaType))
2837 return QMetaType::convert(valueType, gadgetPtr, metaType, data);
2838 } else {
2839 QVariant empty(valueType);
2840 if (QQmlValueTypeProvider::populateValueType(
2841 metaType, data, valueType, empty.data(), vtw->engine())) {
2842 return true;
2843 }
2844 if (QMetaType::canConvert(valueType, metaType))
2845 return QMetaType::convert(valueType, empty.data(), metaType, data);
2846 }
2847 }
2848
2849 // Try to use magic; for compatibility with qjsvalue_cast.
2850
2851 if (convertToNativeQObject(value, metaType, reinterpret_cast<void **>(data)))
2852 return true;
2853
2854 const bool isPointer = (metaType.flags() & QMetaType::IsPointer);
2855 const QV4::VariantObject *variantObject = value.as<QV4::VariantObject>();
2856 if (variantObject) {
2857 // Actually a reference, because we're poking it for its data() below and we want
2858 // the _original_ data, not some copy.
2859 QVariant &var = variantObject->d()->data();
2860
2861 if (var.metaType() == metaType) {
2862 metaType.destruct(data);
2863 metaType.construct(data, var.data());
2864 return true;
2865 }
2866
2867 if (isPointer) {
2868 const QByteArray pointedToTypeName = QByteArray(metaType.name()).chopped(1);
2869 const QMetaType valueType = QMetaType::fromName(pointedToTypeName);
2870
2871 if (valueType == var.metaType()) {
2872 // ### Qt7: Remove this. Returning pointers to potentially gc'd data is crazy.
2873 // We have T t, T* is requested, so return &t.
2874 *reinterpret_cast<const void **>(data) = var.data();
2875 return true;
2876 } else if (Object *o = value.objectValue()) {
2877 // Look in the prototype chain.
2878 QV4::Scope scope(o->engine());
2879 QV4::ScopedObject proto(scope, o->getPrototypeOf());
2880 while (proto) {
2881 bool canCast = false;
2882 if (QV4::VariantObject *vo = proto->as<QV4::VariantObject>()) {
2883 const QVariant &v = vo->d()->data();
2884 canCast = (metaType == v.metaType());
2885 }
2886 else if (proto->as<QV4::QObjectWrapper>()) {
2887 QV4::ScopedObject p(scope, proto.getPointer());
2888 if (QObject *qobject = qtObjectFromJS(p)) {
2889 if (const QMetaObject *metaObject = metaType.metaObject())
2890 canCast = metaObject->cast(qobject) != nullptr;
2891 else
2892 canCast = qobject->qt_metacast(pointedToTypeName);
2893 }
2894 }
2895 if (canCast) {
2896 const QMetaType varType = var.metaType();
2897 if (varType.flags() & QMetaType::IsPointer) {
2898 *reinterpret_cast<const void **>(data)
2899 = *reinterpret_cast<void *const *>(var.data());
2900 } else {
2901 *reinterpret_cast<const void **>(data) = var.data();
2902 }
2903 return true;
2904 }
2905 proto = proto->getPrototypeOf();
2906 }
2907 }
2908 } else if (QQmlValueTypeProvider::populateValueType(
2909 metaType, data, var.metaType(), var.data(), variantObject->engine())) {
2910 return true;
2911 }
2912 } else if (value.isNull() && isPointer) {
2913 *reinterpret_cast<void* *>(data) = nullptr;
2914 return true;
2915 } else if (metaType == QMetaType::fromType<QJSValue>()) {
2916 QJSValuePrivate::setValue(reinterpret_cast<QJSValue*>(data), value);
2917 return true;
2918 } else if (metaType == QMetaType::fromType<QJSPrimitiveValue>()) {
2919 *reinterpret_cast<QJSPrimitiveValue *>(data) = createPrimitive(&value);
2920 return true;
2921 } else if (metaType == QMetaType::fromType<QJSManagedValue>()) {
2922 QJSManagedValue *managedData = reinterpret_cast<QJSManagedValue *>(data);
2923
2924 const Managed *managedValue = value.as<Managed>();
2925 if (Value *d = QJSManagedValuePrivate::member(managedData)) {
2926 // If the QJSManagedValue has an engine already,
2927 // we can assign a primitive without risking crosstalk between engines.
2928 if (!managedValue) {
2929 *d = value;
2930 return true;
2931 }
2932
2933 // If the engines match, we don't have to allocate a new persistent value
2934 if (reinterpret_cast<const Managed *>(d)->engine() == managedValue->engine()) {
2935 *d = value;
2936 return true;
2937 }
2938 }
2939
2940 if (managedValue) {
2941 // If value is itself managed, we create a new QJSManagedValue
2942 // to make sure the engine matches.
2943 *managedData = QJSManagedValuePrivate::create(*managedValue);
2944 return true;
2945 }
2946
2947 // The default-constructed QJSManagedValue (without engine) equals undefined.
2948 // So we can get away with doing nothing in this case.
2949 if (value.isUndefined())
2950 return true;
2951
2952 // Otherwise we can't do it. We need an engine from somewhere.
2953 return false;
2954 } else if (!isPointer) {
2955 const QV4::Managed *managed = value.as<QV4::Managed>();
2956 if (QQmlValueTypeProvider::populateValueType(
2957 metaType, data, value, managed ? managed->engine() : nullptr)) {
2958 return true;
2959 }
2960 }
2961
2962 if (const QV4::Sequence *sequence = value.as<Sequence>()) {
2963 const QVariant result = QV4::SequencePrototype::toVariant(sequence);
2964 if (result.metaType() == metaType) {
2965 metaType.destruct(data);
2966 metaType.construct(data, result.constData());
2967 return true;
2968 }
2969
2970 if (convertToIterable(metaType, data, sequence))
2971 return true;
2972 }
2973
2974 if (const QV4::ArrayObject *array = value.as<ArrayObject>()) {
2975 if (convertToIterable(metaType, data, array))
2976 return true;
2977 }
2978
2979 return false;
2980}
2981
2982static bool convertToNativeQObject(const QV4::Value &value, QMetaType targetType, void **result)
2983{
2984 if (!(targetType.flags() & QMetaType::IsPointer))
2985 return false;
2986 if (QObject *qobject = qtObjectFromJS(value)) {
2987 // If the target type has a metaObject, use that for casting.
2988 if (const QMetaObject *targetMetaObject = targetType.metaObject()) {
2989 if (QObject *instance = targetMetaObject->cast(qobject)) {
2990 *result = instance;
2991 return true;
2992 }
2993 return false;
2994 }
2995
2996 // We have to call the generated qt_metacast rather than metaObject->cast() here so that
2997 // it works for types without QMetaObject, such as QStandardItem.
2998 const QByteArray targetTypeName = targetType.name();
2999 const int start = targetTypeName.startsWith("const ") ? 6 : 0;
3000 const QByteArray className = targetTypeName.mid(start, targetTypeName.size() - start - 1);
3001 if (void *instance = qobject->qt_metacast(className)) {
3002 *result = instance;
3003 return true;
3004 }
3005 }
3006 return false;
3007}
3008
3009static QObject *qtObjectFromJS(const QV4::Value &value)
3010{
3011 if (!value.isObject())
3012 return nullptr;
3013
3014 QV4::Scope scope(value.as<QV4::Managed>()->engine());
3015 QV4::Scoped<QV4::VariantObject> v(scope, value);
3016
3017 if (v) {
3018 QVariant variant = v->d()->data();
3019 int type = variant.userType();
3020 if (type == QMetaType::QObjectStar)
3021 return *reinterpret_cast<QObject* const *>(variant.constData());
3022 }
3023 QV4::Scoped<QV4::QObjectWrapper> wrapper(scope, value);
3024 if (wrapper)
3025 return wrapper->object();
3026
3027 QV4::Scoped<QV4::QQmlTypeWrapper> typeWrapper(scope, value);
3028 if (typeWrapper)
3029 return typeWrapper->object();
3030
3031 return nullptr;
3032}
3033
3042
3043QMutex *ExecutionEngine::registrationMutex()
3044{
3045 return &registrationData()->mutex;
3046}
3047
3048int ExecutionEngine::registerExtension()
3049{
3050 return registrationData()->extensionCount++;
3051}
3052
3053QT_END_NAMESPACE
Combined button and popup list for selecting options.
Definition qjsvalue.h:24
static char * v4StackTrace(const ExecutionContext *context)
static bool globalNamesAreStaticallyKnown(QV4::Object *globalObject)
static QObject * qtObjectFromJS(const QV4::Value &value)
static QVariant objectToVariant(const QV4::Object *o, V4ObjectSet *visitedObjects=nullptr, JSToQVariantConversionBehavior behavior=JSToQVariantConversionBehavior::Safish)
Q_QML_EXPORT char * qt_v4StackTraceForEngine(void *executionEngine)
DEFINE_BOOL_CONFIG_OPTION(forceDiskCache, QML_FORCE_DISK_CACHE)
static void freeze_recursive(QV4::ExecutionEngine *v4, QV4::Object *object)
ReturnType convertJSValueToVariantType(const QJSValue &value)
static QVariant toVariant(const QV4::Value &value, QMetaType typeHint, JSToQVariantConversionBehavior conversionBehavior, V4ObjectSet *visitedObjects)
JSToQVariantConversionBehavior
static QtMetaContainerPrivate::QMetaSequenceInterface emptySequenceInterface()
static ExecutionEngine::DiskCacheOptions transFormDiskCache(const char *v)
Q_GLOBAL_STATIC(QV4EngineRegistrationData, registrationData)
static QtMetaContainerPrivate::QMetaSequenceInterface sequenceInterface()
Q_QML_EXPORT char * qt_v4StackTrace(void *executionContext)
static bool convertToNativeQObject(const QV4::Value &value, QMetaType targetType, void **result)
Association objectToVariantAssociation(const QV4::Object *o, V4ObjectSet *visitedObjects, JSToQVariantConversionBehavior conversionBehvior)
static QMetaSequence::Iterable jsvalueToSequence(const QJSValue &value)
bool convertToIterable(QMetaType metaType, void *data, Source *sequence)
QSet< QV4::Heap::Object * > V4ObjectSet
ReturnedValue throwTypeError(const FunctionObject *b, const QV4::Value *, const QV4::Value *, int)
QJSValue const * data