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>
|
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>
|
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>
|
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"
|
2013-05-21 15:06:36 +00:00
|
|
|
#include "qv4sequenceobject_p.h"
|
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"
|
2014-09-11 13:37:31 +00:00
|
|
|
#include "qv4typedarray_p.h"
|
2014-12-30 14:31:09 +00:00
|
|
|
#include <private/qv8engine_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>
|
|
|
|
#include <private/qqmllocale_p.h>
|
2013-05-28 07:36:04 +00:00
|
|
|
|
2013-12-20 14:38:37 +00:00
|
|
|
#include <QtCore/QTextStream>
|
2014-06-13 12:30:03 +00:00
|
|
|
#include <QDateTime>
|
2013-12-20 14:38:37 +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
|
|
|
|
|
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-08-04 16:53:51 +00:00
|
|
|
ReturnedValue throwTypeError(const BuiltinFunction *b, CallData *)
|
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
|
|
|
}
|
|
|
|
|
2013-11-11 10:22:24 +00:00
|
|
|
|
2016-03-23 12:17:10 +00:00
|
|
|
#ifdef V4_BOOTSTRAP
|
2014-12-30 14:31:09 +00:00
|
|
|
QJSEngine *ExecutionEngine::jsEngine() const
|
|
|
|
{
|
|
|
|
return v8Engine->publicEngine();
|
|
|
|
}
|
|
|
|
|
2014-12-30 15:38:20 +00:00
|
|
|
QQmlEngine *ExecutionEngine::qmlEngine() const
|
|
|
|
{
|
|
|
|
return v8Engine->engine();
|
|
|
|
}
|
2016-03-23 12:17:10 +00:00
|
|
|
#endif // V4_BOOTSTRAP
|
2014-12-30 15:38:20 +00:00
|
|
|
|
2016-04-25 13:01:04 +00:00
|
|
|
qint32 ExecutionEngine::maxCallDepth = -1;
|
2014-12-30 15:38:20 +00:00
|
|
|
|
2017-06-22 07:44:55 +00:00
|
|
|
ExecutionEngine::ExecutionEngine()
|
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)
|
2013-01-28 15:46:09 +00:00
|
|
|
, globalCode(0)
|
2013-11-29 13:26:52 +00:00
|
|
|
, v8Engine(0)
|
2014-03-10 14:18:54 +00:00
|
|
|
, argumentsAccessors(0)
|
|
|
|
, nArgumentsAccessors(0)
|
2013-06-04 08:05:51 +00:00
|
|
|
, m_engineId(engineSerial.fetchAndAddOrdered(1))
|
2013-03-30 16:43:03 +00:00
|
|
|
, regExpCache(0)
|
2013-06-04 12:28:13 +00:00
|
|
|
, m_multiplyWrappedQObjects(0)
|
2012-11-17 20:54:26 +00:00
|
|
|
{
|
2017-03-15 08:25:52 +00:00
|
|
|
memoryManager = new QV4::MemoryManager(this);
|
|
|
|
|
2016-04-25 13:01:04 +00:00
|
|
|
if (maxCallDepth == -1) {
|
|
|
|
bool ok = false;
|
|
|
|
maxCallDepth = qEnvironmentVariableIntValue("QV4_MAX_CALL_DEPTH", &ok);
|
|
|
|
if (!ok || maxCallDepth <= 0) {
|
2017-06-29 10:17:43 +00:00
|
|
|
#ifdef QT_NO_DEBUG
|
2016-04-25 13:01:04 +00:00
|
|
|
maxCallDepth = 1234;
|
2017-06-29 10:17:43 +00:00
|
|
|
#else
|
|
|
|
// no (tail call) optimization is done, so there'll be a lot mare stack frames active
|
|
|
|
maxCallDepth = 200;
|
|
|
|
#endif
|
2016-04-25 13:01:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
Q_ASSERT(maxCallDepth > 0);
|
|
|
|
|
2013-11-11 10:22:24 +00:00
|
|
|
// reserve space for the JS stack
|
2017-03-09 09:36:16 +00:00
|
|
|
// we allow it to grow to a bit more than JSStackLimit, as we can overshoot due to ScopedValues
|
|
|
|
// allocated outside of JIT'ed methods.
|
|
|
|
*jsStack = WTF::PageAllocation::allocate(JSStackLimit + 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
|
2017-03-09 09:36:16 +00:00
|
|
|
VALGRIND_MAKE_MEM_UNDEFINED(jsStackBase, JSStackLimit + 256*1024);
|
2016-05-26 15:22:34 +00:00
|
|
|
#endif
|
|
|
|
|
2013-09-03 10:40:07 +00:00
|
|
|
jsStackTop = jsStackBase;
|
|
|
|
|
2017-03-09 09:36:16 +00:00
|
|
|
*gcStack = WTF::PageAllocation::allocate(GCStackLimit, WTF::OSAllocator::JSVMStackPages,
|
|
|
|
/* writable */ true, /* executable */ false,
|
|
|
|
/* includesGuardPages */ true);
|
|
|
|
|
2015-03-13 16:21:18 +00:00
|
|
|
exceptionValue = jsAlloca(1);
|
|
|
|
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);
|
2015-03-13 16:21:18 +00:00
|
|
|
|
2013-11-11 10:22:24 +00:00
|
|
|
// set up stack limits
|
2014-01-24 21:55:39 +00:00
|
|
|
jsStackLimit = jsStackBase + JSStackLimit/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
|
|
|
|
2014-04-16 07:36:38 +00:00
|
|
|
classPool = new InternalClassPool;
|
|
|
|
|
2017-05-12 08:16:51 +00:00
|
|
|
internalClasses[Class_Empty] = new (classPool) InternalClass(this);
|
2017-05-12 08:29:23 +00:00
|
|
|
internalClasses[Class_String] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::String::staticVTable());
|
|
|
|
internalClasses[Class_MemberData] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::MemberData::staticVTable());
|
|
|
|
internalClasses[Class_SimpleArrayData] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::SimpleArrayData::staticVTable());
|
|
|
|
internalClasses[Class_SparseArrayData] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::SparseArrayData::staticVTable());
|
2017-05-12 13:12:45 +00:00
|
|
|
internalClasses[Class_ExecutionContext] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::ExecutionContext::staticVTable());
|
2017-07-04 20:23:17 +00:00
|
|
|
internalClasses[Class_CallContext] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::CallContext::staticVTable());
|
2013-05-12 13:00:48 +00:00
|
|
|
|
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"));
|
|
|
|
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"));
|
|
|
|
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"));
|
2012-11-17 20:54:26 +00:00
|
|
|
|
2017-05-15 07:56:05 +00:00
|
|
|
InternalClass *ic = internalClasses[Class_Empty]->changeVTable(QV4::Object::staticVTable());
|
|
|
|
jsObjects[ObjectProto] = memoryManager->allocObject<ObjectPrototype>(ic);
|
|
|
|
internalClasses[Class_Object] = ic->changePrototype(objectPrototype()->d());
|
2014-03-31 13:48:02 +00:00
|
|
|
|
2017-05-15 07:56:05 +00:00
|
|
|
ic = newInternalClass(ArrayPrototype::staticVTable(), objectPrototype());
|
|
|
|
Q_ASSERT(ic->prototype);
|
|
|
|
ic = ic->addMember(id_length(), Attr_NotConfigurable|Attr_NotEnumerable);
|
|
|
|
Q_ASSERT(ic->prototype);
|
|
|
|
jsObjects[ArrayProto] = memoryManager->allocObject<ArrayPrototype>(ic, objectPrototype());
|
|
|
|
internalClasses[Class_ArrayObject] = ic->changePrototype(arrayPrototype()->d());
|
2017-02-20 12:27:22 +00:00
|
|
|
jsObjects[PropertyListProto] = memoryManager->allocObject<PropertyListPrototype>();
|
2013-08-29 12:31:32 +00:00
|
|
|
|
2017-05-15 07:56:05 +00:00
|
|
|
InternalClass *argsClass = newInternalClass(ArgumentsObject::staticVTable(), objectPrototype());
|
|
|
|
argsClass = argsClass->addMember(id_length(), Attr_NotEnumerable);
|
2017-05-12 08:16:51 +00:00
|
|
|
internalClasses[EngineBase::Class_ArgumentsObject] = argsClass->addMember(id_callee(), Attr_Data|Attr_NotEnumerable);
|
|
|
|
argsClass = argsClass->addMember(id_callee(), Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
|
|
|
|
internalClasses[EngineBase::Class_StrictArgumentsObject] = argsClass->addMember(id_caller(), 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());
|
|
|
|
ic = ic->addMember(id_length(), Attr_ReadOnly);
|
|
|
|
jsObjects[StringProto] = memoryManager->allocObject<StringPrototype>(ic);
|
|
|
|
internalClasses[Class_StringObject] = ic->changePrototype(stringPrototype()->d());
|
2017-05-12 08:16:51 +00:00
|
|
|
Q_ASSERT(internalClasses[EngineBase::Class_StringObject]->find(id_length()) == Heap::StringObject::LengthPropertyIndex);
|
2017-05-15 07:56:05 +00:00
|
|
|
|
2017-05-12 13:12:45 +00:00
|
|
|
jsObjects[NumberProto] = memoryManager->allocObject<NumberPrototype>();
|
|
|
|
jsObjects[BooleanProto] = memoryManager->allocObject<BooleanPrototype>();
|
|
|
|
jsObjects[DateProto] = memoryManager->allocObject<DatePrototype>();
|
2013-08-29 19:23:04 +00:00
|
|
|
|
2013-09-01 19:22:57 +00:00
|
|
|
uint index;
|
2017-05-15 07:56:05 +00:00
|
|
|
ic = newInternalClass(QV4::FunctionPrototype::staticVTable(), objectPrototype());
|
|
|
|
ic = ic->addMember(id_prototype(), Attr_NotEnumerable, &index);
|
2014-11-03 02:17:57 +00:00
|
|
|
Q_ASSERT(index == Heap::FunctionObject::Index_Prototype);
|
2017-05-15 07:56:05 +00:00
|
|
|
jsObjects[FunctionProto] = memoryManager->allocObject<FunctionPrototype>(ic, objectPrototype());
|
|
|
|
ic = newInternalClass(FunctionObject::staticVTable(), functionPrototype());
|
|
|
|
ic = ic->addMember(id_prototype(), Attr_NotEnumerable|Attr_NotConfigurable, &index);
|
2014-11-03 02:17:57 +00:00
|
|
|
Q_ASSERT(index == Heap::FunctionObject::Index_Prototype);
|
2017-05-15 07:56:05 +00:00
|
|
|
internalClasses[EngineBase::Class_FunctionObject] = ic;
|
|
|
|
ic = ic->addMember(id_name(), Attr_ReadOnly, &index);
|
2016-12-09 09:47:57 +00:00
|
|
|
Q_ASSERT(index == Heap::ScriptFunction::Index_Name);
|
2017-05-15 07:56:05 +00:00
|
|
|
ic = ic->changeVTable(ScriptFunction::staticVTable());
|
|
|
|
internalClasses[EngineBase::Class_ScriptFunction] = ic->addMember(id_length(), Attr_ReadOnly, &index);
|
|
|
|
Q_ASSERT(index == Heap::ScriptFunction::Index_Length);
|
|
|
|
internalClasses[EngineBase::Class_BuiltinFunction] = ic->changeVTable(BuiltinFunction::staticVTable());
|
2016-12-09 09:47:57 +00:00
|
|
|
Q_ASSERT(index == Heap::ScriptFunction::Index_Length);
|
2017-05-12 08:16:51 +00:00
|
|
|
internalClasses[EngineBase::Class_ObjectProto] = internalClasses[Class_Object]->addMember(id_constructor(), Attr_NotEnumerable, &index);
|
2014-11-03 02:17:57 +00:00
|
|
|
Q_ASSERT(index == Heap::FunctionObject::Index_ProtoConstructor);
|
2013-08-29 19:23:04 +00:00
|
|
|
|
2015-08-27 12:38:24 +00:00
|
|
|
Scope scope(this);
|
|
|
|
ScopedString str(scope);
|
2017-05-12 13:12:45 +00:00
|
|
|
internalClasses[Class_RegExp] = internalClasses[EngineBase::Class_Empty]->changeVTable(QV4::RegExp::staticVTable());
|
2017-05-15 07:56:05 +00:00
|
|
|
ic = newInternalClass(QV4::RegExpObject::staticVTable(), objectPrototype());
|
|
|
|
ic = ic->addMember(id_lastIndex(), Attr_NotEnumerable|Attr_NotConfigurable, &index);
|
2015-08-27 12:38:24 +00:00
|
|
|
Q_ASSERT(index == RegExpObject::Index_LastIndex);
|
2017-05-15 07:56:05 +00:00
|
|
|
ic = ic->addMember((str = newIdentifier(QStringLiteral("source"))), Attr_ReadOnly, &index);
|
2015-08-27 12:38:24 +00:00
|
|
|
Q_ASSERT(index == RegExpObject::Index_Source);
|
2017-05-15 07:56:05 +00:00
|
|
|
ic = ic->addMember((str = newIdentifier(QStringLiteral("global"))), Attr_ReadOnly, &index);
|
2015-08-27 12:38:24 +00:00
|
|
|
Q_ASSERT(index == RegExpObject::Index_Global);
|
2017-05-15 07:56:05 +00:00
|
|
|
ic = ic->addMember((str = newIdentifier(QStringLiteral("ignoreCase"))), Attr_ReadOnly, &index);
|
2015-08-27 12:38:24 +00:00
|
|
|
Q_ASSERT(index == RegExpObject::Index_IgnoreCase);
|
2017-05-15 07:56:05 +00:00
|
|
|
ic = ic->addMember((str = newIdentifier(QStringLiteral("multiline"))), Attr_ReadOnly, &index);
|
2015-08-27 12:38:24 +00:00
|
|
|
Q_ASSERT(index == RegExpObject::Index_Multiline);
|
2017-05-15 07:56:05 +00:00
|
|
|
jsObjects[RegExpProto] = memoryManager->allocObject<RegExpPrototype>(ic, objectPrototype());
|
|
|
|
internalClasses[Class_RegExpObject] = ic->changePrototype(regExpPrototype()->d());
|
2015-08-27 12:38:24 +00:00
|
|
|
|
2017-05-15 07:56:05 +00:00
|
|
|
ic = internalClasses[Class_ArrayObject]->addMember(id_index(), Attr_Data, &index);
|
2013-09-02 12:25:15 +00:00
|
|
|
Q_ASSERT(index == RegExpObject::Index_ArrayIndex);
|
2017-05-15 07:56:05 +00:00
|
|
|
internalClasses[EngineBase::Class_RegExpExecArray] = ic->addMember(id_input(), Attr_Data, &index);
|
2013-09-02 12:25:15 +00:00
|
|
|
Q_ASSERT(index == RegExpObject::Index_ArrayInput);
|
2013-08-29 19:23:04 +00:00
|
|
|
|
2017-05-15 07:56:05 +00:00
|
|
|
ic = newInternalClass(ErrorObject::staticVTable(), 0);
|
|
|
|
ic = ic->addMember((str = newIdentifier(QStringLiteral("stack"))), Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable, &index);
|
2015-08-27 20:47:23 +00:00
|
|
|
Q_ASSERT(index == ErrorObject::Index_Stack);
|
2017-05-15 07:56:05 +00:00
|
|
|
ic = ic->addMember((str = newIdentifier(QStringLiteral("fileName"))), Attr_Data|Attr_NotEnumerable, &index);
|
2015-08-27 20:47:23 +00:00
|
|
|
Q_ASSERT(index == ErrorObject::Index_FileName);
|
2017-05-15 07:56:05 +00:00
|
|
|
ic = ic->addMember((str = newIdentifier(QStringLiteral("lineNumber"))), Attr_Data|Attr_NotEnumerable, &index);
|
|
|
|
internalClasses[EngineBase::Class_ErrorObject] = ic;
|
2015-08-27 20:47:23 +00:00
|
|
|
Q_ASSERT(index == ErrorObject::Index_LineNumber);
|
2017-05-15 07:56:05 +00:00
|
|
|
internalClasses[EngineBase::Class_ErrorObjectWithMessage] = ic->addMember((str = newIdentifier(QStringLiteral("message"))), Attr_Data|Attr_NotEnumerable, &index);
|
2015-09-01 11:46:46 +00:00
|
|
|
Q_ASSERT(index == ErrorObject::Index_Message);
|
2017-05-15 07:56:05 +00:00
|
|
|
ic = newInternalClass(ErrorObject::staticVTable(), objectPrototype());
|
|
|
|
ic = ic->addMember(id_constructor(), Attr_Data|Attr_NotEnumerable, &index);
|
2015-09-01 11:46:46 +00:00
|
|
|
Q_ASSERT(index == ErrorPrototype::Index_Constructor);
|
2017-05-15 07:56:05 +00:00
|
|
|
ic = ic->addMember((str = newIdentifier(QStringLiteral("message"))), Attr_Data|Attr_NotEnumerable, &index);
|
2015-09-01 11:46:46 +00:00
|
|
|
Q_ASSERT(index == ErrorPrototype::Index_Message);
|
2017-05-15 07:56:05 +00:00
|
|
|
internalClasses[EngineBase::Class_ErrorProto] = ic->addMember(id_name(), Attr_Data|Attr_NotEnumerable, &index);
|
2015-09-01 11:46:46 +00:00
|
|
|
Q_ASSERT(index == ErrorPrototype::Index_Name);
|
2015-08-27 20:47:23 +00:00
|
|
|
|
|
|
|
jsObjects[GetStack_Function] = BuiltinFunction::create(rootContext(), str = newIdentifier(QStringLiteral("stack")), ErrorObject::method_get_stack);
|
|
|
|
getStackFunction()->defineReadonlyProperty(id_length(), Primitive::fromInt32(0));
|
|
|
|
|
2017-05-12 08:16:51 +00:00
|
|
|
jsObjects[ErrorProto] = memoryManager->allocObject<ErrorPrototype>(internalClasses[EngineBase::Class_ErrorProto], objectPrototype());
|
2017-05-15 07:56:05 +00:00
|
|
|
jsObjects[EvalErrorProto] = memoryManager->allocObject<EvalErrorPrototype>(internalClasses[EngineBase::Class_ErrorProto]->changePrototype(errorPrototype()->d()), errorPrototype());
|
|
|
|
jsObjects[RangeErrorProto] = memoryManager->allocObject<RangeErrorPrototype>(internalClasses[EngineBase::Class_ErrorProto]->changePrototype(errorPrototype()->d()), errorPrototype());
|
|
|
|
jsObjects[ReferenceErrorProto] = memoryManager->allocObject<ReferenceErrorPrototype>(internalClasses[EngineBase::Class_ErrorProto]->changePrototype(errorPrototype()->d()), errorPrototype());
|
|
|
|
jsObjects[SyntaxErrorProto] = memoryManager->allocObject<SyntaxErrorPrototype>(internalClasses[EngineBase::Class_ErrorProto]->changePrototype(errorPrototype()->d()), errorPrototype());
|
|
|
|
jsObjects[TypeErrorProto] = memoryManager->allocObject<TypeErrorPrototype>(internalClasses[EngineBase::Class_ErrorProto]->changePrototype(errorPrototype()->d()), errorPrototype());
|
|
|
|
jsObjects[URIErrorProto] = memoryManager->allocObject<URIErrorPrototype>(internalClasses[EngineBase::Class_ErrorProto]->changePrototype(errorPrototype()->d()), errorPrototype());
|
2015-01-10 19:35:18 +00:00
|
|
|
|
2017-05-12 13:12:45 +00:00
|
|
|
jsObjects[VariantProto] = memoryManager->allocObject<VariantPrototype>();
|
2015-03-25 13:40:35 +00:00
|
|
|
Q_ASSERT(variantPrototype()->prototype() == objectPrototype()->d());
|
2014-11-24 14:38:41 +00:00
|
|
|
|
2017-05-15 07:56:05 +00:00
|
|
|
ic = newInternalClass(SequencePrototype::staticVTable(), SequencePrototype::defaultPrototype(this));
|
|
|
|
jsObjects[SequenceProto] = ScopedValue(scope, memoryManager->allocObject<SequencePrototype>(ic, SequencePrototype::defaultPrototype(this)));
|
2014-06-13 12:30:03 +00:00
|
|
|
|
2015-08-24 14:47:48 +00:00
|
|
|
ExecutionContext *global = rootContext();
|
2015-08-28 10:58:08 +00:00
|
|
|
jsObjects[Object_Ctor] = memoryManager->allocObject<ObjectCtor>(global);
|
|
|
|
jsObjects[String_Ctor] = memoryManager->allocObject<StringCtor>(global);
|
|
|
|
jsObjects[Number_Ctor] = memoryManager->allocObject<NumberCtor>(global);
|
|
|
|
jsObjects[Boolean_Ctor] = memoryManager->allocObject<BooleanCtor>(global);
|
|
|
|
jsObjects[Array_Ctor] = memoryManager->allocObject<ArrayCtor>(global);
|
|
|
|
jsObjects[Function_Ctor] = memoryManager->allocObject<FunctionCtor>(global);
|
|
|
|
jsObjects[Date_Ctor] = memoryManager->allocObject<DateCtor>(global);
|
|
|
|
jsObjects[RegExp_Ctor] = memoryManager->allocObject<RegExpCtor>(global);
|
|
|
|
jsObjects[Error_Ctor] = memoryManager->allocObject<ErrorCtor>(global);
|
|
|
|
jsObjects[EvalError_Ctor] = memoryManager->allocObject<EvalErrorCtor>(global);
|
|
|
|
jsObjects[RangeError_Ctor] = memoryManager->allocObject<RangeErrorCtor>(global);
|
|
|
|
jsObjects[ReferenceError_Ctor] = memoryManager->allocObject<ReferenceErrorCtor>(global);
|
|
|
|
jsObjects[SyntaxError_Ctor] = memoryManager->allocObject<SyntaxErrorCtor>(global);
|
|
|
|
jsObjects[TypeError_Ctor] = memoryManager->allocObject<TypeErrorCtor>(global);
|
|
|
|
jsObjects[URIError_Ctor] = memoryManager->allocObject<URIErrorCtor>(global);
|
2015-03-25 20:06:18 +00:00
|
|
|
|
|
|
|
static_cast<ObjectPrototype *>(objectPrototype())->init(this, objectCtor());
|
|
|
|
static_cast<StringPrototype *>(stringPrototype())->init(this, stringCtor());
|
|
|
|
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());
|
|
|
|
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());
|
2015-03-25 13:40:35 +00:00
|
|
|
|
|
|
|
static_cast<VariantPrototype *>(variantPrototype())->init();
|
|
|
|
sequencePrototype()->cast<SequencePrototype>()->init();
|
2013-05-14 00:01:04 +00:00
|
|
|
|
2014-09-10 12:50:28 +00:00
|
|
|
|
|
|
|
// typed arrays
|
|
|
|
|
2015-08-28 10:58:08 +00:00
|
|
|
jsObjects[ArrayBuffer_Ctor] = memoryManager->allocObject<ArrayBufferCtor>(global);
|
|
|
|
jsObjects[ArrayBufferProto] = memoryManager->allocObject<ArrayBufferPrototype>();
|
2015-03-25 20:06:18 +00:00
|
|
|
static_cast<ArrayBufferPrototype *>(arrayBufferPrototype())->init(this, arrayBufferCtor());
|
2014-09-10 12:50:28 +00:00
|
|
|
|
2015-08-28 10:58:08 +00:00
|
|
|
jsObjects[DataView_Ctor] = memoryManager->allocObject<DataViewCtor>(global);
|
|
|
|
jsObjects[DataViewProto] = memoryManager->allocObject<DataViewPrototype>();
|
2015-03-25 20:06:18 +00:00
|
|
|
static_cast<DataViewPrototype *>(dataViewPrototype())->init(this, dataViewCtor());
|
2015-04-26 12:24:08 +00:00
|
|
|
jsObjects[ValueTypeProto] = (Heap::Base *) 0;
|
2015-09-09 13:23:18 +00:00
|
|
|
jsObjects[SignalHandlerProto] = (Heap::Base *) 0;
|
2014-09-10 14:39:23 +00:00
|
|
|
|
2014-11-06 16:40:48 +00:00
|
|
|
for (int i = 0; i < Heap::TypedArray::NTypes; ++i) {
|
2015-08-28 10:58:08 +00:00
|
|
|
static_cast<Value &>(typedArrayCtors[i]) = memoryManager->allocObject<TypedArrayCtor>(global, Heap::TypedArray::Type(i));
|
2015-08-28 11:33:10 +00:00
|
|
|
static_cast<Value &>(typedArrayPrototype[i]) = memoryManager->allocObject<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());
|
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());
|
|
|
|
|
|
|
|
globalObject->defineDefaultProperty(QStringLiteral("ArrayBuffer"), *arrayBufferCtor());
|
|
|
|
globalObject->defineDefaultProperty(QStringLiteral("DataView"), *dataViewCtor());
|
2014-11-06 16:40:48 +00:00
|
|
|
for (int i = 0; i < Heap::TypedArray::NTypes; ++i)
|
2015-03-13 16:21:18 +00:00
|
|
|
globalObject->defineDefaultProperty((str = typedArrayCtors[i].as<FunctionObject>()->name())->toQString(), typedArrayCtors[i]);
|
2013-09-26 11:05:25 +00:00
|
|
|
ScopedObject o(scope);
|
2015-08-28 10:58:08 +00:00
|
|
|
globalObject->defineDefaultProperty(QStringLiteral("Math"), (o = memoryManager->allocObject<MathObject>()));
|
|
|
|
globalObject->defineDefaultProperty(QStringLiteral("JSON"), (o = memoryManager->allocObject<JsonObject>()));
|
2013-09-18 10:31:55 +00:00
|
|
|
|
2015-03-13 16:21:18 +00:00
|
|
|
globalObject->defineReadonlyProperty(QStringLiteral("undefined"), Primitive::undefinedValue());
|
|
|
|
globalObject->defineReadonlyProperty(QStringLiteral("NaN"), Primitive::fromDouble(std::numeric_limits<double>::quiet_NaN()));
|
|
|
|
globalObject->defineReadonlyProperty(QStringLiteral("Infinity"), Primitive::fromDouble(Q_INFINITY));
|
2012-12-12 23:53:04 +00:00
|
|
|
|
2014-05-09 10:15:23 +00:00
|
|
|
|
2015-08-28 10:58:08 +00:00
|
|
|
jsObjects[Eval_Function] = memoryManager->allocObject<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));
|
|
|
|
ExecutionContext *global = rootContext();
|
|
|
|
ScopedFunctionObject parseIntFn(scope, BuiltinFunction::create(global, pi, GlobalFunctions::method_parseInt));
|
|
|
|
ScopedFunctionObject parseFloatFn(scope, BuiltinFunction::create(global, pf, GlobalFunctions::method_parseFloat));
|
|
|
|
parseIntFn->defineReadonlyConfigurableProperty(id_length(), Primitive::fromInt32(2));
|
|
|
|
parseFloatFn->defineReadonlyConfigurableProperty(id_length(), Primitive::fromInt32(1));
|
|
|
|
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
|
|
|
|
2014-12-31 18:34:52 +00:00
|
|
|
ScopedString name(scope, newString(QStringLiteral("thrower")));
|
2015-03-25 20:31:16 +00:00
|
|
|
jsObjects[ThrowerObject] = BuiltinFunction::create(global, name, ::throwTypeError);
|
2012-11-17 20:54:26 +00:00
|
|
|
}
|
|
|
|
|
2012-12-04 10:30:26 +00:00
|
|
|
ExecutionEngine::~ExecutionEngine()
|
|
|
|
{
|
2013-06-04 12:28:13 +00:00
|
|
|
delete m_multiplyWrappedQObjects;
|
|
|
|
m_multiplyWrappedQObjects = 0;
|
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
|
|
|
|
2017-05-12 08:16:51 +00:00
|
|
|
internalClasses[Class_Empty]->destroy();
|
2014-04-16 07:36:38 +00:00
|
|
|
delete classPool;
|
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;
|
2014-03-10 14:18:54 +00:00
|
|
|
delete [] argumentsAccessors;
|
2012-12-04 10:30:26 +00:00
|
|
|
}
|
|
|
|
|
2016-07-28 08:21:06 +00:00
|
|
|
#ifndef QT_NO_QML_DEBUGGER
|
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
|
|
|
}
|
2016-07-28 08:21:06 +00:00
|
|
|
#endif // QT_NO_QML_DEBUGGER
|
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;
|
2015-08-24 13:31:46 +00:00
|
|
|
jsObjects[IntegerNull] = Encode((int)0);
|
2013-03-14 13:03:04 +00:00
|
|
|
}
|
|
|
|
|
2013-05-06 11:29:24 +00:00
|
|
|
InternalClass *ExecutionEngine::newClass(const InternalClass &other)
|
|
|
|
{
|
2014-04-16 07:36:38 +00:00
|
|
|
return new (classPool) InternalClass(other);
|
2013-05-06 11:29:24 +00:00
|
|
|
}
|
|
|
|
|
2017-05-15 07:56:05 +00:00
|
|
|
InternalClass *ExecutionEngine::newInternalClass(const VTable *vtable, Object *prototype)
|
|
|
|
{
|
|
|
|
return internalClasses[EngineBase::Class_Empty]->changeVTable(vtable)->changePrototype(prototype ? prototype->d() : 0);
|
|
|
|
}
|
|
|
|
|
2014-11-11 12:34:18 +00:00
|
|
|
Heap::Object *ExecutionEngine::newObject()
|
2012-11-17 20:54:26 +00:00
|
|
|
{
|
2015-08-28 08:57:37 +00:00
|
|
|
return memoryManager->allocObject<Object>();
|
2012-11-17 20:54:26 +00:00
|
|
|
}
|
|
|
|
|
2014-11-24 14:38:41 +00:00
|
|
|
Heap::Object *ExecutionEngine::newObject(InternalClass *internalClass, QV4::Object *prototype)
|
2013-04-23 05:31:02 +00:00
|
|
|
{
|
2015-08-26 14:40:11 +00:00
|
|
|
return memoryManager->allocObject<Object>(internalClass, prototype);
|
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
|
|
|
{
|
2014-05-09 13:06:29 +00:00
|
|
|
Scope scope(this);
|
2015-07-03 11:20:18 +00:00
|
|
|
return ScopedString(scope, memoryManager->allocWithStringData<String>(s.length() * sizeof(QChar), s))->d();
|
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
|
|
|
{
|
2013-06-27 07:04:11 +00:00
|
|
|
return identifierTable->insertString(text);
|
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
|
|
|
{
|
2015-08-28 08:57:37 +00:00
|
|
|
return memoryManager->allocObject<StringObject>(string);
|
2012-11-17 20:54:26 +00:00
|
|
|
}
|
|
|
|
|
2015-01-16 11:44:51 +00:00
|
|
|
Heap::Object *ExecutionEngine::newNumberObject(double value)
|
2012-11-17 20:54:26 +00:00
|
|
|
{
|
2015-08-28 08:57:37 +00:00
|
|
|
return memoryManager->allocObject<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
|
|
|
{
|
2015-08-28 08:57:37 +00:00
|
|
|
return memoryManager->allocObject<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);
|
2015-08-28 08:57:37 +00:00
|
|
|
ScopedArrayObject object(scope, memoryManager->allocObject<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);
|
|
|
|
ScopedArrayObject a(scope, memoryManager->allocObject<ArrayObject>());
|
|
|
|
|
|
|
|
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-11-03 21:08:02 +00:00
|
|
|
for (int i = 0; i < length; ++i) {
|
|
|
|
if (values[i].isManaged()) {
|
|
|
|
d->needsMark = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
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
|
|
|
{
|
2014-05-09 12:14:02 +00:00
|
|
|
Scope scope(this);
|
2015-08-28 08:57:37 +00:00
|
|
|
ScopedArrayObject object(scope, memoryManager->allocObject<ArrayObject>(list));
|
2014-11-11 12:34:18 +00:00
|
|
|
return object->d();
|
2012-11-17 20:54:26 +00:00
|
|
|
}
|
|
|
|
|
2015-08-26 14:40:11 +00:00
|
|
|
Heap::ArrayObject *ExecutionEngine::newArrayObject(InternalClass *internalClass, Object *prototype)
|
2013-09-02 12:25:15 +00:00
|
|
|
{
|
2014-05-09 12:14:02 +00:00
|
|
|
Scope scope(this);
|
2015-08-26 14:40:11 +00:00
|
|
|
ScopedArrayObject object(scope, memoryManager->allocObject<ArrayObject>(internalClass, prototype));
|
2014-11-11 12:34:18 +00:00
|
|
|
return object->d();
|
2013-09-02 12:25:15 +00:00
|
|
|
}
|
|
|
|
|
2015-03-04 19:57:14 +00:00
|
|
|
Heap::ArrayBuffer *ExecutionEngine::newArrayBuffer(const QByteArray &array)
|
|
|
|
{
|
2015-08-28 08:57:37 +00:00
|
|
|
return memoryManager->allocObject<ArrayBuffer>(array);
|
2015-08-27 10:17:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Heap::ArrayBuffer *ExecutionEngine::newArrayBuffer(size_t length)
|
|
|
|
{
|
2015-08-28 08:57:37 +00:00
|
|
|
return memoryManager->allocObject<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
|
|
|
{
|
2015-08-28 08:57:37 +00:00
|
|
|
return memoryManager->allocObject<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);
|
2015-08-28 08:57:37 +00:00
|
|
|
Scoped<DateObject> object(scope, memoryManager->allocObject<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);
|
|
|
|
Scoped<DateObject> object(scope, memoryManager->allocObject<DateObject>(t));
|
|
|
|
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
|
|
|
{
|
2017-06-22 08:01:17 +00:00
|
|
|
bool global = (flags & QV4::CompiledData::RegExp::RegExp_Global);
|
2017-10-22 10:05:18 +00:00
|
|
|
bool ignoreCase = (flags & QV4::CompiledData::RegExp::RegExp_IgnoreCase);
|
|
|
|
bool multiline = (flags & QV4::CompiledData::RegExp::RegExp_Multiline);
|
2012-11-17 20:54:26 +00:00
|
|
|
|
2013-10-15 13:00:24 +00:00
|
|
|
Scope scope(this);
|
2017-08-08 10:39:54 +00:00
|
|
|
Scoped<RegExp> re(scope, RegExp::create(this, pattern, ignoreCase, multiline, global));
|
|
|
|
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
|
|
|
{
|
2017-08-08 10:39:54 +00:00
|
|
|
return memoryManager->allocObject<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
|
|
|
{
|
2015-08-28 08:57:37 +00:00
|
|
|
return memoryManager->allocObject<RegExpObject>(re);
|
2013-05-02 20:33:47 +00:00
|
|
|
}
|
|
|
|
|
2015-01-15 10:36:57 +00:00
|
|
|
Heap::Object *ExecutionEngine::newErrorObject(const Value &value)
|
2012-11-17 20:54:26 +00:00
|
|
|
{
|
2015-09-01 11:46:46 +00:00
|
|
|
return ErrorObject::create<ErrorObject>(this, value);
|
2012-11-17 20:54:26 +00:00
|
|
|
}
|
|
|
|
|
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
|
|
|
{
|
2015-09-01 11:46:46 +00:00
|
|
|
return ErrorObject::create<URIErrorObject>(this, message);
|
2013-01-22 14:13:15 +00:00
|
|
|
}
|
|
|
|
|
2014-11-11 12:34:18 +00:00
|
|
|
Heap::Object *ExecutionEngine::newVariantObject(const QVariant &v)
|
2013-05-14 00:01:04 +00:00
|
|
|
{
|
2015-08-28 08:57:37 +00:00
|
|
|
return memoryManager->allocObject<VariantObject>(v);
|
2013-05-14 00:01:04 +00:00
|
|
|
}
|
|
|
|
|
2014-11-11 12:34:18 +00:00
|
|
|
Heap::Object *ExecutionEngine::newForEachIteratorObject(Object *o)
|
2012-11-17 20:54:26 +00:00
|
|
|
{
|
2014-05-09 13:23:18 +00:00
|
|
|
Scope scope(this);
|
2015-08-28 11:33:10 +00:00
|
|
|
ScopedObject obj(scope, memoryManager->allocObject<ForEachIteratorObject>(o));
|
2014-11-11 12:34:18 +00:00
|
|
|
return obj->d();
|
2013-05-03 14:51:32 +00:00
|
|
|
}
|
|
|
|
|
2016-11-28 14:33:48 +00:00
|
|
|
Heap::QmlContext *ExecutionEngine::qmlContext() const
|
|
|
|
{
|
2017-08-08 08:56:34 +00:00
|
|
|
if (!currentStackFrame)
|
|
|
|
return 0;
|
|
|
|
Heap::ExecutionContext *ctx = currentContext()->d();
|
2016-11-28 14:33:48 +00:00
|
|
|
|
|
|
|
if (ctx->type != Heap::ExecutionContext::Type_QmlContext && !ctx->outer)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
while (ctx->outer && ctx->outer->type != Heap::ExecutionContext::Type_GlobalContext)
|
|
|
|
ctx = ctx->outer;
|
|
|
|
|
|
|
|
Q_ASSERT(ctx);
|
|
|
|
if (ctx->type != Heap::ExecutionContext::Type_QmlContext)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
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)
|
|
|
|
return 0;
|
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
|
|
|
}
|
|
|
|
|
2015-08-12 12:14:40 +00:00
|
|
|
ReturnedValue ExecutionEngine::qmlSingletonWrapper(String *name)
|
|
|
|
{
|
|
|
|
QQmlContextData *ctx = callingQmlContext();
|
|
|
|
if (!ctx->imports)
|
|
|
|
return Encode::undefined();
|
|
|
|
// Search for attached properties, enums and imported scripts
|
|
|
|
QQmlTypeNameCache::Result r = ctx->imports->query(name);
|
|
|
|
|
|
|
|
Q_ASSERT(r.isValid());
|
2017-06-23 11:20:23 +00:00
|
|
|
Q_ASSERT(r.type.isValid());
|
|
|
|
Q_ASSERT(r.type.isSingleton());
|
2015-08-12 12:14:40 +00:00
|
|
|
|
2017-06-23 11:20:23 +00:00
|
|
|
QQmlType::SingletonInstanceInfo *siinfo = r.type.singletonInstanceInfo();
|
2015-08-12 12:14:40 +00:00
|
|
|
QQmlEngine *e = qmlEngine();
|
|
|
|
siinfo->init(e);
|
|
|
|
|
|
|
|
if (QObject *qobjectSingleton = siinfo->qobjectApi(e))
|
|
|
|
return QV4::QObjectWrapper::wrap(this, qobjectSingleton);
|
|
|
|
return QJSValuePrivate::convertedToValue(this, siinfo->scriptApi(e));
|
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
return 0;
|
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-09 15:14:11 +00:00
|
|
|
QString CppStackFrame::source() const
|
2017-08-03 11:41:13 +00:00
|
|
|
{
|
|
|
|
return v4Function->sourceFile();
|
|
|
|
}
|
|
|
|
|
2017-08-09 15:14:11 +00:00
|
|
|
QString CppStackFrame::function() const
|
2017-08-03 11:41:13 +00:00
|
|
|
{
|
|
|
|
return v4Function->name()->toQString();
|
|
|
|
}
|
|
|
|
|
2017-08-21 08:59:53 +00:00
|
|
|
int CppStackFrame::lineNumber() const
|
|
|
|
{
|
2017-08-29 10:35:05 +00:00
|
|
|
auto findLine = [](const CompiledData::CodeOffsetToLine &entry, uint offset) {
|
|
|
|
return entry.codeOffset < offset;
|
|
|
|
};
|
|
|
|
|
2017-08-21 08:59:53 +00:00
|
|
|
const QV4::CompiledData::Function *cf = v4Function->compiledFunction;
|
2017-08-29 10:35:05 +00:00
|
|
|
uint offset = static_cast<uint>(instructionPointer - v4Function->codeData);
|
|
|
|
const CompiledData::CodeOffsetToLine *lineNumbers = cf->lineNumberTable();
|
|
|
|
uint nLineNumbers = cf->nLineNumbers;
|
|
|
|
const CompiledData::CodeOffsetToLine *line = std::lower_bound(lineNumbers, lineNumbers + nLineNumbers, offset, findLine) - 1;
|
|
|
|
return line->line;
|
2017-08-21 08:59:53 +00:00
|
|
|
}
|
|
|
|
|
2017-08-09 15:14:11 +00:00
|
|
|
ReturnedValue CppStackFrame::thisObject() const {
|
2017-08-30 13:16:15 +00:00
|
|
|
return jsFrame->thisObject.asReturnedValue();
|
2017-08-09 15:14:11 +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);
|
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 << ',';
|
2017-08-04 08:03:03 +00:00
|
|
|
const QUrl url(stackTrace.at(i).source);
|
2013-12-20 14:38:37 +00:00
|
|
|
const QString fileName = url.isLocalFile() ? url.toLocalFile() : url.toString();
|
2017-08-04 08:03:03 +00:00
|
|
|
str << "frame={level=\"" << i << "\",func=\"" << stackTrace.at(i).function
|
2013-12-20 14:38:37 +00:00
|
|
|
<< "\",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));
|
|
|
|
}
|
|
|
|
|
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) {
|
|
|
|
base.setUrl(f->v4Function->sourceFile());
|
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)
|
2013-08-14 14:02:56 +00:00
|
|
|
base.setUrl(globalCode->sourceFile());
|
2013-05-29 07:59:40 +00:00
|
|
|
|
|
|
|
if (base.isEmpty())
|
|
|
|
return src;
|
|
|
|
|
|
|
|
return base.resolved(src);
|
|
|
|
}
|
|
|
|
|
2013-01-18 11:47:43 +00:00
|
|
|
void ExecutionEngine::requireArgumentsAccessors(int n)
|
|
|
|
{
|
2014-03-10 14:18:54 +00:00
|
|
|
if (n <= nArgumentsAccessors)
|
2013-01-18 11:47:43 +00:00
|
|
|
return;
|
|
|
|
|
2013-10-11 10:26:27 +00:00
|
|
|
Scope scope(this);
|
|
|
|
ScopedFunctionObject get(scope);
|
|
|
|
ScopedFunctionObject set(scope);
|
|
|
|
|
2014-03-10 14:18:54 +00:00
|
|
|
if (n >= nArgumentsAccessors) {
|
|
|
|
Property *oldAccessors = argumentsAccessors;
|
|
|
|
int oldSize = nArgumentsAccessors;
|
|
|
|
nArgumentsAccessors = qMax(8, n);
|
|
|
|
argumentsAccessors = new Property[nArgumentsAccessors];
|
|
|
|
if (oldAccessors) {
|
|
|
|
memcpy(argumentsAccessors, oldAccessors, oldSize*sizeof(Property));
|
|
|
|
delete [] oldAccessors;
|
|
|
|
}
|
2015-08-24 14:47:48 +00:00
|
|
|
ExecutionContext *global = rootContext();
|
2014-03-10 14:18:54 +00:00
|
|
|
for (int i = oldSize; i < nArgumentsAccessors; ++i) {
|
2015-08-28 10:58:08 +00:00
|
|
|
argumentsAccessors[i].value = ScopedValue(scope, memoryManager->allocObject<ArgumentsGetterFunction>(global, i));
|
|
|
|
argumentsAccessors[i].set = ScopedValue(scope, memoryManager->allocObject<ArgumentsSetterFunction>(global, i));
|
2014-03-10 14:18:54 +00:00
|
|
|
}
|
2013-01-18 11:47:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-09 09:36:16 +00:00
|
|
|
void ExecutionEngine::markObjects(MarkStack *markStack)
|
2013-01-28 15:46:09 +00:00
|
|
|
{
|
2017-03-09 09:36:16 +00:00
|
|
|
identifierTable->mark(markStack);
|
2013-01-30 13:56:40 +00:00
|
|
|
|
2017-04-04 08:05:58 +00:00
|
|
|
for (int i = 0; i < nArgumentsAccessors; ++i) {
|
|
|
|
const Property &pd = argumentsAccessors[i];
|
|
|
|
if (Heap::FunctionObject *getter = pd.getter())
|
2017-03-09 09:36:16 +00:00
|
|
|
getter->mark(markStack);
|
2017-04-04 08:05:58 +00:00
|
|
|
if (Heap::FunctionObject *setter = pd.setter())
|
2017-03-09 09:36:16 +00:00
|
|
|
setter->mark(markStack);
|
2017-04-04 08:05:58 +00:00
|
|
|
}
|
2013-01-28 15:46:09 +00:00
|
|
|
|
2017-03-09 09:36:16 +00:00
|
|
|
classPool->markObjects(markStack);
|
2017-09-08 13:12:47 +00:00
|
|
|
markStack->drain();
|
2013-08-29 11:24:38 +00:00
|
|
|
|
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();
|
|
|
|
*exceptionValue = Primitive::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);
|
|
|
|
}
|
|
|
|
|
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();
|
2017-08-04 08:03:03 +00:00
|
|
|
error.setUrl(QUrl(frame.source));
|
2013-10-17 06:56:51 +00:00
|
|
|
error.setLine(frame.line);
|
|
|
|
error.setColumn(frame.column);
|
|
|
|
}
|
|
|
|
QV4::Scoped<QV4::ErrorObject> errorObj(scope, exception);
|
|
|
|
if (!!errorObj && errorObj->asSyntaxError()) {
|
2014-11-12 12:55:55 +00:00
|
|
|
QV4::ScopedString m(scope, newString(QStringLiteral("message")));
|
2014-12-01 15:13:20 +00:00
|
|
|
QV4::ScopedValue v(scope, errorObj->get(m));
|
2013-10-17 06:56:51 +00:00
|
|
|
error.setDescription(v->toQStringNoThrow());
|
|
|
|
} else
|
|
|
|
error.setDescription(exception->toQStringNoThrow());
|
|
|
|
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);
|
2015-04-26 20:58:49 +00:00
|
|
|
static QVariant objectToVariant(QV4::ExecutionEngine *e, const QV4::Object *o, V4ObjectSet *visitedObjects = 0);
|
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);
|
|
|
|
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
|
|
|
{
|
|
|
|
return ::toVariant(this, value, typeHint, createJSValueForObjects, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
if (typeHint == QVariant::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>()) {
|
|
|
|
return qVariantFromValue<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();
|
|
|
|
} else if (object->isListType())
|
|
|
|
return QV4::SequencePrototype::toVariant(object);
|
|
|
|
}
|
|
|
|
|
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) {
|
|
|
|
qobjectWrapper = a->getIndexed(ii);
|
|
|
|
if (!!qobjectWrapper) {
|
|
|
|
list << qobjectWrapper->object();
|
|
|
|
} else {
|
|
|
|
list << 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return qVariantFromValue<QList<QObject*> >(list);
|
|
|
|
} else if (typeHint == QMetaType::QJsonArray) {
|
|
|
|
return QVariant::fromValue(QV4::JsonObject::toJsonArray(a));
|
|
|
|
}
|
|
|
|
|
|
|
|
bool succeeded = false;
|
|
|
|
QVariant retn = QV4::SequencePrototype::toVariant(value, typeHint, &succeeded);
|
|
|
|
if (succeeded)
|
|
|
|
return retn;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
if (typeHint == QVariant::Char && str.size() == 1)
|
|
|
|
return str.at(0);
|
|
|
|
return str;
|
|
|
|
}
|
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;
|
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);
|
|
|
|
|
|
|
|
if (QV4::RegExpObject *re = o->as<QV4::RegExpObject>())
|
|
|
|
return re->toQRegExp();
|
|
|
|
|
|
|
|
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) {
|
|
|
|
v = a->getIndexed(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;
|
|
|
|
}
|
|
|
|
|
|
|
|
static QV4::ReturnedValue arrayFromVariantList(QV4::ExecutionEngine *e, const QVariantList &list)
|
|
|
|
{
|
|
|
|
QV4::Scope scope(e);
|
|
|
|
QV4::ScopedArrayObject a(scope, e->newArrayObject());
|
|
|
|
int len = list.count();
|
|
|
|
a->arrayReserve(len);
|
|
|
|
QV4::ScopedValue v(scope);
|
|
|
|
for (int ii = 0; ii < len; ++ii)
|
2015-01-02 14:07:35 +00:00
|
|
|
a->arrayPut(ii, (v = scope.engine->fromVariant(list.at(ii))));
|
2015-01-02 13:37:26 +00:00
|
|
|
|
|
|
|
a->setArrayLengthUnchecked(len);
|
|
|
|
return a.asReturnedValue();
|
|
|
|
}
|
|
|
|
|
|
|
|
static QV4::ReturnedValue objectFromVariantMap(QV4::ExecutionEngine *e, const QVariantMap &map)
|
|
|
|
{
|
|
|
|
QV4::Scope scope(e);
|
|
|
|
QV4::ScopedObject o(scope, e->newObject());
|
|
|
|
QV4::ScopedString s(scope);
|
|
|
|
QV4::ScopedValue v(scope);
|
2015-02-23 12:44:12 +00:00
|
|
|
for (QVariantMap::const_iterator iter = map.begin(), cend = map.end(); iter != cend; ++iter) {
|
2015-01-02 13:37:26 +00:00
|
|
|
s = e->newString(iter.key());
|
|
|
|
uint idx = s->asArrayIndex();
|
|
|
|
if (idx > 16 && (!o->arrayData() || idx > o->arrayData()->length() * 2))
|
|
|
|
o->initSparseArray();
|
2015-01-02 14:07:35 +00:00
|
|
|
o->put(s, (v = e->fromVariant(iter.value())));
|
2015-01-02 13:37:26 +00:00
|
|
|
}
|
|
|
|
return o.asReturnedValue();
|
|
|
|
}
|
|
|
|
|
|
|
|
Q_CORE_EXPORT QString qt_regexp_toCanonical(const QString &, QRegExp::PatternSyntax);
|
|
|
|
|
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:
|
2015-01-02 14:07:35 +00:00
|
|
|
return QV4::Encode(newDateObject(QDateTime(*reinterpret_cast<const QDate *>(ptr))));
|
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)));
|
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));
|
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
|
|
|
}
|
|
|
|
case QMetaType::QVariantList:
|
2015-01-02 14:07:35 +00:00
|
|
|
return arrayFromVariantList(this, *reinterpret_cast<const QVariantList *>(ptr));
|
2015-01-02 13:37:26 +00:00
|
|
|
case QMetaType::QVariantMap:
|
2015-01-02 14:07:35 +00:00
|
|
|
return objectFromVariantMap(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));
|
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));
|
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
|
|
|
|
|
|
|
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();
|
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();
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
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());
|
|
|
|
v = variantToJS(v4, it.value());
|
|
|
|
uint idx = s->asArrayIndex();
|
|
|
|
if (idx < UINT_MAX)
|
|
|
|
o->arraySet(idx, v);
|
|
|
|
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
|
|
|
{
|
|
|
|
Q_ASSERT(data != 0);
|
|
|
|
|
|
|
|
// check if it's one of the types we know
|
|
|
|
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*>(data));
|
|
|
|
case QMetaType::Int:
|
|
|
|
return QV4::Encode(*reinterpret_cast<const int*>(data));
|
|
|
|
case QMetaType::UInt:
|
|
|
|
return QV4::Encode(*reinterpret_cast<const uint*>(data));
|
|
|
|
case QMetaType::LongLong:
|
|
|
|
return QV4::Encode(double(*reinterpret_cast<const qlonglong*>(data)));
|
|
|
|
case QMetaType::ULongLong:
|
|
|
|
#if defined(Q_OS_WIN) && defined(_MSC_FULL_VER) && _MSC_FULL_VER <= 12008804
|
|
|
|
#pragma message("** NOTE: You need the Visual Studio Processor Pack to compile support for 64bit unsigned integers.")
|
|
|
|
return QV4::Encode(double((qlonglong)*reinterpret_cast<const qulonglong*>(data)));
|
|
|
|
#elif defined(Q_CC_MSVC) && !defined(Q_CC_MSVC_NET)
|
|
|
|
return QV4::Encode(double((qlonglong)*reinterpret_cast<const qulonglong*>(data)));
|
|
|
|
#else
|
|
|
|
return QV4::Encode(double(*reinterpret_cast<const qulonglong*>(data)));
|
|
|
|
#endif
|
|
|
|
case QMetaType::Double:
|
|
|
|
return QV4::Encode(*reinterpret_cast<const double*>(data));
|
|
|
|
case QMetaType::QString:
|
2015-01-02 14:07:35 +00:00
|
|
|
return newString(*reinterpret_cast<const QString*>(data))->asReturnedValue();
|
2015-12-28 12:22:29 +00:00
|
|
|
case QMetaType::QByteArray:
|
|
|
|
return newArrayBuffer(*reinterpret_cast<const QByteArray*>(data))->asReturnedValue();
|
2015-01-02 13:37:26 +00:00
|
|
|
case QMetaType::Float:
|
|
|
|
return QV4::Encode(*reinterpret_cast<const float*>(data));
|
|
|
|
case QMetaType::Short:
|
|
|
|
return QV4::Encode((int)*reinterpret_cast<const short*>(data));
|
|
|
|
case QMetaType::UShort:
|
|
|
|
return QV4::Encode((int)*reinterpret_cast<const unsigned short*>(data));
|
|
|
|
case QMetaType::Char:
|
|
|
|
return QV4::Encode((int)*reinterpret_cast<const char*>(data));
|
|
|
|
case QMetaType::UChar:
|
|
|
|
return QV4::Encode((int)*reinterpret_cast<const unsigned char*>(data));
|
|
|
|
case QMetaType::QChar:
|
|
|
|
return QV4::Encode((int)(*reinterpret_cast<const QChar*>(data)).unicode());
|
|
|
|
case QMetaType::QStringList:
|
2015-01-02 14:07:35 +00:00
|
|
|
return QV4::Encode(newArrayObject(*reinterpret_cast<const QStringList *>(data)));
|
2015-01-02 13:37:26 +00:00
|
|
|
case QMetaType::QVariantList:
|
2015-01-02 14:07:35 +00:00
|
|
|
return variantListToJS(this, *reinterpret_cast<const QVariantList *>(data));
|
2015-01-02 13:37:26 +00:00
|
|
|
case QMetaType::QVariantMap:
|
2015-01-02 14:07:35 +00:00
|
|
|
return variantMapToJS(this, *reinterpret_cast<const QVariantMap *>(data));
|
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 *>(data)));
|
2015-01-02 13:37:26 +00:00
|
|
|
case QMetaType::QDate:
|
2015-01-02 14:07:35 +00:00
|
|
|
return QV4::Encode(newDateObject(QDateTime(*reinterpret_cast<const QDate *>(data))));
|
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 *>(data)));
|
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 *>(data));
|
2015-01-02 13:37:26 +00:00
|
|
|
case QMetaType::QVariant:
|
2015-01-02 14:07:35 +00:00
|
|
|
return variantToJS(this, *reinterpret_cast<const QVariant*>(data));
|
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 *>(data));
|
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 *>(data));
|
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 *>(data));
|
2015-01-02 13:37:26 +00:00
|
|
|
default:
|
|
|
|
if (type == qMetaTypeId<QJSValue>()) {
|
2015-01-14 15:22:33 +00:00
|
|
|
return QJSValuePrivate::convertedToValue(this, *reinterpret_cast<const QJSValue*>(data));
|
2015-01-02 13:37:26 +00:00
|
|
|
} else {
|
|
|
|
QByteArray typeName = QMetaType::typeName(type);
|
|
|
|
if (typeName.endsWith('*') && !*reinterpret_cast<void* const *>(data)) {
|
|
|
|
return QV4::Encode::null();
|
|
|
|
}
|
|
|
|
QMetaType mt(type);
|
|
|
|
if (mt.flags() & QMetaType::IsGadget) {
|
|
|
|
Q_ASSERT(mt.metaObject());
|
2015-01-02 14:07:35 +00:00
|
|
|
return QV4::QQmlValueTypeWrapper::create(this, QVariant(type, data), mt.metaObject(), type);
|
2015-01-02 13:37:26 +00:00
|
|
|
}
|
|
|
|
// Fall back to wrapping in a QVariant.
|
2015-01-02 14:07:35 +00:00
|
|
|
return QV4::Encode(newVariantObject(QVariant(type, data)));
|
2015-01-02 13:37:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
Q_UNREACHABLE();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
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);
|
2016-11-25 09:27:02 +00:00
|
|
|
QV4::ScopedObject proto(scope, o->prototype());
|
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))
|
2015-01-02 13:37:26 +00:00
|
|
|
canCast = qobject->qt_metacast(className) != 0;
|
|
|
|
}
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
proto = proto->prototype();
|
|
|
|
}
|
|
|
|
}
|
2015-04-26 20:58:49 +00:00
|
|
|
} else if (value->isNull() && name.endsWith('*')) {
|
2015-01-02 13:37:26 +00:00
|
|
|
*reinterpret_cast<void* *>(data) = 0;
|
|
|
|
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())
|
2015-01-02 13:37:26 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
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)
|
|
|
|
return 0;
|
|
|
|
return wrapper->object();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-06-24 13:28:00 +00:00
|
|
|
QT_END_NAMESPACE
|