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

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