| 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 |  | 
| 138 | Q_DECLARE_METATYPE(QList<int>) | 
| 139 |  | 
| 140 | QT_BEGIN_NAMESPACE | 
| 141 |  | 
| 142 | using namespace QV4; | 
| 143 |  | 
| 144 | static QBasicAtomicInt engineSerial = Q_BASIC_ATOMIC_INITIALIZER(1); | 
| 145 |  | 
| 146 | ReturnedValue throwTypeError(const FunctionObject *b, const QV4::Value *, const QV4::Value *, int) | 
| 147 | { | 
| 148 |     return b->engine()->throwTypeError(); | 
| 149 | } | 
| 150 |  | 
| 151 | qint32 ExecutionEngine::maxCallDepth = -1; | 
| 152 |  | 
| 153 | template <typename ReturnType> | 
| 154 | ReturnType convertJSValueToVariantType(const QJSValue &value) | 
| 155 | { | 
| 156 |     return value.toVariant().value<ReturnType>(); | 
| 157 | } | 
| 158 |  | 
| 159 | static 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 |  | 
| 172 | static 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 |  | 
| 190 | struct JSArrayIterator { | 
| 191 |     QJSValue const* data; | 
| 192 |     quint32 index; | 
| 193 | }; | 
| 194 |  | 
| 195 | namespace  { | 
| 196 | void createNewIteratorIfNonExisting(void **iterator) { | 
| 197 |     if (*iterator == nullptr) | 
| 198 |         *iterator = new JSArrayIterator; | 
| 199 | } | 
| 200 | } | 
| 201 |  | 
| 202 | static 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 |  | 
| 275 | ExecutionEngine::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 |  | 
| 815 | ExecutionEngine::~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 |  | 
| 842 | ExecutionContext *ExecutionEngine::currentContext() const | 
| 843 | { | 
| 844 |     return static_cast<ExecutionContext *>(¤tStackFrame->jsFrame->context); | 
| 845 | } | 
| 846 |  | 
| 847 | #if QT_CONFIG(qml_debug) | 
| 848 | void ExecutionEngine::setDebugger(Debugging::Debugger *debugger) | 
| 849 | { | 
| 850 |     Q_ASSERT(!m_debugger); | 
| 851 |     m_debugger.reset(other: debugger); | 
| 852 | } | 
| 853 |  | 
| 854 | void 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 |  | 
| 861 | void 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 |  | 
| 872 | Heap::InternalClass *ExecutionEngine::newClass(Heap::InternalClass *other) | 
| 873 | { | 
| 874 |     Heap::InternalClass *ic = memoryManager->allocIC<InternalClass>(); | 
| 875 |     ic->init(other); | 
| 876 |     return ic; | 
| 877 | } | 
| 878 |  | 
| 879 | Heap::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 |  | 
| 886 | Heap::Object *ExecutionEngine::newObject() | 
| 887 | { | 
| 888 |     return memoryManager->allocate<Object>(); | 
| 889 | } | 
| 890 |  | 
| 891 | Heap::Object *ExecutionEngine::newObject(Heap::InternalClass *internalClass) | 
| 892 | { | 
| 893 |     return memoryManager->allocObject<Object>(ic: internalClass); | 
| 894 | } | 
| 895 |  | 
| 896 | Heap::String *ExecutionEngine::newString(const QString &s) | 
| 897 | { | 
| 898 |     return memoryManager->allocWithStringData<String>(unmanagedSize: s.length() * sizeof(QChar), arg1: s); | 
| 899 | } | 
| 900 |  | 
| 901 | Heap::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 |  | 
| 909 | Heap::Object *ExecutionEngine::newStringObject(const String *string) | 
| 910 | { | 
| 911 |     return memoryManager->allocate<StringObject>(args: string); | 
| 912 | } | 
| 913 |  | 
| 914 | Heap::Object *ExecutionEngine::newSymbolObject(const Symbol *symbol) | 
| 915 | { | 
| 916 |     return memoryManager->allocObject<SymbolObject>(ic: classes[Class_SymbolObject], args: symbol); | 
| 917 | } | 
| 918 |  | 
| 919 | Heap::Object *ExecutionEngine::newNumberObject(double value) | 
| 920 | { | 
| 921 |     return memoryManager->allocate<NumberObject>(args: value); | 
| 922 | } | 
| 923 |  | 
| 924 | Heap::Object *ExecutionEngine::newBooleanObject(bool b) | 
| 925 | { | 
| 926 |     return memoryManager->allocate<BooleanObject>(args: b); | 
| 927 | } | 
| 928 |  | 
| 929 | Heap::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 |  | 
| 942 | Heap::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 |  | 
| 964 | Heap::ArrayObject *ExecutionEngine::newArrayObject(const QStringList &list) | 
| 965 | { | 
| 966 |     return memoryManager->allocate<ArrayObject>(args: list); | 
| 967 | } | 
| 968 |  | 
| 969 | Heap::ArrayObject *ExecutionEngine::newArrayObject(Heap::InternalClass *internalClass) | 
| 970 | { | 
| 971 |     return memoryManager->allocObject<ArrayObject>(ic: internalClass); | 
| 972 | } | 
| 973 |  | 
| 974 | Heap::ArrayBuffer *ExecutionEngine::newArrayBuffer(const QByteArray &array) | 
| 975 | { | 
| 976 |     return memoryManager->allocate<ArrayBuffer>(args: array); | 
| 977 | } | 
| 978 |  | 
| 979 | Heap::ArrayBuffer *ExecutionEngine::newArrayBuffer(size_t length) | 
| 980 | { | 
| 981 |     return memoryManager->allocate<ArrayBuffer>(args: length); | 
| 982 | } | 
| 983 |  | 
| 984 |  | 
| 985 | Heap::DateObject *ExecutionEngine::newDateObject(const Value &value) | 
| 986 | { | 
| 987 |     return memoryManager->allocate<DateObject>(args: value); | 
| 988 | } | 
| 989 |  | 
| 990 | Heap::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 |  | 
| 997 | Heap::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 |  | 
| 1004 | Heap::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 |  | 
| 1011 | Heap::RegExpObject *ExecutionEngine::newRegExpObject(RegExp *re) | 
| 1012 | { | 
| 1013 |     return memoryManager->allocate<RegExpObject>(args: re); | 
| 1014 | } | 
| 1015 |  | 
| 1016 | Heap::RegExpObject *ExecutionEngine::newRegExpObject(const QRegExp &re) | 
| 1017 | { | 
| 1018 |     return memoryManager->allocate<RegExpObject>(args: re); | 
| 1019 | } | 
| 1020 |  | 
| 1021 | #if QT_CONFIG(regularexpression) | 
| 1022 | Heap::RegExpObject *ExecutionEngine::newRegExpObject(const QRegularExpression &re) | 
| 1023 | { | 
| 1024 |     return memoryManager->allocate<RegExpObject>(args: re); | 
| 1025 | } | 
| 1026 | #endif | 
| 1027 |  | 
| 1028 | Heap::Object *ExecutionEngine::newErrorObject(const Value &value) | 
| 1029 | { | 
| 1030 |     return ErrorObject::create<ErrorObject>(e: this, message: value, newTarget: errorCtor()); | 
| 1031 | } | 
| 1032 |  | 
| 1033 | Heap::Object *ExecutionEngine::newErrorObject(const QString &message) | 
| 1034 | { | 
| 1035 |     return ErrorObject::create<ErrorObject>(e: this, message); | 
| 1036 | } | 
| 1037 |  | 
| 1038 | Heap::Object *ExecutionEngine::newSyntaxErrorObject(const QString &message) | 
| 1039 | { | 
| 1040 |     return ErrorObject::create<SyntaxErrorObject>(e: this, message); | 
| 1041 | } | 
| 1042 |  | 
| 1043 | Heap::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 |  | 
| 1049 | Heap::Object *ExecutionEngine::newReferenceErrorObject(const QString &message) | 
| 1050 | { | 
| 1051 |     return ErrorObject::create<ReferenceErrorObject>(e: this, message); | 
| 1052 | } | 
| 1053 |  | 
| 1054 | Heap::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 |  | 
| 1060 | Heap::Object *ExecutionEngine::newTypeErrorObject(const QString &message) | 
| 1061 | { | 
| 1062 |     return ErrorObject::create<TypeErrorObject>(e: this, message); | 
| 1063 | } | 
| 1064 |  | 
| 1065 | Heap::Object *ExecutionEngine::newRangeErrorObject(const QString &message) | 
| 1066 | { | 
| 1067 |     return ErrorObject::create<RangeErrorObject>(e: this, message); | 
| 1068 | } | 
| 1069 |  | 
| 1070 | Heap::Object *ExecutionEngine::newURIErrorObject(const Value &message) | 
| 1071 | { | 
| 1072 |     return ErrorObject::create<URIErrorObject>(e: this, message, newTarget: uRIErrorCtor()); | 
| 1073 | } | 
| 1074 |  | 
| 1075 | Heap::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 |  | 
| 1086 | Heap::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 |  | 
| 1101 | Promise::ReactionHandler *ExecutionEngine::getPromiseReactionHandler() | 
| 1102 | { | 
| 1103 |     Q_ASSERT(m_reactionHandler); | 
| 1104 |     return m_reactionHandler.data(); | 
| 1105 | } | 
| 1106 |  | 
| 1107 | Heap::Object *ExecutionEngine::newURIErrorObject(const QString &message) | 
| 1108 | { | 
| 1109 |     return ErrorObject::create<URIErrorObject>(e: this, message); | 
| 1110 | } | 
| 1111 |  | 
| 1112 | Heap::Object *ExecutionEngine::newEvalErrorObject(const QString &message) | 
| 1113 | { | 
| 1114 |     return ErrorObject::create<EvalErrorObject>(e: this, message); | 
| 1115 | } | 
| 1116 |  | 
| 1117 | Heap::Object *ExecutionEngine::newVariantObject(const QVariant &v) | 
| 1118 | { | 
| 1119 |     return memoryManager->allocate<VariantObject>(args: v); | 
| 1120 | } | 
| 1121 |  | 
| 1122 | Heap::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 |  | 
| 1129 | Heap::Object *ExecutionEngine::newMapIteratorObject(Object *o) | 
| 1130 | { | 
| 1131 |     return memoryManager->allocate<MapIteratorObject>(args: o->d(), args: this); | 
| 1132 | } | 
| 1133 |  | 
| 1134 | Heap::Object *ExecutionEngine::newSetIteratorObject(Object *o) | 
| 1135 | { | 
| 1136 |     return memoryManager->allocate<SetIteratorObject>(args: o->d(), args: this); | 
| 1137 | } | 
| 1138 |  | 
| 1139 | Heap::Object *ExecutionEngine::newArrayIteratorObject(Object *o) | 
| 1140 | { | 
| 1141 |     return memoryManager->allocate<ArrayIteratorObject>(args: o->d(), args: this); | 
| 1142 | } | 
| 1143 |  | 
| 1144 | Heap::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 |  | 
| 1163 | QObject *ExecutionEngine::qmlScopeObject() const | 
| 1164 | { | 
| 1165 |     Heap::QmlContext *ctx = qmlContext(); | 
| 1166 |     if (!ctx) | 
| 1167 |         return nullptr; | 
| 1168 |  | 
| 1169 |     return ctx->qml()->scopeObject; | 
| 1170 | } | 
| 1171 |  | 
| 1172 | QQmlContextData *ExecutionEngine::callingQmlContext() const | 
| 1173 | { | 
| 1174 |     Heap::QmlContext *ctx = qmlContext(); | 
| 1175 |     if (!ctx) | 
| 1176 |         return nullptr; | 
| 1177 |  | 
| 1178 |     return ctx->qml()->context->contextData(); | 
| 1179 | } | 
| 1180 |  | 
| 1181 | StackTrace 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 |  | 
| 1214 | static 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 |  | 
| 1235 | extern "C"  Q_QML_EXPORT char *qt_v4StackTrace(void *executionContext) | 
| 1236 | { | 
| 1237 |     return v4StackTrace(context: reinterpret_cast<const ExecutionContext *>(executionContext)); | 
| 1238 | } | 
| 1239 |  | 
| 1240 | extern "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 |  | 
| 1246 | QUrl 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 |  | 
| 1271 | void 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 |  | 
| 1284 | ReturnedValue 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 |  | 
| 1308 | ReturnedValue 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 |  | 
| 1320 | ReturnedValue 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 |  | 
| 1328 | ReturnedValue 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 |  | 
| 1335 | ReturnedValue ExecutionEngine::throwSyntaxError(const QString &message) | 
| 1336 | { | 
| 1337 |     Scope scope(this); | 
| 1338 |     ScopedObject error(scope, newSyntaxErrorObject(message)); | 
| 1339 |     return throwError(value: error); | 
| 1340 | } | 
| 1341 |  | 
| 1342 |  | 
| 1343 | ReturnedValue ExecutionEngine::throwTypeError() | 
| 1344 | { | 
| 1345 |     Scope scope(this); | 
| 1346 |     ScopedObject error(scope, newTypeErrorObject(QStringLiteral("Type error" ))); | 
| 1347 |     return throwError(value: error); | 
| 1348 | } | 
| 1349 |  | 
| 1350 | ReturnedValue ExecutionEngine::throwTypeError(const QString &message) | 
| 1351 | { | 
| 1352 |     Scope scope(this); | 
| 1353 |     ScopedObject error(scope, newTypeErrorObject(message)); | 
| 1354 |     return throwError(value: error); | 
| 1355 | } | 
| 1356 |  | 
| 1357 | ReturnedValue 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 |  | 
| 1365 | ReturnedValue 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 |  | 
| 1374 | ReturnedValue 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 |  | 
| 1382 | ReturnedValue ExecutionEngine::throwRangeError(const QString &message) | 
| 1383 | { | 
| 1384 |     Scope scope(this); | 
| 1385 |     ScopedObject error(scope, newRangeErrorObject(message)); | 
| 1386 |     return throwError(value: error); | 
| 1387 | } | 
| 1388 |  | 
| 1389 | ReturnedValue 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 |  | 
| 1398 | ReturnedValue ExecutionEngine::throwURIError(const Value &msg) | 
| 1399 | { | 
| 1400 |     Scope scope(this); | 
| 1401 |     ScopedObject error(scope, newURIErrorObject(message: msg)); | 
| 1402 |     return throwError(value: error); | 
| 1403 | } | 
| 1404 |  | 
| 1405 | ReturnedValue 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 |  | 
| 1414 | QQmlError 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 |  | 
| 1433 | typedef QSet<QV4::Heap::Object *> V4ObjectSet; | 
| 1434 | static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int typeHint, bool createJSValueForObjects, V4ObjectSet *visitedObjects); | 
| 1435 | static QObject *qtObjectFromJS(QV4::ExecutionEngine *engine, const QV4::Value &value); | 
| 1436 | static QVariant objectToVariant(QV4::ExecutionEngine *e, const QV4::Object *o, V4ObjectSet *visitedObjects = nullptr); | 
| 1437 | static bool convertToNativeQObject(QV4::ExecutionEngine *e, const QV4::Value &value, | 
| 1438 |                             const QByteArray &targetType, | 
| 1439 |                             void **result); | 
| 1440 | static QV4::ReturnedValue variantListToJS(QV4::ExecutionEngine *v4, const QVariantList &lst); | 
| 1441 | static QV4::ReturnedValue sequentialIterableToJS(QV4::ExecutionEngine *v4, const QSequentialIterable &lst); | 
| 1442 | static QV4::ReturnedValue variantMapToJS(QV4::ExecutionEngine *v4, const QVariantMap &vmap); | 
| 1443 | static QV4::ReturnedValue variantToJS(QV4::ExecutionEngine *v4, const QVariant &value) | 
| 1444 | { | 
| 1445 |     return v4->metaTypeToJS(type: value.userType(), data: value.constData()); | 
| 1446 | } | 
| 1447 |  | 
| 1448 |  | 
| 1449 | QVariant ExecutionEngine::toVariant(const Value &value, int typeHint, bool createJSValueForObjects) | 
| 1450 | { | 
| 1451 |     return ::toVariant(e: this, value, typeHint, createJSValueForObjects, visitedObjects: nullptr); | 
| 1452 | } | 
| 1453 |  | 
| 1454 |  | 
| 1455 | static 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 |  | 
| 1606 | static 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 |  | 
| 1660 | QV4::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 |  | 
| 1806 | QVariantMap 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. | 
| 1816 | static 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. | 
| 1832 | static 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. | 
| 1848 | static 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. | 
| 1869 | QV4::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 |  | 
| 1882 | int ExecutionEngine::maxJSStackSize() const | 
| 1883 | { | 
| 1884 |     return m_maxJSStackSize; | 
| 1885 | } | 
| 1886 |  | 
| 1887 | int ExecutionEngine::maxGCStackSize() const | 
| 1888 | { | 
| 1889 |     return m_maxGCStackSize; | 
| 1890 | } | 
| 1891 |  | 
| 1892 | ReturnedValue ExecutionEngine::global() | 
| 1893 | { | 
| 1894 |     return globalObject->asReturnedValue(); | 
| 1895 | } | 
| 1896 |  | 
| 1897 | QQmlRefPointer<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 |  | 
| 1920 | QQmlRefPointer<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 |  | 
| 1939 | void 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 |  | 
| 1947 | QQmlRefPointer<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 |  | 
| 1960 | QQmlRefPointer<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 |  | 
| 1982 | void ExecutionEngine::initQmlGlobalObject() | 
| 1983 | { | 
| 1984 |     initializeGlobal(); | 
| 1985 |     freezeObject(value: *globalObject); | 
| 1986 | } | 
| 1987 |  | 
| 1988 | void 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 |  | 
| 2020 | const QSet<QString> &ExecutionEngine::illegalNames() const | 
| 2021 | { | 
| 2022 |     return m_illegalNames; | 
| 2023 | } | 
| 2024 |  | 
| 2025 | void ExecutionEngine::setQmlEngine(QQmlEngine *engine) | 
| 2026 | { | 
| 2027 |     m_qmlEngine = engine; | 
| 2028 |     initQmlGlobalObject(); | 
| 2029 | } | 
| 2030 |  | 
| 2031 | static 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 |  | 
| 2063 | void 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 |  | 
| 2070 | void ExecutionEngine::startTimer(const QString &timerName) | 
| 2071 | { | 
| 2072 |     if (!m_time.isValid()) | 
| 2073 |         m_time.start(); | 
| 2074 |     m_startedTimers[timerName] = m_time.elapsed(); | 
| 2075 | } | 
| 2076 |  | 
| 2077 | qint64 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 |  | 
| 2088 | int 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 |  | 
| 2097 | void 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. | 
| 2111 | bool 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 |  | 
| 2319 | static 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 |  | 
| 2334 | static 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 |  | 
| 2354 | struct QV4EngineRegistrationData | 
| 2355 | { | 
| 2356 |     QV4EngineRegistrationData() : extensionCount(0) {} | 
| 2357 |  | 
| 2358 |     QMutex mutex; | 
| 2359 |     int extensionCount; | 
| 2360 | }; | 
| 2361 | Q_GLOBAL_STATIC(QV4EngineRegistrationData, registrationData); | 
| 2362 |  | 
| 2363 | QMutex *ExecutionEngine::registrationMutex() | 
| 2364 | { | 
| 2365 |     return ®istrationData()->mutex; | 
| 2366 | } | 
| 2367 |  | 
| 2368 | int ExecutionEngine::registerExtension() | 
| 2369 | { | 
| 2370 |     return registrationData()->extensionCount++; | 
| 2371 | } | 
| 2372 |  | 
| 2373 | #if QT_CONFIG(qml_network) | 
| 2374 | QNetworkAccessManager *QV4::detail::getNetworkAccessManager(ExecutionEngine *engine) | 
| 2375 | { | 
| 2376 |     return engine->qmlEngine()->networkAccessManager(); | 
| 2377 | } | 
| 2378 | #endif // qml_network | 
| 2379 |  | 
| 2380 | QT_END_NAMESPACE | 
| 2381 |  |