2012-11-17 20:54:26 +00:00
|
|
|
/****************************************************************************
|
|
|
|
**
|
2016-01-19 09:38:36 +00:00
|
|
|
** Copyright (C) 2016 The Qt Company Ltd.
|
|
|
|
** Contact: https://www.qt.io/licensing/
|
2012-11-17 20:54:26 +00:00
|
|
|
**
|
2013-06-24 11:50:51 +00:00
|
|
|
** This file is part of the QtQml module of the Qt Toolkit.
|
2012-11-17 20:54:26 +00:00
|
|
|
**
|
2016-01-19 09:38:36 +00:00
|
|
|
** $QT_BEGIN_LICENSE:LGPL$
|
2012-11-17 20:54:26 +00:00
|
|
|
** Commercial License Usage
|
|
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
|
|
** accordance with the commercial license agreement provided with the
|
|
|
|
** Software or, alternatively, in accordance with the terms contained in
|
2015-01-28 11:55:39 +00:00
|
|
|
** a written agreement between you and The Qt Company. For licensing terms
|
2016-01-19 09:38:36 +00:00
|
|
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
|
|
|
** information use the contact form at https://www.qt.io/contact-us.
|
2012-11-17 20:54:26 +00:00
|
|
|
**
|
|
|
|
** GNU Lesser General Public License Usage
|
|
|
|
** Alternatively, this file may be used under the terms of the GNU Lesser
|
2016-01-19 09:38:36 +00:00
|
|
|
** General Public License version 3 as published by the Free Software
|
|
|
|
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
|
|
|
** packaging of this file. Please review the following information to
|
|
|
|
** ensure the GNU Lesser General Public License version 3 requirements
|
|
|
|
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
2012-11-17 20:54:26 +00:00
|
|
|
**
|
2016-01-19 09:38:36 +00:00
|
|
|
** GNU General Public License Usage
|
|
|
|
** Alternatively, this file may be used under the terms of the GNU
|
|
|
|
** General Public License version 2.0 or (at your option) the GNU General
|
|
|
|
** Public license version 3 or any later version approved by the KDE Free
|
|
|
|
** Qt Foundation. The licenses are as published by the Free Software
|
|
|
|
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
|
|
|
|
** included in the packaging of this file. Please review the following
|
|
|
|
** information to ensure the GNU General Public License requirements will
|
|
|
|
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
|
|
|
|
** https://www.gnu.org/licenses/gpl-3.0.html.
|
2012-11-17 20:54:26 +00:00
|
|
|
**
|
|
|
|
** $QT_END_LICENSE$
|
|
|
|
**
|
|
|
|
****************************************************************************/
|
2013-04-15 09:50:16 +00:00
|
|
|
#include <qv4engine_p.h>
|
2018-08-16 11:06:22 +00:00
|
|
|
|
|
|
|
#include <private/qv4compileddata_p.h>
|
|
|
|
#include <private/qv4codegen_p.h>
|
2019-05-23 12:57:09 +00:00
|
|
|
#include <private/qqmljsdiagnosticmessage_p.h>
|
2018-08-16 11:06:22 +00:00
|
|
|
|
|
|
|
#include <QtCore/QTextStream>
|
2019-12-09 14:26:14 +00:00
|
|
|
#include <QtCore/private/qvariant_p.h>
|
2018-08-16 11:06:22 +00:00
|
|
|
#include <QDateTime>
|
|
|
|
#include <QDir>
|
|
|
|
#include <QFileInfo>
|
2018-10-09 12:58:01 +00:00
|
|
|
#include <QLoggingCategory>
|
2019-02-13 14:54:14 +00:00
|
|
|
#if QT_CONFIG(regularexpression)
|
|
|
|
#include <QRegularExpression>
|
|
|
|
#endif
|
2018-08-16 11:06:22 +00:00
|
|
|
|
2016-11-28 14:33:48 +00:00
|
|
|
#include <qv4qmlcontext_p.h>
|
2015-02-14 21:46:41 +00:00
|
|
|
#include <qv4value_p.h>
|
2013-04-15 09:50:16 +00:00
|
|
|
#include <qv4object_p.h>
|
|
|
|
#include <qv4objectproto_p.h>
|
2013-09-30 11:48:05 +00:00
|
|
|
#include <qv4objectiterator_p.h>
|
2018-05-27 13:04:23 +00:00
|
|
|
#include <qv4setiterator_p.h>
|
2018-05-29 20:41:34 +00:00
|
|
|
#include <qv4mapiterator_p.h>
|
Add Array Iterator objects from ES6 (22.1.5)
And implement / expose them via:
22.1.3.4 - Array.prototype.entries()
22.1.3.13 - Array.prototype.keys()
22.1.3.29 - Array.prototype.values()
22.1.3.31 - Array.prototype[Symbol.iterator]
Most tests for Array iterators now pass.
At the same time, expose them on TypedArray's prototype:
- 22.2.3.15 %TypedArray%.prototype.keys
- 22.2.3.29 %TypedArray%.prototype.values
- 22.2.3.6 %TypedArray%.prototype.entries
- 22.2.3.31 %TypedArray%.prototype[Symbol.iterator]
For TypedArray, test coverage improves a tiny bit (3 passing tests), but the
vast majority fail as it seems like the object structure for TypedArray is
currently incomplete as far as ES6 expects.
It seems that ES6 expects the object structure to be:
* %TypedArray% (inherits FunctionObject)
(this is the TypedArray intrinsic object, and responsible for initializing
the TypedArray instances)
* All the TypedArray ctors (e.g. UInt8Array)
These inherit %TypedArray%, and make a super call to it to do their work
* %TypedArrayPrototype% (inherits Object)
(this is the initial prototype for %TypedArray%)
* All the ctors have their own separate instance of this
* The instances also make use it
So, for instance, a lot of the tests attempt to access the prototype like:
var proto = Object.getPrototypeOf(Int8Array)
var keys = proto.prototype.keys
As ES6 expects Int8Array.prototype to be %TypedArray% (22.2.5), this expands to:
Object.getPrototypeOf(%TypedArray%)
which it expects to be %TypedArrayPrototype%.
But since we have no intrinsic object, and the ctors inherit
FunctionObject, we instead return the wrong prototype into 'var proto'.
Change-Id: I5e1a95a0420ecb70a0e35a5df3f65557510c5925
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
2017-02-09 18:58:50 +00:00
|
|
|
#include <qv4arrayiterator_p.h>
|
2013-04-15 09:50:16 +00:00
|
|
|
#include <qv4arrayobject_p.h>
|
|
|
|
#include <qv4booleanobject_p.h>
|
|
|
|
#include <qv4globalobject_p.h>
|
|
|
|
#include <qv4errorobject_p.h>
|
|
|
|
#include <qv4functionobject_p.h>
|
2013-05-08 12:24:30 +00:00
|
|
|
#include "qv4function_p.h"
|
2013-04-15 09:50:16 +00:00
|
|
|
#include <qv4mathobject_p.h>
|
|
|
|
#include <qv4numberobject_p.h>
|
|
|
|
#include <qv4regexpobject_p.h>
|
2013-11-21 13:26:08 +00:00
|
|
|
#include <qv4regexp_p.h>
|
2018-04-03 13:23:07 +00:00
|
|
|
#include "qv4symbol_p.h"
|
2018-05-27 13:04:23 +00:00
|
|
|
#include "qv4setobject_p.h"
|
2018-05-29 20:41:34 +00:00
|
|
|
#include "qv4mapobject_p.h"
|
2013-05-14 00:01:04 +00:00
|
|
|
#include <qv4variantobject_p.h>
|
2013-04-15 09:50:16 +00:00
|
|
|
#include <qv4runtime_p.h>
|
2015-02-12 20:16:42 +00:00
|
|
|
#include <private/qv4mm_p.h>
|
2013-04-15 09:50:16 +00:00
|
|
|
#include <qv4argumentsobject_p.h>
|
|
|
|
#include <qv4dateobject_p.h>
|
|
|
|
#include <qv4jsonobject_p.h>
|
|
|
|
#include <qv4stringobject_p.h>
|
2013-06-27 21:02:45 +00:00
|
|
|
#include <qv4identifiertable_p.h>
|
2013-04-15 09:50:16 +00:00
|
|
|
#include "qv4debugging_p.h"
|
2014-01-22 16:46:20 +00:00
|
|
|
#include "qv4profiling_p.h"
|
2013-04-15 09:50:16 +00:00
|
|
|
#include "qv4executableallocator_p.h"
|
Add Array Iterator objects from ES6 (22.1.5)
And implement / expose them via:
22.1.3.4 - Array.prototype.entries()
22.1.3.13 - Array.prototype.keys()
22.1.3.29 - Array.prototype.values()
22.1.3.31 - Array.prototype[Symbol.iterator]
Most tests for Array iterators now pass.
At the same time, expose them on TypedArray's prototype:
- 22.2.3.15 %TypedArray%.prototype.keys
- 22.2.3.29 %TypedArray%.prototype.values
- 22.2.3.6 %TypedArray%.prototype.entries
- 22.2.3.31 %TypedArray%.prototype[Symbol.iterator]
For TypedArray, test coverage improves a tiny bit (3 passing tests), but the
vast majority fail as it seems like the object structure for TypedArray is
currently incomplete as far as ES6 expects.
It seems that ES6 expects the object structure to be:
* %TypedArray% (inherits FunctionObject)
(this is the TypedArray intrinsic object, and responsible for initializing
the TypedArray instances)
* All the TypedArray ctors (e.g. UInt8Array)
These inherit %TypedArray%, and make a super call to it to do their work
* %TypedArrayPrototype% (inherits Object)
(this is the initial prototype for %TypedArray%)
* All the ctors have their own separate instance of this
* The instances also make use it
So, for instance, a lot of the tests attempt to access the prototype like:
var proto = Object.getPrototypeOf(Int8Array)
var keys = proto.prototype.keys
As ES6 expects Int8Array.prototype to be %TypedArray% (22.2.5), this expands to:
Object.getPrototypeOf(%TypedArray%)
which it expects to be %TypedArrayPrototype%.
But since we have no intrinsic object, and the ctors inherit
FunctionObject, we instead return the wrong prototype into 'var proto'.
Change-Id: I5e1a95a0420ecb70a0e35a5df3f65557510c5925
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
2017-02-09 18:58:50 +00:00
|
|
|
#include "qv4iterator_p.h"
|
2018-04-26 11:12:38 +00:00
|
|
|
#include "qv4stringiterator_p.h"
|
2018-04-27 09:41:13 +00:00
|
|
|
#include "qv4generatorobject_p.h"
|
2018-06-15 21:00:32 +00:00
|
|
|
#include "qv4reflect_p.h"
|
2018-06-17 08:57:21 +00:00
|
|
|
#include "qv4proxy_p.h"
|
2018-06-27 12:18:17 +00:00
|
|
|
#include "qv4stackframe_p.h"
|
2018-08-24 13:57:31 +00:00
|
|
|
#include "qv4atomics_p.h"
|
2017-12-18 15:20:11 +00:00
|
|
|
|
|
|
|
#if QT_CONFIG(qml_sequence_object)
|
2013-05-21 15:06:36 +00:00
|
|
|
#include "qv4sequenceobject_p.h"
|
2017-12-18 15:20:11 +00:00
|
|
|
#endif
|
|
|
|
|
2013-06-07 09:21:18 +00:00
|
|
|
#include "qv4qobjectwrapper_p.h"
|
2014-03-31 13:48:02 +00:00
|
|
|
#include "qv4memberdata_p.h"
|
2014-09-10 12:50:28 +00:00
|
|
|
#include "qv4arraybuffer_p.h"
|
2014-09-10 14:39:23 +00:00
|
|
|
#include "qv4dataview_p.h"
|
2015-07-16 16:35:55 +00:00
|
|
|
#include "qv4promiseobject_p.h"
|
2014-09-11 13:37:31 +00:00
|
|
|
#include "qv4typedarray_p.h"
|
2015-01-02 13:37:26 +00:00
|
|
|
#include <private/qjsvalue_p.h>
|
|
|
|
#include <private/qqmltypewrapper_p.h>
|
|
|
|
#include <private/qqmlvaluetypewrapper_p.h>
|
|
|
|
#include <private/qqmlvaluetype_p.h>
|
|
|
|
#include <private/qqmllistwrapper_p.h>
|
|
|
|
#include <private/qqmllist_p.h>
|
2018-07-10 12:52:34 +00:00
|
|
|
#include <private/qqmltypeloader_p.h>
|
2019-04-05 07:59:10 +00:00
|
|
|
#include <private/qqmlbuiltinfunctions_p.h>
|
2017-12-18 18:43:56 +00:00
|
|
|
#if QT_CONFIG(qml_locale)
|
2015-01-02 13:37:26 +00:00
|
|
|
#include <private/qqmllocale_p.h>
|
2017-12-18 18:43:56 +00:00
|
|
|
#endif
|
2019-04-05 07:59:10 +00:00
|
|
|
#if QT_CONFIG(qml_xml_http_request)
|
|
|
|
#include <private/qv4domerrors_p.h>
|
|
|
|
#include <private/qqmlxmlhttprequest_p.h>
|
|
|
|
#endif
|
|
|
|
#include <private/qv4sqlerrors_p.h>
|
2018-07-10 12:52:34 +00:00
|
|
|
#include <qqmlfile.h>
|
2019-12-09 14:26:14 +00:00
|
|
|
#include <qmetatype.h>
|
2013-05-28 07:36:04 +00:00
|
|
|
|
2013-11-11 10:22:24 +00:00
|
|
|
#if USE(PTHREADS)
|
|
|
|
# include <pthread.h>
|
2017-01-26 10:46:16 +00:00
|
|
|
#if !defined(Q_OS_INTEGRITY)
|
2013-12-17 15:11:19 +00:00
|
|
|
# include <sys/resource.h>
|
2017-01-26 10:46:16 +00:00
|
|
|
#endif
|
2014-01-21 09:55:18 +00:00
|
|
|
#if HAVE(PTHREAD_NP_H)
|
|
|
|
# include <pthread_np.h>
|
|
|
|
#endif
|
2013-11-11 10:22:24 +00:00
|
|
|
#endif
|
|
|
|
|
2014-12-15 07:47:35 +00:00
|
|
|
#ifdef V4_USE_VALGRIND
|
|
|
|
#include <valgrind/memcheck.h>
|
|
|
|
#endif
|
|
|
|
|
2019-04-05 07:59:10 +00:00
|
|
|
Q_DECLARE_METATYPE(QList<int>)
|
|
|
|
|
2013-06-24 13:28:00 +00:00
|
|
|
QT_BEGIN_NAMESPACE
|
|
|
|
|
2013-04-19 11:03:42 +00:00
|
|
|
using namespace QV4;
|
2012-11-17 20:54:26 +00:00
|
|
|
|
2013-06-04 08:05:51 +00:00
|
|
|
static QBasicAtomicInt engineSerial = Q_BASIC_ATOMIC_INITIALIZER(1);
|
|
|
|
|
2017-12-05 09:45:14 +00:00
|
|
|
ReturnedValue throwTypeError(const FunctionObject *b, const QV4::Value *, const QV4::Value *, int)
|
2013-09-18 07:30:45 +00:00
|
|
|
{
|
2017-08-04 16:53:51 +00:00
|
|
|
return b->engine()->throwTypeError();
|
2013-09-18 07:30:45 +00:00
|
|
|
}
|
|
|
|
|
2016-04-25 13:01:04 +00:00
|
|
|
qint32 ExecutionEngine::maxCallDepth = -1;
|
2014-12-30 15:38:20 +00:00
|
|
|
|
2019-04-05 07:59:10 +00:00
|
|
|
template <typename ReturnType>
|
|
|
|
ReturnType convertJSValueToVariantType(const QJSValue &value)
|
|
|
|
{
|
|
|
|
return value.toVariant().value<ReturnType>();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void saveJSValue(QDataStream &stream, const void *data)
|
|
|
|
{
|
|
|
|
const QJSValue *jsv = reinterpret_cast<const QJSValue *>(data);
|
|
|
|
quint32 isNullOrUndefined = 0;
|
|
|
|
if (jsv->isNull())
|
|
|
|
isNullOrUndefined |= 0x1;
|
|
|
|
if (jsv->isUndefined())
|
|
|
|
isNullOrUndefined |= 0x2;
|
|
|
|
stream << isNullOrUndefined;
|
|
|
|
if (!isNullOrUndefined)
|
|
|
|
reinterpret_cast<const QJSValue*>(data)->toVariant().save(stream);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void restoreJSValue(QDataStream &stream, void *data)
|
|
|
|
{
|
|
|
|
QJSValue *jsv = reinterpret_cast<QJSValue*>(data);
|
|
|
|
|
|
|
|
quint32 isNullOrUndefined;
|
|
|
|
stream >> isNullOrUndefined;
|
|
|
|
|
|
|
|
if (isNullOrUndefined & 0x1) {
|
|
|
|
*jsv = QJSValue(QJSValue::NullValue);
|
|
|
|
} else if (isNullOrUndefined & 0x2) {
|
|
|
|
*jsv = QJSValue();
|
|
|
|
} else {
|
|
|
|
QVariant v;
|
|
|
|
v.load(stream);
|
|
|
|
QJSValuePrivate::setVariant(jsv, v);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-09 14:26:14 +00:00
|
|
|
struct JSArrayIterator {
|
|
|
|
QJSValue const* data;
|
|
|
|
quint32 index;
|
|
|
|
};
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
void createNewIteratorIfNonExisting(void **iterator) {
|
|
|
|
if (*iterator == nullptr)
|
|
|
|
*iterator = new JSArrayIterator;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static QtMetaTypePrivate::QSequentialIterableImpl jsvalueToSequence (const QJSValue& value) {
|
|
|
|
using namespace QtMetaTypePrivate;
|
|
|
|
|
|
|
|
QSequentialIterableImpl iterator {};
|
|
|
|
if (!value.isArray()) {
|
|
|
|
// set up some functions so that non-array QSequentialIterables do not crash
|
|
|
|
// but instead appear as an empty sequence
|
|
|
|
iterator._size = [](const void *) {return 0;};
|
|
|
|
iterator._moveToBegin = [](const void *, void **) {};
|
|
|
|
iterator._moveToEnd = [](const void *, void **) {};
|
|
|
|
iterator._advance = [](void **, int) {};
|
|
|
|
iterator._equalIter = [](void * const *, void * const *){return true; /*all iterators are nullptr*/};
|
|
|
|
iterator._destroyIter = [](void **){};
|
|
|
|
return iterator;
|
|
|
|
}
|
|
|
|
|
|
|
|
iterator._iterable = &value;
|
|
|
|
iterator._iterator = nullptr;
|
|
|
|
iterator._metaType_id = qMetaTypeId<QVariant>();
|
|
|
|
iterator._metaType_flags = QVariantConstructionFlags::ShouldDeleteVariantData;
|
|
|
|
iterator._iteratorCapabilities = RandomAccessCapability | BiDirectionalCapability | ForwardCapability;
|
|
|
|
iterator._size = [](const void *p) -> int {
|
|
|
|
return static_cast<QJSValue const *>(p)->property(QString::fromLatin1("length")).toInt();
|
|
|
|
};
|
|
|
|
/* Lifetime management notes:
|
|
|
|
* _at and _get return a pointer to a JSValue allocated via QMetaType::create
|
|
|
|
* Because we set QVariantConstructionFlags::ShouldDeleteVariantData, QSequentialIterable::at
|
|
|
|
* and QSequentialIterable::operator*() will free that memory
|
|
|
|
*/
|
|
|
|
|
|
|
|
iterator._at = [](const void *iterable, int index) -> void const * {
|
|
|
|
auto const value = static_cast<QJSValue const *>(iterable)->property(quint32(index)).toVariant();
|
|
|
|
return QMetaType::create(qMetaTypeId<QVariant>(), &value);
|
|
|
|
};
|
|
|
|
iterator._moveToBegin = [](const void *iterable, void **iterator) {
|
|
|
|
createNewIteratorIfNonExisting(iterator);
|
|
|
|
auto jsArrayIterator = static_cast<JSArrayIterator *>(*iterator);
|
|
|
|
jsArrayIterator->index = 0;
|
|
|
|
jsArrayIterator->data = reinterpret_cast<QJSValue const*>(iterable);
|
|
|
|
};
|
|
|
|
iterator._moveToEnd = [](const void *iterable, void **iterator) {
|
|
|
|
createNewIteratorIfNonExisting(iterator);
|
|
|
|
auto jsArrayIterator = static_cast<JSArrayIterator *>(*iterator);
|
|
|
|
auto length = static_cast<QJSValue const *>(iterable)->property(QString::fromLatin1("length")).toInt();
|
|
|
|
jsArrayIterator->data = reinterpret_cast<QJSValue const*>(iterable);
|
|
|
|
jsArrayIterator->index = quint32(length);
|
|
|
|
};
|
|
|
|
iterator._advance = [](void **iterator, int advanceBy) {
|
|
|
|
static_cast<JSArrayIterator *>(*iterator)->index += quint32(advanceBy);
|
|
|
|
};
|
|
|
|
iterator._get = []( void * const *iterator, int metaTypeId, uint flags) -> VariantData {
|
|
|
|
auto const * const arrayIterator = static_cast<const JSArrayIterator *>(*iterator);
|
|
|
|
QJSValue const * const jsArray = arrayIterator->data;
|
|
|
|
auto const value = jsArray->property(arrayIterator->index).toVariant();
|
|
|
|
Q_ASSERT(flags & QVariantConstructionFlags::ShouldDeleteVariantData);
|
|
|
|
return {metaTypeId, QMetaType::create(qMetaTypeId<QVariant>(), &value), flags};
|
|
|
|
};
|
|
|
|
iterator._destroyIter = [](void **iterator) {
|
|
|
|
delete static_cast<JSArrayIterator *>(*iterator);
|
|
|
|
};
|
|
|
|
iterator._equalIter = [](void * const *p, void * const *other) {
|
|
|
|
auto this_ = static_cast<const JSArrayIterator *>(*p);
|
|
|
|
auto that_ = static_cast<const JSArrayIterator *>(*other);
|
|
|
|
return this_->index == that_->index && this_->data == that_->data;
|
|
|
|
};
|
|
|
|
iterator._copyIter = [](void **iterator, void * const * otherIterator) {
|
|
|
|
auto *otherIter = (static_cast<JSArrayIterator const *>(*otherIterator));
|
|
|
|
static_cast<JSArrayIterator *>(*iterator)->index = otherIter->index;
|
|
|
|
static_cast<JSArrayIterator *>(*iterator)->data = otherIter->data;
|
|
|
|
};
|
|
|
|
return iterator;
|
|
|
|
}
|
|
|
|
|
2017-12-19 16:14:15 +00:00
|
|
|
ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
|
2017-05-12 07:33:25 +00:00
|
|
|
: executableAllocator(new QV4::ExecutableAllocator)
|
2013-05-12 10:07:15 +00:00
|
|
|
, regExpAllocator(new QV4::ExecutableAllocator)
|
2013-04-19 09:47:50 +00:00
|
|
|
, bumperPointerAllocator(new WTF::BumpPointerAllocator)
|
2013-09-03 10:40:07 +00:00
|
|
|
, jsStack(new WTF::PageAllocation)
|
2017-03-09 09:36:16 +00:00
|
|
|
, gcStack(new WTF::PageAllocation)
|
2018-02-21 09:41:54 +00:00
|
|
|
, globalCode(nullptr)
|
2017-12-19 16:14:15 +00:00
|
|
|
, publicEngine(jsEngine)
|
2013-06-04 08:05:51 +00:00
|
|
|
, m_engineId(engineSerial.fetchAndAddOrdered(1))
|
2018-02-21 09:41:54 +00:00
|
|
|
, regExpCache(nullptr)
|
|
|
|
, m_multiplyWrappedQObjects(nullptr)
|
2019-04-17 13:15:52 +00:00
|
|
|
#if QT_CONFIG(qml_jit)
|
2018-02-16 13:19:25 +00:00
|
|
|
, m_canAllocateExecutableMemory(OSAllocator::canAllocateExecutableMemory())
|
|
|
|
#endif
|
2019-04-05 07:59:10 +00:00
|
|
|
#if QT_CONFIG(qml_xml_http_request)
|
|
|
|
, m_xmlHttpRequestData(nullptr)
|
|
|
|
#endif
|
|
|
|
, m_qmlEngine(nullptr)
|
2012-11-17 20:54:26 +00:00
|
|
|
{
|
2019-06-27 11:43:04 +00:00
|
|
|
bool ok = false;
|
|
|
|
const int envMaxJSStackSize = qEnvironmentVariableIntValue("QV4_JS_MAX_STACK_SIZE", &ok);
|
|
|
|
if (ok && envMaxJSStackSize > 0)
|
|
|
|
m_maxJSStackSize = envMaxJSStackSize;
|
|
|
|
|
|
|
|
const int envMaxGCStackSize = qEnvironmentVariableIntValue("QV4_GC_MAX_STACK_SIZE", &ok);
|
|
|
|
if (ok && envMaxGCStackSize > 0)
|
|
|
|
m_maxGCStackSize = envMaxGCStackSize;
|
|
|
|
|
2017-03-15 08:25:52 +00:00
|
|
|
memoryManager = new QV4::MemoryManager(this);
|
|
|
|
|
2016-04-25 13:01:04 +00:00
|
|
|
if (maxCallDepth == -1) {
|
2019-09-02 12:44:29 +00:00
|
|
|
if (qEnvironmentVariableIsSet("QV4_CRASH_ON_STACKOVERFLOW")) {
|
|
|
|
maxCallDepth = std::numeric_limits<qint32>::max();
|
|
|
|
} else {
|
|
|
|
ok = false;
|
|
|
|
maxCallDepth = qEnvironmentVariableIntValue("QV4_MAX_CALL_DEPTH", &ok);
|
|
|
|
if (!ok || maxCallDepth <= 0) {
|
2019-12-08 23:09:02 +00:00
|
|
|
#if defined(QT_NO_DEBUG) && !defined(__SANITIZE_ADDRESS__) && !__has_feature(address_sanitizer)
|
2019-09-02 12:44:29 +00:00
|
|
|
maxCallDepth = 1234;
|
2016-09-05 11:12:58 +00:00
|
|
|
#else
|
2019-09-02 12:44:29 +00:00
|
|
|
// no (tail call) optimization is done, so there'll be a lot mare stack frames active
|
|
|
|
maxCallDepth = 200;
|
2016-09-05 11:12:58 +00:00
|
|
|
#endif
|
2019-09-02 12:44:29 +00:00
|
|
|
}
|
2016-04-25 13:01:04 +00:00
|
|
|
}
|
2013-05-07 09:54:45 +00:00
|
|
|
}
|
2016-04-25 13:01:04 +00:00
|
|
|
Q_ASSERT(maxCallDepth > 0);
|
2013-03-05 15:11:22 +00:00
|
|
|
|
2013-11-11 10:22:24 +00:00
|
|
|
// reserve space for the JS stack
|
2019-06-27 11:43:04 +00:00
|
|
|
// we allow it to grow to a bit more than m_maxJSStackSize, as we can overshoot due to ScopedValues
|
2017-03-09 09:36:16 +00:00
|
|
|
// allocated outside of JIT'ed methods.
|
2019-06-27 11:43:04 +00:00
|
|
|
*jsStack = WTF::PageAllocation::allocate(m_maxJSStackSize + 256*1024, WTF::OSAllocator::JSVMStackPages,
|
2014-10-22 10:34:47 +00:00
|
|
|
/* writable */ true, /* executable */ false,
|
|
|
|
/* includesGuardPages */ true);
|
2014-01-24 21:55:39 +00:00
|
|
|
jsStackBase = (Value *)jsStack->base();
|
2016-05-26 15:22:34 +00:00
|
|
|
#ifdef V4_USE_VALGRIND
|
2019-06-27 11:43:04 +00:00
|
|
|
VALGRIND_MAKE_MEM_UNDEFINED(jsStackBase, m_maxJSStackSize + 256*1024);
|
2016-05-26 15:22:34 +00:00
|
|
|
#endif
|
|
|
|
|
2013-09-03 10:40:07 +00:00
|
|
|
jsStackTop = jsStackBase;
|
|
|
|
|
2019-06-27 11:43:04 +00:00
|
|
|
*gcStack = WTF::PageAllocation::allocate(m_maxGCStackSize, WTF::OSAllocator::JSVMStackPages,
|
2017-03-09 09:36:16 +00:00
|
|
|
/* writable */ true, /* executable */ false,
|
|
|
|
/* includesGuardPages */ true);
|
|
|
|
|
2017-11-23 10:34:27 +00:00
|
|
|
{
|
2019-06-27 11:43:04 +00:00
|
|
|
ok = false;
|
2017-11-23 10:34:27 +00:00
|
|
|
jitCallCountThreshold = qEnvironmentVariableIntValue("QV4_JIT_CALL_THRESHOLD", &ok);
|
|
|
|
if (!ok)
|
|
|
|
jitCallCountThreshold = 3;
|
|
|
|
if (qEnvironmentVariableIsSet("QV4_FORCE_INTERPRETER"))
|
|
|
|
jitCallCountThreshold = std::numeric_limits<int>::max();
|
|
|
|
}
|
|
|
|
|
2015-03-13 16:21:18 +00:00
|
|
|
exceptionValue = jsAlloca(1);
|
2018-05-25 07:03:51 +00:00
|
|
|
*exceptionValue = Encode::undefined();
|
2015-03-13 16:21:18 +00:00
|
|
|
globalObject = static_cast<Object *>(jsAlloca(1));
|
2015-03-25 12:49:51 +00:00
|
|
|
jsObjects = jsAlloca(NJSObjects);
|
2015-03-25 20:06:18 +00:00
|
|
|
typedArrayPrototype = static_cast<Object *>(jsAlloca(NTypedArrayTypes));
|
|
|
|
typedArrayCtors = static_cast<FunctionObject *>(jsAlloca(NTypedArrayTypes));
|
2015-04-26 07:22:17 +00:00
|
|
|
jsStrings = jsAlloca(NJSStrings);
|
2018-04-08 14:43:10 +00:00
|
|
|
jsSymbols = jsAlloca(NJSSymbols);
|
2015-03-13 16:21:18 +00:00
|
|
|
|
2013-11-11 10:22:24 +00:00
|
|
|
// set up stack limits
|
2019-06-27 11:43:04 +00:00
|
|
|
jsStackLimit = jsStackBase + m_maxJSStackSize/sizeof(Value);
|
2013-11-11 10:22:24 +00:00
|
|
|
|
2013-06-27 06:57:47 +00:00
|
|
|
identifierTable = new IdentifierTable(this);
|
2013-01-30 13:56:40 +00:00
|
|
|
|
2018-01-05 14:30:23 +00:00
|
|
|
memset(classes, 0, sizeof(classes));
|
|
|
|
classes[Class_Empty] = memoryManager->allocIC<InternalClass>();
|
|
|
|
classes[Class_Empty]->init(this);
|
|
|
|
|
2018-04-04 07:31:10 +00:00
|
|
|
classes[Class_MemberData] = classes[Class_Empty]->changeVTable(QV4::MemberData::staticVTable());
|
|
|
|
classes[Class_SimpleArrayData] = classes[Class_Empty]->changeVTable(QV4::SimpleArrayData::staticVTable());
|
|
|
|
classes[Class_SparseArrayData] = classes[Class_Empty]->changeVTable(QV4::SparseArrayData::staticVTable());
|
|
|
|
classes[Class_ExecutionContext] = classes[Class_Empty]->changeVTable(QV4::ExecutionContext::staticVTable());
|
|
|
|
classes[Class_CallContext] = classes[Class_Empty]->changeVTable(QV4::CallContext::staticVTable());
|
|
|
|
classes[Class_QmlContext] = classes[Class_Empty]->changeVTable(QV4::QmlContext::staticVTable());
|
2013-05-12 13:00:48 +00:00
|
|
|
|
2018-04-03 13:23:07 +00:00
|
|
|
Scope scope(this);
|
|
|
|
Scoped<InternalClass> ic(scope);
|
|
|
|
ic = classes[Class_Empty]->changeVTable(QV4::Object::staticVTable());
|
|
|
|
jsObjects[ObjectProto] = memoryManager->allocObject<ObjectPrototype>(ic->d());
|
|
|
|
classes[Class_Object] = ic->changePrototype(objectPrototype()->d());
|
|
|
|
classes[Class_QmlContextWrapper] = classes[Class_Object]->changeVTable(QV4::QQmlContextWrapper::staticVTable());
|
|
|
|
|
|
|
|
ic = newInternalClass(QV4::StringObject::staticVTable(), objectPrototype());
|
2018-05-04 08:52:44 +00:00
|
|
|
jsObjects[StringProto] = memoryManager->allocObject<StringPrototype>(ic->d(), /*init =*/ false);
|
2018-04-03 13:23:07 +00:00
|
|
|
classes[Class_String] = classes[Class_Empty]->changeVTable(QV4::String::staticVTable())->changePrototype(stringPrototype()->d());
|
|
|
|
Q_ASSERT(stringPrototype()->d() && classes[Class_String]->prototype);
|
|
|
|
|
|
|
|
jsObjects[SymbolProto] = memoryManager->allocate<SymbolPrototype>();
|
|
|
|
classes[Class_Symbol] = classes[EngineBase::Class_Empty]->changeVTable(QV4::Symbol::staticVTable())->changePrototype(symbolPrototype()->d());
|
|
|
|
|
2015-04-26 07:22:17 +00:00
|
|
|
jsStrings[String_Empty] = newIdentifier(QString());
|
|
|
|
jsStrings[String_undefined] = newIdentifier(QStringLiteral("undefined"));
|
|
|
|
jsStrings[String_null] = newIdentifier(QStringLiteral("null"));
|
|
|
|
jsStrings[String_true] = newIdentifier(QStringLiteral("true"));
|
|
|
|
jsStrings[String_false] = newIdentifier(QStringLiteral("false"));
|
|
|
|
jsStrings[String_boolean] = newIdentifier(QStringLiteral("boolean"));
|
|
|
|
jsStrings[String_number] = newIdentifier(QStringLiteral("number"));
|
|
|
|
jsStrings[String_string] = newIdentifier(QStringLiteral("string"));
|
2018-05-27 20:58:32 +00:00
|
|
|
jsStrings[String_default] = newIdentifier(QStringLiteral("default"));
|
2018-04-08 12:28:40 +00:00
|
|
|
jsStrings[String_symbol] = newIdentifier(QStringLiteral("symbol"));
|
2015-04-26 07:22:17 +00:00
|
|
|
jsStrings[String_object] = newIdentifier(QStringLiteral("object"));
|
|
|
|
jsStrings[String_function] = newIdentifier(QStringLiteral("function"));
|
|
|
|
jsStrings[String_length] = newIdentifier(QStringLiteral("length"));
|
|
|
|
jsStrings[String_prototype] = newIdentifier(QStringLiteral("prototype"));
|
|
|
|
jsStrings[String_constructor] = newIdentifier(QStringLiteral("constructor"));
|
|
|
|
jsStrings[String_arguments] = newIdentifier(QStringLiteral("arguments"));
|
|
|
|
jsStrings[String_caller] = newIdentifier(QStringLiteral("caller"));
|
|
|
|
jsStrings[String_callee] = newIdentifier(QStringLiteral("callee"));
|
|
|
|
jsStrings[String_this] = newIdentifier(QStringLiteral("this"));
|
|
|
|
jsStrings[String___proto__] = newIdentifier(QStringLiteral("__proto__"));
|
|
|
|
jsStrings[String_enumerable] = newIdentifier(QStringLiteral("enumerable"));
|
|
|
|
jsStrings[String_configurable] = newIdentifier(QStringLiteral("configurable"));
|
|
|
|
jsStrings[String_writable] = newIdentifier(QStringLiteral("writable"));
|
|
|
|
jsStrings[String_value] = newIdentifier(QStringLiteral("value"));
|
|
|
|
jsStrings[String_get] = newIdentifier(QStringLiteral("get"));
|
|
|
|
jsStrings[String_set] = newIdentifier(QStringLiteral("set"));
|
|
|
|
jsStrings[String_eval] = newIdentifier(QStringLiteral("eval"));
|
|
|
|
jsStrings[String_uintMax] = newIdentifier(QStringLiteral("4294967295"));
|
|
|
|
jsStrings[String_name] = newIdentifier(QStringLiteral("name"));
|
|
|
|
jsStrings[String_index] = newIdentifier(QStringLiteral("index"));
|
|
|
|
jsStrings[String_input] = newIdentifier(QStringLiteral("input"));
|
|
|
|
jsStrings[String_toString] = newIdentifier(QStringLiteral("toString"));
|
2018-08-14 17:54:31 +00:00
|
|
|
jsStrings[String_toLocaleString] = newIdentifier(QStringLiteral("toLocaleString"));
|
2015-04-26 07:22:17 +00:00
|
|
|
jsStrings[String_destroy] = newIdentifier(QStringLiteral("destroy"));
|
|
|
|
jsStrings[String_valueOf] = newIdentifier(QStringLiteral("valueOf"));
|
|
|
|
jsStrings[String_byteLength] = newIdentifier(QStringLiteral("byteLength"));
|
|
|
|
jsStrings[String_byteOffset] = newIdentifier(QStringLiteral("byteOffset"));
|
|
|
|
jsStrings[String_buffer] = newIdentifier(QStringLiteral("buffer"));
|
|
|
|
jsStrings[String_lastIndex] = newIdentifier(QStringLiteral("lastIndex"));
|
2018-05-11 20:23:56 +00:00
|
|
|
jsStrings[String_next] = newIdentifier(QStringLiteral("next"));
|
|
|
|
jsStrings[String_done] = newIdentifier(QStringLiteral("done"));
|
2018-05-14 12:12:33 +00:00
|
|
|
jsStrings[String_return] = newIdentifier(QStringLiteral("return"));
|
2018-05-31 14:06:34 +00:00
|
|
|
jsStrings[String_throw] = newIdentifier(QStringLiteral("throw"));
|
2018-08-08 11:55:17 +00:00
|
|
|
jsStrings[String_global] = newIdentifier(QStringLiteral("global"));
|
|
|
|
jsStrings[String_ignoreCase] = newIdentifier(QStringLiteral("ignoreCase"));
|
|
|
|
jsStrings[String_multiline] = newIdentifier(QStringLiteral("multiline"));
|
|
|
|
jsStrings[String_unicode] = newIdentifier(QStringLiteral("unicode"));
|
|
|
|
jsStrings[String_sticky] = newIdentifier(QStringLiteral("sticky"));
|
2018-08-10 07:21:11 +00:00
|
|
|
jsStrings[String_source] = newIdentifier(QStringLiteral("source"));
|
|
|
|
jsStrings[String_flags] = newIdentifier(QStringLiteral("flags"));
|
2012-11-17 20:54:26 +00:00
|
|
|
|
2018-04-08 14:43:10 +00:00
|
|
|
jsSymbols[Symbol_hasInstance] = Symbol::create(this, QStringLiteral("@Symbol.hasInstance"));
|
|
|
|
jsSymbols[Symbol_isConcatSpreadable] = Symbol::create(this, QStringLiteral("@Symbol.isConcatSpreadable"));
|
|
|
|
jsSymbols[Symbol_iterator] = Symbol::create(this, QStringLiteral("@Symbol.iterator"));
|
|
|
|
jsSymbols[Symbol_match] = Symbol::create(this, QStringLiteral("@Symbol.match"));
|
|
|
|
jsSymbols[Symbol_replace] = Symbol::create(this, QStringLiteral("@Symbol.replace"));
|
|
|
|
jsSymbols[Symbol_search] = Symbol::create(this, QStringLiteral("@Symbol.search"));
|
|
|
|
jsSymbols[Symbol_species] = Symbol::create(this, QStringLiteral("@Symbol.species"));
|
|
|
|
jsSymbols[Symbol_split] = Symbol::create(this, QStringLiteral("@Symbol.split"));
|
|
|
|
jsSymbols[Symbol_toPrimitive] = Symbol::create(this, QStringLiteral("@Symbol.toPrimitive"));
|
|
|
|
jsSymbols[Symbol_toStringTag] = Symbol::create(this, QStringLiteral("@Symbol.toStringTag"));
|
|
|
|
jsSymbols[Symbol_unscopables] = Symbol::create(this, QStringLiteral("@Symbol.unscopables"));
|
2018-06-17 08:57:21 +00:00
|
|
|
jsSymbols[Symbol_revokableProxy] = Symbol::create(this, QStringLiteral("@Proxy.revokableProxy"));
|
2018-04-08 14:43:10 +00:00
|
|
|
|
2017-05-15 07:56:05 +00:00
|
|
|
ic = newInternalClass(ArrayPrototype::staticVTable(), objectPrototype());
|
2018-01-05 14:30:23 +00:00
|
|
|
Q_ASSERT(ic->d()->prototype);
|
2018-06-23 21:07:23 +00:00
|
|
|
ic = ic->addMember(id_length()->propertyKey(), Attr_NotConfigurable|Attr_NotEnumerable);
|
2018-01-05 14:30:23 +00:00
|
|
|
Q_ASSERT(ic->d()->prototype);
|
|
|
|
jsObjects[ArrayProto] = memoryManager->allocObject<ArrayPrototype>(ic->d());
|
2018-04-04 07:31:10 +00:00
|
|
|
classes[Class_ArrayObject] = ic->changePrototype(arrayPrototype()->d());
|
2018-04-10 20:45:27 +00:00
|
|
|
jsObjects[PropertyListProto] = memoryManager->allocate<PropertyListPrototype>();
|
2013-08-29 12:31:32 +00:00
|
|
|
|
2018-01-05 14:30:23 +00:00
|
|
|
Scoped<InternalClass> argsClass(scope);
|
|
|
|
argsClass = newInternalClass(ArgumentsObject::staticVTable(), objectPrototype());
|
2018-06-23 21:07:23 +00:00
|
|
|
argsClass = argsClass->addMember(id_length()->propertyKey(), Attr_NotEnumerable);
|
|
|
|
argsClass = argsClass->addMember(symbol_iterator()->propertyKey(), Attr_Data|Attr_NotEnumerable);
|
|
|
|
classes[Class_ArgumentsObject] = argsClass->addMember(id_callee()->propertyKey(), Attr_Data|Attr_NotEnumerable);
|
2017-11-06 14:59:01 +00:00
|
|
|
argsClass = newInternalClass(StrictArgumentsObject::staticVTable(), objectPrototype());
|
2018-06-23 21:07:23 +00:00
|
|
|
argsClass = argsClass->addMember(id_length()->propertyKey(), Attr_NotEnumerable);
|
|
|
|
argsClass = argsClass->addMember(symbol_iterator()->propertyKey(), Attr_Data|Attr_NotEnumerable);
|
|
|
|
classes[Class_StrictArgumentsObject] = argsClass->addMember(id_callee()->propertyKey(), Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
|
2013-11-21 12:15:46 +00:00
|
|
|
|
2015-03-13 16:21:18 +00:00
|
|
|
*static_cast<Value *>(globalObject) = newObject();
|
2015-08-07 11:56:31 +00:00
|
|
|
Q_ASSERT(globalObject->d()->vtable());
|
2013-03-14 13:03:04 +00:00
|
|
|
initRootContext();
|
2013-03-04 10:48:49 +00:00
|
|
|
|
2017-05-15 07:56:05 +00:00
|
|
|
ic = newInternalClass(QV4::StringObject::staticVTable(), objectPrototype());
|
2018-06-23 21:07:23 +00:00
|
|
|
ic = ic->addMember(id_length()->propertyKey(), Attr_ReadOnly);
|
2018-04-04 07:31:10 +00:00
|
|
|
classes[Class_StringObject] = ic->changePrototype(stringPrototype()->d());
|
2018-09-23 09:15:52 +00:00
|
|
|
Q_ASSERT(classes[Class_StringObject]->verifyIndex(id_length()->propertyKey(), Heap::StringObject::LengthPropertyIndex));
|
2017-05-15 07:56:05 +00:00
|
|
|
|
2018-04-08 14:43:10 +00:00
|
|
|
classes[Class_SymbolObject] = newInternalClass(QV4::SymbolObject::staticVTable(), symbolPrototype());
|
|
|
|
|
2018-04-10 20:45:27 +00:00
|
|
|
jsObjects[NumberProto] = memoryManager->allocate<NumberPrototype>();
|
|
|
|
jsObjects[BooleanProto] = memoryManager->allocate<BooleanPrototype>();
|
|
|
|
jsObjects[DateProto] = memoryManager->allocate<DatePrototype>();
|
2013-08-29 19:23:04 +00:00
|
|
|
|
2018-11-02 09:43:07 +00:00
|
|
|
#if defined(QT_NO_DEBUG) && !defined(QT_FORCE_ASSERTS)
|
2018-09-23 13:46:25 +00:00
|
|
|
InternalClassEntry *index = nullptr;
|
|
|
|
#else
|
|
|
|
InternalClassEntry _index;
|
|
|
|
auto *index = &_index;
|
|
|
|
#endif
|
2017-05-15 07:56:05 +00:00
|
|
|
ic = newInternalClass(QV4::FunctionPrototype::staticVTable(), objectPrototype());
|
2018-09-16 17:44:45 +00:00
|
|
|
auto addProtoHasInstance = [&] {
|
|
|
|
// Add an invalid prototype slot, so that all function objects have the same layout
|
|
|
|
// This helps speed up instanceof operations and other things where we need to query
|
|
|
|
// prototype property (as we always know it's location)
|
|
|
|
ic = ic->addMember(id_prototype()->propertyKey(), Attr_Invalid, index);
|
|
|
|
Q_ASSERT(index->index == Heap::FunctionObject::Index_Prototype);
|
|
|
|
// add an invalid @hasInstance slot, so that we can quickly track whether the
|
|
|
|
// hasInstance method has been reimplemented. This is required for a fast
|
|
|
|
// instanceof implementation
|
|
|
|
ic = ic->addMember(symbol_hasInstance()->propertyKey(), Attr_Invalid, index);
|
|
|
|
Q_ASSERT(index->index == Heap::FunctionObject::Index_HasInstance);
|
|
|
|
};
|
|
|
|
addProtoHasInstance();
|
2018-01-05 14:30:23 +00:00
|
|
|
jsObjects[FunctionProto] = memoryManager->allocObject<FunctionPrototype>(ic->d());
|
2017-05-15 07:56:05 +00:00
|
|
|
ic = newInternalClass(FunctionObject::staticVTable(), functionPrototype());
|
2018-09-16 17:44:45 +00:00
|
|
|
addProtoHasInstance();
|
2018-01-05 14:30:23 +00:00
|
|
|
classes[Class_FunctionObject] = ic->d();
|
2018-09-23 13:46:25 +00:00
|
|
|
ic = ic->addMember(id_name()->propertyKey(), Attr_ReadOnly, index);
|
|
|
|
Q_ASSERT(index->index == Heap::ArrowFunction::Index_Name);
|
|
|
|
ic = ic->addMember(id_length()->propertyKey(), Attr_ReadOnly_ButConfigurable, index);
|
|
|
|
Q_ASSERT(index->index == Heap::ArrowFunction::Index_Length);
|
2018-09-18 15:01:59 +00:00
|
|
|
classes[Class_ArrowFunction] = ic->changeVTable(ArrowFunction::staticVTable());
|
2018-06-22 10:32:13 +00:00
|
|
|
ic = ic->changeVTable(MemberFunction::staticVTable());
|
|
|
|
classes[Class_MemberFunction] = ic->d();
|
|
|
|
ic = ic->changeVTable(GeneratorFunction::staticVTable());
|
2018-04-27 09:41:13 +00:00
|
|
|
classes[Class_GeneratorFunction] = ic->d();
|
2018-07-03 09:07:15 +00:00
|
|
|
ic = ic->changeVTable(MemberGeneratorFunction::staticVTable());
|
|
|
|
classes[Class_MemberGeneratorFunction] = ic->d();
|
2018-09-19 13:27:41 +00:00
|
|
|
|
|
|
|
ic = ic->changeMember(id_prototype()->propertyKey(), Attr_NotConfigurable|Attr_NotEnumerable);
|
|
|
|
ic = ic->changeVTable(ScriptFunction::staticVTable());
|
|
|
|
classes[Class_ScriptFunction] = ic->d();
|
|
|
|
ic = ic->changeVTable(ConstructorFunction::staticVTable());
|
|
|
|
classes[Class_ConstructorFunction] = ic->d();
|
|
|
|
|
2018-09-23 13:46:25 +00:00
|
|
|
classes[Class_ObjectProto] = classes[Class_Object]->addMember(id_constructor()->propertyKey(), Attr_NotEnumerable, index);
|
|
|
|
Q_ASSERT(index->index == Heap::FunctionObject::Index_ProtoConstructor);
|
2013-08-29 19:23:04 +00:00
|
|
|
|
2018-04-27 09:41:13 +00:00
|
|
|
jsObjects[GeneratorProto] = memoryManager->allocObject<GeneratorPrototype>(classes[Class_Object]);
|
|
|
|
classes[Class_GeneratorObject] = newInternalClass(QV4::GeneratorObject::staticVTable(), generatorPrototype());
|
|
|
|
|
2015-08-27 12:38:24 +00:00
|
|
|
ScopedString str(scope);
|
2018-04-04 07:31:10 +00:00
|
|
|
classes[Class_RegExp] = classes[Class_Empty]->changeVTable(QV4::RegExp::staticVTable());
|
2017-05-15 07:56:05 +00:00
|
|
|
ic = newInternalClass(QV4::RegExpObject::staticVTable(), objectPrototype());
|
2018-09-23 13:46:25 +00:00
|
|
|
ic = ic->addMember(id_lastIndex()->propertyKey(), Attr_NotEnumerable|Attr_NotConfigurable, index);
|
|
|
|
Q_ASSERT(index->index == RegExpObject::Index_LastIndex);
|
2018-08-08 19:33:18 +00:00
|
|
|
jsObjects[RegExpProto] = memoryManager->allocObject<RegExpPrototype>(classes[Class_Object]);
|
2018-04-04 07:31:10 +00:00
|
|
|
classes[Class_RegExpObject] = ic->changePrototype(regExpPrototype()->d());
|
2015-08-27 12:38:24 +00:00
|
|
|
|
2018-09-23 13:46:25 +00:00
|
|
|
ic = classes[Class_ArrayObject]->addMember(id_index()->propertyKey(), Attr_Data, index);
|
|
|
|
Q_ASSERT(index->index == RegExpObject::Index_ArrayIndex);
|
|
|
|
classes[Class_RegExpExecArray] = ic->addMember(id_input()->propertyKey(), Attr_Data, index);
|
|
|
|
Q_ASSERT(index->index == RegExpObject::Index_ArrayInput);
|
2013-08-29 19:23:04 +00:00
|
|
|
|
2018-02-21 09:41:54 +00:00
|
|
|
ic = newInternalClass(ErrorObject::staticVTable(), nullptr);
|
2018-09-23 13:46:25 +00:00
|
|
|
ic = ic->addMember((str = newIdentifier(QStringLiteral("stack")))->propertyKey(), Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable, index);
|
|
|
|
Q_ASSERT(index->index == ErrorObject::Index_Stack);
|
|
|
|
Q_ASSERT(index->setterIndex == ErrorObject::Index_StackSetter);
|
|
|
|
ic = ic->addMember((str = newIdentifier(QStringLiteral("fileName")))->propertyKey(), Attr_Data|Attr_NotEnumerable, index);
|
|
|
|
Q_ASSERT(index->index == ErrorObject::Index_FileName);
|
|
|
|
ic = ic->addMember((str = newIdentifier(QStringLiteral("lineNumber")))->propertyKey(), Attr_Data|Attr_NotEnumerable, index);
|
2018-01-05 14:30:23 +00:00
|
|
|
classes[Class_ErrorObject] = ic->d();
|
2018-09-23 13:46:25 +00:00
|
|
|
Q_ASSERT(index->index == ErrorObject::Index_LineNumber);
|
|
|
|
classes[Class_ErrorObjectWithMessage] = ic->addMember((str = newIdentifier(QStringLiteral("message")))->propertyKey(), Attr_Data|Attr_NotEnumerable, index);
|
|
|
|
Q_ASSERT(index->index == ErrorObject::Index_Message);
|
2018-08-01 19:39:35 +00:00
|
|
|
ic = newInternalClass(Object::staticVTable(), objectPrototype());
|
2018-09-23 13:46:25 +00:00
|
|
|
ic = ic->addMember(id_constructor()->propertyKey(), Attr_Data|Attr_NotEnumerable, index);
|
|
|
|
Q_ASSERT(index->index == ErrorPrototype::Index_Constructor);
|
|
|
|
ic = ic->addMember((str = newIdentifier(QStringLiteral("message")))->propertyKey(), Attr_Data|Attr_NotEnumerable, index);
|
|
|
|
Q_ASSERT(index->index == ErrorPrototype::Index_Message);
|
|
|
|
classes[Class_ErrorProto] = ic->addMember(id_name()->propertyKey(), Attr_Data|Attr_NotEnumerable, index);
|
|
|
|
Q_ASSERT(index->index == ErrorPrototype::Index_Name);
|
2015-08-27 20:47:23 +00:00
|
|
|
|
2018-06-17 08:57:21 +00:00
|
|
|
classes[Class_ProxyObject] = classes[Class_Empty]->changeVTable(ProxyObject::staticVTable());
|
2018-08-23 14:06:26 +00:00
|
|
|
classes[Class_ProxyFunctionObject] = classes[Class_Empty]->changeVTable(ProxyFunctionObject::staticVTable());
|
2018-06-17 08:57:21 +00:00
|
|
|
|
2018-04-26 09:48:04 +00:00
|
|
|
jsObjects[GetStack_Function] = FunctionObject::createBuiltinFunction(this, str = newIdentifier(QStringLiteral("stack")), ErrorObject::method_get_stack, 0);
|
2015-08-27 20:47:23 +00:00
|
|
|
|
2018-04-04 07:31:10 +00:00
|
|
|
jsObjects[ErrorProto] = memoryManager->allocObject<ErrorPrototype>(classes[Class_ErrorProto]);
|
2018-01-05 14:30:23 +00:00
|
|
|
ic = classes[Class_ErrorProto]->changePrototype(errorPrototype()->d());
|
|
|
|
jsObjects[EvalErrorProto] = memoryManager->allocObject<EvalErrorPrototype>(ic->d());
|
|
|
|
jsObjects[RangeErrorProto] = memoryManager->allocObject<RangeErrorPrototype>(ic->d());
|
|
|
|
jsObjects[ReferenceErrorProto] = memoryManager->allocObject<ReferenceErrorPrototype>(ic->d());
|
|
|
|
jsObjects[SyntaxErrorProto] = memoryManager->allocObject<SyntaxErrorPrototype>(ic->d());
|
|
|
|
jsObjects[TypeErrorProto] = memoryManager->allocObject<TypeErrorPrototype>(ic->d());
|
|
|
|
jsObjects[URIErrorProto] = memoryManager->allocObject<URIErrorPrototype>(ic->d());
|
2015-01-10 19:35:18 +00:00
|
|
|
|
2018-04-10 20:45:27 +00:00
|
|
|
jsObjects[VariantProto] = memoryManager->allocate<VariantPrototype>();
|
2018-06-19 11:28:26 +00:00
|
|
|
Q_ASSERT(variantPrototype()->getPrototypeOf() == objectPrototype()->d());
|
2014-11-24 14:38:41 +00:00
|
|
|
|
2017-12-18 15:20:11 +00:00
|
|
|
#if QT_CONFIG(qml_sequence_object)
|
2017-05-15 07:56:05 +00:00
|
|
|
ic = newInternalClass(SequencePrototype::staticVTable(), SequencePrototype::defaultPrototype(this));
|
2018-01-05 14:30:23 +00:00
|
|
|
jsObjects[SequenceProto] = ScopedValue(scope, memoryManager->allocObject<SequencePrototype>(ic->d()));
|
2017-12-18 15:20:11 +00:00
|
|
|
#endif
|
2014-06-13 12:30:03 +00:00
|
|
|
|
2015-08-24 14:47:48 +00:00
|
|
|
ExecutionContext *global = rootContext();
|
2018-04-03 13:23:07 +00:00
|
|
|
|
2018-04-10 20:45:27 +00:00
|
|
|
jsObjects[Object_Ctor] = memoryManager->allocate<ObjectCtor>(global);
|
|
|
|
jsObjects[String_Ctor] = memoryManager->allocate<StringCtor>(global);
|
2018-04-03 13:23:07 +00:00
|
|
|
jsObjects[Symbol_Ctor] = memoryManager->allocate<SymbolCtor>(global);
|
2018-04-10 20:45:27 +00:00
|
|
|
jsObjects[Number_Ctor] = memoryManager->allocate<NumberCtor>(global);
|
|
|
|
jsObjects[Boolean_Ctor] = memoryManager->allocate<BooleanCtor>(global);
|
|
|
|
jsObjects[Array_Ctor] = memoryManager->allocate<ArrayCtor>(global);
|
|
|
|
jsObjects[Function_Ctor] = memoryManager->allocate<FunctionCtor>(global);
|
2018-04-27 09:41:13 +00:00
|
|
|
jsObjects[GeneratorFunction_Ctor] = memoryManager->allocate<GeneratorFunctionCtor>(global);
|
2018-04-10 20:45:27 +00:00
|
|
|
jsObjects[Date_Ctor] = memoryManager->allocate<DateCtor>(global);
|
|
|
|
jsObjects[RegExp_Ctor] = memoryManager->allocate<RegExpCtor>(global);
|
|
|
|
jsObjects[Error_Ctor] = memoryManager->allocate<ErrorCtor>(global);
|
|
|
|
jsObjects[EvalError_Ctor] = memoryManager->allocate<EvalErrorCtor>(global);
|
|
|
|
jsObjects[RangeError_Ctor] = memoryManager->allocate<RangeErrorCtor>(global);
|
|
|
|
jsObjects[ReferenceError_Ctor] = memoryManager->allocate<ReferenceErrorCtor>(global);
|
|
|
|
jsObjects[SyntaxError_Ctor] = memoryManager->allocate<SyntaxErrorCtor>(global);
|
|
|
|
jsObjects[TypeError_Ctor] = memoryManager->allocate<TypeErrorCtor>(global);
|
|
|
|
jsObjects[URIError_Ctor] = memoryManager->allocate<URIErrorCtor>(global);
|
Add Array Iterator objects from ES6 (22.1.5)
And implement / expose them via:
22.1.3.4 - Array.prototype.entries()
22.1.3.13 - Array.prototype.keys()
22.1.3.29 - Array.prototype.values()
22.1.3.31 - Array.prototype[Symbol.iterator]
Most tests for Array iterators now pass.
At the same time, expose them on TypedArray's prototype:
- 22.2.3.15 %TypedArray%.prototype.keys
- 22.2.3.29 %TypedArray%.prototype.values
- 22.2.3.6 %TypedArray%.prototype.entries
- 22.2.3.31 %TypedArray%.prototype[Symbol.iterator]
For TypedArray, test coverage improves a tiny bit (3 passing tests), but the
vast majority fail as it seems like the object structure for TypedArray is
currently incomplete as far as ES6 expects.
It seems that ES6 expects the object structure to be:
* %TypedArray% (inherits FunctionObject)
(this is the TypedArray intrinsic object, and responsible for initializing
the TypedArray instances)
* All the TypedArray ctors (e.g. UInt8Array)
These inherit %TypedArray%, and make a super call to it to do their work
* %TypedArrayPrototype% (inherits Object)
(this is the initial prototype for %TypedArray%)
* All the ctors have their own separate instance of this
* The instances also make use it
So, for instance, a lot of the tests attempt to access the prototype like:
var proto = Object.getPrototypeOf(Int8Array)
var keys = proto.prototype.keys
As ES6 expects Int8Array.prototype to be %TypedArray% (22.2.5), this expands to:
Object.getPrototypeOf(%TypedArray%)
which it expects to be %TypedArrayPrototype%.
But since we have no intrinsic object, and the ctors inherit
FunctionObject, we instead return the wrong prototype into 'var proto'.
Change-Id: I5e1a95a0420ecb70a0e35a5df3f65557510c5925
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
2017-02-09 18:58:50 +00:00
|
|
|
jsObjects[IteratorProto] = memoryManager->allocate<IteratorPrototype>();
|
2019-03-25 14:43:13 +00:00
|
|
|
|
|
|
|
ic = newInternalClass(ForInIteratorPrototype::staticVTable(), iteratorPrototype());
|
|
|
|
jsObjects[ForInIteratorProto] = memoryManager->allocObject<ForInIteratorPrototype>(ic);
|
|
|
|
ic = newInternalClass(SetIteratorPrototype::staticVTable(), iteratorPrototype());
|
|
|
|
jsObjects[MapIteratorProto] = memoryManager->allocObject<MapIteratorPrototype>(ic);
|
|
|
|
ic = newInternalClass(SetIteratorPrototype::staticVTable(), iteratorPrototype());
|
|
|
|
jsObjects[SetIteratorProto] = memoryManager->allocObject<SetIteratorPrototype>(ic);
|
|
|
|
ic = newInternalClass(ArrayIteratorPrototype::staticVTable(), iteratorPrototype());
|
|
|
|
jsObjects[ArrayIteratorProto] = memoryManager->allocObject<ArrayIteratorPrototype>(ic);
|
|
|
|
ic = newInternalClass(StringIteratorPrototype::staticVTable(), iteratorPrototype());
|
|
|
|
jsObjects[StringIteratorProto] = memoryManager->allocObject<StringIteratorPrototype>(ic);
|
2015-03-25 20:06:18 +00:00
|
|
|
|
2018-05-14 21:07:45 +00:00
|
|
|
str = newString(QStringLiteral("get [Symbol.species]"));
|
|
|
|
jsObjects[GetSymbolSpecies] = FunctionObject::createBuiltinFunction(this, str, ArrayPrototype::method_get_species, 0);
|
|
|
|
|
2015-03-25 20:06:18 +00:00
|
|
|
static_cast<ObjectPrototype *>(objectPrototype())->init(this, objectCtor());
|
|
|
|
static_cast<StringPrototype *>(stringPrototype())->init(this, stringCtor());
|
2018-04-03 13:23:07 +00:00
|
|
|
static_cast<SymbolPrototype *>(symbolPrototype())->init(this, symbolCtor());
|
2015-03-25 20:06:18 +00:00
|
|
|
static_cast<NumberPrototype *>(numberPrototype())->init(this, numberCtor());
|
|
|
|
static_cast<BooleanPrototype *>(booleanPrototype())->init(this, booleanCtor());
|
|
|
|
static_cast<ArrayPrototype *>(arrayPrototype())->init(this, arrayCtor());
|
2017-02-20 12:27:22 +00:00
|
|
|
static_cast<PropertyListPrototype *>(propertyListPrototype())->init(this);
|
2015-03-25 20:06:18 +00:00
|
|
|
static_cast<DatePrototype *>(datePrototype())->init(this, dateCtor());
|
|
|
|
static_cast<FunctionPrototype *>(functionPrototype())->init(this, functionCtor());
|
2018-04-27 09:41:13 +00:00
|
|
|
static_cast<GeneratorPrototype *>(generatorPrototype())->init(this, generatorFunctionCtor());
|
2015-03-25 20:06:18 +00:00
|
|
|
static_cast<RegExpPrototype *>(regExpPrototype())->init(this, regExpCtor());
|
|
|
|
static_cast<ErrorPrototype *>(errorPrototype())->init(this, errorCtor());
|
|
|
|
static_cast<EvalErrorPrototype *>(evalErrorPrototype())->init(this, evalErrorCtor());
|
|
|
|
static_cast<RangeErrorPrototype *>(rangeErrorPrototype())->init(this, rangeErrorCtor());
|
|
|
|
static_cast<ReferenceErrorPrototype *>(referenceErrorPrototype())->init(this, referenceErrorCtor());
|
|
|
|
static_cast<SyntaxErrorPrototype *>(syntaxErrorPrototype())->init(this, syntaxErrorCtor());
|
|
|
|
static_cast<TypeErrorPrototype *>(typeErrorPrototype())->init(this, typeErrorCtor());
|
|
|
|
static_cast<URIErrorPrototype *>(uRIErrorPrototype())->init(this, uRIErrorCtor());
|
Add Array Iterator objects from ES6 (22.1.5)
And implement / expose them via:
22.1.3.4 - Array.prototype.entries()
22.1.3.13 - Array.prototype.keys()
22.1.3.29 - Array.prototype.values()
22.1.3.31 - Array.prototype[Symbol.iterator]
Most tests for Array iterators now pass.
At the same time, expose them on TypedArray's prototype:
- 22.2.3.15 %TypedArray%.prototype.keys
- 22.2.3.29 %TypedArray%.prototype.values
- 22.2.3.6 %TypedArray%.prototype.entries
- 22.2.3.31 %TypedArray%.prototype[Symbol.iterator]
For TypedArray, test coverage improves a tiny bit (3 passing tests), but the
vast majority fail as it seems like the object structure for TypedArray is
currently incomplete as far as ES6 expects.
It seems that ES6 expects the object structure to be:
* %TypedArray% (inherits FunctionObject)
(this is the TypedArray intrinsic object, and responsible for initializing
the TypedArray instances)
* All the TypedArray ctors (e.g. UInt8Array)
These inherit %TypedArray%, and make a super call to it to do their work
* %TypedArrayPrototype% (inherits Object)
(this is the initial prototype for %TypedArray%)
* All the ctors have their own separate instance of this
* The instances also make use it
So, for instance, a lot of the tests attempt to access the prototype like:
var proto = Object.getPrototypeOf(Int8Array)
var keys = proto.prototype.keys
As ES6 expects Int8Array.prototype to be %TypedArray% (22.2.5), this expands to:
Object.getPrototypeOf(%TypedArray%)
which it expects to be %TypedArrayPrototype%.
But since we have no intrinsic object, and the ctors inherit
FunctionObject, we instead return the wrong prototype into 'var proto'.
Change-Id: I5e1a95a0420ecb70a0e35a5df3f65557510c5925
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
2017-02-09 18:58:50 +00:00
|
|
|
|
|
|
|
static_cast<IteratorPrototype *>(iteratorPrototype())->init(this);
|
2018-05-03 19:50:18 +00:00
|
|
|
static_cast<ForInIteratorPrototype *>(forInIteratorPrototype())->init(this);
|
2018-05-29 20:41:34 +00:00
|
|
|
static_cast<MapIteratorPrototype *>(mapIteratorPrototype())->init(this);
|
2018-05-27 13:04:23 +00:00
|
|
|
static_cast<SetIteratorPrototype *>(setIteratorPrototype())->init(this);
|
Add Array Iterator objects from ES6 (22.1.5)
And implement / expose them via:
22.1.3.4 - Array.prototype.entries()
22.1.3.13 - Array.prototype.keys()
22.1.3.29 - Array.prototype.values()
22.1.3.31 - Array.prototype[Symbol.iterator]
Most tests for Array iterators now pass.
At the same time, expose them on TypedArray's prototype:
- 22.2.3.15 %TypedArray%.prototype.keys
- 22.2.3.29 %TypedArray%.prototype.values
- 22.2.3.6 %TypedArray%.prototype.entries
- 22.2.3.31 %TypedArray%.prototype[Symbol.iterator]
For TypedArray, test coverage improves a tiny bit (3 passing tests), but the
vast majority fail as it seems like the object structure for TypedArray is
currently incomplete as far as ES6 expects.
It seems that ES6 expects the object structure to be:
* %TypedArray% (inherits FunctionObject)
(this is the TypedArray intrinsic object, and responsible for initializing
the TypedArray instances)
* All the TypedArray ctors (e.g. UInt8Array)
These inherit %TypedArray%, and make a super call to it to do their work
* %TypedArrayPrototype% (inherits Object)
(this is the initial prototype for %TypedArray%)
* All the ctors have their own separate instance of this
* The instances also make use it
So, for instance, a lot of the tests attempt to access the prototype like:
var proto = Object.getPrototypeOf(Int8Array)
var keys = proto.prototype.keys
As ES6 expects Int8Array.prototype to be %TypedArray% (22.2.5), this expands to:
Object.getPrototypeOf(%TypedArray%)
which it expects to be %TypedArrayPrototype%.
But since we have no intrinsic object, and the ctors inherit
FunctionObject, we instead return the wrong prototype into 'var proto'.
Change-Id: I5e1a95a0420ecb70a0e35a5df3f65557510c5925
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
2017-02-09 18:58:50 +00:00
|
|
|
static_cast<ArrayIteratorPrototype *>(arrayIteratorPrototype())->init(this);
|
2018-04-26 11:12:38 +00:00
|
|
|
static_cast<StringIteratorPrototype *>(stringIteratorPrototype())->init(this);
|
|
|
|
|
2015-03-25 13:40:35 +00:00
|
|
|
static_cast<VariantPrototype *>(variantPrototype())->init();
|
2013-05-14 00:01:04 +00:00
|
|
|
|
2017-12-18 15:20:11 +00:00
|
|
|
#if QT_CONFIG(qml_sequence_object)
|
|
|
|
sequencePrototype()->cast<SequencePrototype>()->init();
|
|
|
|
#endif
|
2014-09-10 12:50:28 +00:00
|
|
|
|
2018-08-26 13:07:50 +00:00
|
|
|
jsObjects[WeakMap_Ctor] = memoryManager->allocate<WeakMapCtor>(global);
|
|
|
|
jsObjects[WeakMapProto] = memoryManager->allocate<WeakMapPrototype>();
|
|
|
|
static_cast<WeakMapPrototype *>(weakMapPrototype())->init(this, weakMapCtor());
|
|
|
|
|
2018-05-29 20:41:34 +00:00
|
|
|
jsObjects[Map_Ctor] = memoryManager->allocate<MapCtor>(global);
|
|
|
|
jsObjects[MapProto] = memoryManager->allocate<MapPrototype>();
|
|
|
|
static_cast<MapPrototype *>(mapPrototype())->init(this, mapCtor());
|
|
|
|
|
2018-08-26 15:50:44 +00:00
|
|
|
jsObjects[WeakSet_Ctor] = memoryManager->allocate<WeakSetCtor>(global);
|
|
|
|
jsObjects[WeakSetProto] = memoryManager->allocate<WeakSetPrototype>();
|
|
|
|
static_cast<WeakSetPrototype *>(weakSetPrototype())->init(this, weakSetCtor());
|
|
|
|
|
2018-05-27 13:04:23 +00:00
|
|
|
jsObjects[Set_Ctor] = memoryManager->allocate<SetCtor>(global);
|
|
|
|
jsObjects[SetProto] = memoryManager->allocate<SetPrototype>();
|
|
|
|
static_cast<SetPrototype *>(setPrototype())->init(this, setCtor());
|
|
|
|
|
2015-07-16 16:35:55 +00:00
|
|
|
//
|
|
|
|
// promises
|
|
|
|
//
|
|
|
|
|
|
|
|
jsObjects[Promise_Ctor] = memoryManager->allocate<PromiseCtor>(global);
|
|
|
|
jsObjects[PromiseProto] = memoryManager->allocate<PromisePrototype>();
|
|
|
|
static_cast<PromisePrototype *>(promisePrototype())->init(this, promiseCtor());
|
|
|
|
|
2014-09-10 12:50:28 +00:00
|
|
|
// typed arrays
|
|
|
|
|
2018-08-24 10:03:12 +00:00
|
|
|
jsObjects[SharedArrayBuffer_Ctor] = memoryManager->allocate<SharedArrayBufferCtor>(global);
|
|
|
|
jsObjects[SharedArrayBufferProto] = memoryManager->allocate<SharedArrayBufferPrototype>();
|
|
|
|
static_cast<SharedArrayBufferPrototype *>(sharedArrayBufferPrototype())->init(this, sharedArrayBufferCtor());
|
|
|
|
|
2018-04-10 20:45:27 +00:00
|
|
|
jsObjects[ArrayBuffer_Ctor] = memoryManager->allocate<ArrayBufferCtor>(global);
|
|
|
|
jsObjects[ArrayBufferProto] = memoryManager->allocate<ArrayBufferPrototype>();
|
2015-03-25 20:06:18 +00:00
|
|
|
static_cast<ArrayBufferPrototype *>(arrayBufferPrototype())->init(this, arrayBufferCtor());
|
2014-09-10 12:50:28 +00:00
|
|
|
|
2018-04-10 20:45:27 +00:00
|
|
|
jsObjects[DataView_Ctor] = memoryManager->allocate<DataViewCtor>(global);
|
|
|
|
jsObjects[DataViewProto] = memoryManager->allocate<DataViewPrototype>();
|
2015-03-25 20:06:18 +00:00
|
|
|
static_cast<DataViewPrototype *>(dataViewPrototype())->init(this, dataViewCtor());
|
2018-02-21 09:41:54 +00:00
|
|
|
jsObjects[ValueTypeProto] = (Heap::Base *) nullptr;
|
|
|
|
jsObjects[SignalHandlerProto] = (Heap::Base *) nullptr;
|
2014-09-10 14:39:23 +00:00
|
|
|
|
2018-05-23 21:04:49 +00:00
|
|
|
jsObjects[IntrinsicTypedArray_Ctor] = memoryManager->allocate<IntrinsicTypedArrayCtor>(global);
|
|
|
|
jsObjects[IntrinsicTypedArrayProto] = memoryManager->allocate<IntrinsicTypedArrayPrototype>();
|
|
|
|
static_cast<IntrinsicTypedArrayPrototype *>(intrinsicTypedArrayPrototype())
|
|
|
|
->init(this, static_cast<IntrinsicTypedArrayCtor *>(intrinsicTypedArrayCtor()));
|
|
|
|
|
2018-08-24 11:56:37 +00:00
|
|
|
for (int i = 0; i < NTypedArrayTypes; ++i) {
|
2018-04-10 20:45:27 +00:00
|
|
|
static_cast<Value &>(typedArrayCtors[i]) = memoryManager->allocate<TypedArrayCtor>(global, Heap::TypedArray::Type(i));
|
|
|
|
static_cast<Value &>(typedArrayPrototype[i]) = memoryManager->allocate<TypedArrayPrototype>(Heap::TypedArray::Type(i));
|
2015-02-13 12:39:20 +00:00
|
|
|
typedArrayPrototype[i].as<TypedArrayPrototype>()->init(this, static_cast<TypedArrayCtor *>(typedArrayCtors[i].as<Object>()));
|
2014-09-11 13:37:31 +00:00
|
|
|
}
|
|
|
|
|
2012-11-17 20:54:26 +00:00
|
|
|
//
|
|
|
|
// set up the global object
|
|
|
|
//
|
2017-07-04 14:07:50 +00:00
|
|
|
rootContext()->d()->activation.set(scope.engine, globalObject->d());
|
2015-08-07 11:56:31 +00:00
|
|
|
Q_ASSERT(globalObject->d()->vtable());
|
2015-03-13 16:21:18 +00:00
|
|
|
|
2015-03-25 20:06:18 +00:00
|
|
|
globalObject->defineDefaultProperty(QStringLiteral("Object"), *objectCtor());
|
|
|
|
globalObject->defineDefaultProperty(QStringLiteral("String"), *stringCtor());
|
2018-04-03 13:23:07 +00:00
|
|
|
globalObject->defineDefaultProperty(QStringLiteral("Symbol"), *symbolCtor());
|
2017-02-02 19:43:59 +00:00
|
|
|
FunctionObject *numberObject = numberCtor();
|
|
|
|
globalObject->defineDefaultProperty(QStringLiteral("Number"), *numberObject);
|
2015-03-25 20:06:18 +00:00
|
|
|
globalObject->defineDefaultProperty(QStringLiteral("Boolean"), *booleanCtor());
|
|
|
|
globalObject->defineDefaultProperty(QStringLiteral("Array"), *arrayCtor());
|
|
|
|
globalObject->defineDefaultProperty(QStringLiteral("Function"), *functionCtor());
|
|
|
|
globalObject->defineDefaultProperty(QStringLiteral("Date"), *dateCtor());
|
|
|
|
globalObject->defineDefaultProperty(QStringLiteral("RegExp"), *regExpCtor());
|
|
|
|
globalObject->defineDefaultProperty(QStringLiteral("Error"), *errorCtor());
|
|
|
|
globalObject->defineDefaultProperty(QStringLiteral("EvalError"), *evalErrorCtor());
|
|
|
|
globalObject->defineDefaultProperty(QStringLiteral("RangeError"), *rangeErrorCtor());
|
|
|
|
globalObject->defineDefaultProperty(QStringLiteral("ReferenceError"), *referenceErrorCtor());
|
|
|
|
globalObject->defineDefaultProperty(QStringLiteral("SyntaxError"), *syntaxErrorCtor());
|
|
|
|
globalObject->defineDefaultProperty(QStringLiteral("TypeError"), *typeErrorCtor());
|
|
|
|
globalObject->defineDefaultProperty(QStringLiteral("URIError"), *uRIErrorCtor());
|
2015-07-16 16:35:55 +00:00
|
|
|
globalObject->defineDefaultProperty(QStringLiteral("Promise"), *promiseCtor());
|
2015-03-25 20:06:18 +00:00
|
|
|
|
2018-08-24 10:03:12 +00:00
|
|
|
globalObject->defineDefaultProperty(QStringLiteral("SharedArrayBuffer"), *sharedArrayBufferCtor());
|
2015-03-25 20:06:18 +00:00
|
|
|
globalObject->defineDefaultProperty(QStringLiteral("ArrayBuffer"), *arrayBufferCtor());
|
|
|
|
globalObject->defineDefaultProperty(QStringLiteral("DataView"), *dataViewCtor());
|
2018-08-26 15:50:44 +00:00
|
|
|
globalObject->defineDefaultProperty(QStringLiteral("WeakSet"), *weakSetCtor());
|
2018-05-27 13:04:23 +00:00
|
|
|
globalObject->defineDefaultProperty(QStringLiteral("Set"), *setCtor());
|
2018-08-26 13:07:50 +00:00
|
|
|
globalObject->defineDefaultProperty(QStringLiteral("WeakMap"), *weakMapCtor());
|
2018-05-29 20:41:34 +00:00
|
|
|
globalObject->defineDefaultProperty(QStringLiteral("Map"), *mapCtor());
|
|
|
|
|
2018-08-24 11:56:37 +00:00
|
|
|
for (int i = 0; i < NTypedArrayTypes; ++i)
|
|
|
|
globalObject->defineDefaultProperty((str = typedArrayCtors[i].as<FunctionObject>()->name()), typedArrayCtors[i]);
|
2013-09-26 11:05:25 +00:00
|
|
|
ScopedObject o(scope);
|
2018-08-24 13:57:31 +00:00
|
|
|
globalObject->defineDefaultProperty(QStringLiteral("Atomics"), (o = memoryManager->allocate<Atomics>()));
|
2018-04-10 20:45:27 +00:00
|
|
|
globalObject->defineDefaultProperty(QStringLiteral("Math"), (o = memoryManager->allocate<MathObject>()));
|
|
|
|
globalObject->defineDefaultProperty(QStringLiteral("JSON"), (o = memoryManager->allocate<JsonObject>()));
|
2018-06-15 21:00:32 +00:00
|
|
|
globalObject->defineDefaultProperty(QStringLiteral("Reflect"), (o = memoryManager->allocate<Reflect>()));
|
2018-06-17 08:57:21 +00:00
|
|
|
globalObject->defineDefaultProperty(QStringLiteral("Proxy"), (o = memoryManager->allocate<Proxy>(rootContext())));
|
2013-09-18 10:31:55 +00:00
|
|
|
|
2018-09-11 09:07:32 +00:00
|
|
|
globalObject->defineReadonlyProperty(QStringLiteral("undefined"), Value::undefinedValue());
|
|
|
|
globalObject->defineReadonlyProperty(QStringLiteral("NaN"), Value::fromDouble(std::numeric_limits<double>::quiet_NaN()));
|
|
|
|
globalObject->defineReadonlyProperty(QStringLiteral("Infinity"), Value::fromDouble(Q_INFINITY));
|
2012-12-12 23:53:04 +00:00
|
|
|
|
2014-05-09 10:15:23 +00:00
|
|
|
|
2018-04-10 20:45:27 +00:00
|
|
|
jsObjects[Eval_Function] = memoryManager->allocate<EvalFunction>(global);
|
2015-03-25 20:31:16 +00:00
|
|
|
globalObject->defineDefaultProperty(QStringLiteral("eval"), *evalFunction());
|
2015-03-13 16:21:18 +00:00
|
|
|
|
2017-02-02 19:43:59 +00:00
|
|
|
// ES6: 20.1.2.12 & 20.1.2.13:
|
|
|
|
// parseInt and parseFloat must be the same FunctionObject on the global &
|
|
|
|
// Number object.
|
|
|
|
{
|
|
|
|
QString piString(QStringLiteral("parseInt"));
|
|
|
|
QString pfString(QStringLiteral("parseFloat"));
|
|
|
|
Scope scope(this);
|
|
|
|
ScopedString pi(scope, newIdentifier(piString));
|
|
|
|
ScopedString pf(scope, newIdentifier(pfString));
|
2018-04-26 09:48:04 +00:00
|
|
|
ScopedFunctionObject parseIntFn(scope, FunctionObject::createBuiltinFunction(this, pi, GlobalFunctions::method_parseInt, 2));
|
|
|
|
ScopedFunctionObject parseFloatFn(scope, FunctionObject::createBuiltinFunction(this, pf, GlobalFunctions::method_parseFloat, 1));
|
2017-02-02 19:43:59 +00:00
|
|
|
globalObject->defineDefaultProperty(piString, parseIntFn);
|
|
|
|
globalObject->defineDefaultProperty(pfString, parseFloatFn);
|
|
|
|
numberObject->defineDefaultProperty(piString, parseIntFn);
|
|
|
|
numberObject->defineDefaultProperty(pfString, parseFloatFn);
|
|
|
|
}
|
|
|
|
|
2015-03-13 16:21:18 +00:00
|
|
|
globalObject->defineDefaultProperty(QStringLiteral("isNaN"), GlobalFunctions::method_isNaN, 1);
|
|
|
|
globalObject->defineDefaultProperty(QStringLiteral("isFinite"), GlobalFunctions::method_isFinite, 1);
|
|
|
|
globalObject->defineDefaultProperty(QStringLiteral("decodeURI"), GlobalFunctions::method_decodeURI, 1);
|
|
|
|
globalObject->defineDefaultProperty(QStringLiteral("decodeURIComponent"), GlobalFunctions::method_decodeURIComponent, 1);
|
|
|
|
globalObject->defineDefaultProperty(QStringLiteral("encodeURI"), GlobalFunctions::method_encodeURI, 1);
|
|
|
|
globalObject->defineDefaultProperty(QStringLiteral("encodeURIComponent"), GlobalFunctions::method_encodeURIComponent, 1);
|
|
|
|
globalObject->defineDefaultProperty(QStringLiteral("escape"), GlobalFunctions::method_escape, 1);
|
|
|
|
globalObject->defineDefaultProperty(QStringLiteral("unescape"), GlobalFunctions::method_unescape, 1);
|
2013-09-18 07:30:45 +00:00
|
|
|
|
2018-05-15 21:29:33 +00:00
|
|
|
ScopedFunctionObject t(scope, memoryManager->allocate<FunctionObject>(rootContext(), nullptr, ::throwTypeError));
|
2018-09-11 09:07:32 +00:00
|
|
|
t->defineReadonlyProperty(id_length(), Value::fromInt32(0));
|
Clean up frozen(), sealed(), nonExtensible() and propertiesFrozen()
They all had some interesting bugs and duplicated each other:
a, propertiesFrozen() changed each property individually, creating a lot
of unnecessary intermediate classes. frozen() changed them all at once.
b, If a class happened to contain only properties that matched the
characteristics of being "sealed" or "frozen", sealed(), frozen() and
propertiesFrozen() would set the flags in place and return the same
class. This is bad because it violates the assumption that an
InternalClass is immutable and it breaks the recursive freezing
algorithm we rely on for the global object. It would stop freezing child
objects at any such class, even if the children were not frozen.
c, propertiesFrozen() did not set any of the flags even though it
effectively sealed and froze the class. Therefore, when requesting the
same class as frozen() it would iterate through all the properties
again.
d, frozen() implicitly also sealed the object and made it
non-extensible. sealed() also implicitly made it non-extensible. This is
impractical as we want to allow objects to be extensible even though all
their properties are frozen. Therefore we only set the flag that belongs
to each method now. We do know, however, that a frozen object is
implicitly sealed. Therefore we can short-circuit this transition.
Furthermore, we need to remove the assert in InternalClass::init() as
you can indeed use frozen objects as prototypes for others, but that
needs to be recorded in the original InternalClass via the isUsedAsProto
flag. In order to set this flag, we need to perform a transition and
therefore, derive from the old InternalClass.
The JavaScript isFrozen() method asks for an _implicitly_, "duck typed",
frozen state, which is different from what our "isFrozen" flag denotes.
Therefore we add a separate const method that just checks whether all
properties are frozen.
Task-number: QTBUG-76033
Change-Id: I375fef83fb99035d470490fdf2348766b090831e
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
2019-05-28 13:13:05 +00:00
|
|
|
t->setInternalClass(t->internalClass()->cryopreserved());
|
2018-05-15 21:29:33 +00:00
|
|
|
jsObjects[ThrowerObject] = t;
|
2018-03-15 15:40:36 +00:00
|
|
|
|
|
|
|
ScopedProperty pd(scope);
|
|
|
|
pd->value = thrower();
|
|
|
|
pd->set = thrower();
|
|
|
|
functionPrototype()->insertMember(id_caller(), pd, Attr_Accessor|Attr_ReadOnly_ButConfigurable);
|
|
|
|
functionPrototype()->insertMember(id_arguments(), pd, Attr_Accessor|Attr_ReadOnly_ButConfigurable);
|
2019-04-05 07:59:10 +00:00
|
|
|
|
|
|
|
qMetaTypeId<QJSValue>();
|
|
|
|
qMetaTypeId<QList<int> >();
|
|
|
|
|
|
|
|
if (!QMetaType::hasRegisteredConverterFunction<QJSValue, QVariantMap>())
|
|
|
|
QMetaType::registerConverter<QJSValue, QVariantMap>(convertJSValueToVariantType<QVariantMap>);
|
|
|
|
if (!QMetaType::hasRegisteredConverterFunction<QJSValue, QVariantList>())
|
|
|
|
QMetaType::registerConverter<QJSValue, QVariantList>(convertJSValueToVariantType<QVariantList>);
|
|
|
|
if (!QMetaType::hasRegisteredConverterFunction<QJSValue, QStringList>())
|
|
|
|
QMetaType::registerConverter<QJSValue, QStringList>(convertJSValueToVariantType<QStringList>);
|
2019-12-09 14:26:14 +00:00
|
|
|
if (!QMetaType::hasRegisteredConverterFunction<QJSValue, QtMetaTypePrivate::QSequentialIterableImpl>())
|
|
|
|
QMetaType::registerConverter<QJSValue, QtMetaTypePrivate::QSequentialIterableImpl>(jsvalueToSequence);
|
2019-04-05 07:59:10 +00:00
|
|
|
QMetaType::registerStreamOperators(qMetaTypeId<QJSValue>(), saveJSValue, restoreJSValue);
|
|
|
|
|
|
|
|
QV4::QObjectWrapper::initializeBindings(this);
|
|
|
|
|
|
|
|
m_delayedCallQueue.init(this);
|
2012-11-17 20:54:26 +00:00
|
|
|
}
|
|
|
|
|
2012-12-04 10:30:26 +00:00
|
|
|
ExecutionEngine::~ExecutionEngine()
|
|
|
|
{
|
2018-07-10 12:52:34 +00:00
|
|
|
modules.clear();
|
2019-04-05 07:59:10 +00:00
|
|
|
qDeleteAll(m_extensionData);
|
2013-06-04 12:28:13 +00:00
|
|
|
delete m_multiplyWrappedQObjects;
|
2018-02-21 09:41:54 +00:00
|
|
|
m_multiplyWrappedQObjects = nullptr;
|
2013-08-12 14:13:37 +00:00
|
|
|
delete identifierTable;
|
2013-05-29 12:58:52 +00:00
|
|
|
delete memoryManager;
|
2013-09-19 07:32:42 +00:00
|
|
|
|
2017-10-04 15:21:44 +00:00
|
|
|
while (!compilationUnits.isEmpty())
|
|
|
|
(*compilationUnits.begin())->unlink();
|
2013-09-19 07:32:42 +00:00
|
|
|
|
2013-04-19 09:47:50 +00:00
|
|
|
delete bumperPointerAllocator;
|
2013-03-30 16:43:03 +00:00
|
|
|
delete regExpCache;
|
2013-05-12 10:07:15 +00:00
|
|
|
delete regExpAllocator;
|
2013-03-25 16:31:38 +00:00
|
|
|
delete executableAllocator;
|
2013-09-03 10:40:07 +00:00
|
|
|
jsStack->deallocate();
|
|
|
|
delete jsStack;
|
2017-03-09 09:36:16 +00:00
|
|
|
gcStack->deallocate();
|
|
|
|
delete gcStack;
|
2019-04-05 07:59:10 +00:00
|
|
|
|
|
|
|
#if QT_CONFIG(qml_xml_http_request)
|
|
|
|
qt_rem_qmlxmlhttprequest(this, m_xmlHttpRequestData);
|
|
|
|
m_xmlHttpRequestData = nullptr;
|
|
|
|
#endif
|
2012-12-04 10:30:26 +00:00
|
|
|
}
|
|
|
|
|
2018-06-27 10:19:04 +00:00
|
|
|
ExecutionContext *ExecutionEngine::currentContext() const
|
|
|
|
{
|
|
|
|
return static_cast<ExecutionContext *>(¤tStackFrame->jsFrame->context);
|
|
|
|
}
|
|
|
|
|
2017-10-06 15:30:36 +00:00
|
|
|
#if QT_CONFIG(qml_debug)
|
2016-07-25 15:02:45 +00:00
|
|
|
void ExecutionEngine::setDebugger(Debugging::Debugger *debugger)
|
2013-07-24 08:29:04 +00:00
|
|
|
{
|
2016-07-25 15:02:45 +00:00
|
|
|
Q_ASSERT(!m_debugger);
|
2017-09-05 13:23:05 +00:00
|
|
|
m_debugger.reset(debugger);
|
2013-07-24 08:29:04 +00:00
|
|
|
}
|
|
|
|
|
2016-07-25 15:02:45 +00:00
|
|
|
void ExecutionEngine::setProfiler(Profiling::Profiler *profiler)
|
2014-01-22 16:46:20 +00:00
|
|
|
{
|
2016-07-25 15:02:45 +00:00
|
|
|
Q_ASSERT(!m_profiler);
|
2017-09-05 13:23:05 +00:00
|
|
|
m_profiler.reset(profiler);
|
2014-01-22 16:46:20 +00:00
|
|
|
}
|
2017-10-06 15:30:36 +00:00
|
|
|
#endif // QT_CONFIG(qml_debug)
|
2014-01-22 16:46:20 +00:00
|
|
|
|
2013-03-14 13:03:04 +00:00
|
|
|
void ExecutionEngine::initRootContext()
|
|
|
|
{
|
2014-11-13 20:53:27 +00:00
|
|
|
Scope scope(this);
|
2017-08-13 17:43:24 +00:00
|
|
|
Scoped<ExecutionContext> r(scope, memoryManager->allocManaged<ExecutionContext>(sizeof(ExecutionContext::Data)));
|
2017-07-04 20:04:49 +00:00
|
|
|
r->d_unchecked()->init(Heap::ExecutionContext::Type_GlobalContext);
|
|
|
|
r->d()->activation.set(this, globalObject->d());
|
2015-08-24 14:24:34 +00:00
|
|
|
jsObjects[RootContext] = r;
|
2018-05-04 13:16:08 +00:00
|
|
|
jsObjects[ScriptContext] = r;
|
2015-08-24 13:31:46 +00:00
|
|
|
jsObjects[IntegerNull] = Encode((int)0);
|
2013-03-14 13:03:04 +00:00
|
|
|
}
|
|
|
|
|
2018-01-05 14:30:23 +00:00
|
|
|
Heap::InternalClass *ExecutionEngine::newClass(Heap::InternalClass *other)
|
2013-05-06 11:29:24 +00:00
|
|
|
{
|
2018-01-05 14:30:23 +00:00
|
|
|
Heap::InternalClass *ic = memoryManager->allocIC<InternalClass>();
|
|
|
|
ic->init(other);
|
|
|
|
return ic;
|
2013-05-06 11:29:24 +00:00
|
|
|
}
|
|
|
|
|
2018-01-05 14:30:23 +00:00
|
|
|
Heap::InternalClass *ExecutionEngine::newInternalClass(const VTable *vtable, Object *prototype)
|
2017-05-15 07:56:05 +00:00
|
|
|
{
|
2018-01-05 14:30:23 +00:00
|
|
|
Scope scope(this);
|
|
|
|
Scoped<InternalClass> ic(scope, internalClasses(Class_Empty)->changeVTable(vtable));
|
|
|
|
return ic->changePrototype(prototype ? prototype->d() : nullptr);
|
2017-05-15 07:56:05 +00:00
|
|
|
}
|
|
|
|
|
2014-11-11 12:34:18 +00:00
|
|
|
Heap::Object *ExecutionEngine::newObject()
|
2012-11-17 20:54:26 +00:00
|
|
|
{
|
2018-04-10 20:45:27 +00:00
|
|
|
return memoryManager->allocate<Object>();
|
2012-11-17 20:54:26 +00:00
|
|
|
}
|
|
|
|
|
2018-01-05 14:30:23 +00:00
|
|
|
Heap::Object *ExecutionEngine::newObject(Heap::InternalClass *internalClass)
|
2013-04-23 05:31:02 +00:00
|
|
|
{
|
2018-01-08 10:40:39 +00:00
|
|
|
return memoryManager->allocObject<Object>(internalClass);
|
2013-04-23 05:31:02 +00:00
|
|
|
}
|
|
|
|
|
2014-11-11 14:08:30 +00:00
|
|
|
Heap::String *ExecutionEngine::newString(const QString &s)
|
2012-11-17 20:54:26 +00:00
|
|
|
{
|
2018-06-23 21:07:23 +00:00
|
|
|
return memoryManager->allocWithStringData<String>(s.length() * sizeof(QChar), s);
|
2012-11-17 20:54:26 +00:00
|
|
|
}
|
|
|
|
|
2014-11-11 14:08:30 +00:00
|
|
|
Heap::String *ExecutionEngine::newIdentifier(const QString &text)
|
2013-01-30 13:56:40 +00:00
|
|
|
{
|
2018-06-23 21:07:23 +00:00
|
|
|
Scope scope(this);
|
|
|
|
ScopedString s(scope, memoryManager->allocWithStringData<String>(text.length() * sizeof(QChar), text));
|
|
|
|
s->toPropertyKey();
|
|
|
|
return s->d();
|
2013-01-30 13:56:40 +00:00
|
|
|
}
|
|
|
|
|
2015-04-30 22:08:55 +00:00
|
|
|
Heap::Object *ExecutionEngine::newStringObject(const String *string)
|
2012-11-17 20:54:26 +00:00
|
|
|
{
|
2018-04-10 20:45:27 +00:00
|
|
|
return memoryManager->allocate<StringObject>(string);
|
2012-11-17 20:54:26 +00:00
|
|
|
}
|
|
|
|
|
2018-04-08 14:43:10 +00:00
|
|
|
Heap::Object *ExecutionEngine::newSymbolObject(const Symbol *symbol)
|
|
|
|
{
|
|
|
|
return memoryManager->allocObject<SymbolObject>(classes[Class_SymbolObject], symbol);
|
|
|
|
}
|
|
|
|
|
2015-01-16 11:44:51 +00:00
|
|
|
Heap::Object *ExecutionEngine::newNumberObject(double value)
|
2012-11-17 20:54:26 +00:00
|
|
|
{
|
2018-04-10 20:45:27 +00:00
|
|
|
return memoryManager->allocate<NumberObject>(value);
|
2012-11-17 20:54:26 +00:00
|
|
|
}
|
|
|
|
|
2015-01-15 20:54:12 +00:00
|
|
|
Heap::Object *ExecutionEngine::newBooleanObject(bool b)
|
2012-11-17 20:54:26 +00:00
|
|
|
{
|
2018-04-10 20:45:27 +00:00
|
|
|
return memoryManager->allocate<BooleanObject>(b);
|
2012-11-17 20:54:26 +00:00
|
|
|
}
|
|
|
|
|
2014-11-11 12:34:18 +00:00
|
|
|
Heap::ArrayObject *ExecutionEngine::newArrayObject(int count)
|
2012-11-17 20:54:26 +00:00
|
|
|
{
|
2014-05-09 12:14:02 +00:00
|
|
|
Scope scope(this);
|
2018-04-10 20:45:27 +00:00
|
|
|
ScopedArrayObject object(scope, memoryManager->allocate<ArrayObject>());
|
2013-05-31 14:40:12 +00:00
|
|
|
|
|
|
|
if (count) {
|
|
|
|
if (count < 0x1000)
|
|
|
|
object->arrayReserve(count);
|
|
|
|
object->setArrayLengthUnchecked(count);
|
|
|
|
}
|
2014-11-11 12:34:18 +00:00
|
|
|
return object->d();
|
2012-11-17 20:54:26 +00:00
|
|
|
}
|
|
|
|
|
2015-09-08 12:58:16 +00:00
|
|
|
Heap::ArrayObject *ExecutionEngine::newArrayObject(const Value *values, int length)
|
|
|
|
{
|
|
|
|
Scope scope(this);
|
2018-04-10 20:45:27 +00:00
|
|
|
ScopedArrayObject a(scope, memoryManager->allocate<ArrayObject>());
|
2015-09-08 12:58:16 +00:00
|
|
|
|
|
|
|
if (length) {
|
|
|
|
size_t size = sizeof(Heap::ArrayData) + (length-1)*sizeof(Value);
|
|
|
|
Heap::SimpleArrayData *d = scope.engine->memoryManager->allocManaged<SimpleArrayData>(size);
|
2016-09-08 09:07:26 +00:00
|
|
|
d->init();
|
2015-09-08 12:58:16 +00:00
|
|
|
d->type = Heap::ArrayData::Simple;
|
|
|
|
d->offset = 0;
|
2017-01-27 08:57:00 +00:00
|
|
|
d->values.alloc = length;
|
|
|
|
d->values.size = length;
|
2017-02-03 19:58:22 +00:00
|
|
|
// this doesn't require a write barrier, things will be ok, when the new array data gets inserted into
|
|
|
|
// the parent object
|
|
|
|
memcpy(&d->values.values, values, length*sizeof(Value));
|
2017-01-31 13:03:51 +00:00
|
|
|
a->d()->arrayData.set(this, d);
|
2015-09-08 12:58:16 +00:00
|
|
|
a->setArrayLengthUnchecked(length);
|
|
|
|
}
|
|
|
|
return a->d();
|
|
|
|
}
|
|
|
|
|
2014-11-11 12:34:18 +00:00
|
|
|
Heap::ArrayObject *ExecutionEngine::newArrayObject(const QStringList &list)
|
2012-11-17 20:54:26 +00:00
|
|
|
{
|
2018-01-08 10:44:51 +00:00
|
|
|
return memoryManager->allocate<ArrayObject>(list);
|
2012-11-17 20:54:26 +00:00
|
|
|
}
|
|
|
|
|
2018-01-05 14:30:23 +00:00
|
|
|
Heap::ArrayObject *ExecutionEngine::newArrayObject(Heap::InternalClass *internalClass)
|
2013-09-02 12:25:15 +00:00
|
|
|
{
|
2018-01-08 10:44:51 +00:00
|
|
|
return memoryManager->allocObject<ArrayObject>(internalClass);
|
2013-09-02 12:25:15 +00:00
|
|
|
}
|
|
|
|
|
2015-03-04 19:57:14 +00:00
|
|
|
Heap::ArrayBuffer *ExecutionEngine::newArrayBuffer(const QByteArray &array)
|
|
|
|
{
|
2018-04-10 20:45:27 +00:00
|
|
|
return memoryManager->allocate<ArrayBuffer>(array);
|
2015-08-27 10:17:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Heap::ArrayBuffer *ExecutionEngine::newArrayBuffer(size_t length)
|
|
|
|
{
|
2018-04-10 20:45:27 +00:00
|
|
|
return memoryManager->allocate<ArrayBuffer>(length);
|
2015-03-04 19:57:14 +00:00
|
|
|
}
|
|
|
|
|
2013-09-02 12:25:15 +00:00
|
|
|
|
2015-01-15 10:36:57 +00:00
|
|
|
Heap::DateObject *ExecutionEngine::newDateObject(const Value &value)
|
2012-11-17 20:54:26 +00:00
|
|
|
{
|
2018-04-10 20:45:27 +00:00
|
|
|
return memoryManager->allocate<DateObject>(value);
|
2012-11-17 20:54:26 +00:00
|
|
|
}
|
|
|
|
|
2014-11-11 12:34:18 +00:00
|
|
|
Heap::DateObject *ExecutionEngine::newDateObject(const QDateTime &dt)
|
2013-05-02 20:33:47 +00:00
|
|
|
{
|
2014-05-09 12:14:02 +00:00
|
|
|
Scope scope(this);
|
2018-04-10 20:45:27 +00:00
|
|
|
Scoped<DateObject> object(scope, memoryManager->allocate<DateObject>(dt));
|
2014-11-11 12:34:18 +00:00
|
|
|
return object->d();
|
2013-05-02 20:33:47 +00:00
|
|
|
}
|
|
|
|
|
V4: Handle QTime->DateObject conversion better
By specification, date conversion functions for dates before the epoch
are not DST corrected. We converted QTime to a QDateTime where we set
the date part to Jan. 1, 1970, and then convert that to msecs since the
epoch UTC. For places on Earth where they had DST on that day (e.g.
Hobart in Australia), strange things happen: conversion from a QTime to
DateObject will use DST (because it's after the epoch in local time),
but conversions from DateObject to QTime won't use the DST because it's
before the epoch (in UTC).
Now as everyone knows, a 24-hour clock time has no meaning without a
date, only "elapsed time" has. But users still expect to be able to pass
QTime to QML/JS. So, we do the conversion on day 0 of month 0 of year 0,
and all of it in local time. This gives a stable conversion in both
directions, and the values in both C++ and QML/JS are the same for any
timezone (with or without DST) on this planet.
Task-number: QTBUG-54378
Change-Id: I892e16a93f015e92d311c6cae3ae7768b7373f6a
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
2016-07-08 14:40:28 +00:00
|
|
|
Heap::DateObject *ExecutionEngine::newDateObjectFromTime(const QTime &t)
|
|
|
|
{
|
|
|
|
Scope scope(this);
|
2018-04-10 20:45:27 +00:00
|
|
|
Scoped<DateObject> object(scope, memoryManager->allocate<DateObject>(t));
|
V4: Handle QTime->DateObject conversion better
By specification, date conversion functions for dates before the epoch
are not DST corrected. We converted QTime to a QDateTime where we set
the date part to Jan. 1, 1970, and then convert that to msecs since the
epoch UTC. For places on Earth where they had DST on that day (e.g.
Hobart in Australia), strange things happen: conversion from a QTime to
DateObject will use DST (because it's after the epoch in local time),
but conversions from DateObject to QTime won't use the DST because it's
before the epoch (in UTC).
Now as everyone knows, a 24-hour clock time has no meaning without a
date, only "elapsed time" has. But users still expect to be able to pass
QTime to QML/JS. So, we do the conversion on day 0 of month 0 of year 0,
and all of it in local time. This gives a stable conversion in both
directions, and the values in both C++ and QML/JS are the same for any
timezone (with or without DST) on this planet.
Task-number: QTBUG-54378
Change-Id: I892e16a93f015e92d311c6cae3ae7768b7373f6a
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
2016-07-08 14:40:28 +00:00
|
|
|
return object->d();
|
|
|
|
}
|
|
|
|
|
2014-11-11 12:34:18 +00:00
|
|
|
Heap::RegExpObject *ExecutionEngine::newRegExpObject(const QString &pattern, int flags)
|
2012-11-17 20:54:26 +00:00
|
|
|
{
|
2013-10-15 13:00:24 +00:00
|
|
|
Scope scope(this);
|
2018-08-08 11:15:40 +00:00
|
|
|
Scoped<RegExp> re(scope, RegExp::create(this, pattern, static_cast<CompiledData::RegExp::Flags>(flags)));
|
2017-08-08 10:39:54 +00:00
|
|
|
return newRegExpObject(re);
|
2012-12-12 07:28:08 +00:00
|
|
|
}
|
|
|
|
|
2017-08-08 10:39:54 +00:00
|
|
|
Heap::RegExpObject *ExecutionEngine::newRegExpObject(RegExp *re)
|
2012-12-12 07:28:08 +00:00
|
|
|
{
|
2018-04-10 20:45:27 +00:00
|
|
|
return memoryManager->allocate<RegExpObject>(re);
|
2012-11-17 20:54:26 +00:00
|
|
|
}
|
|
|
|
|
2014-11-11 12:34:18 +00:00
|
|
|
Heap::RegExpObject *ExecutionEngine::newRegExpObject(const QRegExp &re)
|
2013-05-02 20:33:47 +00:00
|
|
|
{
|
2018-04-10 20:45:27 +00:00
|
|
|
return memoryManager->allocate<RegExpObject>(re);
|
2013-05-02 20:33:47 +00:00
|
|
|
}
|
|
|
|
|
2019-02-13 14:54:14 +00:00
|
|
|
#if QT_CONFIG(regularexpression)
|
|
|
|
Heap::RegExpObject *ExecutionEngine::newRegExpObject(const QRegularExpression &re)
|
|
|
|
{
|
|
|
|
return memoryManager->allocate<RegExpObject>(re);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2015-01-15 10:36:57 +00:00
|
|
|
Heap::Object *ExecutionEngine::newErrorObject(const Value &value)
|
2012-11-17 20:54:26 +00:00
|
|
|
{
|
2018-08-04 08:39:09 +00:00
|
|
|
return ErrorObject::create<ErrorObject>(this, value, errorCtor());
|
2012-11-17 20:54:26 +00:00
|
|
|
}
|
|
|
|
|
2017-08-01 14:31:53 +00:00
|
|
|
Heap::Object *ExecutionEngine::newErrorObject(const QString &message)
|
|
|
|
{
|
|
|
|
return ErrorObject::create<ErrorObject>(this, message);
|
|
|
|
}
|
|
|
|
|
2014-11-11 12:34:18 +00:00
|
|
|
Heap::Object *ExecutionEngine::newSyntaxErrorObject(const QString &message)
|
2012-11-28 10:00:23 +00:00
|
|
|
{
|
2015-09-01 11:46:46 +00:00
|
|
|
return ErrorObject::create<SyntaxErrorObject>(this, message);
|
2012-11-28 10:00:23 +00:00
|
|
|
}
|
|
|
|
|
2014-11-11 12:34:18 +00:00
|
|
|
Heap::Object *ExecutionEngine::newSyntaxErrorObject(const QString &message, const QString &fileName, int line, int column)
|
2012-12-04 18:50:25 +00:00
|
|
|
{
|
2015-09-01 11:46:46 +00:00
|
|
|
return ErrorObject::create<SyntaxErrorObject>(this, message, fileName, line, column);
|
2012-12-04 18:50:25 +00:00
|
|
|
}
|
|
|
|
|
2013-05-02 19:37:20 +00:00
|
|
|
|
2014-11-11 12:34:18 +00:00
|
|
|
Heap::Object *ExecutionEngine::newReferenceErrorObject(const QString &message)
|
2013-05-02 19:37:20 +00:00
|
|
|
{
|
2015-09-01 11:46:46 +00:00
|
|
|
return ErrorObject::create<ReferenceErrorObject>(this, message);
|
2013-05-02 19:37:20 +00:00
|
|
|
}
|
|
|
|
|
2015-09-01 11:46:46 +00:00
|
|
|
Heap::Object *ExecutionEngine::newReferenceErrorObject(const QString &message, const QString &fileName, int line, int column)
|
2013-06-14 11:08:13 +00:00
|
|
|
{
|
2015-09-01 11:46:46 +00:00
|
|
|
return ErrorObject::create<ReferenceErrorObject>(this, message, fileName, line, column);
|
2013-06-14 11:08:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-11-11 12:34:18 +00:00
|
|
|
Heap::Object *ExecutionEngine::newTypeErrorObject(const QString &message)
|
2012-12-04 18:50:25 +00:00
|
|
|
{
|
2015-09-01 11:46:46 +00:00
|
|
|
return ErrorObject::create<TypeErrorObject>(this, message);
|
2012-12-04 18:50:25 +00:00
|
|
|
}
|
|
|
|
|
2014-11-11 12:34:18 +00:00
|
|
|
Heap::Object *ExecutionEngine::newRangeErrorObject(const QString &message)
|
2013-01-11 08:56:56 +00:00
|
|
|
{
|
2015-09-01 11:46:46 +00:00
|
|
|
return ErrorObject::create<RangeErrorObject>(this, message);
|
2013-01-11 08:56:56 +00:00
|
|
|
}
|
|
|
|
|
2015-01-15 10:36:57 +00:00
|
|
|
Heap::Object *ExecutionEngine::newURIErrorObject(const Value &message)
|
2013-01-22 14:13:15 +00:00
|
|
|
{
|
2018-08-04 08:39:09 +00:00
|
|
|
return ErrorObject::create<URIErrorObject>(this, message, uRIErrorCtor());
|
2013-01-22 14:13:15 +00:00
|
|
|
}
|
|
|
|
|
2015-07-16 16:35:55 +00:00
|
|
|
Heap::PromiseObject *ExecutionEngine::newPromiseObject()
|
|
|
|
{
|
|
|
|
if (!m_reactionHandler) {
|
|
|
|
m_reactionHandler.reset(new Promise::ReactionHandler);
|
|
|
|
}
|
|
|
|
|
|
|
|
Scope scope(this);
|
|
|
|
Scoped<PromiseObject> object(scope, memoryManager->allocate<PromiseObject>(this));
|
|
|
|
return object->d();
|
|
|
|
}
|
|
|
|
|
|
|
|
Heap::Object *ExecutionEngine::newPromiseObject(const QV4::FunctionObject *thisObject, const QV4::PromiseCapability *capability)
|
|
|
|
{
|
|
|
|
if (!m_reactionHandler) {
|
|
|
|
m_reactionHandler.reset(new Promise::ReactionHandler);
|
|
|
|
}
|
|
|
|
|
|
|
|
Scope scope(this);
|
|
|
|
Scoped<CapabilitiesExecutorWrapper> executor(scope, memoryManager->allocate<CapabilitiesExecutorWrapper>());
|
|
|
|
executor->d()->capabilities.set(this, capability->d());
|
|
|
|
executor->insertMember(id_length(), Primitive::fromInt32(2), Attr_NotWritable|Attr_NotEnumerable);
|
|
|
|
|
|
|
|
ScopedObject object(scope, thisObject->callAsConstructor(executor, 1));
|
|
|
|
return object->d();
|
|
|
|
}
|
|
|
|
|
|
|
|
Promise::ReactionHandler *ExecutionEngine::getPromiseReactionHandler()
|
|
|
|
{
|
|
|
|
Q_ASSERT(m_reactionHandler);
|
|
|
|
return m_reactionHandler.data();
|
|
|
|
}
|
|
|
|
|
2017-08-01 14:31:53 +00:00
|
|
|
Heap::Object *ExecutionEngine::newURIErrorObject(const QString &message)
|
|
|
|
{
|
|
|
|
return ErrorObject::create<URIErrorObject>(this, message);
|
|
|
|
}
|
|
|
|
|
|
|
|
Heap::Object *ExecutionEngine::newEvalErrorObject(const QString &message)
|
|
|
|
{
|
|
|
|
return ErrorObject::create<EvalErrorObject>(this, message);
|
|
|
|
}
|
|
|
|
|
2014-11-11 12:34:18 +00:00
|
|
|
Heap::Object *ExecutionEngine::newVariantObject(const QVariant &v)
|
2013-05-14 00:01:04 +00:00
|
|
|
{
|
2018-04-10 20:45:27 +00:00
|
|
|
return memoryManager->allocate<VariantObject>(v);
|
2013-05-14 00:01:04 +00:00
|
|
|
}
|
|
|
|
|
2018-05-03 19:50:18 +00:00
|
|
|
Heap::Object *ExecutionEngine::newForInIteratorObject(Object *o)
|
2012-11-17 20:54:26 +00:00
|
|
|
{
|
2014-05-09 13:23:18 +00:00
|
|
|
Scope scope(this);
|
2018-05-03 19:50:18 +00:00
|
|
|
ScopedObject obj(scope, memoryManager->allocate<ForInIteratorObject>(o));
|
2014-11-11 12:34:18 +00:00
|
|
|
return obj->d();
|
2013-05-03 14:51:32 +00:00
|
|
|
}
|
|
|
|
|
2018-05-29 20:41:34 +00:00
|
|
|
Heap::Object *ExecutionEngine::newMapIteratorObject(Object *o)
|
|
|
|
{
|
|
|
|
return memoryManager->allocate<MapIteratorObject>(o->d(), this);
|
|
|
|
}
|
|
|
|
|
2018-05-27 13:04:23 +00:00
|
|
|
Heap::Object *ExecutionEngine::newSetIteratorObject(Object *o)
|
|
|
|
{
|
|
|
|
return memoryManager->allocate<SetIteratorObject>(o->d(), this);
|
|
|
|
}
|
|
|
|
|
Add Array Iterator objects from ES6 (22.1.5)
And implement / expose them via:
22.1.3.4 - Array.prototype.entries()
22.1.3.13 - Array.prototype.keys()
22.1.3.29 - Array.prototype.values()
22.1.3.31 - Array.prototype[Symbol.iterator]
Most tests for Array iterators now pass.
At the same time, expose them on TypedArray's prototype:
- 22.2.3.15 %TypedArray%.prototype.keys
- 22.2.3.29 %TypedArray%.prototype.values
- 22.2.3.6 %TypedArray%.prototype.entries
- 22.2.3.31 %TypedArray%.prototype[Symbol.iterator]
For TypedArray, test coverage improves a tiny bit (3 passing tests), but the
vast majority fail as it seems like the object structure for TypedArray is
currently incomplete as far as ES6 expects.
It seems that ES6 expects the object structure to be:
* %TypedArray% (inherits FunctionObject)
(this is the TypedArray intrinsic object, and responsible for initializing
the TypedArray instances)
* All the TypedArray ctors (e.g. UInt8Array)
These inherit %TypedArray%, and make a super call to it to do their work
* %TypedArrayPrototype% (inherits Object)
(this is the initial prototype for %TypedArray%)
* All the ctors have their own separate instance of this
* The instances also make use it
So, for instance, a lot of the tests attempt to access the prototype like:
var proto = Object.getPrototypeOf(Int8Array)
var keys = proto.prototype.keys
As ES6 expects Int8Array.prototype to be %TypedArray% (22.2.5), this expands to:
Object.getPrototypeOf(%TypedArray%)
which it expects to be %TypedArrayPrototype%.
But since we have no intrinsic object, and the ctors inherit
FunctionObject, we instead return the wrong prototype into 'var proto'.
Change-Id: I5e1a95a0420ecb70a0e35a5df3f65557510c5925
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
2017-02-09 18:58:50 +00:00
|
|
|
Heap::Object *ExecutionEngine::newArrayIteratorObject(Object *o)
|
|
|
|
{
|
|
|
|
return memoryManager->allocate<ArrayIteratorObject>(o->d(), this);
|
|
|
|
}
|
|
|
|
|
2016-11-28 14:33:48 +00:00
|
|
|
Heap::QmlContext *ExecutionEngine::qmlContext() const
|
|
|
|
{
|
2017-08-08 08:56:34 +00:00
|
|
|
if (!currentStackFrame)
|
2018-02-21 09:41:54 +00:00
|
|
|
return nullptr;
|
2017-08-08 08:56:34 +00:00
|
|
|
Heap::ExecutionContext *ctx = currentContext()->d();
|
2016-11-28 14:33:48 +00:00
|
|
|
|
|
|
|
if (ctx->type != Heap::ExecutionContext::Type_QmlContext && !ctx->outer)
|
2018-02-21 09:41:54 +00:00
|
|
|
return nullptr;
|
2016-11-28 14:33:48 +00:00
|
|
|
|
|
|
|
while (ctx->outer && ctx->outer->type != Heap::ExecutionContext::Type_GlobalContext)
|
|
|
|
ctx = ctx->outer;
|
|
|
|
|
|
|
|
Q_ASSERT(ctx);
|
|
|
|
if (ctx->type != Heap::ExecutionContext::Type_QmlContext)
|
2018-02-21 09:41:54 +00:00
|
|
|
return nullptr;
|
2016-11-28 14:33:48 +00:00
|
|
|
|
|
|
|
return static_cast<Heap::QmlContext *>(ctx);
|
|
|
|
}
|
|
|
|
|
2015-08-21 09:26:22 +00:00
|
|
|
QObject *ExecutionEngine::qmlScopeObject() const
|
2015-06-18 11:12:31 +00:00
|
|
|
{
|
|
|
|
Heap::QmlContext *ctx = qmlContext();
|
2015-06-19 12:18:13 +00:00
|
|
|
if (!ctx)
|
2018-02-21 09:41:54 +00:00
|
|
|
return nullptr;
|
2012-11-17 20:54:26 +00:00
|
|
|
|
2017-07-04 14:07:50 +00:00
|
|
|
return ctx->qml()->scopeObject;
|
2015-06-15 14:41:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
QQmlContextData *ExecutionEngine::callingQmlContext() const
|
|
|
|
{
|
2015-08-21 09:26:22 +00:00
|
|
|
Heap::QmlContext *ctx = qmlContext();
|
|
|
|
if (!ctx)
|
2018-02-21 09:41:54 +00:00
|
|
|
return nullptr;
|
2015-06-15 14:41:24 +00:00
|
|
|
|
2017-07-04 14:07:50 +00:00
|
|
|
return ctx->qml()->context->contextData();
|
2015-06-15 14:41:24 +00:00
|
|
|
}
|
|
|
|
|
2017-08-04 08:03:03 +00:00
|
|
|
StackTrace ExecutionEngine::stackTrace(int frameLimit) const
|
2013-05-22 08:47:36 +00:00
|
|
|
{
|
2014-11-28 08:31:10 +00:00
|
|
|
Scope scope(const_cast<ExecutionEngine *>(this));
|
2014-03-04 12:19:27 +00:00
|
|
|
ScopedString name(scope);
|
2017-08-04 08:03:03 +00:00
|
|
|
StackTrace stack;
|
2013-05-22 08:47:36 +00:00
|
|
|
|
2017-08-09 15:14:11 +00:00
|
|
|
CppStackFrame *f = currentStackFrame;
|
2017-08-03 11:41:13 +00:00
|
|
|
while (f && frameLimit) {
|
2017-08-04 08:03:03 +00:00
|
|
|
QV4::StackFrame frame;
|
|
|
|
frame.source = f->source();
|
|
|
|
frame.function = f->function();
|
2017-10-24 11:56:09 +00:00
|
|
|
frame.line = qAbs(f->lineNumber());
|
2017-08-21 08:59:53 +00:00
|
|
|
frame.column = -1;
|
2013-05-25 13:31:23 +00:00
|
|
|
stack.append(frame);
|
2019-01-14 13:21:21 +00:00
|
|
|
if (f->isTailCalling) {
|
|
|
|
QV4::StackFrame frame;
|
|
|
|
frame.function = QStringLiteral("[elided tail calls]");
|
|
|
|
stack.append(frame);
|
|
|
|
}
|
2017-08-03 11:41:13 +00:00
|
|
|
--frameLimit;
|
|
|
|
f = f->parent;
|
2013-05-25 13:31:23 +00:00
|
|
|
}
|
2013-05-22 08:47:36 +00:00
|
|
|
|
2017-08-03 11:41:13 +00:00
|
|
|
return stack;
|
2013-05-22 08:47:36 +00:00
|
|
|
}
|
|
|
|
|
2013-12-20 14:38:37 +00:00
|
|
|
/* Helper and "C" linkage exported function to format a GDBMI stacktrace for
|
|
|
|
* invocation by a debugger.
|
|
|
|
* Sample GDB invocation: print qt_v4StackTrace((void*)0x7fffffffb290)
|
|
|
|
* Sample CDB invocation: .call Qt5Qmld!qt_v4StackTrace(0x7fffffffb290) ; gh
|
|
|
|
* Note: The helper is there to suppress MSVC warning 4190 about anything
|
|
|
|
* with UDT return types in a "C" linkage function. */
|
|
|
|
|
|
|
|
static inline char *v4StackTrace(const ExecutionContext *context)
|
|
|
|
{
|
|
|
|
QString result;
|
|
|
|
QTextStream str(&result);
|
|
|
|
str << "stack=[";
|
2017-05-19 13:50:22 +00:00
|
|
|
if (context && context->engine()) {
|
|
|
|
const QVector<StackFrame> stackTrace = context->engine()->stackTrace(20);
|
2013-12-20 14:38:37 +00:00
|
|
|
for (int i = 0; i < stackTrace.size(); ++i) {
|
|
|
|
if (i)
|
|
|
|
str << ',';
|
|
|
|
const QUrl url(stackTrace.at(i).source);
|
|
|
|
const QString fileName = url.isLocalFile() ? url.toLocalFile() : url.toString();
|
|
|
|
str << "frame={level=\"" << i << "\",func=\"" << stackTrace.at(i).function
|
|
|
|
<< "\",file=\"" << fileName << "\",fullname=\"" << fileName
|
|
|
|
<< "\",line=\"" << stackTrace.at(i).line << "\",language=\"js\"}";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
str << ']';
|
|
|
|
return qstrdup(result.toLocal8Bit().constData());
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" Q_QML_EXPORT char *qt_v4StackTrace(void *executionContext)
|
|
|
|
{
|
|
|
|
return v4StackTrace(reinterpret_cast<const ExecutionContext *>(executionContext));
|
|
|
|
}
|
|
|
|
|
2019-03-29 15:02:09 +00:00
|
|
|
extern "C" Q_QML_EXPORT char *qt_v4StackTraceForEngine(void *executionEngine)
|
|
|
|
{
|
|
|
|
auto engine = (reinterpret_cast<const ExecutionEngine *>(executionEngine));
|
|
|
|
return v4StackTrace(engine->currentContext());
|
|
|
|
}
|
|
|
|
|
2013-05-29 07:59:40 +00:00
|
|
|
QUrl ExecutionEngine::resolvedUrl(const QString &file)
|
|
|
|
{
|
|
|
|
QUrl src(file);
|
|
|
|
if (!src.isRelative())
|
|
|
|
return src;
|
|
|
|
|
|
|
|
QUrl base;
|
2017-08-09 15:14:11 +00:00
|
|
|
CppStackFrame *f = currentStackFrame;
|
2017-08-07 06:37:45 +00:00
|
|
|
while (f) {
|
|
|
|
if (f->v4Function) {
|
2018-01-30 09:42:34 +00:00
|
|
|
base = f->v4Function->finalUrl();
|
2013-05-29 07:59:40 +00:00
|
|
|
break;
|
|
|
|
}
|
2017-08-07 06:37:45 +00:00
|
|
|
f = f->parent;
|
2013-05-29 07:59:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (base.isEmpty() && globalCode)
|
2017-12-11 11:44:47 +00:00
|
|
|
base = globalCode->finalUrl();
|
2013-05-29 07:59:40 +00:00
|
|
|
|
|
|
|
if (base.isEmpty())
|
|
|
|
return src;
|
|
|
|
|
|
|
|
return base.resolved(src);
|
|
|
|
}
|
|
|
|
|
2017-03-09 09:36:16 +00:00
|
|
|
void ExecutionEngine::markObjects(MarkStack *markStack)
|
2013-01-28 15:46:09 +00:00
|
|
|
{
|
2018-01-05 14:30:23 +00:00
|
|
|
for (int i = 0; i < NClasses; ++i)
|
2020-01-06 12:55:53 +00:00
|
|
|
if (classes[i]) {
|
2018-01-05 14:30:23 +00:00
|
|
|
classes[i]->mark(markStack);
|
2020-01-06 12:55:53 +00:00
|
|
|
if (markStack->top >= markStack->limit)
|
|
|
|
markStack->drain();
|
|
|
|
}
|
2017-09-08 13:12:47 +00:00
|
|
|
markStack->drain();
|
2013-08-29 11:24:38 +00:00
|
|
|
|
2018-04-06 14:24:59 +00:00
|
|
|
identifierTable->markObjects(markStack);
|
|
|
|
|
2017-10-05 09:02:36 +00:00
|
|
|
for (auto compilationUnit: compilationUnits) {
|
2017-10-15 19:30:20 +00:00
|
|
|
compilationUnit->markObjects(markStack);
|
2017-09-08 13:12:47 +00:00
|
|
|
markStack->drain();
|
|
|
|
}
|
2013-01-28 15:46:09 +00:00
|
|
|
}
|
2013-05-25 13:31:23 +00:00
|
|
|
|
2015-01-15 10:36:57 +00:00
|
|
|
ReturnedValue ExecutionEngine::throwError(const Value &value)
|
2013-10-01 14:19:28 +00:00
|
|
|
{
|
2013-10-22 11:26:08 +00:00
|
|
|
// we can get in here with an exception already set, as the runtime
|
|
|
|
// doesn't check after every operation that can throw.
|
|
|
|
// in this case preserve the first exception to give correct error
|
|
|
|
// information
|
|
|
|
if (hasException)
|
|
|
|
return Encode::undefined();
|
|
|
|
|
2013-10-01 14:19:28 +00:00
|
|
|
hasException = true;
|
2015-03-13 16:21:18 +00:00
|
|
|
*exceptionValue = value;
|
2013-10-01 14:19:28 +00:00
|
|
|
QV4::Scope scope(this);
|
|
|
|
QV4::Scoped<ErrorObject> error(scope, value);
|
|
|
|
if (!!error)
|
2016-09-09 08:06:31 +00:00
|
|
|
exceptionStackTrace = *error->d()->stackTrace;
|
2013-10-01 14:19:28 +00:00
|
|
|
else
|
|
|
|
exceptionStackTrace = stackTrace();
|
|
|
|
|
2016-07-25 15:02:45 +00:00
|
|
|
if (QV4::Debugging::Debugger *debug = debugger())
|
|
|
|
debug->aboutToThrow();
|
2013-10-01 14:19:28 +00:00
|
|
|
|
2013-10-21 07:57:58 +00:00
|
|
|
return Encode::undefined();
|
2013-10-01 14:19:28 +00:00
|
|
|
}
|
|
|
|
|
2014-11-12 12:55:55 +00:00
|
|
|
ReturnedValue ExecutionEngine::catchException(StackTrace *trace)
|
2013-10-01 14:19:28 +00:00
|
|
|
{
|
2013-10-16 12:03:48 +00:00
|
|
|
Q_ASSERT(hasException);
|
2013-10-01 14:19:28 +00:00
|
|
|
if (trace)
|
|
|
|
*trace = exceptionStackTrace;
|
|
|
|
exceptionStackTrace.clear();
|
|
|
|
hasException = false;
|
2015-03-13 16:21:18 +00:00
|
|
|
ReturnedValue res = exceptionValue->asReturnedValue();
|
2018-09-11 09:07:32 +00:00
|
|
|
*exceptionValue = Value::emptyValue();
|
2013-10-01 14:19:28 +00:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2014-07-28 08:07:57 +00:00
|
|
|
ReturnedValue ExecutionEngine::throwError(const QString &message)
|
|
|
|
{
|
|
|
|
Scope scope(this);
|
|
|
|
ScopedValue v(scope, newString(message));
|
|
|
|
v = newErrorObject(v);
|
|
|
|
return throwError(v);
|
|
|
|
}
|
|
|
|
|
|
|
|
ReturnedValue ExecutionEngine::throwSyntaxError(const QString &message, const QString &fileName, int line, int column)
|
|
|
|
{
|
|
|
|
Scope scope(this);
|
2014-12-31 18:37:47 +00:00
|
|
|
ScopedObject error(scope, newSyntaxErrorObject(message, fileName, line, column));
|
2014-07-28 08:07:57 +00:00
|
|
|
return throwError(error);
|
|
|
|
}
|
|
|
|
|
|
|
|
ReturnedValue ExecutionEngine::throwSyntaxError(const QString &message)
|
|
|
|
{
|
|
|
|
Scope scope(this);
|
2014-12-31 18:37:47 +00:00
|
|
|
ScopedObject error(scope, newSyntaxErrorObject(message));
|
2014-07-28 08:07:57 +00:00
|
|
|
return throwError(error);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ReturnedValue ExecutionEngine::throwTypeError()
|
|
|
|
{
|
|
|
|
Scope scope(this);
|
2014-12-31 18:37:47 +00:00
|
|
|
ScopedObject error(scope, newTypeErrorObject(QStringLiteral("Type error")));
|
2014-07-28 08:07:57 +00:00
|
|
|
return throwError(error);
|
|
|
|
}
|
|
|
|
|
|
|
|
ReturnedValue ExecutionEngine::throwTypeError(const QString &message)
|
|
|
|
{
|
|
|
|
Scope scope(this);
|
2014-12-31 18:37:47 +00:00
|
|
|
ScopedObject error(scope, newTypeErrorObject(message));
|
2014-07-28 08:07:57 +00:00
|
|
|
return throwError(error);
|
|
|
|
}
|
|
|
|
|
2019-01-02 15:09:56 +00:00
|
|
|
ReturnedValue ExecutionEngine::throwReferenceError(const QString &name)
|
|
|
|
{
|
|
|
|
Scope scope(this);
|
|
|
|
QString msg = name + QLatin1String(" is not defined");
|
|
|
|
ScopedObject error(scope, newReferenceErrorObject(msg));
|
2014-07-28 08:07:57 +00:00
|
|
|
return throwError(error);
|
|
|
|
}
|
|
|
|
|
2015-01-15 10:36:57 +00:00
|
|
|
ReturnedValue ExecutionEngine::throwReferenceError(const Value &value)
|
2014-07-28 08:07:57 +00:00
|
|
|
{
|
|
|
|
Scope scope(this);
|
2015-01-15 10:36:57 +00:00
|
|
|
ScopedString s(scope, value.toString(this));
|
2016-06-07 14:15:07 +00:00
|
|
|
QString msg = s->toQString() + QLatin1String(" is not defined");
|
2014-12-31 18:37:47 +00:00
|
|
|
ScopedObject error(scope, newReferenceErrorObject(msg));
|
2014-07-28 08:07:57 +00:00
|
|
|
return throwError(error);
|
|
|
|
}
|
|
|
|
|
|
|
|
ReturnedValue ExecutionEngine::throwReferenceError(const QString &message, const QString &fileName, int line, int column)
|
|
|
|
{
|
|
|
|
Scope scope(this);
|
|
|
|
QString msg = message;
|
2014-12-31 18:37:47 +00:00
|
|
|
ScopedObject error(scope, newReferenceErrorObject(msg, fileName, line, column));
|
2014-07-28 08:07:57 +00:00
|
|
|
return throwError(error);
|
|
|
|
}
|
|
|
|
|
|
|
|
ReturnedValue ExecutionEngine::throwRangeError(const QString &message)
|
|
|
|
{
|
|
|
|
Scope scope(this);
|
|
|
|
ScopedObject error(scope, newRangeErrorObject(message));
|
|
|
|
return throwError(error);
|
|
|
|
}
|
|
|
|
|
2015-01-15 10:36:57 +00:00
|
|
|
ReturnedValue ExecutionEngine::throwRangeError(const Value &value)
|
2014-07-28 08:07:57 +00:00
|
|
|
{
|
|
|
|
Scope scope(this);
|
2015-01-15 10:36:57 +00:00
|
|
|
ScopedString s(scope, value.toString(this));
|
2016-06-07 14:15:07 +00:00
|
|
|
QString msg = s->toQString() + QLatin1String(" out of range");
|
2014-07-28 08:07:57 +00:00
|
|
|
ScopedObject error(scope, newRangeErrorObject(msg));
|
|
|
|
return throwError(error);
|
|
|
|
}
|
|
|
|
|
2015-01-15 10:36:57 +00:00
|
|
|
ReturnedValue ExecutionEngine::throwURIError(const Value &msg)
|
2014-07-28 08:07:57 +00:00
|
|
|
{
|
|
|
|
Scope scope(this);
|
|
|
|
ScopedObject error(scope, newURIErrorObject(msg));
|
|
|
|
return throwError(error);
|
|
|
|
}
|
|
|
|
|
|
|
|
ReturnedValue ExecutionEngine::throwUnimplemented(const QString &message)
|
|
|
|
{
|
|
|
|
Scope scope(this);
|
2016-08-24 07:49:13 +00:00
|
|
|
ScopedValue v(scope, newString(QLatin1String("Unimplemented ") + message));
|
2014-07-28 08:07:57 +00:00
|
|
|
v = newErrorObject(v);
|
|
|
|
return throwError(v);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-11-12 12:55:55 +00:00
|
|
|
QQmlError ExecutionEngine::catchExceptionAsQmlError()
|
2013-10-17 06:56:51 +00:00
|
|
|
{
|
|
|
|
QV4::StackTrace trace;
|
2014-11-12 12:55:55 +00:00
|
|
|
QV4::Scope scope(this);
|
|
|
|
QV4::ScopedValue exception(scope, catchException(&trace));
|
2013-10-17 06:56:51 +00:00
|
|
|
QQmlError error;
|
|
|
|
if (!trace.isEmpty()) {
|
2016-01-05 15:30:34 +00:00
|
|
|
QV4::StackFrame frame = trace.constFirst();
|
2013-10-17 06:56:51 +00:00
|
|
|
error.setUrl(QUrl(frame.source));
|
|
|
|
error.setLine(frame.line);
|
|
|
|
error.setColumn(frame.column);
|
|
|
|
}
|
|
|
|
QV4::Scoped<QV4::ErrorObject> errorObj(scope, exception);
|
2018-04-10 10:47:53 +00:00
|
|
|
error.setDescription(exception->toQStringNoThrow());
|
2013-10-17 06:56:51 +00:00
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
2015-01-02 14:07:35 +00:00
|
|
|
// Variant conversion code
|
|
|
|
|
|
|
|
typedef QSet<QV4::Heap::Object *> V4ObjectSet;
|
2015-01-15 10:36:57 +00:00
|
|
|
static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int typeHint, bool createJSValueForObjects, V4ObjectSet *visitedObjects);
|
|
|
|
static QObject *qtObjectFromJS(QV4::ExecutionEngine *engine, const QV4::Value &value);
|
2018-02-21 09:41:54 +00:00
|
|
|
static QVariant objectToVariant(QV4::ExecutionEngine *e, const QV4::Object *o, V4ObjectSet *visitedObjects = nullptr);
|
2015-01-15 10:36:57 +00:00
|
|
|
static bool convertToNativeQObject(QV4::ExecutionEngine *e, const QV4::Value &value,
|
2015-01-02 14:07:35 +00:00
|
|
|
const QByteArray &targetType,
|
|
|
|
void **result);
|
|
|
|
static QV4::ReturnedValue variantListToJS(QV4::ExecutionEngine *v4, const QVariantList &lst);
|
QV4Engine: Unify fromValue and metaTypeToJS
Somehow, we ended up with two codepaths doing essentially the same
thing: constructing a JS value from a QVariant. metaTypeToJS is invoked
from QJSEngine::toScriptValue, whereas fromVariant() is used in various
places internally.
metaTypeToJS lacks proper handling for a number of cases, such as
builtin types like QPointF, which lead to toScriptValue(QPointF)
(incorrectly, and uselessly) constructing a VariantObject which couldn't
then do anything useful.
[ChangeLog][QtQml] QJSEngine::toScriptValue will now return correct
JavaScript objects in more cases, for example, for gadget types like
QPointF.
[ChangeLog][QtQml] QJSEngine::toScriptValue now uses the same
behavior as the rest of the engine when building JavaScript values, which
will cause the types of some returned JavaScript objects to change. For
instance, string lists are now returned as sequence objects, not array
objects, and QChar now constructs a JavaScript string.
Change-Id: I0290eb7c9c46e7b508d497cc33cd61d9378f3872
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
2019-02-12 13:37:23 +00:00
|
|
|
static QV4::ReturnedValue sequentialIterableToJS(QV4::ExecutionEngine *v4, const QSequentialIterable &lst);
|
2015-01-02 14:07:35 +00:00
|
|
|
static QV4::ReturnedValue variantMapToJS(QV4::ExecutionEngine *v4, const QVariantMap &vmap);
|
|
|
|
static QV4::ReturnedValue variantToJS(QV4::ExecutionEngine *v4, const QVariant &value)
|
|
|
|
{
|
|
|
|
return v4->metaTypeToJS(value.userType(), value.constData());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-01-15 10:36:57 +00:00
|
|
|
QVariant ExecutionEngine::toVariant(const Value &value, int typeHint, bool createJSValueForObjects)
|
2015-01-02 14:07:35 +00:00
|
|
|
{
|
2018-02-21 09:41:54 +00:00
|
|
|
return ::toVariant(this, value, typeHint, createJSValueForObjects, nullptr);
|
2015-01-02 14:07:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-01-15 10:36:57 +00:00
|
|
|
static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int typeHint, bool createJSValueForObjects, V4ObjectSet *visitedObjects)
|
2015-01-02 13:37:26 +00:00
|
|
|
{
|
2015-01-15 10:36:57 +00:00
|
|
|
Q_ASSERT (!value.isEmpty());
|
2015-01-02 13:37:26 +00:00
|
|
|
QV4::Scope scope(e);
|
|
|
|
|
2015-02-13 09:02:28 +00:00
|
|
|
if (const QV4::VariantObject *v = value.as<QV4::VariantObject>())
|
2016-10-05 10:18:20 +00:00
|
|
|
return v->d()->data();
|
2015-01-02 13:37:26 +00:00
|
|
|
|
2019-12-03 19:24:38 +00:00
|
|
|
if (typeHint == QMetaType::Bool)
|
2015-01-15 10:36:57 +00:00
|
|
|
return QVariant(value.toBoolean());
|
2015-01-02 13:37:26 +00:00
|
|
|
|
|
|
|
if (typeHint == QMetaType::QJsonValue)
|
|
|
|
return QVariant::fromValue(QV4::JsonObject::toJsonValue(value));
|
|
|
|
|
|
|
|
if (typeHint == qMetaTypeId<QJSValue>())
|
2015-01-14 11:50:34 +00:00
|
|
|
return QVariant::fromValue(QJSValue(e, value.asReturnedValue()));
|
2015-01-02 13:37:26 +00:00
|
|
|
|
2017-01-26 10:46:16 +00:00
|
|
|
if (value.as<QV4::Object>()) {
|
2015-01-02 13:37:26 +00:00
|
|
|
QV4::ScopedObject object(scope, value);
|
|
|
|
if (typeHint == QMetaType::QJsonObject
|
2015-02-13 12:56:05 +00:00
|
|
|
&& !value.as<ArrayObject>() && !value.as<FunctionObject>()) {
|
2015-01-02 13:37:26 +00:00
|
|
|
return QVariant::fromValue(QV4::JsonObject::toJsonObject(object));
|
|
|
|
} else if (QV4::QObjectWrapper *wrapper = object->as<QV4::QObjectWrapper>()) {
|
2019-04-05 07:42:17 +00:00
|
|
|
return QVariant::fromValue<QObject *>(wrapper->object());
|
2017-05-04 08:56:01 +00:00
|
|
|
} else if (object->as<QV4::QQmlContextWrapper>()) {
|
2015-01-02 13:37:26 +00:00
|
|
|
return QVariant();
|
2017-05-03 09:00:41 +00:00
|
|
|
} else if (QV4::QQmlTypeWrapper *w = object->as<QV4::QQmlTypeWrapper>()) {
|
2015-01-02 13:37:26 +00:00
|
|
|
return w->toVariant();
|
|
|
|
} else if (QV4::QQmlValueTypeWrapper *v = object->as<QV4::QQmlValueTypeWrapper>()) {
|
|
|
|
return v->toVariant();
|
|
|
|
} else if (QV4::QmlListWrapper *l = object->as<QV4::QmlListWrapper>()) {
|
|
|
|
return l->toVariant();
|
2017-12-18 15:20:11 +00:00
|
|
|
#if QT_CONFIG(qml_sequence_object)
|
|
|
|
} else if (object->isListType()) {
|
2015-01-02 13:37:26 +00:00
|
|
|
return QV4::SequencePrototype::toVariant(object);
|
2017-12-18 15:20:11 +00:00
|
|
|
#endif
|
|
|
|
}
|
2015-01-02 13:37:26 +00:00
|
|
|
}
|
|
|
|
|
2015-02-13 09:42:01 +00:00
|
|
|
if (value.as<ArrayObject>()) {
|
2015-01-02 13:37:26 +00:00
|
|
|
QV4::ScopedArrayObject a(scope, value);
|
|
|
|
if (typeHint == qMetaTypeId<QList<QObject *> >()) {
|
|
|
|
QList<QObject *> list;
|
|
|
|
uint length = a->getLength();
|
|
|
|
QV4::Scoped<QV4::QObjectWrapper> qobjectWrapper(scope);
|
|
|
|
for (uint ii = 0; ii < length; ++ii) {
|
2018-06-22 20:59:43 +00:00
|
|
|
qobjectWrapper = a->get(ii);
|
2015-01-02 13:37:26 +00:00
|
|
|
if (!!qobjectWrapper) {
|
|
|
|
list << qobjectWrapper->object();
|
|
|
|
} else {
|
|
|
|
list << 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-05 07:42:17 +00:00
|
|
|
return QVariant::fromValue<QList<QObject*> >(list);
|
2015-01-02 13:37:26 +00:00
|
|
|
} else if (typeHint == QMetaType::QJsonArray) {
|
|
|
|
return QVariant::fromValue(QV4::JsonObject::toJsonArray(a));
|
|
|
|
}
|
|
|
|
|
2020-01-02 13:42:12 +00:00
|
|
|
QVariant retn;
|
2017-12-18 15:20:11 +00:00
|
|
|
#if QT_CONFIG(qml_sequence_object)
|
2015-01-02 13:37:26 +00:00
|
|
|
bool succeeded = false;
|
2020-01-02 13:42:12 +00:00
|
|
|
retn = QV4::SequencePrototype::toVariant(value, typeHint, &succeeded);
|
2015-01-02 13:37:26 +00:00
|
|
|
if (succeeded)
|
|
|
|
return retn;
|
2017-12-18 15:20:11 +00:00
|
|
|
#endif
|
2020-02-07 08:57:02 +00:00
|
|
|
if (typeHint != -1) {
|
2020-02-20 09:36:37 +00:00
|
|
|
// the QVariant constructor will create a copy, so we have manually
|
|
|
|
// destroy the value returned by QMetaType::create
|
|
|
|
auto temp = QMetaType::create(typeHint);
|
|
|
|
retn = QVariant(typeHint, temp);
|
|
|
|
QMetaType::destroy(typeHint, temp);
|
2020-02-07 08:57:02 +00:00
|
|
|
auto retnAsIterable = retn.value<QtMetaTypePrivate::QSequentialIterableImpl>();
|
|
|
|
if (retnAsIterable._iteratorCapabilities & QtMetaTypePrivate::ContainerIsAppendable) {
|
|
|
|
auto const length = a->getLength();
|
|
|
|
QV4::ScopedValue arrayValue(scope);
|
|
|
|
for (qint64 i = 0; i < length; ++i) {
|
|
|
|
arrayValue = a->get(i);
|
|
|
|
QVariant asVariant = toVariant(e, arrayValue, retnAsIterable._metaType_id, false, visitedObjects);
|
|
|
|
auto originalType = asVariant.userType();
|
|
|
|
bool couldConvert = asVariant.convert(retnAsIterable._metaType_id);
|
|
|
|
if (!couldConvert) {
|
|
|
|
qWarning() << QLatin1String("Could not convert array value at position %1 from %2 to %3")
|
|
|
|
.arg(QString::number(i),
|
2020-02-20 14:21:08 +00:00
|
|
|
QString::fromUtf8(QMetaType::typeName(originalType)),
|
|
|
|
QString::fromUtf8(QMetaType::typeName(retnAsIterable._metaType_id)));
|
2020-02-07 08:57:02 +00:00
|
|
|
// create default constructed value
|
|
|
|
asVariant = QVariant(retnAsIterable._metaType_id, nullptr);
|
|
|
|
}
|
|
|
|
retnAsIterable.append(asVariant.constData());
|
2020-01-02 13:42:12 +00:00
|
|
|
}
|
2020-02-07 08:57:02 +00:00
|
|
|
return retn;
|
2020-01-02 13:42:12 +00:00
|
|
|
}
|
|
|
|
}
|
2015-01-02 13:37:26 +00:00
|
|
|
}
|
|
|
|
|
2015-01-15 10:36:57 +00:00
|
|
|
if (value.isUndefined())
|
2015-01-02 13:37:26 +00:00
|
|
|
return QVariant();
|
2015-01-15 10:36:57 +00:00
|
|
|
if (value.isNull())
|
2016-08-05 08:02:52 +00:00
|
|
|
return QVariant::fromValue(nullptr);
|
2015-01-15 10:36:57 +00:00
|
|
|
if (value.isBoolean())
|
|
|
|
return value.booleanValue();
|
|
|
|
if (value.isInteger())
|
|
|
|
return value.integerValue();
|
|
|
|
if (value.isNumber())
|
|
|
|
return value.asDouble();
|
2016-11-24 15:05:14 +00:00
|
|
|
if (String *s = value.stringValue()) {
|
|
|
|
const QString &str = s->toQString();
|
2016-06-02 10:08:29 +00:00
|
|
|
// QChars are stored as a strings
|
2019-12-03 19:24:38 +00:00
|
|
|
if (typeHint == QMetaType::QChar && str.size() == 1)
|
2016-06-02 10:08:29 +00:00
|
|
|
return str.at(0);
|
|
|
|
return str;
|
|
|
|
}
|
2017-12-18 18:43:56 +00:00
|
|
|
#if QT_CONFIG(qml_locale)
|
2015-02-13 09:02:28 +00:00
|
|
|
if (const QV4::QQmlLocaleData *ld = value.as<QV4::QQmlLocaleData>())
|
2016-09-09 08:06:31 +00:00
|
|
|
return *ld->d()->locale;
|
2017-12-18 18:43:56 +00:00
|
|
|
#endif
|
2015-02-13 10:31:45 +00:00
|
|
|
if (const QV4::DateObject *d = value.as<DateObject>())
|
2015-01-02 13:37:26 +00:00
|
|
|
return d->toQDateTime();
|
2015-12-28 12:22:29 +00:00
|
|
|
if (const ArrayBuffer *d = value.as<ArrayBuffer>())
|
2015-05-23 12:10:36 +00:00
|
|
|
return d->asByteArray();
|
2015-01-02 13:37:26 +00:00
|
|
|
// NOTE: since we convert QTime to JS Date, round trip will change the variant type (to QDateTime)!
|
|
|
|
|
|
|
|
QV4::ScopedObject o(scope, value);
|
|
|
|
Q_ASSERT(o);
|
|
|
|
|
2019-02-13 14:54:14 +00:00
|
|
|
if (QV4::RegExpObject *re = o->as<QV4::RegExpObject>()) {
|
|
|
|
#if QT_CONFIG(regularexpression)
|
|
|
|
if (typeHint != QMetaType::QRegExp)
|
|
|
|
return re->toQRegularExpression();
|
|
|
|
#endif
|
2015-01-02 13:37:26 +00:00
|
|
|
return re->toQRegExp();
|
2019-02-13 14:54:14 +00:00
|
|
|
}
|
2015-01-02 13:37:26 +00:00
|
|
|
|
|
|
|
if (createJSValueForObjects)
|
2015-01-14 11:50:34 +00:00
|
|
|
return QVariant::fromValue(QJSValue(scope.engine, o->asReturnedValue()));
|
2015-01-02 13:37:26 +00:00
|
|
|
|
|
|
|
return objectToVariant(e, o, visitedObjects);
|
|
|
|
}
|
|
|
|
|
2015-04-26 20:58:49 +00:00
|
|
|
static QVariant objectToVariant(QV4::ExecutionEngine *e, const QV4::Object *o, V4ObjectSet *visitedObjects)
|
2015-01-02 13:37:26 +00:00
|
|
|
{
|
|
|
|
Q_ASSERT(o);
|
|
|
|
|
|
|
|
V4ObjectSet recursionGuardSet;
|
|
|
|
if (!visitedObjects) {
|
|
|
|
visitedObjects = &recursionGuardSet;
|
|
|
|
} else if (visitedObjects->contains(o->d())) {
|
|
|
|
// Avoid recursion.
|
|
|
|
// For compatibility with QVariant{List,Map} conversion, we return an
|
|
|
|
// empty object (and no error is thrown).
|
2015-02-13 09:42:01 +00:00
|
|
|
if (o->as<ArrayObject>())
|
2015-01-02 13:37:26 +00:00
|
|
|
return QVariantList();
|
|
|
|
return QVariantMap();
|
|
|
|
}
|
|
|
|
visitedObjects->insert(o->d());
|
|
|
|
|
|
|
|
QVariant result;
|
|
|
|
|
2015-02-13 09:42:01 +00:00
|
|
|
if (o->as<ArrayObject>()) {
|
2015-01-02 13:37:26 +00:00
|
|
|
QV4::Scope scope(e);
|
|
|
|
QV4::ScopedArrayObject a(scope, o->asReturnedValue());
|
|
|
|
QV4::ScopedValue v(scope);
|
|
|
|
QVariantList list;
|
|
|
|
|
|
|
|
int length = a->getLength();
|
|
|
|
for (int ii = 0; ii < length; ++ii) {
|
2018-06-22 20:59:43 +00:00
|
|
|
v = a->get(ii);
|
2015-01-02 14:07:35 +00:00
|
|
|
list << ::toVariant(e, v, -1, /*createJSValueForObjects*/false, visitedObjects);
|
2015-01-02 13:37:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
result = list;
|
2015-02-13 12:56:05 +00:00
|
|
|
} else if (!o->as<FunctionObject>()) {
|
2015-01-02 13:37:26 +00:00
|
|
|
QVariantMap map;
|
|
|
|
QV4::Scope scope(e);
|
|
|
|
QV4::ObjectIterator it(scope, o, QV4::ObjectIterator::EnumerableOnly);
|
|
|
|
QV4::ScopedValue name(scope);
|
|
|
|
QV4::ScopedValue val(scope);
|
|
|
|
while (1) {
|
|
|
|
name = it.nextPropertyNameAsString(val);
|
|
|
|
if (name->isNull())
|
|
|
|
break;
|
|
|
|
|
|
|
|
QString key = name->toQStringNoThrow();
|
2015-01-02 14:07:35 +00:00
|
|
|
map.insert(key, ::toVariant(e, val, /*type hint*/-1, /*createJSValueForObjects*/false, visitedObjects));
|
2015-01-02 13:37:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
result = map;
|
|
|
|
}
|
|
|
|
|
|
|
|
visitedObjects->remove(o->d());
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2015-01-02 14:07:35 +00:00
|
|
|
QV4::ReturnedValue QV4::ExecutionEngine::fromVariant(const QVariant &variant)
|
2015-01-02 13:37:26 +00:00
|
|
|
{
|
|
|
|
int type = variant.userType();
|
|
|
|
const void *ptr = variant.constData();
|
|
|
|
|
|
|
|
if (type < QMetaType::User) {
|
|
|
|
switch (QMetaType::Type(type)) {
|
|
|
|
case QMetaType::UnknownType:
|
|
|
|
case QMetaType::Void:
|
|
|
|
return QV4::Encode::undefined();
|
2016-08-05 08:02:52 +00:00
|
|
|
case QMetaType::Nullptr:
|
2015-01-02 13:37:26 +00:00
|
|
|
case QMetaType::VoidStar:
|
|
|
|
return QV4::Encode::null();
|
|
|
|
case QMetaType::Bool:
|
|
|
|
return QV4::Encode(*reinterpret_cast<const bool*>(ptr));
|
|
|
|
case QMetaType::Int:
|
|
|
|
return QV4::Encode(*reinterpret_cast<const int*>(ptr));
|
|
|
|
case QMetaType::UInt:
|
|
|
|
return QV4::Encode(*reinterpret_cast<const uint*>(ptr));
|
|
|
|
case QMetaType::LongLong:
|
|
|
|
return QV4::Encode((double)*reinterpret_cast<const qlonglong*>(ptr));
|
|
|
|
case QMetaType::ULongLong:
|
|
|
|
return QV4::Encode((double)*reinterpret_cast<const qulonglong*>(ptr));
|
|
|
|
case QMetaType::Double:
|
|
|
|
return QV4::Encode(*reinterpret_cast<const double*>(ptr));
|
|
|
|
case QMetaType::QString:
|
2015-01-02 14:07:35 +00:00
|
|
|
return newString(*reinterpret_cast<const QString*>(ptr))->asReturnedValue();
|
2015-12-28 12:22:29 +00:00
|
|
|
case QMetaType::QByteArray:
|
|
|
|
return newArrayBuffer(*reinterpret_cast<const QByteArray*>(ptr))->asReturnedValue();
|
2015-01-02 13:37:26 +00:00
|
|
|
case QMetaType::Float:
|
|
|
|
return QV4::Encode(*reinterpret_cast<const float*>(ptr));
|
|
|
|
case QMetaType::Short:
|
|
|
|
return QV4::Encode((int)*reinterpret_cast<const short*>(ptr));
|
|
|
|
case QMetaType::UShort:
|
|
|
|
return QV4::Encode((int)*reinterpret_cast<const unsigned short*>(ptr));
|
|
|
|
case QMetaType::Char:
|
2016-06-02 10:08:29 +00:00
|
|
|
return QV4::Encode((int)*reinterpret_cast<const char*>(ptr));
|
2015-01-02 13:37:26 +00:00
|
|
|
case QMetaType::UChar:
|
2016-06-02 10:08:29 +00:00
|
|
|
return QV4::Encode((int)*reinterpret_cast<const unsigned char*>(ptr));
|
2015-01-02 13:37:26 +00:00
|
|
|
case QMetaType::QChar:
|
2015-03-12 14:33:50 +00:00
|
|
|
return newString(*reinterpret_cast<const QChar *>(ptr))->asReturnedValue();
|
2015-01-02 13:37:26 +00:00
|
|
|
case QMetaType::QDateTime:
|
2015-01-02 14:07:35 +00:00
|
|
|
return QV4::Encode(newDateObject(*reinterpret_cast<const QDateTime *>(ptr)));
|
2015-01-02 13:37:26 +00:00
|
|
|
case QMetaType::QDate:
|
2016-11-03 18:00:24 +00:00
|
|
|
return QV4::Encode(newDateObject(QDateTime(*reinterpret_cast<const QDate *>(ptr), QTime(0, 0, 0), Qt::UTC)));
|
2015-01-02 13:37:26 +00:00
|
|
|
case QMetaType::QTime:
|
V4: Handle QTime->DateObject conversion better
By specification, date conversion functions for dates before the epoch
are not DST corrected. We converted QTime to a QDateTime where we set
the date part to Jan. 1, 1970, and then convert that to msecs since the
epoch UTC. For places on Earth where they had DST on that day (e.g.
Hobart in Australia), strange things happen: conversion from a QTime to
DateObject will use DST (because it's after the epoch in local time),
but conversions from DateObject to QTime won't use the DST because it's
before the epoch (in UTC).
Now as everyone knows, a 24-hour clock time has no meaning without a
date, only "elapsed time" has. But users still expect to be able to pass
QTime to QML/JS. So, we do the conversion on day 0 of month 0 of year 0,
and all of it in local time. This gives a stable conversion in both
directions, and the values in both C++ and QML/JS are the same for any
timezone (with or without DST) on this planet.
Task-number: QTBUG-54378
Change-Id: I892e16a93f015e92d311c6cae3ae7768b7373f6a
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
2016-07-08 14:40:28 +00:00
|
|
|
return QV4::Encode(newDateObjectFromTime(*reinterpret_cast<const QTime *>(ptr)));
|
2015-01-02 13:37:26 +00:00
|
|
|
case QMetaType::QRegExp:
|
2015-01-02 14:07:35 +00:00
|
|
|
return QV4::Encode(newRegExpObject(*reinterpret_cast<const QRegExp *>(ptr)));
|
2019-02-13 14:54:14 +00:00
|
|
|
#if QT_CONFIG(regularexpression)
|
|
|
|
case QMetaType::QRegularExpression:
|
|
|
|
return QV4::Encode(newRegExpObject(*reinterpret_cast<const QRegularExpression *>(ptr)));
|
|
|
|
#endif
|
2015-01-02 13:37:26 +00:00
|
|
|
case QMetaType::QObjectStar:
|
2015-01-02 14:07:35 +00:00
|
|
|
return QV4::QObjectWrapper::wrap(this, *reinterpret_cast<QObject* const *>(ptr));
|
2017-12-18 15:20:11 +00:00
|
|
|
#if QT_CONFIG(qml_sequence_object)
|
2015-01-02 13:37:26 +00:00
|
|
|
case QMetaType::QStringList:
|
|
|
|
{
|
|
|
|
bool succeeded = false;
|
2015-01-02 14:07:35 +00:00
|
|
|
QV4::Scope scope(this);
|
|
|
|
QV4::ScopedValue retn(scope, QV4::SequencePrototype::fromVariant(this, variant, &succeeded));
|
2015-01-02 13:37:26 +00:00
|
|
|
if (succeeded)
|
2015-01-15 20:28:01 +00:00
|
|
|
return retn->asReturnedValue();
|
2015-01-02 14:07:35 +00:00
|
|
|
return QV4::Encode(newArrayObject(*reinterpret_cast<const QStringList *>(ptr)));
|
2015-01-02 13:37:26 +00:00
|
|
|
}
|
2017-12-18 15:20:11 +00:00
|
|
|
#endif
|
2015-01-02 13:37:26 +00:00
|
|
|
case QMetaType::QVariantList:
|
QV4Engine: Unify fromValue and metaTypeToJS
Somehow, we ended up with two codepaths doing essentially the same
thing: constructing a JS value from a QVariant. metaTypeToJS is invoked
from QJSEngine::toScriptValue, whereas fromVariant() is used in various
places internally.
metaTypeToJS lacks proper handling for a number of cases, such as
builtin types like QPointF, which lead to toScriptValue(QPointF)
(incorrectly, and uselessly) constructing a VariantObject which couldn't
then do anything useful.
[ChangeLog][QtQml] QJSEngine::toScriptValue will now return correct
JavaScript objects in more cases, for example, for gadget types like
QPointF.
[ChangeLog][QtQml] QJSEngine::toScriptValue now uses the same
behavior as the rest of the engine when building JavaScript values, which
will cause the types of some returned JavaScript objects to change. For
instance, string lists are now returned as sequence objects, not array
objects, and QChar now constructs a JavaScript string.
Change-Id: I0290eb7c9c46e7b508d497cc33cd61d9378f3872
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
2019-02-12 13:37:23 +00:00
|
|
|
return variantListToJS(this, *reinterpret_cast<const QVariantList *>(ptr));
|
2015-01-02 13:37:26 +00:00
|
|
|
case QMetaType::QVariantMap:
|
QV4Engine: Unify fromValue and metaTypeToJS
Somehow, we ended up with two codepaths doing essentially the same
thing: constructing a JS value from a QVariant. metaTypeToJS is invoked
from QJSEngine::toScriptValue, whereas fromVariant() is used in various
places internally.
metaTypeToJS lacks proper handling for a number of cases, such as
builtin types like QPointF, which lead to toScriptValue(QPointF)
(incorrectly, and uselessly) constructing a VariantObject which couldn't
then do anything useful.
[ChangeLog][QtQml] QJSEngine::toScriptValue will now return correct
JavaScript objects in more cases, for example, for gadget types like
QPointF.
[ChangeLog][QtQml] QJSEngine::toScriptValue now uses the same
behavior as the rest of the engine when building JavaScript values, which
will cause the types of some returned JavaScript objects to change. For
instance, string lists are now returned as sequence objects, not array
objects, and QChar now constructs a JavaScript string.
Change-Id: I0290eb7c9c46e7b508d497cc33cd61d9378f3872
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
2019-02-12 13:37:23 +00:00
|
|
|
return variantMapToJS(this, *reinterpret_cast<const QVariantMap *>(ptr));
|
2015-01-02 13:37:26 +00:00
|
|
|
case QMetaType::QJsonValue:
|
2015-01-02 14:07:35 +00:00
|
|
|
return QV4::JsonObject::fromJsonValue(this, *reinterpret_cast<const QJsonValue *>(ptr));
|
2015-01-02 13:37:26 +00:00
|
|
|
case QMetaType::QJsonObject:
|
2015-01-02 14:07:35 +00:00
|
|
|
return QV4::JsonObject::fromJsonObject(this, *reinterpret_cast<const QJsonObject *>(ptr));
|
2015-01-02 13:37:26 +00:00
|
|
|
case QMetaType::QJsonArray:
|
2015-01-02 14:07:35 +00:00
|
|
|
return QV4::JsonObject::fromJsonArray(this, *reinterpret_cast<const QJsonArray *>(ptr));
|
2017-12-18 18:43:56 +00:00
|
|
|
#if QT_CONFIG(qml_locale)
|
2015-01-02 13:37:26 +00:00
|
|
|
case QMetaType::QLocale:
|
2015-01-02 14:07:35 +00:00
|
|
|
return QQmlLocale::wrap(this, *reinterpret_cast<const QLocale*>(ptr));
|
2017-12-18 18:43:56 +00:00
|
|
|
#endif
|
2019-04-12 08:42:56 +00:00
|
|
|
case QMetaType::QPixmap:
|
|
|
|
case QMetaType::QImage:
|
|
|
|
// Scarce value types
|
|
|
|
return QV4::Encode(newVariantObject(variant));
|
2015-01-02 13:37:26 +00:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (const QMetaObject *vtmo = QQmlValueTypeFactory::metaObjectForMetaType(type))
|
2015-01-02 14:07:35 +00:00
|
|
|
return QV4::QQmlValueTypeWrapper::create(this, variant, vtmo, type);
|
2015-01-02 13:37:26 +00:00
|
|
|
} else {
|
2015-01-02 14:07:35 +00:00
|
|
|
QV4::Scope scope(this);
|
2015-01-02 13:37:26 +00:00
|
|
|
if (type == qMetaTypeId<QQmlListReference>()) {
|
|
|
|
typedef QQmlListReferencePrivate QDLRP;
|
2015-03-07 22:35:47 +00:00
|
|
|
QDLRP *p = QDLRP::get((QQmlListReference*)const_cast<void *>(ptr));
|
2015-01-02 13:37:26 +00:00
|
|
|
if (p->object) {
|
|
|
|
return QV4::QmlListWrapper::create(scope.engine, p->property, p->propertyType);
|
|
|
|
} else {
|
|
|
|
return QV4::Encode::null();
|
|
|
|
}
|
|
|
|
} else if (type == qMetaTypeId<QJSValue>()) {
|
|
|
|
const QJSValue *value = reinterpret_cast<const QJSValue *>(ptr);
|
2015-01-14 15:22:33 +00:00
|
|
|
return QJSValuePrivate::convertedToValue(this, *value);
|
2015-01-02 13:37:26 +00:00
|
|
|
} else if (type == qMetaTypeId<QList<QObject *> >()) {
|
|
|
|
// XXX Can this be made more by using Array as a prototype and implementing
|
|
|
|
// directly against QList<QObject*>?
|
2015-03-07 22:35:47 +00:00
|
|
|
const QList<QObject *> &list = *(const QList<QObject *>*)ptr;
|
2015-01-02 14:07:35 +00:00
|
|
|
QV4::ScopedArrayObject a(scope, newArrayObject());
|
2015-01-02 13:37:26 +00:00
|
|
|
a->arrayReserve(list.count());
|
|
|
|
QV4::ScopedValue v(scope);
|
|
|
|
for (int ii = 0; ii < list.count(); ++ii)
|
2015-01-02 14:07:35 +00:00
|
|
|
a->arrayPut(ii, (v = QV4::QObjectWrapper::wrap(this, list.at(ii))));
|
2015-01-02 13:37:26 +00:00
|
|
|
a->setArrayLengthUnchecked(list.count());
|
|
|
|
return a.asReturnedValue();
|
|
|
|
} else if (QMetaType::typeFlags(type) & QMetaType::PointerToQObject) {
|
2015-01-02 14:07:35 +00:00
|
|
|
return QV4::QObjectWrapper::wrap(this, *reinterpret_cast<QObject* const *>(ptr));
|
2015-01-02 13:37:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool objOk;
|
|
|
|
QObject *obj = QQmlMetaType::toQObject(variant, &objOk);
|
|
|
|
if (objOk)
|
2015-01-02 14:07:35 +00:00
|
|
|
return QV4::QObjectWrapper::wrap(this, obj);
|
2015-01-02 13:37:26 +00:00
|
|
|
|
2017-12-18 15:20:11 +00:00
|
|
|
#if QT_CONFIG(qml_sequence_object)
|
2015-01-02 13:37:26 +00:00
|
|
|
bool succeeded = false;
|
2015-01-02 14:07:35 +00:00
|
|
|
QV4::ScopedValue retn(scope, QV4::SequencePrototype::fromVariant(this, variant, &succeeded));
|
2015-01-02 13:37:26 +00:00
|
|
|
if (succeeded)
|
2015-01-15 20:28:01 +00:00
|
|
|
return retn->asReturnedValue();
|
2017-12-18 15:20:11 +00:00
|
|
|
#endif
|
2015-01-02 13:37:26 +00:00
|
|
|
|
QV4Engine: Unify fromValue and metaTypeToJS
Somehow, we ended up with two codepaths doing essentially the same
thing: constructing a JS value from a QVariant. metaTypeToJS is invoked
from QJSEngine::toScriptValue, whereas fromVariant() is used in various
places internally.
metaTypeToJS lacks proper handling for a number of cases, such as
builtin types like QPointF, which lead to toScriptValue(QPointF)
(incorrectly, and uselessly) constructing a VariantObject which couldn't
then do anything useful.
[ChangeLog][QtQml] QJSEngine::toScriptValue will now return correct
JavaScript objects in more cases, for example, for gadget types like
QPointF.
[ChangeLog][QtQml] QJSEngine::toScriptValue now uses the same
behavior as the rest of the engine when building JavaScript values, which
will cause the types of some returned JavaScript objects to change. For
instance, string lists are now returned as sequence objects, not array
objects, and QChar now constructs a JavaScript string.
Change-Id: I0290eb7c9c46e7b508d497cc33cd61d9378f3872
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
2019-02-12 13:37:23 +00:00
|
|
|
if (QMetaType::hasRegisteredConverterFunction(type, qMetaTypeId<QtMetaTypePrivate::QSequentialIterableImpl>())) {
|
|
|
|
QSequentialIterable lst = variant.value<QSequentialIterable>();
|
|
|
|
return sequentialIterableToJS(this, lst);
|
|
|
|
}
|
|
|
|
|
2015-01-02 13:37:26 +00:00
|
|
|
if (const QMetaObject *vtmo = QQmlValueTypeFactory::metaObjectForMetaType(type))
|
2015-01-02 14:07:35 +00:00
|
|
|
return QV4::QQmlValueTypeWrapper::create(this, variant, vtmo, type);
|
2015-01-02 13:37:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// XXX TODO: To be compatible, we still need to handle:
|
|
|
|
// + QObjectList
|
|
|
|
// + QList<int>
|
|
|
|
|
2015-01-02 14:07:35 +00:00
|
|
|
return QV4::Encode(newVariantObject(variant));
|
2015-01-02 13:37:26 +00:00
|
|
|
}
|
|
|
|
|
2015-04-26 20:58:49 +00:00
|
|
|
QVariantMap ExecutionEngine::variantMapFromJS(const Object *o)
|
2015-01-02 13:37:26 +00:00
|
|
|
{
|
2015-01-02 14:07:35 +00:00
|
|
|
return objectToVariant(this, o).toMap();
|
2015-01-02 13:37:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Converts a QVariantList to JS.
|
|
|
|
// The result is a new Array object with length equal to the length
|
|
|
|
// of the QVariantList, and the elements being the QVariantList's
|
|
|
|
// elements converted to JS, recursively.
|
2015-01-02 14:07:35 +00:00
|
|
|
static QV4::ReturnedValue variantListToJS(QV4::ExecutionEngine *v4, const QVariantList &lst)
|
2015-01-02 13:37:26 +00:00
|
|
|
{
|
|
|
|
QV4::Scope scope(v4);
|
|
|
|
QV4::ScopedArrayObject a(scope, v4->newArrayObject());
|
|
|
|
a->arrayReserve(lst.size());
|
|
|
|
QV4::ScopedValue v(scope);
|
|
|
|
for (int i = 0; i < lst.size(); i++)
|
|
|
|
a->arrayPut(i, (v = variantToJS(v4, lst.at(i))));
|
|
|
|
a->setArrayLengthUnchecked(lst.size());
|
|
|
|
return a.asReturnedValue();
|
|
|
|
}
|
|
|
|
|
2018-09-24 13:05:13 +00:00
|
|
|
// Converts a QSequentialIterable to JS.
|
|
|
|
// The result is a new Array object with length equal to the length
|
|
|
|
// of the QSequentialIterable, and the elements being the QSequentialIterable's
|
|
|
|
// elements converted to JS, recursively.
|
|
|
|
static QV4::ReturnedValue sequentialIterableToJS(QV4::ExecutionEngine *v4, const QSequentialIterable &lst)
|
|
|
|
{
|
|
|
|
QV4::Scope scope(v4);
|
|
|
|
QV4::ScopedArrayObject a(scope, v4->newArrayObject());
|
|
|
|
a->arrayReserve(lst.size());
|
|
|
|
QV4::ScopedValue v(scope);
|
|
|
|
for (int i = 0; i < lst.size(); i++)
|
|
|
|
a->arrayPut(i, (v = variantToJS(v4, lst.at(i))));
|
|
|
|
a->setArrayLengthUnchecked(lst.size());
|
|
|
|
return a.asReturnedValue();
|
|
|
|
}
|
|
|
|
|
2015-01-02 13:37:26 +00:00
|
|
|
// Converts a QVariantMap to JS.
|
|
|
|
// The result is a new Object object with property names being
|
|
|
|
// the keys of the QVariantMap, and values being the values of
|
|
|
|
// the QVariantMap converted to JS, recursively.
|
2015-01-02 14:07:35 +00:00
|
|
|
static QV4::ReturnedValue variantMapToJS(QV4::ExecutionEngine *v4, const QVariantMap &vmap)
|
2015-01-02 13:37:26 +00:00
|
|
|
{
|
|
|
|
QV4::Scope scope(v4);
|
|
|
|
QV4::ScopedObject o(scope, v4->newObject());
|
|
|
|
QV4::ScopedString s(scope);
|
2018-06-23 21:47:25 +00:00
|
|
|
QV4::ScopedPropertyKey key(scope);
|
2015-01-02 13:37:26 +00:00
|
|
|
QV4::ScopedValue v(scope);
|
2015-02-23 12:44:12 +00:00
|
|
|
for (QVariantMap::const_iterator it = vmap.constBegin(), cend = vmap.constEnd(); it != cend; ++it) {
|
2015-01-02 13:37:26 +00:00
|
|
|
s = v4->newIdentifier(it.key());
|
2018-06-23 21:47:25 +00:00
|
|
|
key = s->propertyKey();
|
2015-01-02 13:37:26 +00:00
|
|
|
v = variantToJS(v4, it.value());
|
2019-03-29 08:24:27 +00:00
|
|
|
if (key->isArrayIndex())
|
|
|
|
o->arraySet(key->asArrayIndex(), v);
|
2015-01-02 13:37:26 +00:00
|
|
|
else
|
|
|
|
o->insertMember(s, v);
|
|
|
|
}
|
|
|
|
return o.asReturnedValue();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Converts the meta-type defined by the given type and data to JS.
|
|
|
|
// Returns the value if conversion succeeded, an empty handle otherwise.
|
2015-01-02 14:07:35 +00:00
|
|
|
QV4::ReturnedValue ExecutionEngine::metaTypeToJS(int type, const void *data)
|
2015-01-02 13:37:26 +00:00
|
|
|
{
|
2018-02-21 09:41:54 +00:00
|
|
|
Q_ASSERT(data != nullptr);
|
2015-01-02 13:37:26 +00:00
|
|
|
|
QV4Engine: Unify fromValue and metaTypeToJS
Somehow, we ended up with two codepaths doing essentially the same
thing: constructing a JS value from a QVariant. metaTypeToJS is invoked
from QJSEngine::toScriptValue, whereas fromVariant() is used in various
places internally.
metaTypeToJS lacks proper handling for a number of cases, such as
builtin types like QPointF, which lead to toScriptValue(QPointF)
(incorrectly, and uselessly) constructing a VariantObject which couldn't
then do anything useful.
[ChangeLog][QtQml] QJSEngine::toScriptValue will now return correct
JavaScript objects in more cases, for example, for gadget types like
QPointF.
[ChangeLog][QtQml] QJSEngine::toScriptValue now uses the same
behavior as the rest of the engine when building JavaScript values, which
will cause the types of some returned JavaScript objects to change. For
instance, string lists are now returned as sequence objects, not array
objects, and QChar now constructs a JavaScript string.
Change-Id: I0290eb7c9c46e7b508d497cc33cd61d9378f3872
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
2019-02-12 13:37:23 +00:00
|
|
|
QVariant variant(type, data);
|
2019-12-03 19:24:38 +00:00
|
|
|
if (QMetaType::Type(variant.userType()) == QMetaType::QVariant) {
|
QV4Engine: Unify fromValue and metaTypeToJS
Somehow, we ended up with two codepaths doing essentially the same
thing: constructing a JS value from a QVariant. metaTypeToJS is invoked
from QJSEngine::toScriptValue, whereas fromVariant() is used in various
places internally.
metaTypeToJS lacks proper handling for a number of cases, such as
builtin types like QPointF, which lead to toScriptValue(QPointF)
(incorrectly, and uselessly) constructing a VariantObject which couldn't
then do anything useful.
[ChangeLog][QtQml] QJSEngine::toScriptValue will now return correct
JavaScript objects in more cases, for example, for gadget types like
QPointF.
[ChangeLog][QtQml] QJSEngine::toScriptValue now uses the same
behavior as the rest of the engine when building JavaScript values, which
will cause the types of some returned JavaScript objects to change. For
instance, string lists are now returned as sequence objects, not array
objects, and QChar now constructs a JavaScript string.
Change-Id: I0290eb7c9c46e7b508d497cc33cd61d9378f3872
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
2019-02-12 13:37:23 +00:00
|
|
|
// unwrap it: this is tested in QJSEngine, and makes the most sense for
|
|
|
|
// end-user code too.
|
2015-01-02 14:07:35 +00:00
|
|
|
return variantToJS(this, *reinterpret_cast<const QVariant*>(data));
|
2015-01-02 13:37:26 +00:00
|
|
|
}
|
QV4Engine: Unify fromValue and metaTypeToJS
Somehow, we ended up with two codepaths doing essentially the same
thing: constructing a JS value from a QVariant. metaTypeToJS is invoked
from QJSEngine::toScriptValue, whereas fromVariant() is used in various
places internally.
metaTypeToJS lacks proper handling for a number of cases, such as
builtin types like QPointF, which lead to toScriptValue(QPointF)
(incorrectly, and uselessly) constructing a VariantObject which couldn't
then do anything useful.
[ChangeLog][QtQml] QJSEngine::toScriptValue will now return correct
JavaScript objects in more cases, for example, for gadget types like
QPointF.
[ChangeLog][QtQml] QJSEngine::toScriptValue now uses the same
behavior as the rest of the engine when building JavaScript values, which
will cause the types of some returned JavaScript objects to change. For
instance, string lists are now returned as sequence objects, not array
objects, and QChar now constructs a JavaScript string.
Change-Id: I0290eb7c9c46e7b508d497cc33cd61d9378f3872
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
2019-02-12 13:37:23 +00:00
|
|
|
return fromVariant(variant);
|
2015-01-02 13:37:26 +00:00
|
|
|
}
|
|
|
|
|
2019-06-27 11:43:04 +00:00
|
|
|
int ExecutionEngine::maxJSStackSize() const
|
|
|
|
{
|
|
|
|
return m_maxJSStackSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ExecutionEngine::maxGCStackSize() const
|
|
|
|
{
|
|
|
|
return m_maxGCStackSize;
|
|
|
|
}
|
|
|
|
|
2017-12-19 10:14:27 +00:00
|
|
|
ReturnedValue ExecutionEngine::global()
|
|
|
|
{
|
|
|
|
return globalObject->asReturnedValue();
|
|
|
|
}
|
|
|
|
|
2019-05-07 10:47:33 +00:00
|
|
|
QQmlRefPointer<ExecutableCompilationUnit> ExecutionEngine::compileModule(const QUrl &url)
|
2018-07-10 12:52:34 +00:00
|
|
|
{
|
2019-08-26 09:48:48 +00:00
|
|
|
QQmlMetaType::CachedUnitLookupError cacheError = QQmlMetaType::CachedUnitLookupError::NoError;
|
|
|
|
if (const QV4::CompiledData::Unit *cachedUnit = QQmlMetaType::findCachedCompilationUnit(url, &cacheError)) {
|
2019-09-12 06:01:21 +00:00
|
|
|
return ExecutableCompilationUnit::create(
|
|
|
|
QV4::CompiledData::CompilationUnit(cachedUnit, url.fileName(), url.toString()));
|
2019-08-26 09:48:48 +00:00
|
|
|
}
|
|
|
|
|
2018-07-10 12:52:34 +00:00
|
|
|
QFile f(QQmlFile::urlToLocalFileOrQrc(url));
|
2018-08-13 12:16:21 +00:00
|
|
|
if (!f.open(QIODevice::ReadOnly)) {
|
|
|
|
throwError(QStringLiteral("Could not open module %1 for reading").arg(url.toString()));
|
2018-07-10 12:52:34 +00:00
|
|
|
return nullptr;
|
2018-08-13 12:16:21 +00:00
|
|
|
}
|
2018-07-10 12:52:34 +00:00
|
|
|
|
2018-08-16 09:45:27 +00:00
|
|
|
const QDateTime timeStamp = QFileInfo(f).lastModified();
|
|
|
|
|
2018-07-10 12:52:34 +00:00
|
|
|
const QString sourceCode = QString::fromUtf8(f.readAll());
|
|
|
|
f.close();
|
|
|
|
|
2018-08-16 09:45:27 +00:00
|
|
|
return compileModule(url, sourceCode, timeStamp);
|
2018-07-10 12:52:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-05-07 10:47:33 +00:00
|
|
|
QQmlRefPointer<ExecutableCompilationUnit> ExecutionEngine::compileModule(
|
|
|
|
const QUrl &url, const QString &sourceCode, const QDateTime &sourceTimeStamp)
|
2018-07-10 12:52:34 +00:00
|
|
|
{
|
|
|
|
QList<QQmlJS::DiagnosticMessage> diagnostics;
|
2019-05-08 11:29:50 +00:00
|
|
|
auto unit = Compiler::Codegen::compileModule(/*debugMode*/debugger() != nullptr, url.toString(),
|
|
|
|
sourceCode, sourceTimeStamp, &diagnostics);
|
2018-07-10 12:52:34 +00:00
|
|
|
for (const QQmlJS::DiagnosticMessage &m : diagnostics) {
|
|
|
|
if (m.isError()) {
|
2019-05-23 12:57:09 +00:00
|
|
|
throwSyntaxError(m.message, url.toString(), m.line, m.column);
|
2018-07-10 12:52:34 +00:00
|
|
|
return nullptr;
|
|
|
|
} else {
|
2019-05-23 12:57:09 +00:00
|
|
|
qWarning() << url << ':' << m.line << ':' << m.column
|
2018-07-10 12:52:34 +00:00
|
|
|
<< ": warning: " << m.message;
|
|
|
|
}
|
|
|
|
}
|
2019-05-07 10:47:33 +00:00
|
|
|
|
|
|
|
return ExecutableCompilationUnit::create(std::move(unit));
|
2018-07-10 12:52:34 +00:00
|
|
|
}
|
|
|
|
|
2019-05-07 10:47:33 +00:00
|
|
|
void ExecutionEngine::injectModule(const QQmlRefPointer<ExecutableCompilationUnit> &moduleUnit)
|
2018-07-10 12:52:34 +00:00
|
|
|
{
|
2018-08-16 08:57:25 +00:00
|
|
|
// Injection can happen from the QML type loader thread for example, but instantiation and
|
|
|
|
// evaluation must be limited to the ExecutionEngine's thread.
|
|
|
|
QMutexLocker moduleGuard(&moduleMutex);
|
2018-07-10 12:52:34 +00:00
|
|
|
modules.insert(moduleUnit->finalUrl(), moduleUnit);
|
|
|
|
}
|
|
|
|
|
2019-05-07 10:47:33 +00:00
|
|
|
QQmlRefPointer<ExecutableCompilationUnit> ExecutionEngine::moduleForUrl(const QUrl &_url, const ExecutableCompilationUnit *referrer) const
|
2018-08-16 08:57:25 +00:00
|
|
|
{
|
|
|
|
QUrl url = QQmlTypeLoader::normalize(_url);
|
|
|
|
if (referrer)
|
|
|
|
url = referrer->finalUrl().resolved(url);
|
|
|
|
|
|
|
|
QMutexLocker moduleGuard(&moduleMutex);
|
|
|
|
auto existingModule = modules.find(url);
|
|
|
|
if (existingModule == modules.end())
|
|
|
|
return nullptr;
|
|
|
|
return *existingModule;
|
|
|
|
}
|
|
|
|
|
2019-05-07 10:47:33 +00:00
|
|
|
QQmlRefPointer<ExecutableCompilationUnit> ExecutionEngine::loadModule(const QUrl &_url, const ExecutableCompilationUnit *referrer)
|
2018-07-10 12:52:34 +00:00
|
|
|
{
|
|
|
|
QUrl url = QQmlTypeLoader::normalize(_url);
|
|
|
|
if (referrer)
|
|
|
|
url = referrer->finalUrl().resolved(url);
|
|
|
|
|
2018-08-16 08:57:25 +00:00
|
|
|
QMutexLocker moduleGuard(&moduleMutex);
|
2018-07-10 12:52:34 +00:00
|
|
|
auto existingModule = modules.find(url);
|
|
|
|
if (existingModule != modules.end())
|
|
|
|
return *existingModule;
|
|
|
|
|
2018-08-16 08:57:25 +00:00
|
|
|
moduleGuard.unlock();
|
|
|
|
|
2018-07-10 12:52:34 +00:00
|
|
|
auto newModule = compileModule(url);
|
2018-08-16 08:57:25 +00:00
|
|
|
if (newModule) {
|
|
|
|
moduleGuard.relock();
|
2018-07-10 12:52:34 +00:00
|
|
|
modules.insert(url, newModule);
|
2018-08-16 08:57:25 +00:00
|
|
|
}
|
2018-07-10 12:52:34 +00:00
|
|
|
|
|
|
|
return newModule;
|
|
|
|
}
|
|
|
|
|
2019-04-05 07:59:10 +00:00
|
|
|
void ExecutionEngine::initQmlGlobalObject()
|
|
|
|
{
|
|
|
|
initializeGlobal();
|
|
|
|
freezeObject(*globalObject);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ExecutionEngine::initializeGlobal()
|
|
|
|
{
|
|
|
|
QV4::Scope scope(this);
|
|
|
|
|
|
|
|
QV4::ScopedObject qt(scope, memoryManager->allocate<QV4::QtObject>(qmlEngine()));
|
|
|
|
globalObject->defineDefaultProperty(QStringLiteral("Qt"), qt);
|
|
|
|
|
2020-01-22 12:37:48 +00:00
|
|
|
QV4::GlobalExtensions::init(globalObject, QJSEngine::AllExtensions);
|
|
|
|
|
2019-04-05 07:59:10 +00:00
|
|
|
#if QT_CONFIG(qml_locale)
|
|
|
|
QQmlLocale::registerStringLocaleCompare(this);
|
|
|
|
QQmlDateExtension::registerExtension(this);
|
|
|
|
QQmlNumberExtension::registerExtension(this);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if QT_CONFIG(qml_xml_http_request)
|
|
|
|
qt_add_domexceptions(this);
|
|
|
|
m_xmlHttpRequestData = qt_add_qmlxmlhttprequest(this);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
qt_add_sqlexceptions(this);
|
|
|
|
|
|
|
|
{
|
|
|
|
for (uint i = 0; i < globalObject->internalClass()->size; ++i) {
|
|
|
|
if (globalObject->internalClass()->nameMap.at(i).isString()) {
|
|
|
|
QV4::PropertyKey id = globalObject->internalClass()->nameMap.at(i);
|
|
|
|
m_illegalNames.insert(id.toQString());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const QSet<QString> &ExecutionEngine::illegalNames() const
|
|
|
|
{
|
|
|
|
return m_illegalNames;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ExecutionEngine::setQmlEngine(QQmlEngine *engine)
|
|
|
|
{
|
|
|
|
m_qmlEngine = engine;
|
|
|
|
initQmlGlobalObject();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void freeze_recursive(QV4::ExecutionEngine *v4, QV4::Object *object)
|
|
|
|
{
|
Clean up frozen(), sealed(), nonExtensible() and propertiesFrozen()
They all had some interesting bugs and duplicated each other:
a, propertiesFrozen() changed each property individually, creating a lot
of unnecessary intermediate classes. frozen() changed them all at once.
b, If a class happened to contain only properties that matched the
characteristics of being "sealed" or "frozen", sealed(), frozen() and
propertiesFrozen() would set the flags in place and return the same
class. This is bad because it violates the assumption that an
InternalClass is immutable and it breaks the recursive freezing
algorithm we rely on for the global object. It would stop freezing child
objects at any such class, even if the children were not frozen.
c, propertiesFrozen() did not set any of the flags even though it
effectively sealed and froze the class. Therefore, when requesting the
same class as frozen() it would iterate through all the properties
again.
d, frozen() implicitly also sealed the object and made it
non-extensible. sealed() also implicitly made it non-extensible. This is
impractical as we want to allow objects to be extensible even though all
their properties are frozen. Therefore we only set the flag that belongs
to each method now. We do know, however, that a frozen object is
implicitly sealed. Therefore we can short-circuit this transition.
Furthermore, we need to remove the assert in InternalClass::init() as
you can indeed use frozen objects as prototypes for others, but that
needs to be recorded in the original InternalClass via the isUsedAsProto
flag. In order to set this flag, we need to perform a transition and
therefore, derive from the old InternalClass.
The JavaScript isFrozen() method asks for an _implicitly_, "duck typed",
frozen state, which is different from what our "isFrozen" flag denotes.
Therefore we add a separate const method that just checks whether all
properties are frozen.
Task-number: QTBUG-76033
Change-Id: I375fef83fb99035d470490fdf2348766b090831e
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
2019-05-28 13:13:05 +00:00
|
|
|
if (object->as<QV4::QObjectWrapper>() || object->internalClass()->isFrozen)
|
2019-04-05 07:59:10 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
QV4::Scope scope(v4);
|
|
|
|
|
|
|
|
bool instanceOfObject = false;
|
|
|
|
QV4::ScopedObject p(scope, object->getPrototypeOf());
|
|
|
|
while (p) {
|
|
|
|
if (p->d() == v4->objectPrototype()->d()) {
|
|
|
|
instanceOfObject = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
p = p->getPrototypeOf();
|
|
|
|
}
|
|
|
|
if (!instanceOfObject)
|
|
|
|
return;
|
|
|
|
|
Clean up frozen(), sealed(), nonExtensible() and propertiesFrozen()
They all had some interesting bugs and duplicated each other:
a, propertiesFrozen() changed each property individually, creating a lot
of unnecessary intermediate classes. frozen() changed them all at once.
b, If a class happened to contain only properties that matched the
characteristics of being "sealed" or "frozen", sealed(), frozen() and
propertiesFrozen() would set the flags in place and return the same
class. This is bad because it violates the assumption that an
InternalClass is immutable and it breaks the recursive freezing
algorithm we rely on for the global object. It would stop freezing child
objects at any such class, even if the children were not frozen.
c, propertiesFrozen() did not set any of the flags even though it
effectively sealed and froze the class. Therefore, when requesting the
same class as frozen() it would iterate through all the properties
again.
d, frozen() implicitly also sealed the object and made it
non-extensible. sealed() also implicitly made it non-extensible. This is
impractical as we want to allow objects to be extensible even though all
their properties are frozen. Therefore we only set the flag that belongs
to each method now. We do know, however, that a frozen object is
implicitly sealed. Therefore we can short-circuit this transition.
Furthermore, we need to remove the assert in InternalClass::init() as
you can indeed use frozen objects as prototypes for others, but that
needs to be recorded in the original InternalClass via the isUsedAsProto
flag. In order to set this flag, we need to perform a transition and
therefore, derive from the old InternalClass.
The JavaScript isFrozen() method asks for an _implicitly_, "duck typed",
frozen state, which is different from what our "isFrozen" flag denotes.
Therefore we add a separate const method that just checks whether all
properties are frozen.
Task-number: QTBUG-76033
Change-Id: I375fef83fb99035d470490fdf2348766b090831e
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
2019-05-28 13:13:05 +00:00
|
|
|
Heap::InternalClass *frozen = object->internalClass()->frozen();
|
|
|
|
object->setInternalClass(frozen); // Immediately assign frozen to prevent it from getting GC'd
|
2019-04-05 07:59:10 +00:00
|
|
|
|
|
|
|
QV4::ScopedObject o(scope);
|
|
|
|
for (uint i = 0; i < frozen->size; ++i) {
|
|
|
|
if (!frozen->nameMap.at(i).isStringOrSymbol())
|
|
|
|
continue;
|
|
|
|
o = *object->propertyData(i);
|
|
|
|
if (o)
|
|
|
|
freeze_recursive(v4, o);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ExecutionEngine::freezeObject(const QV4::Value &value)
|
|
|
|
{
|
|
|
|
QV4::Scope scope(this);
|
|
|
|
QV4::ScopedObject o(scope, value);
|
|
|
|
freeze_recursive(this, o);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ExecutionEngine::startTimer(const QString &timerName)
|
|
|
|
{
|
|
|
|
if (!m_time.isValid())
|
|
|
|
m_time.start();
|
|
|
|
m_startedTimers[timerName] = m_time.elapsed();
|
|
|
|
}
|
|
|
|
|
|
|
|
qint64 ExecutionEngine::stopTimer(const QString &timerName, bool *wasRunning)
|
|
|
|
{
|
|
|
|
if (!m_startedTimers.contains(timerName)) {
|
|
|
|
*wasRunning = false;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
*wasRunning = true;
|
|
|
|
qint64 startedAt = m_startedTimers.take(timerName);
|
|
|
|
return m_time.elapsed() - startedAt;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ExecutionEngine::consoleCountHelper(const QString &file, quint16 line, quint16 column)
|
|
|
|
{
|
|
|
|
const QString key = file + QString::number(line) + QString::number(column);
|
|
|
|
int number = m_consoleCount.value(key, 0);
|
|
|
|
number++;
|
|
|
|
m_consoleCount.insert(key, number);
|
|
|
|
return number;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ExecutionEngine::setExtensionData(int index, Deletable *data)
|
|
|
|
{
|
|
|
|
if (m_extensionData.count() <= index)
|
|
|
|
m_extensionData.resize(index + 1);
|
|
|
|
|
|
|
|
if (m_extensionData.at(index))
|
|
|
|
delete m_extensionData.at(index);
|
|
|
|
|
|
|
|
m_extensionData[index] = data;
|
|
|
|
}
|
|
|
|
|
2015-01-02 13:37:26 +00:00
|
|
|
// Converts a JS value to a meta-type.
|
|
|
|
// data must point to a place that can store a value of the given type.
|
|
|
|
// Returns true if conversion succeeded, false otherwise.
|
2015-04-26 20:58:49 +00:00
|
|
|
bool ExecutionEngine::metaTypeFromJS(const Value *value, int type, void *data)
|
2015-01-02 13:37:26 +00:00
|
|
|
{
|
|
|
|
// check if it's one of the types we know
|
|
|
|
switch (QMetaType::Type(type)) {
|
|
|
|
case QMetaType::Bool:
|
2015-04-26 20:58:49 +00:00
|
|
|
*reinterpret_cast<bool*>(data) = value->toBoolean();
|
2015-01-02 13:37:26 +00:00
|
|
|
return true;
|
|
|
|
case QMetaType::Int:
|
2015-04-26 20:58:49 +00:00
|
|
|
*reinterpret_cast<int*>(data) = value->toInt32();
|
2015-01-02 13:37:26 +00:00
|
|
|
return true;
|
|
|
|
case QMetaType::UInt:
|
2015-04-26 20:58:49 +00:00
|
|
|
*reinterpret_cast<uint*>(data) = value->toUInt32();
|
2015-01-02 13:37:26 +00:00
|
|
|
return true;
|
|
|
|
case QMetaType::LongLong:
|
2015-04-26 20:58:49 +00:00
|
|
|
*reinterpret_cast<qlonglong*>(data) = qlonglong(value->toInteger());
|
2015-01-02 13:37:26 +00:00
|
|
|
return true;
|
|
|
|
case QMetaType::ULongLong:
|
2015-04-26 20:58:49 +00:00
|
|
|
*reinterpret_cast<qulonglong*>(data) = qulonglong(value->toInteger());
|
2015-01-02 13:37:26 +00:00
|
|
|
return true;
|
|
|
|
case QMetaType::Double:
|
2015-04-26 20:58:49 +00:00
|
|
|
*reinterpret_cast<double*>(data) = value->toNumber();
|
2015-01-02 13:37:26 +00:00
|
|
|
return true;
|
|
|
|
case QMetaType::QString:
|
2015-04-26 20:58:49 +00:00
|
|
|
if (value->isUndefined() || value->isNull())
|
2015-01-02 13:37:26 +00:00
|
|
|
*reinterpret_cast<QString*>(data) = QString();
|
|
|
|
else
|
2015-04-26 20:58:49 +00:00
|
|
|
*reinterpret_cast<QString*>(data) = value->toQString();
|
2015-01-02 13:37:26 +00:00
|
|
|
return true;
|
2015-12-28 12:22:29 +00:00
|
|
|
case QMetaType::QByteArray:
|
|
|
|
if (const ArrayBuffer *ab = value->as<ArrayBuffer>())
|
|
|
|
*reinterpret_cast<QByteArray*>(data) = ab->asByteArray();
|
|
|
|
else
|
|
|
|
*reinterpret_cast<QByteArray*>(data) = QByteArray();
|
|
|
|
return true;
|
2015-01-02 13:37:26 +00:00
|
|
|
case QMetaType::Float:
|
2015-04-26 20:58:49 +00:00
|
|
|
*reinterpret_cast<float*>(data) = value->toNumber();
|
2015-01-02 13:37:26 +00:00
|
|
|
return true;
|
|
|
|
case QMetaType::Short:
|
2015-04-26 20:58:49 +00:00
|
|
|
*reinterpret_cast<short*>(data) = short(value->toInt32());
|
2015-01-02 13:37:26 +00:00
|
|
|
return true;
|
|
|
|
case QMetaType::UShort:
|
2015-04-26 20:58:49 +00:00
|
|
|
*reinterpret_cast<unsigned short*>(data) = value->toUInt16();
|
2015-01-02 13:37:26 +00:00
|
|
|
return true;
|
|
|
|
case QMetaType::Char:
|
2015-04-26 20:58:49 +00:00
|
|
|
*reinterpret_cast<char*>(data) = char(value->toInt32());
|
2015-01-02 13:37:26 +00:00
|
|
|
return true;
|
|
|
|
case QMetaType::UChar:
|
2015-04-26 20:58:49 +00:00
|
|
|
*reinterpret_cast<unsigned char*>(data) = (unsigned char)(value->toInt32());
|
2015-01-02 13:37:26 +00:00
|
|
|
return true;
|
|
|
|
case QMetaType::QChar:
|
2016-11-24 15:05:14 +00:00
|
|
|
if (String *s = value->stringValue()) {
|
|
|
|
QString str = s->toQString();
|
2015-01-02 13:37:26 +00:00
|
|
|
*reinterpret_cast<QChar*>(data) = str.isEmpty() ? QChar() : str.at(0);
|
|
|
|
} else {
|
2015-04-26 20:58:49 +00:00
|
|
|
*reinterpret_cast<QChar*>(data) = QChar(ushort(value->toUInt16()));
|
2015-01-02 13:37:26 +00:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
case QMetaType::QDateTime:
|
2015-04-26 20:58:49 +00:00
|
|
|
if (const QV4::DateObject *d = value->as<DateObject>()) {
|
2015-01-02 13:37:26 +00:00
|
|
|
*reinterpret_cast<QDateTime *>(data) = d->toQDateTime();
|
|
|
|
return true;
|
|
|
|
} break;
|
|
|
|
case QMetaType::QDate:
|
2015-04-26 20:58:49 +00:00
|
|
|
if (const QV4::DateObject *d = value->as<DateObject>()) {
|
2015-01-02 13:37:26 +00:00
|
|
|
*reinterpret_cast<QDate *>(data) = d->toQDateTime().date();
|
|
|
|
return true;
|
|
|
|
} break;
|
|
|
|
case QMetaType::QRegExp:
|
2015-04-26 20:58:49 +00:00
|
|
|
if (const QV4::RegExpObject *r = value->as<QV4::RegExpObject>()) {
|
2015-01-02 13:37:26 +00:00
|
|
|
*reinterpret_cast<QRegExp *>(data) = r->toQRegExp();
|
|
|
|
return true;
|
|
|
|
} break;
|
2019-02-13 14:54:14 +00:00
|
|
|
#if QT_CONFIG(regularexpression)
|
|
|
|
case QMetaType::QRegularExpression:
|
|
|
|
if (const QV4::RegExpObject *r = value->as<QV4::RegExpObject>()) {
|
|
|
|
*reinterpret_cast<QRegularExpression *>(data) = r->toQRegularExpression();
|
|
|
|
return true;
|
|
|
|
} break;
|
|
|
|
#endif
|
2015-01-02 13:37:26 +00:00
|
|
|
case QMetaType::QObjectStar: {
|
2015-04-26 20:58:49 +00:00
|
|
|
const QV4::QObjectWrapper *qobjectWrapper = value->as<QV4::QObjectWrapper>();
|
|
|
|
if (qobjectWrapper || value->isNull()) {
|
|
|
|
*reinterpret_cast<QObject* *>(data) = qtObjectFromJS(this, *value);
|
2015-01-02 13:37:26 +00:00
|
|
|
return true;
|
|
|
|
} break;
|
|
|
|
}
|
|
|
|
case QMetaType::QStringList: {
|
2015-04-26 20:58:49 +00:00
|
|
|
const QV4::ArrayObject *a = value->as<QV4::ArrayObject>();
|
2015-01-02 13:37:26 +00:00
|
|
|
if (a) {
|
|
|
|
*reinterpret_cast<QStringList *>(data) = a->toQStringList();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case QMetaType::QVariantList: {
|
2015-04-26 20:58:49 +00:00
|
|
|
const QV4::ArrayObject *a = value->as<QV4::ArrayObject>();
|
2015-01-02 13:37:26 +00:00
|
|
|
if (a) {
|
2015-04-26 20:58:49 +00:00
|
|
|
*reinterpret_cast<QVariantList *>(data) = toVariant(*a, /*typeHint*/-1, /*createJSValueForObjects*/false).toList();
|
2015-01-02 13:37:26 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case QMetaType::QVariantMap: {
|
2015-04-26 20:58:49 +00:00
|
|
|
const QV4::Object *o = value->as<QV4::Object>();
|
2015-01-02 13:37:26 +00:00
|
|
|
if (o) {
|
|
|
|
*reinterpret_cast<QVariantMap *>(data) = variantMapFromJS(o);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case QMetaType::QVariant:
|
2015-04-26 20:58:49 +00:00
|
|
|
*reinterpret_cast<QVariant*>(data) = toVariant(*value, /*typeHint*/-1, /*createJSValueForObjects*/false);
|
2015-01-02 13:37:26 +00:00
|
|
|
return true;
|
|
|
|
case QMetaType::QJsonValue:
|
2015-04-26 20:58:49 +00:00
|
|
|
*reinterpret_cast<QJsonValue *>(data) = QV4::JsonObject::toJsonValue(*value);
|
2015-01-02 13:37:26 +00:00
|
|
|
return true;
|
|
|
|
case QMetaType::QJsonObject: {
|
2015-04-26 20:58:49 +00:00
|
|
|
*reinterpret_cast<QJsonObject *>(data) = QV4::JsonObject::toJsonObject(value->as<Object>());
|
2015-01-02 13:37:26 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case QMetaType::QJsonArray: {
|
2015-04-26 20:58:49 +00:00
|
|
|
const QV4::ArrayObject *a = value->as<ArrayObject>();
|
2015-01-02 13:37:26 +00:00
|
|
|
if (a) {
|
2015-04-26 20:58:49 +00:00
|
|
|
*reinterpret_cast<QJsonArray *>(data) = JsonObject::toJsonArray(a);
|
2015-01-02 13:37:26 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
;
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
2015-04-26 20:58:49 +00:00
|
|
|
const QQmlValueTypeWrapper *vtw = value->as<QQmlValueTypeWrapper>();
|
2015-04-10 10:34:46 +00:00
|
|
|
if (vtw && vtw->typeId() == type) {
|
|
|
|
return vtw->toGadget(data);
|
2015-01-02 13:37:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
if (isQtVariant(value)) {
|
|
|
|
const QVariant &var = variantValue(value);
|
|
|
|
// ### Enable once constructInPlace() is in qt master.
|
|
|
|
if (var.userType() == type) {
|
|
|
|
QMetaType::constructInPlace(type, data, var.constData());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (var.canConvert(type)) {
|
|
|
|
QVariant vv = var;
|
|
|
|
vv.convert(type);
|
|
|
|
Q_ASSERT(vv.userType() == type);
|
|
|
|
QMetaType::constructInPlace(type, data, vv.constData());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2015-02-13 09:02:28 +00:00
|
|
|
// Try to use magic; for compatibility with qjsvalue_cast.
|
2015-01-02 13:37:26 +00:00
|
|
|
|
|
|
|
QByteArray name = QMetaType::typeName(type);
|
2015-04-26 20:58:49 +00:00
|
|
|
if (convertToNativeQObject(this, *value, name, reinterpret_cast<void* *>(data)))
|
2015-01-02 13:37:26 +00:00
|
|
|
return true;
|
2015-04-26 20:58:49 +00:00
|
|
|
if (value->as<QV4::VariantObject>() && name.endsWith('*')) {
|
2015-01-02 13:37:26 +00:00
|
|
|
int valueType = QMetaType::type(name.left(name.size()-1));
|
2016-10-05 10:18:20 +00:00
|
|
|
QVariant &var = value->as<QV4::VariantObject>()->d()->data();
|
2015-01-02 13:37:26 +00:00
|
|
|
if (valueType == var.userType()) {
|
|
|
|
// We have T t, T* is requested, so return &t.
|
|
|
|
*reinterpret_cast<void* *>(data) = var.data();
|
|
|
|
return true;
|
2016-11-25 09:27:02 +00:00
|
|
|
} else if (Object *o = value->objectValue()) {
|
2015-01-02 13:37:26 +00:00
|
|
|
// Look in the prototype chain.
|
2015-04-26 20:58:49 +00:00
|
|
|
QV4::Scope scope(this);
|
2018-06-19 11:28:26 +00:00
|
|
|
QV4::ScopedObject proto(scope, o->getPrototypeOf());
|
2015-01-02 13:37:26 +00:00
|
|
|
while (proto) {
|
|
|
|
bool canCast = false;
|
|
|
|
if (QV4::VariantObject *vo = proto->as<QV4::VariantObject>()) {
|
2016-10-05 10:18:20 +00:00
|
|
|
const QVariant &v = vo->d()->data();
|
2015-01-02 13:37:26 +00:00
|
|
|
canCast = (type == v.userType()) || (valueType && (valueType == v.userType()));
|
|
|
|
}
|
|
|
|
else if (proto->as<QV4::QObjectWrapper>()) {
|
|
|
|
QByteArray className = name.left(name.size()-1);
|
|
|
|
QV4::ScopedObject p(scope, proto.getPointer());
|
2015-04-26 20:58:49 +00:00
|
|
|
if (QObject *qobject = qtObjectFromJS(this, p))
|
2018-02-21 09:41:54 +00:00
|
|
|
canCast = qobject->qt_metacast(className) != nullptr;
|
2015-01-02 13:37:26 +00:00
|
|
|
}
|
|
|
|
if (canCast) {
|
|
|
|
QByteArray varTypeName = QMetaType::typeName(var.userType());
|
|
|
|
if (varTypeName.endsWith('*'))
|
|
|
|
*reinterpret_cast<void* *>(data) = *reinterpret_cast<void* *>(var.data());
|
|
|
|
else
|
|
|
|
*reinterpret_cast<void* *>(data) = var.data();
|
|
|
|
return true;
|
|
|
|
}
|
2018-06-19 11:28:26 +00:00
|
|
|
proto = proto->getPrototypeOf();
|
2015-01-02 13:37:26 +00:00
|
|
|
}
|
|
|
|
}
|
2015-04-26 20:58:49 +00:00
|
|
|
} else if (value->isNull() && name.endsWith('*')) {
|
2018-02-21 09:41:54 +00:00
|
|
|
*reinterpret_cast<void* *>(data) = nullptr;
|
2015-01-02 13:37:26 +00:00
|
|
|
return true;
|
|
|
|
} else if (type == qMetaTypeId<QJSValue>()) {
|
2015-04-26 20:58:49 +00:00
|
|
|
*reinterpret_cast<QJSValue*>(data) = QJSValue(this, value->asReturnedValue());
|
2015-01-02 13:37:26 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-01-26 10:46:16 +00:00
|
|
|
static bool convertToNativeQObject(QV4::ExecutionEngine *e, const QV4::Value &value, const QByteArray &targetType, void **result)
|
2015-01-02 13:37:26 +00:00
|
|
|
{
|
|
|
|
if (!targetType.endsWith('*'))
|
|
|
|
return false;
|
|
|
|
if (QObject *qobject = qtObjectFromJS(e, value)) {
|
|
|
|
int start = targetType.startsWith("const ") ? 6 : 0;
|
|
|
|
QByteArray className = targetType.mid(start, targetType.size()-start-1);
|
|
|
|
if (void *instance = qobject->qt_metacast(className)) {
|
|
|
|
*result = instance;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-01-26 10:46:16 +00:00
|
|
|
static QObject *qtObjectFromJS(QV4::ExecutionEngine *engine, const QV4::Value &value)
|
2015-01-02 13:37:26 +00:00
|
|
|
{
|
2015-01-15 10:36:57 +00:00
|
|
|
if (!value.isObject())
|
2018-02-21 09:41:54 +00:00
|
|
|
return nullptr;
|
2015-01-02 13:37:26 +00:00
|
|
|
|
|
|
|
QV4::Scope scope(engine);
|
|
|
|
QV4::Scoped<QV4::VariantObject> v(scope, value);
|
|
|
|
|
|
|
|
if (v) {
|
2016-10-05 10:18:20 +00:00
|
|
|
QVariant variant = v->d()->data();
|
2015-01-02 13:37:26 +00:00
|
|
|
int type = variant.userType();
|
|
|
|
if (type == QMetaType::QObjectStar)
|
|
|
|
return *reinterpret_cast<QObject* const *>(variant.constData());
|
|
|
|
}
|
|
|
|
QV4::Scoped<QV4::QObjectWrapper> wrapper(scope, value);
|
|
|
|
if (!wrapper)
|
2018-02-21 09:41:54 +00:00
|
|
|
return nullptr;
|
2015-01-02 13:37:26 +00:00
|
|
|
return wrapper->object();
|
|
|
|
}
|
|
|
|
|
2019-04-05 07:59:10 +00:00
|
|
|
struct QV4EngineRegistrationData
|
|
|
|
{
|
|
|
|
QV4EngineRegistrationData() : extensionCount(0) {}
|
|
|
|
|
|
|
|
QMutex mutex;
|
|
|
|
int extensionCount;
|
|
|
|
};
|
|
|
|
Q_GLOBAL_STATIC(QV4EngineRegistrationData, registrationData);
|
|
|
|
|
|
|
|
QMutex *ExecutionEngine::registrationMutex()
|
|
|
|
{
|
|
|
|
return ®istrationData()->mutex;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ExecutionEngine::registerExtension()
|
|
|
|
{
|
|
|
|
return registrationData()->extensionCount++;
|
|
|
|
}
|
|
|
|
|
2020-01-03 09:32:01 +00:00
|
|
|
QNetworkAccessManager *QV4::detail::getNetworkAccessManager(ExecutionEngine *engine)
|
|
|
|
{
|
|
|
|
return engine->qmlEngine()->networkAccessManager();
|
|
|
|
}
|
|
|
|
|
2013-06-24 13:28:00 +00:00
|
|
|
QT_END_NAMESPACE
|