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

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