1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtQml module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39#include <qv4engine_p.h>
40
41#include <private/qv4compileddata_p.h>
42#include <private/qv4codegen_p.h>
43#include <private/qqmljsdiagnosticmessage_p.h>
44
45#include <QtCore/QTextStream>
46#include <QtCore/private/qvariant_p.h>
47#include <QDateTime>
48#include <QDir>
49#include <QFileInfo>
50#include <QLoggingCategory>
51#if QT_CONFIG(regularexpression)
52#include <QRegularExpression>
53#endif
54
55#include <qv4qmlcontext_p.h>
56#include <qv4value_p.h>
57#include <qv4object_p.h>
58#include <qv4objectproto_p.h>
59#include <qv4objectiterator_p.h>
60#include <qv4setiterator_p.h>
61#include <qv4mapiterator_p.h>
62#include <qv4arrayiterator_p.h>
63#include <qv4arrayobject_p.h>
64#include <qv4booleanobject_p.h>
65#include <qv4globalobject_p.h>
66#include <qv4errorobject_p.h>
67#include <qv4functionobject_p.h>
68#include "qv4function_p.h"
69#include <qv4mathobject_p.h>
70#include <qv4numberobject_p.h>
71#include <qv4regexpobject_p.h>
72#include <qv4regexp_p.h>
73#include "qv4symbol_p.h"
74#include "qv4setobject_p.h"
75#include "qv4mapobject_p.h"
76#include <qv4variantobject_p.h>
77#include <qv4runtime_p.h>
78#include <private/qv4mm_p.h>
79#include <qv4argumentsobject_p.h>
80#include <qv4dateobject_p.h>
81#include <qv4jsonobject_p.h>
82#include <qv4stringobject_p.h>
83#include <qv4identifiertable_p.h>
84#include "qv4debugging_p.h"
85#include "qv4profiling_p.h"
86#include "qv4executableallocator_p.h"
87#include "qv4iterator_p.h"
88#include "qv4stringiterator_p.h"
89#include "qv4generatorobject_p.h"
90#include "qv4reflect_p.h"
91#include "qv4proxy_p.h"
92#include "qv4stackframe_p.h"
93#include "qv4atomics_p.h"
94
95#if QT_CONFIG(qml_sequence_object)
96#include "qv4sequenceobject_p.h"
97#endif
98
99#include "qv4qobjectwrapper_p.h"
100#include "qv4memberdata_p.h"
101#include "qv4arraybuffer_p.h"
102#include "qv4dataview_p.h"
103#include "qv4promiseobject_p.h"
104#include "qv4typedarray_p.h"
105#include <private/qjsvalue_p.h>
106#include <private/qqmltypewrapper_p.h>
107#include <private/qqmlvaluetypewrapper_p.h>
108#include <private/qqmlvaluetype_p.h>
109#include <private/qqmllistwrapper_p.h>
110#include <private/qqmllist_p.h>
111#include <private/qqmltypeloader_p.h>
112#include <private/qqmlbuiltinfunctions_p.h>
113#if QT_CONFIG(qml_locale)
114#include <private/qqmllocale_p.h>
115#endif
116#if QT_CONFIG(qml_xml_http_request)
117#include <private/qv4domerrors_p.h>
118#include <private/qqmlxmlhttprequest_p.h>
119#endif
120#include <private/qv4sqlerrors_p.h>
121#include <qqmlfile.h>
122#include <qmetatype.h>
123
124#if USE(PTHREADS)
125# include <pthread.h>
126#if !defined(Q_OS_INTEGRITY)
127# include <sys/resource.h>
128#endif
129#if HAVE(PTHREAD_NP_H)
130# include <pthread_np.h>
131#endif
132#endif
133
134#ifdef V4_USE_VALGRIND
135#include <valgrind/memcheck.h>
136#endif
137
138Q_DECLARE_METATYPE(QList<int>)
139
140QT_BEGIN_NAMESPACE
141
142using namespace QV4;
143
144static QBasicAtomicInt engineSerial = Q_BASIC_ATOMIC_INITIALIZER(1);
145
146ReturnedValue throwTypeError(const FunctionObject *b, const QV4::Value *, const QV4::Value *, int)
147{
148 return b->engine()->throwTypeError();
149}
150
151qint32 ExecutionEngine::maxCallDepth = -1;
152
153template <typename ReturnType>
154ReturnType convertJSValueToVariantType(const QJSValue &value)
155{
156 return value.toVariant().value<ReturnType>();
157}
158
159static void saveJSValue(QDataStream &stream, const void *data)
160{
161 const QJSValue *jsv = reinterpret_cast<const QJSValue *>(data);
162 quint32 isNullOrUndefined = 0;
163 if (jsv->isNull())
164 isNullOrUndefined |= 0x1;
165 if (jsv->isUndefined())
166 isNullOrUndefined |= 0x2;
167 stream << isNullOrUndefined;
168 if (!isNullOrUndefined)
169 reinterpret_cast<const QJSValue*>(data)->toVariant().save(ds&: stream);
170}
171
172static void restoreJSValue(QDataStream &stream, void *data)
173{
174 QJSValue *jsv = reinterpret_cast<QJSValue*>(data);
175
176 quint32 isNullOrUndefined;
177 stream >> isNullOrUndefined;
178
179 if (isNullOrUndefined & 0x1) {
180 *jsv = QJSValue(QJSValue::NullValue);
181 } else if (isNullOrUndefined & 0x2) {
182 *jsv = QJSValue();
183 } else {
184 QVariant v;
185 v.load(ds&: stream);
186 QJSValuePrivate::setVariant(jsval: jsv, v);
187 }
188}
189
190struct JSArrayIterator {
191 QJSValue const* data;
192 quint32 index;
193};
194
195namespace {
196void createNewIteratorIfNonExisting(void **iterator) {
197 if (*iterator == nullptr)
198 *iterator = new JSArrayIterator;
199}
200}
201
202static QtMetaTypePrivate::QSequentialIterableImpl jsvalueToSequence (const QJSValue& value) {
203 using namespace QtMetaTypePrivate;
204
205 QSequentialIterableImpl iterator {};
206 if (!value.isArray()) {
207 // set up some functions so that non-array QSequentialIterables do not crash
208 // but instead appear as an empty sequence
209 iterator._size = [](const void *) {return 0;};
210 iterator._moveToBegin = [](const void *, void **) {};
211 iterator._moveToEnd = [](const void *, void **) {};
212 iterator._advance = [](void **, int) {};
213 iterator._equalIter = [](void * const *, void * const *){return true; /*all iterators are nullptr*/};
214 iterator._destroyIter = [](void **){};
215 return iterator;
216 }
217
218 iterator._iterable = &value;
219 iterator._iterator = nullptr;
220 iterator._metaType_id = qMetaTypeId<QVariant>();
221 iterator._metaType_flags = QVariantConstructionFlags::ShouldDeleteVariantData;
222 iterator._iteratorCapabilities = RandomAccessCapability | BiDirectionalCapability | ForwardCapability;
223 iterator._size = [](const void *p) -> int {
224 return static_cast<QJSValue const *>(p)->property(name: QString::fromLatin1(str: "length")).toInt();
225 };
226 /* Lifetime management notes:
227 * _at and _get return a pointer to a JSValue allocated via QMetaType::create
228 * Because we set QVariantConstructionFlags::ShouldDeleteVariantData, QSequentialIterable::at
229 * and QSequentialIterable::operator*() will free that memory
230 */
231
232 iterator._at = [](const void *iterable, int index) -> void const * {
233 auto const value = static_cast<QJSValue const *>(iterable)->property(arrayIndex: quint32(index)).toVariant();
234 return QMetaType::create(type: qMetaTypeId<QVariant>(), copy: &value);
235 };
236 iterator._moveToBegin = [](const void *iterable, void **iterator) {
237 createNewIteratorIfNonExisting(iterator);
238 auto jsArrayIterator = static_cast<JSArrayIterator *>(*iterator);
239 jsArrayIterator->index = 0;
240 jsArrayIterator->data = reinterpret_cast<QJSValue const*>(iterable);
241 };
242 iterator._moveToEnd = [](const void *iterable, void **iterator) {
243 createNewIteratorIfNonExisting(iterator);
244 auto jsArrayIterator = static_cast<JSArrayIterator *>(*iterator);
245 auto length = static_cast<QJSValue const *>(iterable)->property(name: QString::fromLatin1(str: "length")).toInt();
246 jsArrayIterator->data = reinterpret_cast<QJSValue const*>(iterable);
247 jsArrayIterator->index = quint32(length);
248 };
249 iterator._advance = [](void **iterator, int advanceBy) {
250 static_cast<JSArrayIterator *>(*iterator)->index += quint32(advanceBy);
251 };
252 iterator._get = []( void * const *iterator, int metaTypeId, uint flags) -> VariantData {
253 auto const * const arrayIterator = static_cast<const JSArrayIterator *>(*iterator);
254 QJSValue const * const jsArray = arrayIterator->data;
255 auto const value = jsArray->property(arrayIndex: arrayIterator->index).toVariant();
256 Q_ASSERT(flags & QVariantConstructionFlags::ShouldDeleteVariantData);
257 return {metaTypeId, QMetaType::create(type: qMetaTypeId<QVariant>(), copy: &value), flags};
258 };
259 iterator._destroyIter = [](void **iterator) {
260 delete static_cast<JSArrayIterator *>(*iterator);
261 };
262 iterator._equalIter = [](void * const *p, void * const *other) {
263 auto this_ = static_cast<const JSArrayIterator *>(*p);
264 auto that_ = static_cast<const JSArrayIterator *>(*other);
265 return this_->index == that_->index && this_->data == that_->data;
266 };
267 iterator._copyIter = [](void **iterator, void * const * otherIterator) {
268 auto *otherIter = (static_cast<JSArrayIterator const *>(*otherIterator));
269 static_cast<JSArrayIterator *>(*iterator)->index = otherIter->index;
270 static_cast<JSArrayIterator *>(*iterator)->data = otherIter->data;
271 };
272 return iterator;
273}
274
275ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
276 : executableAllocator(new QV4::ExecutableAllocator)
277 , regExpAllocator(new QV4::ExecutableAllocator)
278 , bumperPointerAllocator(new WTF::BumpPointerAllocator)
279 , jsStack(new WTF::PageAllocation)
280 , gcStack(new WTF::PageAllocation)
281 , globalCode(nullptr)
282 , publicEngine(jsEngine)
283 , m_engineId(engineSerial.fetchAndAddOrdered(valueToAdd: 1))
284 , regExpCache(nullptr)
285 , m_multiplyWrappedQObjects(nullptr)
286#if QT_CONFIG(qml_jit)
287 , m_canAllocateExecutableMemory(OSAllocator::canAllocateExecutableMemory())
288#endif
289#if QT_CONFIG(qml_xml_http_request)
290 , m_xmlHttpRequestData(nullptr)
291#endif
292 , m_qmlEngine(nullptr)
293{
294 bool ok = false;
295 const int envMaxJSStackSize = qEnvironmentVariableIntValue(varName: "QV4_JS_MAX_STACK_SIZE", ok: &ok);
296 if (ok && envMaxJSStackSize > 0)
297 m_maxJSStackSize = envMaxJSStackSize;
298
299 const int envMaxGCStackSize = qEnvironmentVariableIntValue(varName: "QV4_GC_MAX_STACK_SIZE", ok: &ok);
300 if (ok && envMaxGCStackSize > 0)
301 m_maxGCStackSize = envMaxGCStackSize;
302
303 memoryManager = new QV4::MemoryManager(this);
304
305 if (maxCallDepth == -1) {
306 if (qEnvironmentVariableIsSet(varName: "QV4_CRASH_ON_STACKOVERFLOW")) {
307 maxCallDepth = std::numeric_limits<qint32>::max();
308 } else {
309 ok = false;
310 maxCallDepth = qEnvironmentVariableIntValue(varName: "QV4_MAX_CALL_DEPTH", ok: &ok);
311 if (!ok || maxCallDepth <= 0) {
312#if defined(QT_NO_DEBUG) && !defined(__SANITIZE_ADDRESS__) && !__has_feature(address_sanitizer)
313#ifdef Q_OS_QNX
314 maxCallDepth = 640; // QNX's stack is only 512k by default
315#else
316 maxCallDepth = 1234;
317#endif
318#else
319 // no (tail call) optimization is done, so there'll be a lot mare stack frames active
320 maxCallDepth = 200;
321#endif
322 }
323 }
324 }
325 Q_ASSERT(maxCallDepth > 0);
326
327 // reserve space for the JS stack
328 // we allow it to grow to a bit more than m_maxJSStackSize, as we can overshoot due to ScopedValues
329 // allocated outside of JIT'ed methods.
330 *jsStack = WTF::PageAllocation::allocate(size: m_maxJSStackSize + 256*1024, usage: WTF::OSAllocator::JSVMStackPages,
331 /* writable */ true, /* executable */ false,
332 /* includesGuardPages */ true);
333 jsStackBase = (Value *)jsStack->base();
334#ifdef V4_USE_VALGRIND
335 VALGRIND_MAKE_MEM_UNDEFINED(jsStackBase, m_maxJSStackSize + 256*1024);
336#endif
337
338 jsStackTop = jsStackBase;
339
340 *gcStack = WTF::PageAllocation::allocate(size: m_maxGCStackSize, usage: WTF::OSAllocator::JSVMStackPages,
341 /* writable */ true, /* executable */ false,
342 /* includesGuardPages */ true);
343
344 {
345 ok = false;
346 jitCallCountThreshold = qEnvironmentVariableIntValue(varName: "QV4_JIT_CALL_THRESHOLD", ok: &ok);
347 if (!ok)
348 jitCallCountThreshold = 3;
349 if (qEnvironmentVariableIsSet(varName: "QV4_FORCE_INTERPRETER"))
350 jitCallCountThreshold = std::numeric_limits<int>::max();
351 }
352
353 exceptionValue = jsAlloca(nValues: 1);
354 *exceptionValue = Encode::undefined();
355 globalObject = static_cast<Object *>(jsAlloca(nValues: 1));
356 jsObjects = jsAlloca(nValues: NJSObjects);
357 typedArrayPrototype = static_cast<Object *>(jsAlloca(nValues: NTypedArrayTypes));
358 typedArrayCtors = static_cast<FunctionObject *>(jsAlloca(nValues: NTypedArrayTypes));
359 jsStrings = jsAlloca(nValues: NJSStrings);
360 jsSymbols = jsAlloca(nValues: NJSSymbols);
361
362 // set up stack limits
363 jsStackLimit = jsStackBase + m_maxJSStackSize/sizeof(Value);
364
365 identifierTable = new IdentifierTable(this);
366
367 memset(s: classes, c: 0, n: sizeof(classes));
368 classes[Class_Empty] = memoryManager->allocIC<InternalClass>();
369 classes[Class_Empty]->init(engine: this);
370
371 classes[Class_MemberData] = classes[Class_Empty]->changeVTable(vt: QV4::MemberData::staticVTable());
372 classes[Class_SimpleArrayData] = classes[Class_Empty]->changeVTable(vt: QV4::SimpleArrayData::staticVTable());
373 classes[Class_SparseArrayData] = classes[Class_Empty]->changeVTable(vt: QV4::SparseArrayData::staticVTable());
374 classes[Class_ExecutionContext] = classes[Class_Empty]->changeVTable(vt: QV4::ExecutionContext::staticVTable());
375 classes[Class_CallContext] = classes[Class_Empty]->changeVTable(vt: QV4::CallContext::staticVTable());
376 classes[Class_QmlContext] = classes[Class_Empty]->changeVTable(vt: QV4::QmlContext::staticVTable());
377
378 Scope scope(this);
379 Scoped<InternalClass> ic(scope);
380 ic = classes[Class_Empty]->changeVTable(vt: QV4::Object::staticVTable());
381 jsObjects[ObjectProto] = memoryManager->allocObject<ObjectPrototype>(ic: ic->d());
382 classes[Class_Object] = ic->changePrototype(proto: objectPrototype()->d());
383 classes[Class_QmlContextWrapper] = classes[Class_Object]->changeVTable(vt: QV4::QQmlContextWrapper::staticVTable());
384
385 ic = newInternalClass(vtable: QV4::StringObject::staticVTable(), prototype: objectPrototype());
386 jsObjects[StringProto] = memoryManager->allocObject<StringPrototype>(ic: ic->d(), /*init =*/ args: false);
387 classes[Class_String] = classes[Class_Empty]->changeVTable(vt: QV4::String::staticVTable())->changePrototype(proto: stringPrototype()->d());
388 Q_ASSERT(stringPrototype()->d() && classes[Class_String]->prototype);
389
390 jsObjects[SymbolProto] = memoryManager->allocate<SymbolPrototype>();
391 classes[Class_Symbol] = classes[EngineBase::Class_Empty]->changeVTable(vt: QV4::Symbol::staticVTable())->changePrototype(proto: symbolPrototype()->d());
392
393 jsStrings[String_Empty] = newIdentifier(text: QString());
394 jsStrings[String_undefined] = newIdentifier(QStringLiteral("undefined"));
395 jsStrings[String_null] = newIdentifier(QStringLiteral("null"));
396 jsStrings[String_true] = newIdentifier(QStringLiteral("true"));
397 jsStrings[String_false] = newIdentifier(QStringLiteral("false"));
398 jsStrings[String_boolean] = newIdentifier(QStringLiteral("boolean"));
399 jsStrings[String_number] = newIdentifier(QStringLiteral("number"));
400 jsStrings[String_string] = newIdentifier(QStringLiteral("string"));
401 jsStrings[String_default] = newIdentifier(QStringLiteral("default"));
402 jsStrings[String_symbol] = newIdentifier(QStringLiteral("symbol"));
403 jsStrings[String_object] = newIdentifier(QStringLiteral("object"));
404 jsStrings[String_function] = newIdentifier(QStringLiteral("function"));
405 jsStrings[String_length] = newIdentifier(QStringLiteral("length"));
406 jsStrings[String_prototype] = newIdentifier(QStringLiteral("prototype"));
407 jsStrings[String_constructor] = newIdentifier(QStringLiteral("constructor"));
408 jsStrings[String_arguments] = newIdentifier(QStringLiteral("arguments"));
409 jsStrings[String_caller] = newIdentifier(QStringLiteral("caller"));
410 jsStrings[String_callee] = newIdentifier(QStringLiteral("callee"));
411 jsStrings[String_this] = newIdentifier(QStringLiteral("this"));
412 jsStrings[String___proto__] = newIdentifier(QStringLiteral("__proto__"));
413 jsStrings[String_enumerable] = newIdentifier(QStringLiteral("enumerable"));
414 jsStrings[String_configurable] = newIdentifier(QStringLiteral("configurable"));
415 jsStrings[String_writable] = newIdentifier(QStringLiteral("writable"));
416 jsStrings[String_value] = newIdentifier(QStringLiteral("value"));
417 jsStrings[String_get] = newIdentifier(QStringLiteral("get"));
418 jsStrings[String_set] = newIdentifier(QStringLiteral("set"));
419 jsStrings[String_eval] = newIdentifier(QStringLiteral("eval"));
420 jsStrings[String_uintMax] = newIdentifier(QStringLiteral("4294967295"));
421 jsStrings[String_name] = newIdentifier(QStringLiteral("name"));
422 jsStrings[String_index] = newIdentifier(QStringLiteral("index"));
423 jsStrings[String_input] = newIdentifier(QStringLiteral("input"));
424 jsStrings[String_toString] = newIdentifier(QStringLiteral("toString"));
425 jsStrings[String_toLocaleString] = newIdentifier(QStringLiteral("toLocaleString"));
426 jsStrings[String_destroy] = newIdentifier(QStringLiteral("destroy"));
427 jsStrings[String_valueOf] = newIdentifier(QStringLiteral("valueOf"));
428 jsStrings[String_byteLength] = newIdentifier(QStringLiteral("byteLength"));
429 jsStrings[String_byteOffset] = newIdentifier(QStringLiteral("byteOffset"));
430 jsStrings[String_buffer] = newIdentifier(QStringLiteral("buffer"));
431 jsStrings[String_lastIndex] = newIdentifier(QStringLiteral("lastIndex"));
432 jsStrings[String_next] = newIdentifier(QStringLiteral("next"));
433 jsStrings[String_done] = newIdentifier(QStringLiteral("done"));
434 jsStrings[String_return] = newIdentifier(QStringLiteral("return"));
435 jsStrings[String_throw] = newIdentifier(QStringLiteral("throw"));
436 jsStrings[String_global] = newIdentifier(QStringLiteral("global"));
437 jsStrings[String_ignoreCase] = newIdentifier(QStringLiteral("ignoreCase"));
438 jsStrings[String_multiline] = newIdentifier(QStringLiteral("multiline"));
439 jsStrings[String_unicode] = newIdentifier(QStringLiteral("unicode"));
440 jsStrings[String_sticky] = newIdentifier(QStringLiteral("sticky"));
441 jsStrings[String_source] = newIdentifier(QStringLiteral("source"));
442 jsStrings[String_flags] = newIdentifier(QStringLiteral("flags"));
443
444 jsSymbols[Symbol_hasInstance] = Symbol::create(e: this, QStringLiteral("@Symbol.hasInstance"));
445 jsSymbols[Symbol_isConcatSpreadable] = Symbol::create(e: this, QStringLiteral("@Symbol.isConcatSpreadable"));
446 jsSymbols[Symbol_iterator] = Symbol::create(e: this, QStringLiteral("@Symbol.iterator"));
447 jsSymbols[Symbol_match] = Symbol::create(e: this, QStringLiteral("@Symbol.match"));
448 jsSymbols[Symbol_replace] = Symbol::create(e: this, QStringLiteral("@Symbol.replace"));
449 jsSymbols[Symbol_search] = Symbol::create(e: this, QStringLiteral("@Symbol.search"));
450 jsSymbols[Symbol_species] = Symbol::create(e: this, QStringLiteral("@Symbol.species"));
451 jsSymbols[Symbol_split] = Symbol::create(e: this, QStringLiteral("@Symbol.split"));
452 jsSymbols[Symbol_toPrimitive] = Symbol::create(e: this, QStringLiteral("@Symbol.toPrimitive"));
453 jsSymbols[Symbol_toStringTag] = Symbol::create(e: this, QStringLiteral("@Symbol.toStringTag"));
454 jsSymbols[Symbol_unscopables] = Symbol::create(e: this, QStringLiteral("@Symbol.unscopables"));
455 jsSymbols[Symbol_revokableProxy] = Symbol::create(e: this, QStringLiteral("@Proxy.revokableProxy"));
456
457 ic = newInternalClass(vtable: ArrayPrototype::staticVTable(), prototype: objectPrototype());
458 Q_ASSERT(ic->d()->prototype);
459 ic = ic->addMember(identifier: id_length()->propertyKey(), data: Attr_NotConfigurable|Attr_NotEnumerable);
460 Q_ASSERT(ic->d()->prototype);
461 jsObjects[ArrayProto] = memoryManager->allocObject<ArrayPrototype>(ic: ic->d());
462 classes[Class_ArrayObject] = ic->changePrototype(proto: arrayPrototype()->d());
463 jsObjects[PropertyListProto] = memoryManager->allocate<PropertyListPrototype>();
464
465 Scoped<InternalClass> argsClass(scope);
466 argsClass = newInternalClass(vtable: ArgumentsObject::staticVTable(), prototype: objectPrototype());
467 argsClass = argsClass->addMember(identifier: id_length()->propertyKey(), data: Attr_NotEnumerable);
468 argsClass = argsClass->addMember(identifier: symbol_iterator()->propertyKey(), data: Attr_Data|Attr_NotEnumerable);
469 classes[Class_ArgumentsObject] = argsClass->addMember(identifier: id_callee()->propertyKey(), data: Attr_Data|Attr_NotEnumerable);
470 argsClass = newInternalClass(vtable: StrictArgumentsObject::staticVTable(), prototype: objectPrototype());
471 argsClass = argsClass->addMember(identifier: id_length()->propertyKey(), data: Attr_NotEnumerable);
472 argsClass = argsClass->addMember(identifier: symbol_iterator()->propertyKey(), data: Attr_Data|Attr_NotEnumerable);
473 classes[Class_StrictArgumentsObject] = argsClass->addMember(identifier: id_callee()->propertyKey(), data: Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
474
475 *static_cast<Value *>(globalObject) = newObject();
476 Q_ASSERT(globalObject->d()->vtable());
477 initRootContext();
478
479 ic = newInternalClass(vtable: QV4::StringObject::staticVTable(), prototype: objectPrototype());
480 ic = ic->addMember(identifier: id_length()->propertyKey(), data: Attr_ReadOnly);
481 classes[Class_StringObject] = ic->changePrototype(proto: stringPrototype()->d());
482 Q_ASSERT(classes[Class_StringObject]->verifyIndex(id_length()->propertyKey(), Heap::StringObject::LengthPropertyIndex));
483
484 classes[Class_SymbolObject] = newInternalClass(vtable: QV4::SymbolObject::staticVTable(), prototype: symbolPrototype());
485
486 jsObjects[NumberProto] = memoryManager->allocate<NumberPrototype>();
487 jsObjects[BooleanProto] = memoryManager->allocate<BooleanPrototype>();
488 jsObjects[DateProto] = memoryManager->allocate<DatePrototype>();
489
490#if defined(QT_NO_DEBUG) && !defined(QT_FORCE_ASSERTS)
491 InternalClassEntry *index = nullptr;
492#else
493 InternalClassEntry _index;
494 auto *index = &_index;
495#endif
496 ic = newInternalClass(vtable: QV4::FunctionPrototype::staticVTable(), prototype: objectPrototype());
497 auto addProtoHasInstance = [&] {
498 // Add an invalid prototype slot, so that all function objects have the same layout
499 // This helps speed up instanceof operations and other things where we need to query
500 // prototype property (as we always know it's location)
501 ic = ic->addMember(identifier: id_prototype()->propertyKey(), data: Attr_Invalid, entry: index);
502 Q_ASSERT(index->index == Heap::FunctionObject::Index_Prototype);
503 // add an invalid @hasInstance slot, so that we can quickly track whether the
504 // hasInstance method has been reimplemented. This is required for a fast
505 // instanceof implementation
506 ic = ic->addMember(identifier: symbol_hasInstance()->propertyKey(), data: Attr_Invalid, entry: index);
507 Q_ASSERT(index->index == Heap::FunctionObject::Index_HasInstance);
508 };
509 addProtoHasInstance();
510 jsObjects[FunctionProto] = memoryManager->allocObject<FunctionPrototype>(ic: ic->d());
511 ic = newInternalClass(vtable: FunctionObject::staticVTable(), prototype: functionPrototype());
512 addProtoHasInstance();
513 classes[Class_FunctionObject] = ic->d();
514 ic = ic->addMember(identifier: id_name()->propertyKey(), data: Attr_ReadOnly, entry: index);
515 Q_ASSERT(index->index == Heap::ArrowFunction::Index_Name);
516 ic = ic->addMember(identifier: id_length()->propertyKey(), data: Attr_ReadOnly_ButConfigurable, entry: index);
517 Q_ASSERT(index->index == Heap::ArrowFunction::Index_Length);
518 classes[Class_ArrowFunction] = ic->changeVTable(vt: ArrowFunction::staticVTable());
519 ic = ic->changeVTable(vt: MemberFunction::staticVTable());
520 classes[Class_MemberFunction] = ic->d();
521 ic = ic->changeVTable(vt: GeneratorFunction::staticVTable());
522 classes[Class_GeneratorFunction] = ic->d();
523 ic = ic->changeVTable(vt: MemberGeneratorFunction::staticVTable());
524 classes[Class_MemberGeneratorFunction] = ic->d();
525
526 ic = ic->changeMember(identifier: id_prototype()->propertyKey(), data: Attr_NotConfigurable|Attr_NotEnumerable);
527 ic = ic->changeVTable(vt: ScriptFunction::staticVTable());
528 classes[Class_ScriptFunction] = ic->d();
529 ic = ic->changeVTable(vt: ConstructorFunction::staticVTable());
530 classes[Class_ConstructorFunction] = ic->d();
531
532 classes[Class_ObjectProto] = classes[Class_Object]->addMember(identifier: id_constructor()->propertyKey(), data: Attr_NotEnumerable, entry: index);
533 Q_ASSERT(index->index == Heap::FunctionObject::Index_ProtoConstructor);
534
535 jsObjects[GeneratorProto] = memoryManager->allocObject<GeneratorPrototype>(ic: classes[Class_Object]);
536 classes[Class_GeneratorObject] = newInternalClass(vtable: QV4::GeneratorObject::staticVTable(), prototype: generatorPrototype());
537
538 ScopedString str(scope);
539 classes[Class_RegExp] = classes[Class_Empty]->changeVTable(vt: QV4::RegExp::staticVTable());
540 ic = newInternalClass(vtable: QV4::RegExpObject::staticVTable(), prototype: objectPrototype());
541 ic = ic->addMember(identifier: id_lastIndex()->propertyKey(), data: Attr_NotEnumerable|Attr_NotConfigurable, entry: index);
542 Q_ASSERT(index->index == RegExpObject::Index_LastIndex);
543 jsObjects[RegExpProto] = memoryManager->allocObject<RegExpPrototype>(ic: classes[Class_Object]);
544 classes[Class_RegExpObject] = ic->changePrototype(proto: regExpPrototype()->d());
545
546 ic = classes[Class_ArrayObject]->addMember(identifier: id_index()->propertyKey(), data: Attr_Data, entry: index);
547 Q_ASSERT(index->index == RegExpObject::Index_ArrayIndex);
548 classes[Class_RegExpExecArray] = ic->addMember(identifier: id_input()->propertyKey(), data: Attr_Data, entry: index);
549 Q_ASSERT(index->index == RegExpObject::Index_ArrayInput);
550
551 ic = newInternalClass(vtable: ErrorObject::staticVTable(), prototype: nullptr);
552 ic = ic->addMember(identifier: (str = newIdentifier(QStringLiteral("stack")))->propertyKey(), data: Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable, entry: index);
553 Q_ASSERT(index->index == ErrorObject::Index_Stack);
554 Q_ASSERT(index->setterIndex == ErrorObject::Index_StackSetter);
555 ic = ic->addMember(identifier: (str = newIdentifier(QStringLiteral("fileName")))->propertyKey(), data: Attr_Data|Attr_NotEnumerable, entry: index);
556 Q_ASSERT(index->index == ErrorObject::Index_FileName);
557 ic = ic->addMember(identifier: (str = newIdentifier(QStringLiteral("lineNumber")))->propertyKey(), data: Attr_Data|Attr_NotEnumerable, entry: index);
558 classes[Class_ErrorObject] = ic->d();
559 Q_ASSERT(index->index == ErrorObject::Index_LineNumber);
560 classes[Class_ErrorObjectWithMessage] = ic->addMember(identifier: (str = newIdentifier(QStringLiteral("message")))->propertyKey(), data: Attr_Data|Attr_NotEnumerable, entry: index);
561 Q_ASSERT(index->index == ErrorObject::Index_Message);
562 ic = newInternalClass(vtable: Object::staticVTable(), prototype: objectPrototype());
563 ic = ic->addMember(identifier: id_constructor()->propertyKey(), data: Attr_Data|Attr_NotEnumerable, entry: index);
564 Q_ASSERT(index->index == ErrorPrototype::Index_Constructor);
565 ic = ic->addMember(identifier: (str = newIdentifier(QStringLiteral("message")))->propertyKey(), data: Attr_Data|Attr_NotEnumerable, entry: index);
566 Q_ASSERT(index->index == ErrorPrototype::Index_Message);
567 classes[Class_ErrorProto] = ic->addMember(identifier: id_name()->propertyKey(), data: Attr_Data|Attr_NotEnumerable, entry: index);
568 Q_ASSERT(index->index == ErrorPrototype::Index_Name);
569
570 classes[Class_ProxyObject] = classes[Class_Empty]->changeVTable(vt: ProxyObject::staticVTable());
571 classes[Class_ProxyFunctionObject] = classes[Class_Empty]->changeVTable(vt: ProxyFunctionObject::staticVTable());
572
573 jsObjects[GetStack_Function] = FunctionObject::createBuiltinFunction(engine: this, nameOrSymbol: str = newIdentifier(QStringLiteral("stack")), code: ErrorObject::method_get_stack, argumentCount: 0);
574
575 jsObjects[ErrorProto] = memoryManager->allocObject<ErrorPrototype>(ic: classes[Class_ErrorProto]);
576 ic = classes[Class_ErrorProto]->changePrototype(proto: errorPrototype()->d());
577 jsObjects[EvalErrorProto] = memoryManager->allocObject<EvalErrorPrototype>(ic: ic->d());
578 jsObjects[RangeErrorProto] = memoryManager->allocObject<RangeErrorPrototype>(ic: ic->d());
579 jsObjects[ReferenceErrorProto] = memoryManager->allocObject<ReferenceErrorPrototype>(ic: ic->d());
580 jsObjects[SyntaxErrorProto] = memoryManager->allocObject<SyntaxErrorPrototype>(ic: ic->d());
581 jsObjects[TypeErrorProto] = memoryManager->allocObject<TypeErrorPrototype>(ic: ic->d());
582 jsObjects[URIErrorProto] = memoryManager->allocObject<URIErrorPrototype>(ic: ic->d());
583
584 jsObjects[VariantProto] = memoryManager->allocate<VariantPrototype>();
585 Q_ASSERT(variantPrototype()->getPrototypeOf() == objectPrototype()->d());
586
587#if QT_CONFIG(qml_sequence_object)
588 ic = newInternalClass(vtable: SequencePrototype::staticVTable(), prototype: SequencePrototype::defaultPrototype(e: this));
589 jsObjects[SequenceProto] = ScopedValue(scope, memoryManager->allocObject<SequencePrototype>(ic: ic->d()));
590#endif
591
592 ExecutionContext *global = rootContext();
593
594 jsObjects[Object_Ctor] = memoryManager->allocate<ObjectCtor>(args: global);
595 jsObjects[String_Ctor] = memoryManager->allocate<StringCtor>(args: global);
596 jsObjects[Symbol_Ctor] = memoryManager->allocate<SymbolCtor>(args: global);
597 jsObjects[Number_Ctor] = memoryManager->allocate<NumberCtor>(args: global);
598 jsObjects[Boolean_Ctor] = memoryManager->allocate<BooleanCtor>(args: global);
599 jsObjects[Array_Ctor] = memoryManager->allocate<ArrayCtor>(args: global);
600 jsObjects[Function_Ctor] = memoryManager->allocate<FunctionCtor>(args: global);
601 jsObjects[GeneratorFunction_Ctor] = memoryManager->allocate<GeneratorFunctionCtor>(args: global);
602 jsObjects[Date_Ctor] = memoryManager->allocate<DateCtor>(args: global);
603 jsObjects[RegExp_Ctor] = memoryManager->allocate<RegExpCtor>(args: global);
604 jsObjects[Error_Ctor] = memoryManager->allocate<ErrorCtor>(args: global);
605 jsObjects[EvalError_Ctor] = memoryManager->allocate<EvalErrorCtor>(args: global);
606 jsObjects[RangeError_Ctor] = memoryManager->allocate<RangeErrorCtor>(args: global);
607 jsObjects[ReferenceError_Ctor] = memoryManager->allocate<ReferenceErrorCtor>(args: global);
608 jsObjects[SyntaxError_Ctor] = memoryManager->allocate<SyntaxErrorCtor>(args: global);
609 jsObjects[TypeError_Ctor] = memoryManager->allocate<TypeErrorCtor>(args: global);
610 jsObjects[URIError_Ctor] = memoryManager->allocate<URIErrorCtor>(args: global);
611 jsObjects[IteratorProto] = memoryManager->allocate<IteratorPrototype>();
612
613 ic = newInternalClass(vtable: ForInIteratorPrototype::staticVTable(), prototype: iteratorPrototype());
614 jsObjects[ForInIteratorProto] = memoryManager->allocObject<ForInIteratorPrototype>(ic);
615 ic = newInternalClass(vtable: SetIteratorPrototype::staticVTable(), prototype: iteratorPrototype());
616 jsObjects[MapIteratorProto] = memoryManager->allocObject<MapIteratorPrototype>(ic);
617 ic = newInternalClass(vtable: SetIteratorPrototype::staticVTable(), prototype: iteratorPrototype());
618 jsObjects[SetIteratorProto] = memoryManager->allocObject<SetIteratorPrototype>(ic);
619 ic = newInternalClass(vtable: ArrayIteratorPrototype::staticVTable(), prototype: iteratorPrototype());
620 jsObjects[ArrayIteratorProto] = memoryManager->allocObject<ArrayIteratorPrototype>(ic);
621 ic = newInternalClass(vtable: StringIteratorPrototype::staticVTable(), prototype: iteratorPrototype());
622 jsObjects[StringIteratorProto] = memoryManager->allocObject<StringIteratorPrototype>(ic);
623
624 str = newString(QStringLiteral("get [Symbol.species]"));
625 jsObjects[GetSymbolSpecies] = FunctionObject::createBuiltinFunction(engine: this, nameOrSymbol: str, code: ArrayPrototype::method_get_species, argumentCount: 0);
626
627 static_cast<ObjectPrototype *>(objectPrototype())->init(engine: this, ctor: objectCtor());
628 static_cast<StringPrototype *>(stringPrototype())->init(engine: this, ctor: stringCtor());
629 static_cast<SymbolPrototype *>(symbolPrototype())->init(engine: this, ctor: symbolCtor());
630 static_cast<NumberPrototype *>(numberPrototype())->init(engine: this, ctor: numberCtor());
631 static_cast<BooleanPrototype *>(booleanPrototype())->init(engine: this, ctor: booleanCtor());
632 static_cast<ArrayPrototype *>(arrayPrototype())->init(engine: this, ctor: arrayCtor());
633 static_cast<PropertyListPrototype *>(propertyListPrototype())->init(engine: this);
634 static_cast<DatePrototype *>(datePrototype())->init(engine: this, ctor: dateCtor());
635 static_cast<FunctionPrototype *>(functionPrototype())->init(engine: this, ctor: functionCtor());
636 static_cast<GeneratorPrototype *>(generatorPrototype())->init(engine: this, ctor: generatorFunctionCtor());
637 static_cast<RegExpPrototype *>(regExpPrototype())->init(engine: this, ctor: regExpCtor());
638 static_cast<ErrorPrototype *>(errorPrototype())->init(engine: this, ctor: errorCtor());
639 static_cast<EvalErrorPrototype *>(evalErrorPrototype())->init(engine: this, ctor: evalErrorCtor());
640 static_cast<RangeErrorPrototype *>(rangeErrorPrototype())->init(engine: this, ctor: rangeErrorCtor());
641 static_cast<ReferenceErrorPrototype *>(referenceErrorPrototype())->init(engine: this, ctor: referenceErrorCtor());
642 static_cast<SyntaxErrorPrototype *>(syntaxErrorPrototype())->init(engine: this, ctor: syntaxErrorCtor());
643 static_cast<TypeErrorPrototype *>(typeErrorPrototype())->init(engine: this, ctor: typeErrorCtor());
644 static_cast<URIErrorPrototype *>(uRIErrorPrototype())->init(engine: this, ctor: uRIErrorCtor());
645
646 static_cast<IteratorPrototype *>(iteratorPrototype())->init(engine: this);
647 static_cast<ForInIteratorPrototype *>(forInIteratorPrototype())->init(engine: this);
648 static_cast<MapIteratorPrototype *>(mapIteratorPrototype())->init(engine: this);
649 static_cast<SetIteratorPrototype *>(setIteratorPrototype())->init(engine: this);
650 static_cast<ArrayIteratorPrototype *>(arrayIteratorPrototype())->init(engine: this);
651 static_cast<StringIteratorPrototype *>(stringIteratorPrototype())->init(engine: this);
652
653 static_cast<VariantPrototype *>(variantPrototype())->init();
654
655#if QT_CONFIG(qml_sequence_object)
656 sequencePrototype()->cast<SequencePrototype>()->init();
657#endif
658
659 jsObjects[WeakMap_Ctor] = memoryManager->allocate<WeakMapCtor>(args: global);
660 jsObjects[WeakMapProto] = memoryManager->allocate<WeakMapPrototype>();
661 static_cast<WeakMapPrototype *>(weakMapPrototype())->init(engine: this, ctor: weakMapCtor());
662
663 jsObjects[Map_Ctor] = memoryManager->allocate<MapCtor>(args: global);
664 jsObjects[MapProto] = memoryManager->allocate<MapPrototype>();
665 static_cast<MapPrototype *>(mapPrototype())->init(engine: this, ctor: mapCtor());
666
667 jsObjects[WeakSet_Ctor] = memoryManager->allocate<WeakSetCtor>(args: global);
668 jsObjects[WeakSetProto] = memoryManager->allocate<WeakSetPrototype>();
669 static_cast<WeakSetPrototype *>(weakSetPrototype())->init(engine: this, ctor: weakSetCtor());
670
671 jsObjects[Set_Ctor] = memoryManager->allocate<SetCtor>(args: global);
672 jsObjects[SetProto] = memoryManager->allocate<SetPrototype>();
673 static_cast<SetPrototype *>(setPrototype())->init(engine: this, ctor: setCtor());
674
675 //
676 // promises
677 //
678
679 jsObjects[Promise_Ctor] = memoryManager->allocate<PromiseCtor>(args: global);
680 jsObjects[PromiseProto] = memoryManager->allocate<PromisePrototype>();
681 static_cast<PromisePrototype *>(promisePrototype())->init(engine: this, ctor: promiseCtor());
682
683 // typed arrays
684
685 jsObjects[SharedArrayBuffer_Ctor] = memoryManager->allocate<SharedArrayBufferCtor>(args: global);
686 jsObjects[SharedArrayBufferProto] = memoryManager->allocate<SharedArrayBufferPrototype>();
687 static_cast<SharedArrayBufferPrototype *>(sharedArrayBufferPrototype())->init(engine: this, ctor: sharedArrayBufferCtor());
688
689 jsObjects[ArrayBuffer_Ctor] = memoryManager->allocate<ArrayBufferCtor>(args: global);
690 jsObjects[ArrayBufferProto] = memoryManager->allocate<ArrayBufferPrototype>();
691 static_cast<ArrayBufferPrototype *>(arrayBufferPrototype())->init(engine: this, ctor: arrayBufferCtor());
692
693 jsObjects[DataView_Ctor] = memoryManager->allocate<DataViewCtor>(args: global);
694 jsObjects[DataViewProto] = memoryManager->allocate<DataViewPrototype>();
695 static_cast<DataViewPrototype *>(dataViewPrototype())->init(engine: this, ctor: dataViewCtor());
696 jsObjects[ValueTypeProto] = (Heap::Base *) nullptr;
697 jsObjects[SignalHandlerProto] = (Heap::Base *) nullptr;
698
699 jsObjects[IntrinsicTypedArray_Ctor] = memoryManager->allocate<IntrinsicTypedArrayCtor>(args: global);
700 jsObjects[IntrinsicTypedArrayProto] = memoryManager->allocate<IntrinsicTypedArrayPrototype>();
701 static_cast<IntrinsicTypedArrayPrototype *>(intrinsicTypedArrayPrototype())
702 ->init(engine: this, ctor: static_cast<IntrinsicTypedArrayCtor *>(intrinsicTypedArrayCtor()));
703
704 for (int i = 0; i < NTypedArrayTypes; ++i) {
705 static_cast<Value &>(typedArrayCtors[i]) = memoryManager->allocate<TypedArrayCtor>(args: global, args: Heap::TypedArray::Type(i));
706 static_cast<Value &>(typedArrayPrototype[i]) = memoryManager->allocate<TypedArrayPrototype>(args: Heap::TypedArray::Type(i));
707 typedArrayPrototype[i].as<TypedArrayPrototype>()->init(engine: this, ctor: static_cast<TypedArrayCtor *>(typedArrayCtors[i].as<Object>()));
708 }
709
710 //
711 // set up the global object
712 //
713 rootContext()->d()->activation.set(e: scope.engine, newVal: globalObject->d());
714 Q_ASSERT(globalObject->d()->vtable());
715
716 globalObject->defineDefaultProperty(QStringLiteral("Object"), value: *objectCtor());
717 globalObject->defineDefaultProperty(QStringLiteral("String"), value: *stringCtor());
718 globalObject->defineDefaultProperty(QStringLiteral("Symbol"), value: *symbolCtor());
719 FunctionObject *numberObject = numberCtor();
720 globalObject->defineDefaultProperty(QStringLiteral("Number"), value: *numberObject);
721 globalObject->defineDefaultProperty(QStringLiteral("Boolean"), value: *booleanCtor());
722 globalObject->defineDefaultProperty(QStringLiteral("Array"), value: *arrayCtor());
723 globalObject->defineDefaultProperty(QStringLiteral("Function"), value: *functionCtor());
724 globalObject->defineDefaultProperty(QStringLiteral("Date"), value: *dateCtor());
725 globalObject->defineDefaultProperty(QStringLiteral("RegExp"), value: *regExpCtor());
726 globalObject->defineDefaultProperty(QStringLiteral("Error"), value: *errorCtor());
727 globalObject->defineDefaultProperty(QStringLiteral("EvalError"), value: *evalErrorCtor());
728 globalObject->defineDefaultProperty(QStringLiteral("RangeError"), value: *rangeErrorCtor());
729 globalObject->defineDefaultProperty(QStringLiteral("ReferenceError"), value: *referenceErrorCtor());
730 globalObject->defineDefaultProperty(QStringLiteral("SyntaxError"), value: *syntaxErrorCtor());
731 globalObject->defineDefaultProperty(QStringLiteral("TypeError"), value: *typeErrorCtor());
732 globalObject->defineDefaultProperty(QStringLiteral("URIError"), value: *uRIErrorCtor());
733 globalObject->defineDefaultProperty(QStringLiteral("Promise"), value: *promiseCtor());
734
735 globalObject->defineDefaultProperty(QStringLiteral("SharedArrayBuffer"), value: *sharedArrayBufferCtor());
736 globalObject->defineDefaultProperty(QStringLiteral("ArrayBuffer"), value: *arrayBufferCtor());
737 globalObject->defineDefaultProperty(QStringLiteral("DataView"), value: *dataViewCtor());
738 globalObject->defineDefaultProperty(QStringLiteral("WeakSet"), value: *weakSetCtor());
739 globalObject->defineDefaultProperty(QStringLiteral("Set"), value: *setCtor());
740 globalObject->defineDefaultProperty(QStringLiteral("WeakMap"), value: *weakMapCtor());
741 globalObject->defineDefaultProperty(QStringLiteral("Map"), value: *mapCtor());
742
743 for (int i = 0; i < NTypedArrayTypes; ++i)
744 globalObject->defineDefaultProperty(name: (str = typedArrayCtors[i].as<FunctionObject>()->name()), value: typedArrayCtors[i]);
745 ScopedObject o(scope);
746 globalObject->defineDefaultProperty(QStringLiteral("Atomics"), value: (o = memoryManager->allocate<Atomics>()));
747 globalObject->defineDefaultProperty(QStringLiteral("Math"), value: (o = memoryManager->allocate<MathObject>()));
748 globalObject->defineDefaultProperty(QStringLiteral("JSON"), value: (o = memoryManager->allocate<JsonObject>()));
749 globalObject->defineDefaultProperty(QStringLiteral("Reflect"), value: (o = memoryManager->allocate<Reflect>()));
750 globalObject->defineDefaultProperty(QStringLiteral("Proxy"), value: (o = memoryManager->allocate<Proxy>(args: rootContext())));
751
752 globalObject->defineReadonlyProperty(QStringLiteral("undefined"), value: Value::undefinedValue());
753 globalObject->defineReadonlyProperty(QStringLiteral("NaN"), value: Value::fromDouble(d: std::numeric_limits<double>::quiet_NaN()));
754 globalObject->defineReadonlyProperty(QStringLiteral("Infinity"), value: Value::fromDouble(Q_INFINITY));
755
756
757 jsObjects[Eval_Function] = memoryManager->allocate<EvalFunction>(args: global);
758 globalObject->defineDefaultProperty(QStringLiteral("eval"), value: *evalFunction());
759
760 // ES6: 20.1.2.12 & 20.1.2.13:
761 // parseInt and parseFloat must be the same FunctionObject on the global &
762 // Number object.
763 {
764 QString piString(QStringLiteral("parseInt"));
765 QString pfString(QStringLiteral("parseFloat"));
766 Scope scope(this);
767 ScopedString pi(scope, newIdentifier(text: piString));
768 ScopedString pf(scope, newIdentifier(text: pfString));
769 ScopedFunctionObject parseIntFn(scope, FunctionObject::createBuiltinFunction(engine: this, nameOrSymbol: pi, code: GlobalFunctions::method_parseInt, argumentCount: 2));
770 ScopedFunctionObject parseFloatFn(scope, FunctionObject::createBuiltinFunction(engine: this, nameOrSymbol: pf, code: GlobalFunctions::method_parseFloat, argumentCount: 1));
771 globalObject->defineDefaultProperty(name: piString, value: parseIntFn);
772 globalObject->defineDefaultProperty(name: pfString, value: parseFloatFn);
773 numberObject->defineDefaultProperty(name: piString, value: parseIntFn);
774 numberObject->defineDefaultProperty(name: pfString, value: parseFloatFn);
775 }
776
777 globalObject->defineDefaultProperty(QStringLiteral("isNaN"), code: GlobalFunctions::method_isNaN, argumentCount: 1);
778 globalObject->defineDefaultProperty(QStringLiteral("isFinite"), code: GlobalFunctions::method_isFinite, argumentCount: 1);
779 globalObject->defineDefaultProperty(QStringLiteral("decodeURI"), code: GlobalFunctions::method_decodeURI, argumentCount: 1);
780 globalObject->defineDefaultProperty(QStringLiteral("decodeURIComponent"), code: GlobalFunctions::method_decodeURIComponent, argumentCount: 1);
781 globalObject->defineDefaultProperty(QStringLiteral("encodeURI"), code: GlobalFunctions::method_encodeURI, argumentCount: 1);
782 globalObject->defineDefaultProperty(QStringLiteral("encodeURIComponent"), code: GlobalFunctions::method_encodeURIComponent, argumentCount: 1);
783 globalObject->defineDefaultProperty(QStringLiteral("escape"), code: GlobalFunctions::method_escape, argumentCount: 1);
784 globalObject->defineDefaultProperty(QStringLiteral("unescape"), code: GlobalFunctions::method_unescape, argumentCount: 1);
785
786 ScopedFunctionObject t(scope, memoryManager->allocate<FunctionObject>(args: rootContext(), args: nullptr, args: ::throwTypeError));
787 t->defineReadonlyProperty(name: id_length(), value: Value::fromInt32(i: 0));
788 t->setInternalClass(t->internalClass()->cryopreserved());
789 jsObjects[ThrowerObject] = t;
790
791 ScopedProperty pd(scope);
792 pd->value = thrower();
793 pd->set = thrower();
794 functionPrototype()->insertMember(s: id_caller(), p: pd, attributes: Attr_Accessor|Attr_ReadOnly_ButConfigurable);
795 functionPrototype()->insertMember(s: id_arguments(), p: pd, attributes: Attr_Accessor|Attr_ReadOnly_ButConfigurable);
796
797 qMetaTypeId<QJSValue>();
798 qMetaTypeId<QList<int> >();
799
800 if (!QMetaType::hasRegisteredConverterFunction<QJSValue, QVariantMap>())
801 QMetaType::registerConverter<QJSValue, QVariantMap>(function: convertJSValueToVariantType<QVariantMap>);
802 if (!QMetaType::hasRegisteredConverterFunction<QJSValue, QVariantList>())
803 QMetaType::registerConverter<QJSValue, QVariantList>(function: convertJSValueToVariantType<QVariantList>);
804 if (!QMetaType::hasRegisteredConverterFunction<QJSValue, QStringList>())
805 QMetaType::registerConverter<QJSValue, QStringList>(function: convertJSValueToVariantType<QStringList>);
806 if (!QMetaType::hasRegisteredConverterFunction<QJSValue, QtMetaTypePrivate::QSequentialIterableImpl>())
807 QMetaType::registerConverter<QJSValue, QtMetaTypePrivate::QSequentialIterableImpl>(function: jsvalueToSequence);
808 QMetaType::registerStreamOperators(type: qMetaTypeId<QJSValue>(), saveOp: saveJSValue, loadOp: restoreJSValue);
809
810 QV4::QObjectWrapper::initializeBindings(engine: this);
811
812 m_delayedCallQueue.init(this);
813}
814
815ExecutionEngine::~ExecutionEngine()
816{
817 modules.clear();
818 qDeleteAll(c: m_extensionData);
819 delete m_multiplyWrappedQObjects;
820 m_multiplyWrappedQObjects = nullptr;
821 delete identifierTable;
822 delete memoryManager;
823
824 while (!compilationUnits.isEmpty())
825 (*compilationUnits.begin())->unlink();
826
827 delete bumperPointerAllocator;
828 delete regExpCache;
829 delete regExpAllocator;
830 delete executableAllocator;
831 jsStack->deallocate();
832 delete jsStack;
833 gcStack->deallocate();
834 delete gcStack;
835
836#if QT_CONFIG(qml_xml_http_request)
837 qt_rem_qmlxmlhttprequest(engine: this, m_xmlHttpRequestData);
838 m_xmlHttpRequestData = nullptr;
839#endif
840}
841
842ExecutionContext *ExecutionEngine::currentContext() const
843{
844 return static_cast<ExecutionContext *>(&currentStackFrame->jsFrame->context);
845}
846
847#if QT_CONFIG(qml_debug)
848void ExecutionEngine::setDebugger(Debugging::Debugger *debugger)
849{
850 Q_ASSERT(!m_debugger);
851 m_debugger.reset(other: debugger);
852}
853
854void ExecutionEngine::setProfiler(Profiling::Profiler *profiler)
855{
856 Q_ASSERT(!m_profiler);
857 m_profiler.reset(other: profiler);
858}
859#endif // QT_CONFIG(qml_debug)
860
861void ExecutionEngine::initRootContext()
862{
863 Scope scope(this);
864 Scoped<ExecutionContext> r(scope, memoryManager->allocManaged<ExecutionContext>(size: sizeof(ExecutionContext::Data)));
865 r->d_unchecked()->init(t: Heap::ExecutionContext::Type_GlobalContext);
866 r->d()->activation.set(e: this, newVal: globalObject->d());
867 jsObjects[RootContext] = r;
868 jsObjects[ScriptContext] = r;
869 jsObjects[IntegerNull] = Encode((int)0);
870}
871
872Heap::InternalClass *ExecutionEngine::newClass(Heap::InternalClass *other)
873{
874 Heap::InternalClass *ic = memoryManager->allocIC<InternalClass>();
875 ic->init(other);
876 return ic;
877}
878
879Heap::InternalClass *ExecutionEngine::newInternalClass(const VTable *vtable, Object *prototype)
880{
881 Scope scope(this);
882 Scoped<InternalClass> ic(scope, internalClasses(icType: Class_Empty)->changeVTable(vt: vtable));
883 return ic->changePrototype(proto: prototype ? prototype->d() : nullptr);
884}
885
886Heap::Object *ExecutionEngine::newObject()
887{
888 return memoryManager->allocate<Object>();
889}
890
891Heap::Object *ExecutionEngine::newObject(Heap::InternalClass *internalClass)
892{
893 return memoryManager->allocObject<Object>(ic: internalClass);
894}
895
896Heap::String *ExecutionEngine::newString(const QString &s)
897{
898 return memoryManager->allocWithStringData<String>(unmanagedSize: s.length() * sizeof(QChar), arg1: s);
899}
900
901Heap::String *ExecutionEngine::newIdentifier(const QString &text)
902{
903 Scope scope(this);
904 ScopedString s(scope, memoryManager->allocWithStringData<String>(unmanagedSize: text.length() * sizeof(QChar), arg1: text));
905 s->toPropertyKey();
906 return s->d();
907}
908
909Heap::Object *ExecutionEngine::newStringObject(const String *string)
910{
911 return memoryManager->allocate<StringObject>(args: string);
912}
913
914Heap::Object *ExecutionEngine::newSymbolObject(const Symbol *symbol)
915{
916 return memoryManager->allocObject<SymbolObject>(ic: classes[Class_SymbolObject], args: symbol);
917}
918
919Heap::Object *ExecutionEngine::newNumberObject(double value)
920{
921 return memoryManager->allocate<NumberObject>(args: value);
922}
923
924Heap::Object *ExecutionEngine::newBooleanObject(bool b)
925{
926 return memoryManager->allocate<BooleanObject>(args: b);
927}
928
929Heap::ArrayObject *ExecutionEngine::newArrayObject(int count)
930{
931 Scope scope(this);
932 ScopedArrayObject object(scope, memoryManager->allocate<ArrayObject>());
933
934 if (count) {
935 if (count < 0x1000)
936 object->arrayReserve(n: count);
937 object->setArrayLengthUnchecked(count);
938 }
939 return object->d();
940}
941
942Heap::ArrayObject *ExecutionEngine::newArrayObject(const Value *values, int length)
943{
944 Scope scope(this);
945 ScopedArrayObject a(scope, memoryManager->allocate<ArrayObject>());
946
947 if (length) {
948 size_t size = sizeof(Heap::ArrayData) + (length-1)*sizeof(Value);
949 Heap::SimpleArrayData *d = scope.engine->memoryManager->allocManaged<SimpleArrayData>(size);
950 d->init();
951 d->type = Heap::ArrayData::Simple;
952 d->offset = 0;
953 d->values.alloc = length;
954 d->values.size = length;
955 // this doesn't require a write barrier, things will be ok, when the new array data gets inserted into
956 // the parent object
957 memcpy(dest: &d->values.values, src: values, n: length*sizeof(Value));
958 a->d()->arrayData.set(e: this, newVal: d);
959 a->setArrayLengthUnchecked(length);
960 }
961 return a->d();
962}
963
964Heap::ArrayObject *ExecutionEngine::newArrayObject(const QStringList &list)
965{
966 return memoryManager->allocate<ArrayObject>(args: list);
967}
968
969Heap::ArrayObject *ExecutionEngine::newArrayObject(Heap::InternalClass *internalClass)
970{
971 return memoryManager->allocObject<ArrayObject>(ic: internalClass);
972}
973
974Heap::ArrayBuffer *ExecutionEngine::newArrayBuffer(const QByteArray &array)
975{
976 return memoryManager->allocate<ArrayBuffer>(args: array);
977}
978
979Heap::ArrayBuffer *ExecutionEngine::newArrayBuffer(size_t length)
980{
981 return memoryManager->allocate<ArrayBuffer>(args: length);
982}
983
984
985Heap::DateObject *ExecutionEngine::newDateObject(const Value &value)
986{
987 return memoryManager->allocate<DateObject>(args: value);
988}
989
990Heap::DateObject *ExecutionEngine::newDateObject(const QDateTime &dt)
991{
992 Scope scope(this);
993 Scoped<DateObject> object(scope, memoryManager->allocate<DateObject>(args: dt));
994 return object->d();
995}
996
997Heap::DateObject *ExecutionEngine::newDateObjectFromTime(const QTime &t)
998{
999 Scope scope(this);
1000 Scoped<DateObject> object(scope, memoryManager->allocate<DateObject>(args: t));
1001 return object->d();
1002}
1003
1004Heap::RegExpObject *ExecutionEngine::newRegExpObject(const QString &pattern, int flags)
1005{
1006 Scope scope(this);
1007 Scoped<RegExp> re(scope, RegExp::create(engine: this, pattern, flags: static_cast<CompiledData::RegExp::Flags>(flags)));
1008 return newRegExpObject(re);
1009}
1010
1011Heap::RegExpObject *ExecutionEngine::newRegExpObject(RegExp *re)
1012{
1013 return memoryManager->allocate<RegExpObject>(args: re);
1014}
1015
1016Heap::RegExpObject *ExecutionEngine::newRegExpObject(const QRegExp &re)
1017{
1018 return memoryManager->allocate<RegExpObject>(args: re);
1019}
1020
1021#if QT_CONFIG(regularexpression)
1022Heap::RegExpObject *ExecutionEngine::newRegExpObject(const QRegularExpression &re)
1023{
1024 return memoryManager->allocate<RegExpObject>(args: re);
1025}
1026#endif
1027
1028Heap::Object *ExecutionEngine::newErrorObject(const Value &value)
1029{
1030 return ErrorObject::create<ErrorObject>(e: this, message: value, newTarget: errorCtor());
1031}
1032
1033Heap::Object *ExecutionEngine::newErrorObject(const QString &message)
1034{
1035 return ErrorObject::create<ErrorObject>(e: this, message);
1036}
1037
1038Heap::Object *ExecutionEngine::newSyntaxErrorObject(const QString &message)
1039{
1040 return ErrorObject::create<SyntaxErrorObject>(e: this, message);
1041}
1042
1043Heap::Object *ExecutionEngine::newSyntaxErrorObject(const QString &message, const QString &fileName, int line, int column)
1044{
1045 return ErrorObject::create<SyntaxErrorObject>(e: this, message, filename: fileName, line, column);
1046}
1047
1048
1049Heap::Object *ExecutionEngine::newReferenceErrorObject(const QString &message)
1050{
1051 return ErrorObject::create<ReferenceErrorObject>(e: this, message);
1052}
1053
1054Heap::Object *ExecutionEngine::newReferenceErrorObject(const QString &message, const QString &fileName, int line, int column)
1055{
1056 return ErrorObject::create<ReferenceErrorObject>(e: this, message, filename: fileName, line, column);
1057}
1058
1059
1060Heap::Object *ExecutionEngine::newTypeErrorObject(const QString &message)
1061{
1062 return ErrorObject::create<TypeErrorObject>(e: this, message);
1063}
1064
1065Heap::Object *ExecutionEngine::newRangeErrorObject(const QString &message)
1066{
1067 return ErrorObject::create<RangeErrorObject>(e: this, message);
1068}
1069
1070Heap::Object *ExecutionEngine::newURIErrorObject(const Value &message)
1071{
1072 return ErrorObject::create<URIErrorObject>(e: this, message, newTarget: uRIErrorCtor());
1073}
1074
1075Heap::PromiseObject *ExecutionEngine::newPromiseObject()
1076{
1077 if (!m_reactionHandler) {
1078 m_reactionHandler.reset(other: new Promise::ReactionHandler);
1079 }
1080
1081 Scope scope(this);
1082 Scoped<PromiseObject> object(scope, memoryManager->allocate<PromiseObject>(args: this));
1083 return object->d();
1084}
1085
1086Heap::Object *ExecutionEngine::newPromiseObject(const QV4::FunctionObject *thisObject, const QV4::PromiseCapability *capability)
1087{
1088 if (!m_reactionHandler) {
1089 m_reactionHandler.reset(other: new Promise::ReactionHandler);
1090 }
1091
1092 Scope scope(this);
1093 Scoped<CapabilitiesExecutorWrapper> executor(scope, memoryManager->allocate<CapabilitiesExecutorWrapper>());
1094 executor->d()->capabilities.set(e: this, newVal: capability->d());
1095 executor->insertMember(s: id_length(), v: Primitive::fromInt32(i: 2), attributes: Attr_NotWritable|Attr_NotEnumerable);
1096
1097 ScopedObject object(scope, thisObject->callAsConstructor(argv: executor, argc: 1));
1098 return object->d();
1099}
1100
1101Promise::ReactionHandler *ExecutionEngine::getPromiseReactionHandler()
1102{
1103 Q_ASSERT(m_reactionHandler);
1104 return m_reactionHandler.data();
1105}
1106
1107Heap::Object *ExecutionEngine::newURIErrorObject(const QString &message)
1108{
1109 return ErrorObject::create<URIErrorObject>(e: this, message);
1110}
1111
1112Heap::Object *ExecutionEngine::newEvalErrorObject(const QString &message)
1113{
1114 return ErrorObject::create<EvalErrorObject>(e: this, message);
1115}
1116
1117Heap::Object *ExecutionEngine::newVariantObject(const QVariant &v)
1118{
1119 return memoryManager->allocate<VariantObject>(args: v);
1120}
1121
1122Heap::Object *ExecutionEngine::newForInIteratorObject(Object *o)
1123{
1124 Scope scope(this);
1125 ScopedObject obj(scope, memoryManager->allocate<ForInIteratorObject>(args: o));
1126 return obj->d();
1127}
1128
1129Heap::Object *ExecutionEngine::newMapIteratorObject(Object *o)
1130{
1131 return memoryManager->allocate<MapIteratorObject>(args: o->d(), args: this);
1132}
1133
1134Heap::Object *ExecutionEngine::newSetIteratorObject(Object *o)
1135{
1136 return memoryManager->allocate<SetIteratorObject>(args: o->d(), args: this);
1137}
1138
1139Heap::Object *ExecutionEngine::newArrayIteratorObject(Object *o)
1140{
1141 return memoryManager->allocate<ArrayIteratorObject>(args: o->d(), args: this);
1142}
1143
1144Heap::QmlContext *ExecutionEngine::qmlContext() const
1145{
1146 if (!currentStackFrame)
1147 return nullptr;
1148 Heap::ExecutionContext *ctx = currentContext()->d();
1149
1150 if (ctx->type != Heap::ExecutionContext::Type_QmlContext && !ctx->outer)
1151 return nullptr;
1152
1153 while (ctx->outer && ctx->outer->type != Heap::ExecutionContext::Type_GlobalContext)
1154 ctx = ctx->outer;
1155
1156 Q_ASSERT(ctx);
1157 if (ctx->type != Heap::ExecutionContext::Type_QmlContext)
1158 return nullptr;
1159
1160 return static_cast<Heap::QmlContext *>(ctx);
1161}
1162
1163QObject *ExecutionEngine::qmlScopeObject() const
1164{
1165 Heap::QmlContext *ctx = qmlContext();
1166 if (!ctx)
1167 return nullptr;
1168
1169 return ctx->qml()->scopeObject;
1170}
1171
1172QQmlContextData *ExecutionEngine::callingQmlContext() const
1173{
1174 Heap::QmlContext *ctx = qmlContext();
1175 if (!ctx)
1176 return nullptr;
1177
1178 return ctx->qml()->context->contextData();
1179}
1180
1181StackTrace ExecutionEngine::stackTrace(int frameLimit) const
1182{
1183 Scope scope(const_cast<ExecutionEngine *>(this));
1184 ScopedString name(scope);
1185 StackTrace stack;
1186
1187 CppStackFrame *f = currentStackFrame;
1188 while (f && frameLimit) {
1189 QV4::StackFrame frame;
1190 frame.source = f->source();
1191 frame.function = f->function();
1192 frame.line = qAbs(t: f->lineNumber());
1193 frame.column = -1;
1194 stack.append(t: frame);
1195 if (f->isTailCalling) {
1196 QV4::StackFrame frame;
1197 frame.function = QStringLiteral("[elided tail calls]");
1198 stack.append(t: frame);
1199 }
1200 --frameLimit;
1201 f = f->parent;
1202 }
1203
1204 return stack;
1205}
1206
1207/* Helper and "C" linkage exported function to format a GDBMI stacktrace for
1208 * invocation by a debugger.
1209 * Sample GDB invocation: print qt_v4StackTrace((void*)0x7fffffffb290)
1210 * Sample CDB invocation: .call Qt5Qmld!qt_v4StackTrace(0x7fffffffb290) ; gh
1211 * Note: The helper is there to suppress MSVC warning 4190 about anything
1212 * with UDT return types in a "C" linkage function. */
1213
1214static inline char *v4StackTrace(const ExecutionContext *context)
1215{
1216 QString result;
1217 QTextStream str(&result);
1218 str << "stack=[";
1219 if (context && context->engine()) {
1220 const QVector<StackFrame> stackTrace = context->engine()->stackTrace(frameLimit: 20);
1221 for (int i = 0; i < stackTrace.size(); ++i) {
1222 if (i)
1223 str << ',';
1224 const QUrl url(stackTrace.at(i).source);
1225 const QString fileName = url.isLocalFile() ? url.toLocalFile() : url.toString();
1226 str << "frame={level=\"" << i << "\",func=\"" << stackTrace.at(i).function
1227 << "\",file=\"" << fileName << "\",fullname=\"" << fileName
1228 << "\",line=\"" << stackTrace.at(i).line << "\",language=\"js\"}";
1229 }
1230 }
1231 str << ']';
1232 return qstrdup(result.toLocal8Bit().constData());
1233}
1234
1235extern "C" Q_QML_EXPORT char *qt_v4StackTrace(void *executionContext)
1236{
1237 return v4StackTrace(context: reinterpret_cast<const ExecutionContext *>(executionContext));
1238}
1239
1240extern "C" Q_QML_EXPORT char *qt_v4StackTraceForEngine(void *executionEngine)
1241{
1242 auto engine = (reinterpret_cast<const ExecutionEngine *>(executionEngine));
1243 return v4StackTrace(context: engine->currentContext());
1244}
1245
1246QUrl ExecutionEngine::resolvedUrl(const QString &file)
1247{
1248 QUrl src(file);
1249 if (!src.isRelative())
1250 return src;
1251
1252 QUrl base;
1253 CppStackFrame *f = currentStackFrame;
1254 while (f) {
1255 if (f->v4Function) {
1256 base = f->v4Function->finalUrl();
1257 break;
1258 }
1259 f = f->parent;
1260 }
1261
1262 if (base.isEmpty() && globalCode)
1263 base = globalCode->finalUrl();
1264
1265 if (base.isEmpty())
1266 return src;
1267
1268 return base.resolved(relative: src);
1269}
1270
1271void ExecutionEngine::markObjects(MarkStack *markStack)
1272{
1273 for (int i = 0; i < NClasses; ++i) {
1274 if (Heap::InternalClass *c = classes[i])
1275 c->mark(markStack);
1276 }
1277
1278 identifierTable->markObjects(markStack);
1279
1280 for (auto compilationUnit: compilationUnits)
1281 compilationUnit->markObjects(markStack);
1282}
1283
1284ReturnedValue ExecutionEngine::throwError(const Value &value)
1285{
1286 // we can get in here with an exception already set, as the runtime
1287 // doesn't check after every operation that can throw.
1288 // in this case preserve the first exception to give correct error
1289 // information
1290 if (hasException)
1291 return Encode::undefined();
1292
1293 hasException = true;
1294 *exceptionValue = value;
1295 QV4::Scope scope(this);
1296 QV4::Scoped<ErrorObject> error(scope, value);
1297 if (!!error)
1298 exceptionStackTrace = *error->d()->stackTrace;
1299 else
1300 exceptionStackTrace = stackTrace();
1301
1302 if (QV4::Debugging::Debugger *debug = debugger())
1303 debug->aboutToThrow();
1304
1305 return Encode::undefined();
1306}
1307
1308ReturnedValue ExecutionEngine::catchException(StackTrace *trace)
1309{
1310 Q_ASSERT(hasException);
1311 if (trace)
1312 *trace = exceptionStackTrace;
1313 exceptionStackTrace.clear();
1314 hasException = false;
1315 ReturnedValue res = exceptionValue->asReturnedValue();
1316 *exceptionValue = Value::emptyValue();
1317 return res;
1318}
1319
1320ReturnedValue ExecutionEngine::throwError(const QString &message)
1321{
1322 Scope scope(this);
1323 ScopedValue v(scope, newString(s: message));
1324 v = newErrorObject(value: v);
1325 return throwError(value: v);
1326}
1327
1328ReturnedValue ExecutionEngine::throwSyntaxError(const QString &message, const QString &fileName, int line, int column)
1329{
1330 Scope scope(this);
1331 ScopedObject error(scope, newSyntaxErrorObject(message, fileName, line, column));
1332 return throwError(value: error);
1333}
1334
1335ReturnedValue ExecutionEngine::throwSyntaxError(const QString &message)
1336{
1337 Scope scope(this);
1338 ScopedObject error(scope, newSyntaxErrorObject(message));
1339 return throwError(value: error);
1340}
1341
1342
1343ReturnedValue ExecutionEngine::throwTypeError()
1344{
1345 Scope scope(this);
1346 ScopedObject error(scope, newTypeErrorObject(QStringLiteral("Type error")));
1347 return throwError(value: error);
1348}
1349
1350ReturnedValue ExecutionEngine::throwTypeError(const QString &message)
1351{
1352 Scope scope(this);
1353 ScopedObject error(scope, newTypeErrorObject(message));
1354 return throwError(value: error);
1355}
1356
1357ReturnedValue ExecutionEngine::throwReferenceError(const QString &name)
1358{
1359 Scope scope(this);
1360 QString msg = name + QLatin1String(" is not defined");
1361 ScopedObject error(scope, newReferenceErrorObject(message: msg));
1362 return throwError(value: error);
1363}
1364
1365ReturnedValue ExecutionEngine::throwReferenceError(const Value &value)
1366{
1367 Scope scope(this);
1368 ScopedString s(scope, value.toString(e: this));
1369 QString msg = s->toQString() + QLatin1String(" is not defined");
1370 ScopedObject error(scope, newReferenceErrorObject(message: msg));
1371 return throwError(value: error);
1372}
1373
1374ReturnedValue ExecutionEngine::throwReferenceError(const QString &message, const QString &fileName, int line, int column)
1375{
1376 Scope scope(this);
1377 QString msg = message;
1378 ScopedObject error(scope, newReferenceErrorObject(message: msg, fileName, line, column));
1379 return throwError(value: error);
1380}
1381
1382ReturnedValue ExecutionEngine::throwRangeError(const QString &message)
1383{
1384 Scope scope(this);
1385 ScopedObject error(scope, newRangeErrorObject(message));
1386 return throwError(value: error);
1387}
1388
1389ReturnedValue ExecutionEngine::throwRangeError(const Value &value)
1390{
1391 Scope scope(this);
1392 ScopedString s(scope, value.toString(e: this));
1393 QString msg = s->toQString() + QLatin1String(" out of range");
1394 ScopedObject error(scope, newRangeErrorObject(message: msg));
1395 return throwError(value: error);
1396}
1397
1398ReturnedValue ExecutionEngine::throwURIError(const Value &msg)
1399{
1400 Scope scope(this);
1401 ScopedObject error(scope, newURIErrorObject(message: msg));
1402 return throwError(value: error);
1403}
1404
1405ReturnedValue ExecutionEngine::throwUnimplemented(const QString &message)
1406{
1407 Scope scope(this);
1408 ScopedValue v(scope, newString(s: QLatin1String("Unimplemented ") + message));
1409 v = newErrorObject(value: v);
1410 return throwError(value: v);
1411}
1412
1413
1414QQmlError ExecutionEngine::catchExceptionAsQmlError()
1415{
1416 QV4::StackTrace trace;
1417 QV4::Scope scope(this);
1418 QV4::ScopedValue exception(scope, catchException(trace: &trace));
1419 QQmlError error;
1420 if (!trace.isEmpty()) {
1421 QV4::StackFrame frame = trace.constFirst();
1422 error.setUrl(QUrl(frame.source));
1423 error.setLine(frame.line);
1424 error.setColumn(frame.column);
1425 }
1426 QV4::Scoped<QV4::ErrorObject> errorObj(scope, exception);
1427 error.setDescription(exception->toQStringNoThrow());
1428 return error;
1429}
1430
1431// Variant conversion code
1432
1433typedef QSet<QV4::Heap::Object *> V4ObjectSet;
1434static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int typeHint, bool createJSValueForObjects, V4ObjectSet *visitedObjects);
1435static QObject *qtObjectFromJS(QV4::ExecutionEngine *engine, const QV4::Value &value);
1436static QVariant objectToVariant(QV4::ExecutionEngine *e, const QV4::Object *o, V4ObjectSet *visitedObjects = nullptr);
1437static bool convertToNativeQObject(QV4::ExecutionEngine *e, const QV4::Value &value,
1438 const QByteArray &targetType,
1439 void **result);
1440static QV4::ReturnedValue variantListToJS(QV4::ExecutionEngine *v4, const QVariantList &lst);
1441static QV4::ReturnedValue sequentialIterableToJS(QV4::ExecutionEngine *v4, const QSequentialIterable &lst);
1442static QV4::ReturnedValue variantMapToJS(QV4::ExecutionEngine *v4, const QVariantMap &vmap);
1443static QV4::ReturnedValue variantToJS(QV4::ExecutionEngine *v4, const QVariant &value)
1444{
1445 return v4->metaTypeToJS(type: value.userType(), data: value.constData());
1446}
1447
1448
1449QVariant ExecutionEngine::toVariant(const Value &value, int typeHint, bool createJSValueForObjects)
1450{
1451 return ::toVariant(e: this, value, typeHint, createJSValueForObjects, visitedObjects: nullptr);
1452}
1453
1454
1455static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int typeHint, bool createJSValueForObjects, V4ObjectSet *visitedObjects)
1456{
1457 Q_ASSERT (!value.isEmpty());
1458 QV4::Scope scope(e);
1459
1460 if (const QV4::VariantObject *v = value.as<QV4::VariantObject>())
1461 return v->d()->data();
1462
1463 if (typeHint == QMetaType::Bool)
1464 return QVariant(value.toBoolean());
1465
1466 if (typeHint == QMetaType::QJsonValue)
1467 return QVariant::fromValue(value: QV4::JsonObject::toJsonValue(value));
1468
1469 if (typeHint == qMetaTypeId<QJSValue>())
1470 return QVariant::fromValue(value: QJSValue(e, value.asReturnedValue()));
1471
1472 if (value.as<QV4::Object>()) {
1473 QV4::ScopedObject object(scope, value);
1474 if (typeHint == QMetaType::QJsonObject
1475 && !value.as<ArrayObject>() && !value.as<FunctionObject>()) {
1476 return QVariant::fromValue(value: QV4::JsonObject::toJsonObject(o: object));
1477 } else if (QV4::QObjectWrapper *wrapper = object->as<QV4::QObjectWrapper>()) {
1478 return QVariant::fromValue<QObject *>(value: wrapper->object());
1479 } else if (object->as<QV4::QQmlContextWrapper>()) {
1480 return QVariant();
1481 } else if (QV4::QQmlTypeWrapper *w = object->as<QV4::QQmlTypeWrapper>()) {
1482 return w->toVariant();
1483 } else if (QV4::QQmlValueTypeWrapper *v = object->as<QV4::QQmlValueTypeWrapper>()) {
1484 return v->toVariant();
1485 } else if (QV4::QmlListWrapper *l = object->as<QV4::QmlListWrapper>()) {
1486 return l->toVariant();
1487#if QT_CONFIG(qml_sequence_object)
1488 } else if (object->isListType()) {
1489 return QV4::SequencePrototype::toVariant(object);
1490#endif
1491 }
1492 }
1493
1494 if (value.as<ArrayObject>()) {
1495 QV4::ScopedArrayObject a(scope, value);
1496 if (typeHint == qMetaTypeId<QList<QObject *> >()) {
1497 QList<QObject *> list;
1498 uint length = a->getLength();
1499 QV4::Scoped<QV4::QObjectWrapper> qobjectWrapper(scope);
1500 for (uint ii = 0; ii < length; ++ii) {
1501 qobjectWrapper = a->get(idx: ii);
1502 if (!!qobjectWrapper) {
1503 list << qobjectWrapper->object();
1504 } else {
1505 list << 0;
1506 }
1507 }
1508
1509 return QVariant::fromValue<QList<QObject*> >(value: list);
1510 } else if (typeHint == QMetaType::QJsonArray) {
1511 return QVariant::fromValue(value: QV4::JsonObject::toJsonArray(a));
1512 }
1513
1514 QVariant retn;
1515#if QT_CONFIG(qml_sequence_object)
1516 bool succeeded = false;
1517 retn = QV4::SequencePrototype::toVariant(array: value, typeHint, succeeded: &succeeded);
1518 if (succeeded)
1519 return retn;
1520#endif
1521 if (typeHint != -1) {
1522 // the QVariant constructor will create a copy, so we have manually
1523 // destroy the value returned by QMetaType::create
1524 auto temp = QMetaType::create(type: typeHint);
1525 retn = QVariant(typeHint, temp);
1526 QMetaType::destroy(type: typeHint, data: temp);
1527 auto retnAsIterable = retn.value<QtMetaTypePrivate::QSequentialIterableImpl>();
1528 if (retnAsIterable.containerCapabilities() & QtMetaTypePrivate::ContainerIsAppendable) {
1529 auto const length = a->getLength();
1530 QV4::ScopedValue arrayValue(scope);
1531 for (qint64 i = 0; i < length; ++i) {
1532 arrayValue = a->get(idx: i);
1533 QVariant asVariant;
1534 if (QMetaType::hasRegisteredConverterFunction(fromTypeId: qMetaTypeId<QJSValue>(), toTypeId: retnAsIterable._metaType_id)) {
1535 // before attempting a conversion from the concrete types,
1536 // check if there exists a conversion from QJSValue -> out type
1537 // prefer that one for compatibility reasons
1538 asVariant = QVariant::fromValue(value: QJSValue(scope.engine, arrayValue->asReturnedValue()));
1539 if (asVariant.convert(targetTypeId: retnAsIterable._metaType_id)) {
1540 retnAsIterable.append(newElement: asVariant.constData());
1541 continue;
1542 }
1543 }
1544 asVariant = toVariant(e, value: arrayValue, typeHint: retnAsIterable._metaType_id, createJSValueForObjects: false, visitedObjects);
1545 auto originalType = asVariant.userType();
1546 bool couldConvert = asVariant.convert(targetTypeId: retnAsIterable._metaType_id);
1547 if (!couldConvert) {
1548 qWarning() << QLatin1String("Could not convert array value at position %1 from %2 to %3")
1549 .arg(args: QString::number(i),
1550 args: QString::fromUtf8(str: QMetaType::typeName(type: originalType)),
1551 args: QString::fromUtf8(str: QMetaType::typeName(type: retnAsIterable._metaType_id)));
1552 // create default constructed value
1553 asVariant = QVariant(retnAsIterable._metaType_id, nullptr);
1554 }
1555 retnAsIterable.append(newElement: asVariant.constData());
1556 }
1557 return retn;
1558 }
1559 }
1560 }
1561
1562 if (value.isUndefined())
1563 return QVariant();
1564 if (value.isNull())
1565 return QVariant::fromValue(value: nullptr);
1566 if (value.isBoolean())
1567 return value.booleanValue();
1568 if (value.isInteger())
1569 return value.integerValue();
1570 if (value.isNumber())
1571 return value.asDouble();
1572 if (String *s = value.stringValue()) {
1573 const QString &str = s->toQString();
1574 // QChars are stored as a strings
1575 if (typeHint == QMetaType::QChar && str.size() == 1)
1576 return str.at(i: 0);
1577 return str;
1578 }
1579#if QT_CONFIG(qml_locale)
1580 if (const QV4::QQmlLocaleData *ld = value.as<QV4::QQmlLocaleData>())
1581 return *ld->d()->locale;
1582#endif
1583 if (const QV4::DateObject *d = value.as<DateObject>())
1584 return d->toQDateTime();
1585 if (const ArrayBuffer *d = value.as<ArrayBuffer>())
1586 return d->asByteArray();
1587 // NOTE: since we convert QTime to JS Date, round trip will change the variant type (to QDateTime)!
1588
1589 QV4::ScopedObject o(scope, value);
1590 Q_ASSERT(o);
1591
1592 if (QV4::RegExpObject *re = o->as<QV4::RegExpObject>()) {
1593#if QT_CONFIG(regularexpression)
1594 if (typeHint != QMetaType::QRegExp)
1595 return re->toQRegularExpression();
1596#endif
1597 return re->toQRegExp();
1598 }
1599
1600 if (createJSValueForObjects)
1601 return QVariant::fromValue(value: QJSValue(scope.engine, o->asReturnedValue()));
1602
1603 return objectToVariant(e, o, visitedObjects);
1604}
1605
1606static QVariant objectToVariant(QV4::ExecutionEngine *e, const QV4::Object *o, V4ObjectSet *visitedObjects)
1607{
1608 Q_ASSERT(o);
1609
1610 V4ObjectSet recursionGuardSet;
1611 if (!visitedObjects) {
1612 visitedObjects = &recursionGuardSet;
1613 } else if (visitedObjects->contains(value: o->d())) {
1614 // Avoid recursion.
1615 // For compatibility with QVariant{List,Map} conversion, we return an
1616 // empty object (and no error is thrown).
1617 if (o->as<ArrayObject>())
1618 return QVariantList();
1619 return QVariantMap();
1620 }
1621 visitedObjects->insert(value: o->d());
1622
1623 QVariant result;
1624
1625 if (o->as<ArrayObject>()) {
1626 QV4::Scope scope(e);
1627 QV4::ScopedArrayObject a(scope, o->asReturnedValue());
1628 QV4::ScopedValue v(scope);
1629 QVariantList list;
1630
1631 int length = a->getLength();
1632 for (int ii = 0; ii < length; ++ii) {
1633 v = a->get(idx: ii);
1634 list << ::toVariant(e, value: v, typeHint: -1, /*createJSValueForObjects*/false, visitedObjects);
1635 }
1636
1637 result = list;
1638 } else if (!o->as<FunctionObject>()) {
1639 QVariantMap map;
1640 QV4::Scope scope(e);
1641 QV4::ObjectIterator it(scope, o, QV4::ObjectIterator::EnumerableOnly);
1642 QV4::ScopedValue name(scope);
1643 QV4::ScopedValue val(scope);
1644 while (1) {
1645 name = it.nextPropertyNameAsString(value: val);
1646 if (name->isNull())
1647 break;
1648
1649 QString key = name->toQStringNoThrow();
1650 map.insert(akey: key, avalue: ::toVariant(e, value: val, /*type hint*/typeHint: -1, /*createJSValueForObjects*/false, visitedObjects));
1651 }
1652
1653 result = map;
1654 }
1655
1656 visitedObjects->remove(value: o->d());
1657 return result;
1658}
1659
1660QV4::ReturnedValue QV4::ExecutionEngine::fromVariant(const QVariant &variant)
1661{
1662 int type = variant.userType();
1663 const void *ptr = variant.constData();
1664
1665 if (type < QMetaType::User) {
1666 switch (QMetaType::Type(type)) {
1667 case QMetaType::UnknownType:
1668 case QMetaType::Void:
1669 return QV4::Encode::undefined();
1670 case QMetaType::Nullptr:
1671 case QMetaType::VoidStar:
1672 return QV4::Encode::null();
1673 case QMetaType::Bool:
1674 return QV4::Encode(*reinterpret_cast<const bool*>(ptr));
1675 case QMetaType::Int:
1676 return QV4::Encode(*reinterpret_cast<const int*>(ptr));
1677 case QMetaType::UInt:
1678 return QV4::Encode(*reinterpret_cast<const uint*>(ptr));
1679 case QMetaType::LongLong:
1680 return QV4::Encode((double)*reinterpret_cast<const qlonglong*>(ptr));
1681 case QMetaType::ULongLong:
1682 return QV4::Encode((double)*reinterpret_cast<const qulonglong*>(ptr));
1683 case QMetaType::Double:
1684 return QV4::Encode(*reinterpret_cast<const double*>(ptr));
1685 case QMetaType::QString:
1686 return newString(s: *reinterpret_cast<const QString*>(ptr))->asReturnedValue();
1687 case QMetaType::QByteArray:
1688 return newArrayBuffer(array: *reinterpret_cast<const QByteArray*>(ptr))->asReturnedValue();
1689 case QMetaType::Float:
1690 return QV4::Encode(*reinterpret_cast<const float*>(ptr));
1691 case QMetaType::Short:
1692 return QV4::Encode((int)*reinterpret_cast<const short*>(ptr));
1693 case QMetaType::UShort:
1694 return QV4::Encode((int)*reinterpret_cast<const unsigned short*>(ptr));
1695 case QMetaType::Char:
1696 return QV4::Encode((int)*reinterpret_cast<const char*>(ptr));
1697 case QMetaType::UChar:
1698 return QV4::Encode((int)*reinterpret_cast<const unsigned char*>(ptr));
1699 case QMetaType::QChar:
1700 return newString(s: *reinterpret_cast<const QChar *>(ptr))->asReturnedValue();
1701 case QMetaType::QDateTime:
1702 return QV4::Encode(newDateObject(dt: *reinterpret_cast<const QDateTime *>(ptr)));
1703 case QMetaType::QDate:
1704 return QV4::Encode(newDateObject(dt: QDateTime(*reinterpret_cast<const QDate *>(ptr), QTime(0, 0, 0), Qt::UTC)));
1705 case QMetaType::QTime:
1706 return QV4::Encode(newDateObjectFromTime(t: *reinterpret_cast<const QTime *>(ptr)));
1707 case QMetaType::QRegExp:
1708 return QV4::Encode(newRegExpObject(re: *reinterpret_cast<const QRegExp *>(ptr)));
1709#if QT_CONFIG(regularexpression)
1710 case QMetaType::QRegularExpression:
1711 return QV4::Encode(newRegExpObject(re: *reinterpret_cast<const QRegularExpression *>(ptr)));
1712#endif
1713 case QMetaType::QObjectStar:
1714 return QV4::QObjectWrapper::wrap(engine: this, object: *reinterpret_cast<QObject* const *>(ptr));
1715#if QT_CONFIG(qml_sequence_object)
1716 case QMetaType::QStringList:
1717 {
1718 bool succeeded = false;
1719 QV4::Scope scope(this);
1720 QV4::ScopedValue retn(scope, QV4::SequencePrototype::fromVariant(engine: this, v: variant, succeeded: &succeeded));
1721 if (succeeded)
1722 return retn->asReturnedValue();
1723 return QV4::Encode(newArrayObject(list: *reinterpret_cast<const QStringList *>(ptr)));
1724 }
1725#endif
1726 case QMetaType::QVariantList:
1727 return variantListToJS(v4: this, lst: *reinterpret_cast<const QVariantList *>(ptr));
1728 case QMetaType::QVariantMap:
1729 return variantMapToJS(v4: this, vmap: *reinterpret_cast<const QVariantMap *>(ptr));
1730 case QMetaType::QJsonValue:
1731 return QV4::JsonObject::fromJsonValue(engine: this, value: *reinterpret_cast<const QJsonValue *>(ptr));
1732 case QMetaType::QJsonObject:
1733 return QV4::JsonObject::fromJsonObject(engine: this, object: *reinterpret_cast<const QJsonObject *>(ptr));
1734 case QMetaType::QJsonArray:
1735 return QV4::JsonObject::fromJsonArray(engine: this, array: *reinterpret_cast<const QJsonArray *>(ptr));
1736#if QT_CONFIG(qml_locale)
1737 case QMetaType::QLocale:
1738 return QQmlLocale::wrap(engine: this, locale: *reinterpret_cast<const QLocale*>(ptr));
1739#endif
1740 case QMetaType::QPixmap:
1741 case QMetaType::QImage:
1742 // Scarce value types
1743 return QV4::Encode(newVariantObject(v: variant));
1744 default:
1745 break;
1746 }
1747
1748 if (const QMetaObject *vtmo = QQmlValueTypeFactory::metaObjectForMetaType(type))
1749 return QV4::QQmlValueTypeWrapper::create(engine: this, variant, metaObject: vtmo, typeId: type);
1750 } else {
1751 QV4::Scope scope(this);
1752 if (type == qMetaTypeId<QQmlListReference>()) {
1753 typedef QQmlListReferencePrivate QDLRP;
1754 QDLRP *p = QDLRP::get(ref: (QQmlListReference*)const_cast<void *>(ptr));
1755 if (p->object) {
1756 return QV4::QmlListWrapper::create(engine: scope.engine, prop: p->property, propType: p->propertyType);
1757 } else {
1758 return QV4::Encode::null();
1759 }
1760 } else if (type == qMetaTypeId<QJSValue>()) {
1761 const QJSValue *value = reinterpret_cast<const QJSValue *>(ptr);
1762 return QJSValuePrivate::convertedToValue(e: this, jsval: *value);
1763 } else if (type == qMetaTypeId<QList<QObject *> >()) {
1764 // XXX Can this be made more by using Array as a prototype and implementing
1765 // directly against QList<QObject*>?
1766 const QList<QObject *> &list = *(const QList<QObject *>*)ptr;
1767 QV4::ScopedArrayObject a(scope, newArrayObject());
1768 a->arrayReserve(n: list.count());
1769 QV4::ScopedValue v(scope);
1770 for (int ii = 0; ii < list.count(); ++ii)
1771 a->arrayPut(index: ii, value: (v = QV4::QObjectWrapper::wrap(engine: this, object: list.at(i: ii))));
1772 a->setArrayLengthUnchecked(list.count());
1773 return a.asReturnedValue();
1774 } else if (QMetaType::typeFlags(type) & QMetaType::PointerToQObject) {
1775 return QV4::QObjectWrapper::wrap(engine: this, object: *reinterpret_cast<QObject* const *>(ptr));
1776 }
1777
1778 bool objOk;
1779 QObject *obj = QQmlMetaType::toQObject(variant, ok: &objOk);
1780 if (objOk)
1781 return QV4::QObjectWrapper::wrap(engine: this, object: obj);
1782
1783#if QT_CONFIG(qml_sequence_object)
1784 bool succeeded = false;
1785 QV4::ScopedValue retn(scope, QV4::SequencePrototype::fromVariant(engine: this, v: variant, succeeded: &succeeded));
1786 if (succeeded)
1787 return retn->asReturnedValue();
1788#endif
1789
1790 if (QMetaType::hasRegisteredConverterFunction(fromTypeId: type, toTypeId: qMetaTypeId<QtMetaTypePrivate::QSequentialIterableImpl>())) {
1791 QSequentialIterable lst = variant.value<QSequentialIterable>();
1792 return sequentialIterableToJS(v4: this, lst);
1793 }
1794
1795 if (const QMetaObject *vtmo = QQmlValueTypeFactory::metaObjectForMetaType(type))
1796 return QV4::QQmlValueTypeWrapper::create(engine: this, variant, metaObject: vtmo, typeId: type);
1797 }
1798
1799 // XXX TODO: To be compatible, we still need to handle:
1800 // + QObjectList
1801 // + QList<int>
1802
1803 return QV4::Encode(newVariantObject(v: variant));
1804}
1805
1806QVariantMap ExecutionEngine::variantMapFromJS(const Object *o)
1807{
1808 return objectToVariant(e: this, o).toMap();
1809}
1810
1811
1812// Converts a QVariantList to JS.
1813// The result is a new Array object with length equal to the length
1814// of the QVariantList, and the elements being the QVariantList's
1815// elements converted to JS, recursively.
1816static QV4::ReturnedValue variantListToJS(QV4::ExecutionEngine *v4, const QVariantList &lst)
1817{
1818 QV4::Scope scope(v4);
1819 QV4::ScopedArrayObject a(scope, v4->newArrayObject());
1820 a->arrayReserve(n: lst.size());
1821 QV4::ScopedValue v(scope);
1822 for (int i = 0; i < lst.size(); i++)
1823 a->arrayPut(index: i, value: (v = variantToJS(v4, value: lst.at(i))));
1824 a->setArrayLengthUnchecked(lst.size());
1825 return a.asReturnedValue();
1826}
1827
1828// Converts a QSequentialIterable to JS.
1829// The result is a new Array object with length equal to the length
1830// of the QSequentialIterable, and the elements being the QSequentialIterable's
1831// elements converted to JS, recursively.
1832static QV4::ReturnedValue sequentialIterableToJS(QV4::ExecutionEngine *v4, const QSequentialIterable &lst)
1833{
1834 QV4::Scope scope(v4);
1835 QV4::ScopedArrayObject a(scope, v4->newArrayObject());
1836 a->arrayReserve(n: lst.size());
1837 QV4::ScopedValue v(scope);
1838 for (int i = 0; i < lst.size(); i++)
1839 a->arrayPut(index: i, value: (v = variantToJS(v4, value: lst.at(idx: i))));
1840 a->setArrayLengthUnchecked(lst.size());
1841 return a.asReturnedValue();
1842}
1843
1844// Converts a QVariantMap to JS.
1845// The result is a new Object object with property names being
1846// the keys of the QVariantMap, and values being the values of
1847// the QVariantMap converted to JS, recursively.
1848static QV4::ReturnedValue variantMapToJS(QV4::ExecutionEngine *v4, const QVariantMap &vmap)
1849{
1850 QV4::Scope scope(v4);
1851 QV4::ScopedObject o(scope, v4->newObject());
1852 QV4::ScopedString s(scope);
1853 QV4::ScopedPropertyKey key(scope);
1854 QV4::ScopedValue v(scope);
1855 for (QVariantMap::const_iterator it = vmap.constBegin(), cend = vmap.constEnd(); it != cend; ++it) {
1856 s = v4->newIdentifier(text: it.key());
1857 key = s->propertyKey();
1858 v = variantToJS(v4, value: it.value());
1859 if (key->isArrayIndex())
1860 o->arraySet(index: key->asArrayIndex(), value: v);
1861 else
1862 o->insertMember(s, v);
1863 }
1864 return o.asReturnedValue();
1865}
1866
1867// Converts the meta-type defined by the given type and data to JS.
1868// Returns the value if conversion succeeded, an empty handle otherwise.
1869QV4::ReturnedValue ExecutionEngine::metaTypeToJS(int type, const void *data)
1870{
1871 Q_ASSERT(data != nullptr);
1872
1873 QVariant variant(type, data);
1874 if (QMetaType::Type(variant.userType()) == QMetaType::QVariant) {
1875 // unwrap it: this is tested in QJSEngine, and makes the most sense for
1876 // end-user code too.
1877 return variantToJS(v4: this, value: *reinterpret_cast<const QVariant*>(data));
1878 }
1879 return fromVariant(variant);
1880}
1881
1882int ExecutionEngine::maxJSStackSize() const
1883{
1884 return m_maxJSStackSize;
1885}
1886
1887int ExecutionEngine::maxGCStackSize() const
1888{
1889 return m_maxGCStackSize;
1890}
1891
1892ReturnedValue ExecutionEngine::global()
1893{
1894 return globalObject->asReturnedValue();
1895}
1896
1897QQmlRefPointer<ExecutableCompilationUnit> ExecutionEngine::compileModule(const QUrl &url)
1898{
1899 QQmlMetaType::CachedUnitLookupError cacheError = QQmlMetaType::CachedUnitLookupError::NoError;
1900 if (const QV4::CompiledData::Unit *cachedUnit = QQmlMetaType::findCachedCompilationUnit(uri: url, status: &cacheError)) {
1901 return ExecutableCompilationUnit::create(
1902 compilationUnit: QV4::CompiledData::CompilationUnit(cachedUnit, url.fileName(), url.toString()));
1903 }
1904
1905 QFile f(QQmlFile::urlToLocalFileOrQrc(url));
1906 if (!f.open(flags: QIODevice::ReadOnly)) {
1907 throwError(QStringLiteral("Could not open module %1 for reading").arg(a: url.toString()));
1908 return nullptr;
1909 }
1910
1911 const QDateTime timeStamp = QFileInfo(f).lastModified();
1912
1913 const QString sourceCode = QString::fromUtf8(str: f.readAll());
1914 f.close();
1915
1916 return compileModule(url, sourceCode, sourceTimeStamp: timeStamp);
1917}
1918
1919
1920QQmlRefPointer<ExecutableCompilationUnit> ExecutionEngine::compileModule(
1921 const QUrl &url, const QString &sourceCode, const QDateTime &sourceTimeStamp)
1922{
1923 QList<QQmlJS::DiagnosticMessage> diagnostics;
1924 auto unit = Compiler::Codegen::compileModule(/*debugMode*/debugger() != nullptr, url: url.toString(),
1925 sourceCode, sourceTimeStamp, diagnostics: &diagnostics);
1926 for (const QQmlJS::DiagnosticMessage &m : diagnostics) {
1927 if (m.isError()) {
1928 throwSyntaxError(message: m.message, fileName: url.toString(), line: m.loc.startLine, column: m.loc.startColumn);
1929 return nullptr;
1930 } else {
1931 qWarning() << url << ':' << m.loc.startLine << ':' << m.loc.startColumn
1932 << ": warning: " << m.message;
1933 }
1934 }
1935
1936 return ExecutableCompilationUnit::create(compilationUnit: std::move(unit));
1937}
1938
1939void ExecutionEngine::injectModule(const QQmlRefPointer<ExecutableCompilationUnit> &moduleUnit)
1940{
1941 // Injection can happen from the QML type loader thread for example, but instantiation and
1942 // evaluation must be limited to the ExecutionEngine's thread.
1943 QMutexLocker moduleGuard(&moduleMutex);
1944 modules.insert(akey: moduleUnit->finalUrl(), avalue: moduleUnit);
1945}
1946
1947QQmlRefPointer<ExecutableCompilationUnit> ExecutionEngine::moduleForUrl(const QUrl &_url, const ExecutableCompilationUnit *referrer) const
1948{
1949 QUrl url = QQmlTypeLoader::normalize(unNormalizedUrl: _url);
1950 if (referrer)
1951 url = referrer->finalUrl().resolved(relative: url);
1952
1953 QMutexLocker moduleGuard(&moduleMutex);
1954 auto existingModule = modules.find(akey: url);
1955 if (existingModule == modules.end())
1956 return nullptr;
1957 return *existingModule;
1958}
1959
1960QQmlRefPointer<ExecutableCompilationUnit> ExecutionEngine::loadModule(const QUrl &_url, const ExecutableCompilationUnit *referrer)
1961{
1962 QUrl url = QQmlTypeLoader::normalize(unNormalizedUrl: _url);
1963 if (referrer)
1964 url = referrer->finalUrl().resolved(relative: url);
1965
1966 QMutexLocker moduleGuard(&moduleMutex);
1967 auto existingModule = modules.find(akey: url);
1968 if (existingModule != modules.end())
1969 return *existingModule;
1970
1971 moduleGuard.unlock();
1972
1973 auto newModule = compileModule(url);
1974 if (newModule) {
1975 moduleGuard.relock();
1976 modules.insert(akey: url, avalue: newModule);
1977 }
1978
1979 return newModule;
1980}
1981
1982void ExecutionEngine::initQmlGlobalObject()
1983{
1984 initializeGlobal();
1985 freezeObject(value: *globalObject);
1986}
1987
1988void ExecutionEngine::initializeGlobal()
1989{
1990 QV4::Scope scope(this);
1991
1992 QV4::ScopedObject qt(scope, memoryManager->allocate<QV4::QtObject>(args: qmlEngine()));
1993 globalObject->defineDefaultProperty(QStringLiteral("Qt"), value: qt);
1994
1995 QV4::GlobalExtensions::init(globalObject, extensions: QJSEngine::AllExtensions);
1996
1997#if QT_CONFIG(qml_locale)
1998 QQmlLocale::registerStringLocaleCompare(engine: this);
1999 QQmlDateExtension::registerExtension(engine: this);
2000 QQmlNumberExtension::registerExtension(engine: this);
2001#endif
2002
2003#if QT_CONFIG(qml_xml_http_request)
2004 qt_add_domexceptions(e: this);
2005 m_xmlHttpRequestData = qt_add_qmlxmlhttprequest(engine: this);
2006#endif
2007
2008 qt_add_sqlexceptions(engine: this);
2009
2010 {
2011 for (uint i = 0; i < globalObject->internalClass()->size; ++i) {
2012 if (globalObject->internalClass()->nameMap.at(i).isString()) {
2013 QV4::PropertyKey id = globalObject->internalClass()->nameMap.at(i);
2014 m_illegalNames.insert(value: id.toQString());
2015 }
2016 }
2017 }
2018}
2019
2020const QSet<QString> &ExecutionEngine::illegalNames() const
2021{
2022 return m_illegalNames;
2023}
2024
2025void ExecutionEngine::setQmlEngine(QQmlEngine *engine)
2026{
2027 m_qmlEngine = engine;
2028 initQmlGlobalObject();
2029}
2030
2031static void freeze_recursive(QV4::ExecutionEngine *v4, QV4::Object *object)
2032{
2033 if (object->as<QV4::QObjectWrapper>() || object->internalClass()->isFrozen)
2034 return;
2035
2036 QV4::Scope scope(v4);
2037
2038 bool instanceOfObject = false;
2039 QV4::ScopedObject p(scope, object->getPrototypeOf());
2040 while (p) {
2041 if (p->d() == v4->objectPrototype()->d()) {
2042 instanceOfObject = true;
2043 break;
2044 }
2045 p = p->getPrototypeOf();
2046 }
2047 if (!instanceOfObject)
2048 return;
2049
2050 Heap::InternalClass *frozen = object->internalClass()->frozen();
2051 object->setInternalClass(frozen); // Immediately assign frozen to prevent it from getting GC'd
2052
2053 QV4::ScopedObject o(scope);
2054 for (uint i = 0; i < frozen->size; ++i) {
2055 if (!frozen->nameMap.at(i).isStringOrSymbol())
2056 continue;
2057 o = *object->propertyData(index: i);
2058 if (o)
2059 freeze_recursive(v4, object: o);
2060 }
2061}
2062
2063void ExecutionEngine::freezeObject(const QV4::Value &value)
2064{
2065 QV4::Scope scope(this);
2066 QV4::ScopedObject o(scope, value);
2067 freeze_recursive(v4: this, object: o);
2068}
2069
2070void ExecutionEngine::startTimer(const QString &timerName)
2071{
2072 if (!m_time.isValid())
2073 m_time.start();
2074 m_startedTimers[timerName] = m_time.elapsed();
2075}
2076
2077qint64 ExecutionEngine::stopTimer(const QString &timerName, bool *wasRunning)
2078{
2079 if (!m_startedTimers.contains(akey: timerName)) {
2080 *wasRunning = false;
2081 return 0;
2082 }
2083 *wasRunning = true;
2084 qint64 startedAt = m_startedTimers.take(akey: timerName);
2085 return m_time.elapsed() - startedAt;
2086}
2087
2088int ExecutionEngine::consoleCountHelper(const QString &file, quint16 line, quint16 column)
2089{
2090 const QString key = file + QString::number(line) + QString::number(column);
2091 int number = m_consoleCount.value(akey: key, adefaultValue: 0);
2092 number++;
2093 m_consoleCount.insert(akey: key, avalue: number);
2094 return number;
2095}
2096
2097void ExecutionEngine::setExtensionData(int index, Deletable *data)
2098{
2099 if (m_extensionData.count() <= index)
2100 m_extensionData.resize(asize: index + 1);
2101
2102 if (m_extensionData.at(i: index))
2103 delete m_extensionData.at(i: index);
2104
2105 m_extensionData[index] = data;
2106}
2107
2108// Converts a JS value to a meta-type.
2109// data must point to a place that can store a value of the given type.
2110// Returns true if conversion succeeded, false otherwise.
2111bool ExecutionEngine::metaTypeFromJS(const Value *value, int type, void *data)
2112{
2113 // check if it's one of the types we know
2114 switch (QMetaType::Type(type)) {
2115 case QMetaType::Bool:
2116 *reinterpret_cast<bool*>(data) = value->toBoolean();
2117 return true;
2118 case QMetaType::Int:
2119 *reinterpret_cast<int*>(data) = value->toInt32();
2120 return true;
2121 case QMetaType::UInt:
2122 *reinterpret_cast<uint*>(data) = value->toUInt32();
2123 return true;
2124 case QMetaType::LongLong:
2125 *reinterpret_cast<qlonglong*>(data) = qlonglong(value->toInteger());
2126 return true;
2127 case QMetaType::ULongLong:
2128 *reinterpret_cast<qulonglong*>(data) = qulonglong(value->toInteger());
2129 return true;
2130 case QMetaType::Double:
2131 *reinterpret_cast<double*>(data) = value->toNumber();
2132 return true;
2133 case QMetaType::QString:
2134 if (value->isUndefined() || value->isNull())
2135 *reinterpret_cast<QString*>(data) = QString();
2136 else
2137 *reinterpret_cast<QString*>(data) = value->toQString();
2138 return true;
2139 case QMetaType::QByteArray:
2140 if (const ArrayBuffer *ab = value->as<ArrayBuffer>())
2141 *reinterpret_cast<QByteArray*>(data) = ab->asByteArray();
2142 else
2143 *reinterpret_cast<QByteArray*>(data) = QByteArray();
2144 return true;
2145 case QMetaType::Float:
2146 *reinterpret_cast<float*>(data) = value->toNumber();
2147 return true;
2148 case QMetaType::Short:
2149 *reinterpret_cast<short*>(data) = short(value->toInt32());
2150 return true;
2151 case QMetaType::UShort:
2152 *reinterpret_cast<unsigned short*>(data) = value->toUInt16();
2153 return true;
2154 case QMetaType::Char:
2155 *reinterpret_cast<char*>(data) = char(value->toInt32());
2156 return true;
2157 case QMetaType::UChar:
2158 *reinterpret_cast<unsigned char*>(data) = (unsigned char)(value->toInt32());
2159 return true;
2160 case QMetaType::QChar:
2161 if (String *s = value->stringValue()) {
2162 QString str = s->toQString();
2163 *reinterpret_cast<QChar*>(data) = str.isEmpty() ? QChar() : str.at(i: 0);
2164 } else {
2165 *reinterpret_cast<QChar*>(data) = QChar(ushort(value->toUInt16()));
2166 }
2167 return true;
2168 case QMetaType::QDateTime:
2169 if (const QV4::DateObject *d = value->as<DateObject>()) {
2170 *reinterpret_cast<QDateTime *>(data) = d->toQDateTime();
2171 return true;
2172 } break;
2173 case QMetaType::QDate:
2174 if (const QV4::DateObject *d = value->as<DateObject>()) {
2175 *reinterpret_cast<QDate *>(data) = d->toQDateTime().date();
2176 return true;
2177 } break;
2178 case QMetaType::QRegExp:
2179 if (const QV4::RegExpObject *r = value->as<QV4::RegExpObject>()) {
2180 *reinterpret_cast<QRegExp *>(data) = r->toQRegExp();
2181 return true;
2182 } break;
2183#if QT_CONFIG(regularexpression)
2184 case QMetaType::QRegularExpression:
2185 if (const QV4::RegExpObject *r = value->as<QV4::RegExpObject>()) {
2186 *reinterpret_cast<QRegularExpression *>(data) = r->toQRegularExpression();
2187 return true;
2188 } break;
2189#endif
2190 case QMetaType::QObjectStar: {
2191 const QV4::QObjectWrapper *qobjectWrapper = value->as<QV4::QObjectWrapper>();
2192 if (qobjectWrapper || value->isNull()) {
2193 *reinterpret_cast<QObject* *>(data) = qtObjectFromJS(engine: this, value: *value);
2194 return true;
2195 } break;
2196 }
2197 case QMetaType::QStringList: {
2198 const QV4::ArrayObject *a = value->as<QV4::ArrayObject>();
2199 if (a) {
2200 *reinterpret_cast<QStringList *>(data) = a->toQStringList();
2201 return true;
2202 }
2203 break;
2204 }
2205 case QMetaType::QVariantList: {
2206 const QV4::ArrayObject *a = value->as<QV4::ArrayObject>();
2207 if (a) {
2208 *reinterpret_cast<QVariantList *>(data) = toVariant(value: *a, /*typeHint*/-1, /*createJSValueForObjects*/false).toList();
2209 return true;
2210 }
2211 break;
2212 }
2213 case QMetaType::QVariantMap: {
2214 const QV4::Object *o = value->as<QV4::Object>();
2215 if (o) {
2216 *reinterpret_cast<QVariantMap *>(data) = variantMapFromJS(o);
2217 return true;
2218 }
2219 break;
2220 }
2221 case QMetaType::QVariant:
2222 *reinterpret_cast<QVariant*>(data) = toVariant(value: *value, /*typeHint*/-1, /*createJSValueForObjects*/false);
2223 return true;
2224 case QMetaType::QJsonValue:
2225 *reinterpret_cast<QJsonValue *>(data) = QV4::JsonObject::toJsonValue(value: *value);
2226 return true;
2227 case QMetaType::QJsonObject: {
2228 *reinterpret_cast<QJsonObject *>(data) = QV4::JsonObject::toJsonObject(o: value->as<Object>());
2229 return true;
2230 }
2231 case QMetaType::QJsonArray: {
2232 const QV4::ArrayObject *a = value->as<ArrayObject>();
2233 if (a) {
2234 *reinterpret_cast<QJsonArray *>(data) = JsonObject::toJsonArray(a);
2235 return true;
2236 }
2237 break;
2238 }
2239 default:
2240 ;
2241 }
2242
2243 {
2244 const QQmlValueTypeWrapper *vtw = value->as<QQmlValueTypeWrapper>();
2245 if (vtw && vtw->typeId() == type) {
2246 return vtw->toGadget(data);
2247 }
2248 }
2249
2250#if 0
2251 if (isQtVariant(value)) {
2252 const QVariant &var = variantValue(value);
2253 // ### Enable once constructInPlace() is in qt master.
2254 if (var.userType() == type) {
2255 QMetaType::constructInPlace(type, data, var.constData());
2256 return true;
2257 }
2258 if (var.canConvert(type)) {
2259 QVariant vv = var;
2260 vv.convert(type);
2261 Q_ASSERT(vv.userType() == type);
2262 QMetaType::constructInPlace(type, data, vv.constData());
2263 return true;
2264 }
2265
2266 }
2267#endif
2268
2269 // Try to use magic; for compatibility with qjsvalue_cast.
2270
2271 QByteArray name = QMetaType::typeName(type);
2272 if (convertToNativeQObject(e: this, value: *value, targetType: name, result: reinterpret_cast<void* *>(data)))
2273 return true;
2274 if (value->as<QV4::VariantObject>() && name.endsWith(c: '*')) {
2275 int valueType = QMetaType::type(typeName: name.left(len: name.size()-1));
2276 QVariant &var = value->as<QV4::VariantObject>()->d()->data();
2277 if (valueType == var.userType()) {
2278 // We have T t, T* is requested, so return &t.
2279 *reinterpret_cast<void* *>(data) = var.data();
2280 return true;
2281 } else if (Object *o = value->objectValue()) {
2282 // Look in the prototype chain.
2283 QV4::Scope scope(this);
2284 QV4::ScopedObject proto(scope, o->getPrototypeOf());
2285 while (proto) {
2286 bool canCast = false;
2287 if (QV4::VariantObject *vo = proto->as<QV4::VariantObject>()) {
2288 const QVariant &v = vo->d()->data();
2289 canCast = (type == v.userType()) || (valueType && (valueType == v.userType()));
2290 }
2291 else if (proto->as<QV4::QObjectWrapper>()) {
2292 QByteArray className = name.left(len: name.size()-1);
2293 QV4::ScopedObject p(scope, proto.getPointer());
2294 if (QObject *qobject = qtObjectFromJS(engine: this, value: p))
2295 canCast = qobject->qt_metacast(className) != nullptr;
2296 }
2297 if (canCast) {
2298 QByteArray varTypeName = QMetaType::typeName(type: var.userType());
2299 if (varTypeName.endsWith(c: '*'))
2300 *reinterpret_cast<void* *>(data) = *reinterpret_cast<void* *>(var.data());
2301 else
2302 *reinterpret_cast<void* *>(data) = var.data();
2303 return true;
2304 }
2305 proto = proto->getPrototypeOf();
2306 }
2307 }
2308 } else if (value->isNull() && name.endsWith(c: '*')) {
2309 *reinterpret_cast<void* *>(data) = nullptr;
2310 return true;
2311 } else if (type == qMetaTypeId<QJSValue>()) {
2312 *reinterpret_cast<QJSValue*>(data) = QJSValue(this, value->asReturnedValue());
2313 return true;
2314 }
2315
2316 return false;
2317}
2318
2319static bool convertToNativeQObject(QV4::ExecutionEngine *e, const QV4::Value &value, const QByteArray &targetType, void **result)
2320{
2321 if (!targetType.endsWith(c: '*'))
2322 return false;
2323 if (QObject *qobject = qtObjectFromJS(engine: e, value)) {
2324 int start = targetType.startsWith(c: "const ") ? 6 : 0;
2325 QByteArray className = targetType.mid(index: start, len: targetType.size()-start-1);
2326 if (void *instance = qobject->qt_metacast(className)) {
2327 *result = instance;
2328 return true;
2329 }
2330 }
2331 return false;
2332}
2333
2334static QObject *qtObjectFromJS(QV4::ExecutionEngine *engine, const QV4::Value &value)
2335{
2336 if (!value.isObject())
2337 return nullptr;
2338
2339 QV4::Scope scope(engine);
2340 QV4::Scoped<QV4::VariantObject> v(scope, value);
2341
2342 if (v) {
2343 QVariant variant = v->d()->data();
2344 int type = variant.userType();
2345 if (type == QMetaType::QObjectStar)
2346 return *reinterpret_cast<QObject* const *>(variant.constData());
2347 }
2348 QV4::Scoped<QV4::QObjectWrapper> wrapper(scope, value);
2349 if (!wrapper)
2350 return nullptr;
2351 return wrapper->object();
2352}
2353
2354struct QV4EngineRegistrationData
2355{
2356 QV4EngineRegistrationData() : extensionCount(0) {}
2357
2358 QMutex mutex;
2359 int extensionCount;
2360};
2361Q_GLOBAL_STATIC(QV4EngineRegistrationData, registrationData);
2362
2363QMutex *ExecutionEngine::registrationMutex()
2364{
2365 return &registrationData()->mutex;
2366}
2367
2368int ExecutionEngine::registerExtension()
2369{
2370 return registrationData()->extensionCount++;
2371}
2372
2373#if QT_CONFIG(qml_network)
2374QNetworkAccessManager *QV4::detail::getNetworkAccessManager(ExecutionEngine *engine)
2375{
2376 return engine->qmlEngine()->networkAccessManager();
2377}
2378#endif // qml_network
2379
2380QT_END_NAMESPACE
2381

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