2012-11-17 20:54:26 +00:00
|
|
|
/****************************************************************************
|
|
|
|
**
|
2015-01-28 11:55:39 +00:00
|
|
|
** Copyright (C) 2015 The Qt Company Ltd.
|
|
|
|
** Contact: http://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
|
|
|
**
|
2014-08-22 06:13:59 +00:00
|
|
|
** $QT_BEGIN_LICENSE:LGPL21$
|
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
|
|
|
|
** and conditions see http://www.qt.io/terms-conditions. For further
|
|
|
|
** information use the contact form at http://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
|
2014-08-22 06:13:59 +00:00
|
|
|
** General Public License version 2.1 or version 3 as published by the Free
|
|
|
|
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
|
|
|
|
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
|
|
|
|
** following information to ensure the GNU Lesser General Public License
|
|
|
|
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
|
|
|
|
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
2012-11-17 20:54:26 +00:00
|
|
|
**
|
2015-01-28 11:55:39 +00:00
|
|
|
** As a special exception, The Qt Company gives you certain additional
|
|
|
|
** rights. These rights are described in The Qt Company LGPL Exception
|
2012-11-17 20:54:26 +00:00
|
|
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
|
|
**
|
|
|
|
** $QT_END_LICENSE$
|
|
|
|
**
|
|
|
|
****************************************************************************/
|
2013-04-15 09:50:16 +00:00
|
|
|
#include <qv4engine_p.h>
|
2013-11-21 12:15:46 +00:00
|
|
|
#include <qv4context_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"
|
2013-06-20 09:32:45 +00:00
|
|
|
#include "qv4qmlextensions_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/qqmlcontextwrapper_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-05-07 09:54:45 +00:00
|
|
|
#ifdef V4_ENABLE_JIT
|
2013-07-24 08:29:04 +00:00
|
|
|
#include "qv4isel_masm_p.h"
|
2013-05-07 09:54:45 +00:00
|
|
|
#endif // V4_ENABLE_JIT
|
|
|
|
|
2013-07-24 08:29:04 +00:00
|
|
|
#include "qv4isel_moth_p.h"
|
|
|
|
|
2013-11-11 10:22:24 +00:00
|
|
|
#if USE(PTHREADS)
|
|
|
|
# include <pthread.h>
|
2013-12-17 15:11:19 +00:00
|
|
|
# include <sys/resource.h>
|
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);
|
|
|
|
|
2013-11-03 14:23:05 +00:00
|
|
|
static ReturnedValue throwTypeError(CallContext *ctx)
|
2013-09-18 07:30:45 +00:00
|
|
|
{
|
2014-07-28 08:07:57 +00:00
|
|
|
return ctx->engine()->throwTypeError();
|
2013-09-18 07:30:45 +00:00
|
|
|
}
|
|
|
|
|
2014-09-11 15:00:06 +00:00
|
|
|
const int MinimumStackSize = 256; // in kbytes
|
|
|
|
|
2013-11-11 10:22:24 +00:00
|
|
|
quintptr getStackLimit()
|
|
|
|
{
|
|
|
|
quintptr stackLimit;
|
2013-11-19 10:29:34 +00:00
|
|
|
#if USE(PTHREADS) && !OS(QNX)
|
2013-11-11 10:22:24 +00:00
|
|
|
# if OS(DARWIN)
|
|
|
|
pthread_t thread_self = pthread_self();
|
|
|
|
void *stackTop = pthread_get_stackaddr_np(thread_self);
|
|
|
|
stackLimit = reinterpret_cast<quintptr>(stackTop);
|
2013-11-20 16:17:01 +00:00
|
|
|
quintptr size = 0;
|
|
|
|
if (pthread_main_np()) {
|
|
|
|
rlimit limit;
|
|
|
|
getrlimit(RLIMIT_STACK, &limit);
|
|
|
|
size = limit.rlim_cur;
|
|
|
|
} else
|
|
|
|
size = pthread_get_stacksize_np(thread_self);
|
|
|
|
stackLimit -= size;
|
2013-11-11 10:22:24 +00:00
|
|
|
# else
|
|
|
|
void* stackBottom = 0;
|
|
|
|
pthread_attr_t attr;
|
2014-01-21 09:55:18 +00:00
|
|
|
#if HAVE(PTHREAD_NP_H) && OS(FREEBSD)
|
2015-01-21 09:10:01 +00:00
|
|
|
// on FreeBSD pthread_attr_init() must be called otherwise getting the attrs crashes
|
|
|
|
if (pthread_attr_init(&attr) == 0 && pthread_attr_get_np(pthread_self(), &attr) == 0) {
|
2014-01-21 09:55:18 +00:00
|
|
|
#else
|
2014-01-13 10:09:34 +00:00
|
|
|
if (pthread_getattr_np(pthread_self(), &attr) == 0) {
|
2014-01-21 09:55:18 +00:00
|
|
|
#endif
|
2014-01-13 10:09:34 +00:00
|
|
|
size_t stackSize = 0;
|
|
|
|
pthread_attr_getstack(&attr, &stackBottom, &stackSize);
|
|
|
|
pthread_attr_destroy(&attr);
|
2013-11-11 10:22:24 +00:00
|
|
|
|
2014-01-13 10:09:34 +00:00
|
|
|
# if defined(Q_OS_ANDROID)
|
|
|
|
// Bionic pretends that the main thread has a tiny stack; work around it
|
|
|
|
if (gettid() == getpid()) {
|
|
|
|
rlimit limit;
|
|
|
|
getrlimit(RLIMIT_STACK, &limit);
|
|
|
|
stackBottom = reinterpret_cast<void*>(reinterpret_cast<quintptr>(stackBottom) + stackSize - limit.rlim_cur);
|
|
|
|
}
|
|
|
|
# endif
|
|
|
|
|
|
|
|
stackLimit = reinterpret_cast<quintptr>(stackBottom);
|
|
|
|
} else {
|
|
|
|
int dummy;
|
|
|
|
// this is inexact, as part of the stack is used when being called here,
|
|
|
|
// but let's simply default to 1MB from where the stack is right now
|
|
|
|
stackLimit = reinterpret_cast<qintptr>(&dummy) - 1024*1024;
|
2013-12-17 15:11:19 +00:00
|
|
|
}
|
|
|
|
|
2013-11-11 10:22:24 +00:00
|
|
|
# endif
|
|
|
|
// This is wrong. StackLimit is the currently committed stack size, not the real end.
|
|
|
|
// only way to get that limit is apparently by using VirtualQuery (Yuck)
|
|
|
|
//#elif OS(WINDOWS)
|
|
|
|
// PNT_TIB tib = (PNT_TIB)NtCurrentTeb();
|
|
|
|
// stackLimit = static_cast<quintptr>(tib->StackLimit);
|
|
|
|
#else
|
|
|
|
int dummy;
|
|
|
|
// this is inexact, as part of the stack is used when being called here,
|
|
|
|
// but let's simply default to 1MB from where the stack is right now
|
|
|
|
stackLimit = reinterpret_cast<qintptr>(&dummy) - 1024*1024;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// 256k slack
|
2014-09-11 15:00:06 +00:00
|
|
|
return stackLimit + MinimumStackSize*1024;
|
2013-11-11 10:22:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2014-02-14 12:58:40 +00:00
|
|
|
ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
|
2014-02-05 15:12:16 +00:00
|
|
|
: current(0)
|
2015-03-13 16:21:18 +00:00
|
|
|
, hasException(false)
|
2015-01-12 20:55:51 +00:00
|
|
|
, memoryManager(new QV4::MemoryManager(this))
|
2013-04-19 11:03:42 +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)
|
2012-11-29 13:41:26 +00:00
|
|
|
, debugger(0)
|
2014-01-22 16:46:20 +00:00
|
|
|
, profiler(0)
|
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)
|
2013-06-20 09:32:45 +00:00
|
|
|
, m_qmlExtensions(0)
|
2012-11-17 20:54:26 +00:00
|
|
|
{
|
2012-12-04 12:40:18 +00:00
|
|
|
MemoryManager::GCBlocker gcBlocker(memoryManager);
|
|
|
|
|
2013-05-07 09:54:45 +00:00
|
|
|
if (!factory) {
|
2013-09-09 14:07:01 +00:00
|
|
|
|
2013-08-12 14:45:47 +00:00
|
|
|
#ifdef V4_ENABLE_JIT
|
2013-09-09 14:07:01 +00:00
|
|
|
static const bool forceMoth = !qgetenv("QV4_FORCE_INTERPRETER").isEmpty();
|
|
|
|
if (forceMoth)
|
2014-02-14 12:58:40 +00:00
|
|
|
factory = new Moth::ISelFactory;
|
2013-09-09 14:07:01 +00:00
|
|
|
else
|
2014-02-14 12:58:40 +00:00
|
|
|
factory = new JIT::ISelFactory;
|
2013-05-07 09:54:45 +00:00
|
|
|
#else // !V4_ENABLE_JIT
|
2014-02-14 12:58:40 +00:00
|
|
|
factory = new Moth::ISelFactory;
|
2013-05-07 09:54:45 +00:00
|
|
|
#endif // V4_ENABLE_JIT
|
|
|
|
}
|
2013-03-05 15:11:22 +00:00
|
|
|
iselFactory.reset(factory);
|
|
|
|
|
2013-11-11 10:22:24 +00:00
|
|
|
// reserve space for the JS stack
|
|
|
|
// we allow it to grow to 2 times JSStackLimit, as we can overshoot due to garbage collection
|
|
|
|
// and ScopedValues allocated outside of JIT'ed methods.
|
2014-10-22 10:34:47 +00:00
|
|
|
*jsStack = WTF::PageAllocation::allocate(2 * JSStackLimit, WTF::OSAllocator::JSVMStackPages,
|
|
|
|
/* writable */ true, /* executable */ false,
|
|
|
|
/* includesGuardPages */ true);
|
2014-01-24 21:55:39 +00:00
|
|
|
jsStackBase = (Value *)jsStack->base();
|
2013-09-03 10:40:07 +00:00
|
|
|
jsStackTop = jsStackBase;
|
|
|
|
|
2015-03-13 16:21:18 +00:00
|
|
|
exceptionValue = jsAlloca(1);
|
|
|
|
globalObject = static_cast<Object *>(jsAlloca(1));
|
|
|
|
|
2014-12-15 07:47:35 +00:00
|
|
|
#ifdef V4_USE_VALGRIND
|
|
|
|
VALGRIND_MAKE_MEM_UNDEFINED(jsStackBase, 2*JSStackLimit);
|
|
|
|
#endif
|
|
|
|
|
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
|
|
|
cStackLimit = getStackLimit();
|
2014-09-11 15:00:06 +00:00
|
|
|
if (!recheckCStackLimits())
|
|
|
|
qFatal("Fatal: Not enough stack space available for QML. Please increase the process stack size to more than %d KBytes.", MinimumStackSize);
|
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;
|
|
|
|
|
|
|
|
emptyClass = new (classPool) InternalClass(this);
|
2013-05-12 13:00:48 +00:00
|
|
|
|
2014-03-17 11:45:41 +00:00
|
|
|
id_empty = newIdentifier(QString());
|
2013-02-14 22:00:11 +00:00
|
|
|
id_undefined = newIdentifier(QStringLiteral("undefined"));
|
|
|
|
id_null = newIdentifier(QStringLiteral("null"));
|
|
|
|
id_true = newIdentifier(QStringLiteral("true"));
|
|
|
|
id_false = newIdentifier(QStringLiteral("false"));
|
|
|
|
id_boolean = newIdentifier(QStringLiteral("boolean"));
|
|
|
|
id_number = newIdentifier(QStringLiteral("number"));
|
|
|
|
id_string = newIdentifier(QStringLiteral("string"));
|
|
|
|
id_object = newIdentifier(QStringLiteral("object"));
|
|
|
|
id_function = newIdentifier(QStringLiteral("function"));
|
2013-01-30 13:56:40 +00:00
|
|
|
id_length = newIdentifier(QStringLiteral("length"));
|
|
|
|
id_prototype = newIdentifier(QStringLiteral("prototype"));
|
|
|
|
id_constructor = newIdentifier(QStringLiteral("constructor"));
|
|
|
|
id_arguments = newIdentifier(QStringLiteral("arguments"));
|
|
|
|
id_caller = newIdentifier(QStringLiteral("caller"));
|
2013-08-16 06:53:47 +00:00
|
|
|
id_callee = newIdentifier(QStringLiteral("callee"));
|
2013-01-30 13:56:40 +00:00
|
|
|
id_this = newIdentifier(QStringLiteral("this"));
|
|
|
|
id___proto__ = newIdentifier(QStringLiteral("__proto__"));
|
|
|
|
id_enumerable = newIdentifier(QStringLiteral("enumerable"));
|
|
|
|
id_configurable = newIdentifier(QStringLiteral("configurable"));
|
|
|
|
id_writable = newIdentifier(QStringLiteral("writable"));
|
|
|
|
id_value = newIdentifier(QStringLiteral("value"));
|
|
|
|
id_get = newIdentifier(QStringLiteral("get"));
|
|
|
|
id_set = newIdentifier(QStringLiteral("set"));
|
|
|
|
id_eval = newIdentifier(QStringLiteral("eval"));
|
2013-05-03 20:40:58 +00:00
|
|
|
id_uintMax = newIdentifier(QStringLiteral("4294967295"));
|
2013-05-04 08:26:54 +00:00
|
|
|
id_name = newIdentifier(QStringLiteral("name"));
|
2013-09-02 12:25:15 +00:00
|
|
|
id_index = newIdentifier(QStringLiteral("index"));
|
|
|
|
id_input = newIdentifier(QStringLiteral("input"));
|
2013-09-18 13:34:13 +00:00
|
|
|
id_toString = newIdentifier(QStringLiteral("toString"));
|
2014-02-27 21:59:39 +00:00
|
|
|
id_destroy = newIdentifier(QStringLiteral("destroy"));
|
2013-09-18 13:34:13 +00:00
|
|
|
id_valueOf = newIdentifier(QStringLiteral("valueOf"));
|
2014-09-10 12:50:28 +00:00
|
|
|
id_byteLength = newIdentifier(QStringLiteral("byteLength"));
|
2014-09-10 14:39:23 +00:00
|
|
|
id_byteOffset = newIdentifier(QStringLiteral("byteOffset"));
|
|
|
|
id_buffer = newIdentifier(QStringLiteral("buffer"));
|
2014-11-11 14:08:30 +00:00
|
|
|
id_lastIndex = newIdentifier(QStringLiteral("lastIndex"));
|
2012-11-17 20:54:26 +00:00
|
|
|
|
2015-01-10 19:35:18 +00:00
|
|
|
objectPrototype = memoryManager->alloc<ObjectPrototype>(emptyClass, (QV4::Object *)0);
|
2014-03-31 13:48:02 +00:00
|
|
|
|
2015-01-10 19:35:18 +00:00
|
|
|
arrayClass = emptyClass->addMember(id_length, Attr_NotConfigurable|Attr_NotEnumerable);
|
2015-02-13 12:39:20 +00:00
|
|
|
arrayPrototype = memoryManager->alloc<ArrayPrototype>(arrayClass, objectPrototype.as<Object>());
|
2013-08-29 12:31:32 +00:00
|
|
|
|
2015-01-10 19:35:18 +00:00
|
|
|
InternalClass *argsClass = emptyClass->addMember(id_length, Attr_NotEnumerable);
|
2013-08-16 06:53:47 +00:00
|
|
|
argumentsObjectClass = argsClass->addMember(id_callee, Attr_Data|Attr_NotEnumerable);
|
|
|
|
strictArgumentsObjectClass = argsClass->addMember(id_callee, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
|
|
|
|
strictArgumentsObjectClass = strictArgumentsObjectClass->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();
|
|
|
|
Q_ASSERT(globalObject->d()->vtable);
|
2013-03-14 13:03:04 +00:00
|
|
|
initRootContext();
|
2013-03-04 10:48:49 +00:00
|
|
|
|
2015-02-13 12:39:20 +00:00
|
|
|
stringPrototype = memoryManager->alloc<StringPrototype>(emptyClass, objectPrototype.as<Object>());
|
|
|
|
numberPrototype = memoryManager->alloc<NumberPrototype>(emptyClass, objectPrototype.as<Object>());
|
|
|
|
booleanPrototype = memoryManager->alloc<BooleanPrototype>(emptyClass, objectPrototype.as<Object>());
|
|
|
|
datePrototype = memoryManager->alloc<DatePrototype>(emptyClass, objectPrototype.as<Object>());
|
2013-08-29 19:23:04 +00:00
|
|
|
|
2013-09-01 19:22:57 +00:00
|
|
|
uint index;
|
2015-01-10 19:35:18 +00:00
|
|
|
InternalClass *functionProtoClass = emptyClass->addMember(id_prototype, Attr_NotEnumerable, &index);
|
2014-11-03 02:17:57 +00:00
|
|
|
Q_ASSERT(index == Heap::FunctionObject::Index_Prototype);
|
2015-02-13 12:39:20 +00:00
|
|
|
functionPrototype = memoryManager->alloc<FunctionPrototype>(functionProtoClass, objectPrototype.as<Object>());
|
2015-01-10 19:35:18 +00:00
|
|
|
functionClass = emptyClass->addMember(id_prototype, Attr_NotEnumerable|Attr_NotConfigurable, &index);
|
2014-11-03 02:17:57 +00:00
|
|
|
Q_ASSERT(index == Heap::FunctionObject::Index_Prototype);
|
2015-04-09 13:50:55 +00:00
|
|
|
simpleScriptFunctionClass = functionClass->addMember(id_name, Attr_ReadOnly, &index);
|
|
|
|
Q_ASSERT(index == Heap::SimpleScriptFunction::Index_Name);
|
|
|
|
simpleScriptFunctionClass = simpleScriptFunctionClass->addMember(id_length, Attr_ReadOnly, &index);
|
|
|
|
Q_ASSERT(index == Heap::SimpleScriptFunction::Index_Length);
|
2015-01-10 19:35:18 +00:00
|
|
|
protoClass = emptyClass->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
|
|
|
|
2014-11-24 14:38:41 +00:00
|
|
|
regExpPrototype = memoryManager->alloc<RegExpPrototype>(this);
|
2013-09-02 12:25:15 +00:00
|
|
|
regExpExecArrayClass = arrayClass->addMember(id_index, Attr_Data, &index);
|
|
|
|
Q_ASSERT(index == RegExpObject::Index_ArrayIndex);
|
|
|
|
regExpExecArrayClass = regExpExecArrayClass->addMember(id_input, Attr_Data, &index);
|
|
|
|
Q_ASSERT(index == RegExpObject::Index_ArrayInput);
|
2013-08-29 19:23:04 +00:00
|
|
|
|
2015-02-13 12:39:20 +00:00
|
|
|
errorPrototype = memoryManager->alloc<ErrorPrototype>(emptyClass, objectPrototype.as<Object>());
|
|
|
|
evalErrorPrototype = memoryManager->alloc<EvalErrorPrototype>(emptyClass, errorPrototype.as<Object>());
|
|
|
|
rangeErrorPrototype = memoryManager->alloc<RangeErrorPrototype>(emptyClass, errorPrototype.as<Object>());
|
|
|
|
referenceErrorPrototype = memoryManager->alloc<ReferenceErrorPrototype>(emptyClass, errorPrototype.as<Object>());
|
|
|
|
syntaxErrorPrototype = memoryManager->alloc<SyntaxErrorPrototype>(emptyClass, errorPrototype.as<Object>());
|
|
|
|
typeErrorPrototype = memoryManager->alloc<TypeErrorPrototype>(emptyClass, errorPrototype.as<Object>());
|
|
|
|
uRIErrorPrototype = memoryManager->alloc<URIErrorPrototype>(emptyClass, errorPrototype.as<Object>());
|
2015-01-10 19:35:18 +00:00
|
|
|
|
2015-02-13 12:39:20 +00:00
|
|
|
variantPrototype = memoryManager->alloc<VariantPrototype>(emptyClass, objectPrototype.as<Object>());
|
|
|
|
Q_ASSERT(variantPrototype.as<Object>()->prototype() == objectPrototype.as<Object>()->d());
|
2014-11-24 14:38:41 +00:00
|
|
|
|
2015-03-13 16:21:18 +00:00
|
|
|
Scope scope(this);
|
2015-02-13 12:39:20 +00:00
|
|
|
sequencePrototype = ScopedValue(scope, memoryManager->alloc<SequencePrototype>(arrayClass, arrayPrototype.as<Object>()));
|
2014-06-13 12:30:03 +00:00
|
|
|
|
2014-11-28 09:05:24 +00:00
|
|
|
ScopedContext global(scope, rootContext());
|
|
|
|
objectCtor = memoryManager->alloc<ObjectCtor>(global);
|
|
|
|
stringCtor = memoryManager->alloc<StringCtor>(global);
|
|
|
|
numberCtor = memoryManager->alloc<NumberCtor>(global);
|
|
|
|
booleanCtor = memoryManager->alloc<BooleanCtor>(global);
|
|
|
|
arrayCtor = memoryManager->alloc<ArrayCtor>(global);
|
|
|
|
functionCtor = memoryManager->alloc<FunctionCtor>(global);
|
|
|
|
dateCtor = memoryManager->alloc<DateCtor>(global);
|
|
|
|
regExpCtor = memoryManager->alloc<RegExpCtor>(global);
|
|
|
|
errorCtor = memoryManager->alloc<ErrorCtor>(global);
|
|
|
|
evalErrorCtor = memoryManager->alloc<EvalErrorCtor>(global);
|
|
|
|
rangeErrorCtor = memoryManager->alloc<RangeErrorCtor>(global);
|
|
|
|
referenceErrorCtor = memoryManager->alloc<ReferenceErrorCtor>(global);
|
|
|
|
syntaxErrorCtor = memoryManager->alloc<SyntaxErrorCtor>(global);
|
|
|
|
typeErrorCtor = memoryManager->alloc<TypeErrorCtor>(global);
|
|
|
|
uRIErrorCtor = memoryManager->alloc<URIErrorCtor>(global);
|
2012-11-17 20:54:26 +00:00
|
|
|
|
2015-02-13 12:39:20 +00:00
|
|
|
static_cast<ObjectPrototype *>(objectPrototype.as<Object>())->init(this, objectCtor.as<Object>());
|
|
|
|
static_cast<StringPrototype *>(stringPrototype.as<Object>())->init(this, stringCtor.as<Object>());
|
|
|
|
static_cast<NumberPrototype *>(numberPrototype.as<Object>())->init(this, numberCtor.as<Object>());
|
|
|
|
static_cast<BooleanPrototype *>(booleanPrototype.as<Object>())->init(this, booleanCtor.as<Object>());
|
|
|
|
static_cast<ArrayPrototype *>(arrayPrototype.as<Object>())->init(this, arrayCtor.as<Object>());
|
|
|
|
static_cast<DatePrototype *>(datePrototype.as<Object>())->init(this, dateCtor.as<Object>());
|
|
|
|
static_cast<FunctionPrototype *>(functionPrototype.as<Object>())->init(this, functionCtor.as<Object>());
|
|
|
|
static_cast<RegExpPrototype *>(regExpPrototype.as<Object>())->init(this, regExpCtor.as<Object>());
|
|
|
|
static_cast<ErrorPrototype *>(errorPrototype.as<Object>())->init(this, errorCtor.as<Object>());
|
|
|
|
static_cast<EvalErrorPrototype *>(evalErrorPrototype.as<Object>())->init(this, evalErrorCtor.as<Object>());
|
|
|
|
static_cast<RangeErrorPrototype *>(rangeErrorPrototype.as<Object>())->init(this, rangeErrorCtor.as<Object>());
|
|
|
|
static_cast<ReferenceErrorPrototype *>(referenceErrorPrototype.as<Object>())->init(this, referenceErrorCtor.as<Object>());
|
|
|
|
static_cast<SyntaxErrorPrototype *>(syntaxErrorPrototype.as<Object>())->init(this, syntaxErrorCtor.as<Object>());
|
|
|
|
static_cast<TypeErrorPrototype *>(typeErrorPrototype.as<Object>())->init(this, typeErrorCtor.as<Object>());
|
|
|
|
static_cast<URIErrorPrototype *>(uRIErrorPrototype.as<Object>())->init(this, uRIErrorCtor.as<Object>());
|
|
|
|
|
|
|
|
static_cast<VariantPrototype *>(variantPrototype.as<Object>())->init();
|
2014-07-24 09:53:59 +00:00
|
|
|
sequencePrototype.cast<SequencePrototype>()->init();
|
2013-05-14 00:01:04 +00:00
|
|
|
|
2014-09-10 12:50:28 +00:00
|
|
|
|
|
|
|
// typed arrays
|
|
|
|
|
2014-11-28 09:05:24 +00:00
|
|
|
arrayBufferCtor = memoryManager->alloc<ArrayBufferCtor>(global);
|
2015-02-13 12:39:20 +00:00
|
|
|
arrayBufferPrototype = memoryManager->alloc<ArrayBufferPrototype>(emptyClass, objectPrototype.as<Object>());
|
|
|
|
static_cast<ArrayBufferPrototype *>(arrayBufferPrototype.as<Object>())->init(this, arrayBufferCtor.as<Object>());
|
2014-09-10 12:50:28 +00:00
|
|
|
|
2014-11-28 09:05:24 +00:00
|
|
|
dataViewCtor = memoryManager->alloc<DataViewCtor>(global);
|
2015-02-13 12:39:20 +00:00
|
|
|
dataViewPrototype = memoryManager->alloc<DataViewPrototype>(emptyClass, objectPrototype.as<Object>());
|
|
|
|
static_cast<DataViewPrototype *>(dataViewPrototype.as<Object>())->init(this, dataViewCtor.as<Object>());
|
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) {
|
2014-11-28 09:05:24 +00:00
|
|
|
typedArrayCtors[i] = memoryManager->alloc<TypedArrayCtor>(global, Heap::TypedArray::Type(i));
|
2014-11-24 14:38:41 +00:00
|
|
|
typedArrayPrototype[i] = memoryManager->alloc<TypedArrayPrototype>(this, 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
|
|
|
|
//
|
2015-03-13 16:21:18 +00:00
|
|
|
rootContext()->global = globalObject->d();
|
|
|
|
rootContext()->callData->thisObject = globalObject;
|
|
|
|
Q_ASSERT(globalObject->d()->vtable);
|
|
|
|
|
|
|
|
globalObject->defineDefaultProperty(QStringLiteral("Object"), objectCtor);
|
|
|
|
globalObject->defineDefaultProperty(QStringLiteral("String"), stringCtor);
|
|
|
|
globalObject->defineDefaultProperty(QStringLiteral("Number"), numberCtor);
|
|
|
|
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-09-11 13:37:31 +00:00
|
|
|
ScopedString str(scope);
|
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-03-13 16:21:18 +00:00
|
|
|
globalObject->defineDefaultProperty(QStringLiteral("Math"), (o = memoryManager->alloc<MathObject>(this)));
|
|
|
|
globalObject->defineDefaultProperty(QStringLiteral("JSON"), (o = memoryManager->alloc<JsonObject>(this)));
|
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
|
|
|
|
2014-11-28 13:02:06 +00:00
|
|
|
evalFunction = memoryManager->alloc<EvalFunction>(global);
|
2015-03-13 16:21:18 +00:00
|
|
|
globalObject->defineDefaultProperty(QStringLiteral("eval"), (o = evalFunction));
|
|
|
|
|
|
|
|
globalObject->defineDefaultProperty(QStringLiteral("parseInt"), GlobalFunctions::method_parseInt, 2);
|
|
|
|
globalObject->defineDefaultProperty(QStringLiteral("parseFloat"), GlobalFunctions::method_parseFloat, 1);
|
|
|
|
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")));
|
2014-12-02 11:23:20 +00:00
|
|
|
thrower = BuiltinFunction::create(global, name, ::throwTypeError);
|
2012-11-17 20:54:26 +00:00
|
|
|
}
|
|
|
|
|
2012-12-04 10:30:26 +00:00
|
|
|
ExecutionEngine::~ExecutionEngine()
|
|
|
|
{
|
2013-07-24 08:29:04 +00:00
|
|
|
delete debugger;
|
2014-06-02 16:33:19 +00:00
|
|
|
debugger = 0;
|
2014-01-22 16:46:20 +00:00
|
|
|
delete profiler;
|
2014-06-02 16:33:19 +00:00
|
|
|
profiler = 0;
|
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
|
|
|
|
|
|
|
QSet<QV4::CompiledData::CompilationUnit*> remainingUnits;
|
|
|
|
qSwap(compilationUnits, remainingUnits);
|
|
|
|
foreach (QV4::CompiledData::CompilationUnit *unit, remainingUnits)
|
|
|
|
unit->unlink();
|
|
|
|
|
2013-06-20 09:32:45 +00:00
|
|
|
delete m_qmlExtensions;
|
2013-05-06 11:29:24 +00:00
|
|
|
emptyClass->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;
|
2014-03-10 14:18:54 +00:00
|
|
|
delete [] argumentsAccessors;
|
2012-12-04 10:30:26 +00:00
|
|
|
}
|
|
|
|
|
2013-07-24 08:29:04 +00:00
|
|
|
void ExecutionEngine::enableDebugger()
|
|
|
|
{
|
|
|
|
Q_ASSERT(!debugger);
|
|
|
|
debugger = new Debugging::Debugger(this);
|
2014-02-14 12:58:40 +00:00
|
|
|
iselFactory.reset(new Moth::ISelFactory);
|
2013-07-24 08:29:04 +00:00
|
|
|
}
|
|
|
|
|
2014-01-22 16:46:20 +00:00
|
|
|
void ExecutionEngine::enableProfiler()
|
|
|
|
{
|
|
|
|
Q_ASSERT(!profiler);
|
2014-06-12 12:33:05 +00:00
|
|
|
profiler = new QV4::Profiling::Profiler(this);
|
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);
|
2015-01-10 16:55:29 +00:00
|
|
|
Scoped<GlobalContext> r(scope, memoryManager->allocManaged<GlobalContext>(sizeof(GlobalContext::Data) + sizeof(CallData)));
|
2014-07-17 13:56:30 +00:00
|
|
|
new (r->d()) GlobalContext::Data(this);
|
|
|
|
r->d()->callData = reinterpret_cast<CallData *>(r->d() + 1);
|
|
|
|
r->d()->callData->tag = QV4::Value::_Integer_Type;
|
|
|
|
r->d()->callData->argc = 0;
|
2015-03-13 16:21:18 +00:00
|
|
|
r->d()->callData->thisObject = globalObject;
|
2014-07-17 13:56:30 +00:00
|
|
|
r->d()->callData->args[0] = Encode::undefined();
|
|
|
|
|
2014-11-28 09:05:24 +00:00
|
|
|
m_rootContext = r->d();
|
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
|
|
|
}
|
|
|
|
|
2014-11-28 09:05:24 +00:00
|
|
|
Heap::ExecutionContext *ExecutionEngine::pushGlobalContext()
|
2013-03-14 13:03:04 +00:00
|
|
|
{
|
2014-07-23 11:56:43 +00:00
|
|
|
Scope scope(this);
|
|
|
|
Scoped<GlobalContext> g(scope, memoryManager->alloc<GlobalContext>(this));
|
2014-11-28 09:05:24 +00:00
|
|
|
g->d()->callData = rootContext()->callData;
|
2013-03-14 13:03:04 +00:00
|
|
|
|
2014-11-28 08:31:10 +00:00
|
|
|
Q_ASSERT(currentContext() == g->d());
|
2014-11-28 09:05:24 +00:00
|
|
|
return g->d();
|
2012-11-17 20:54:26 +00:00
|
|
|
}
|
|
|
|
|
2013-01-13 22:57:35 +00:00
|
|
|
|
2014-11-11 12:34:18 +00:00
|
|
|
Heap::Object *ExecutionEngine::newObject()
|
2012-11-17 20:54:26 +00:00
|
|
|
{
|
2014-05-09 13:23:18 +00:00
|
|
|
Scope scope(this);
|
2014-06-13 12:30:03 +00:00
|
|
|
ScopedObject object(scope, memoryManager->alloc<Object>(this));
|
2014-11-11 12:34:18 +00:00
|
|
|
return object->d();
|
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
|
|
|
{
|
2014-05-09 13:23:18 +00:00
|
|
|
Scope scope(this);
|
2014-11-24 14:38:41 +00:00
|
|
|
ScopedObject object(scope, memoryManager->alloc<Object>(internalClass, prototype));
|
2014-11-11 12:34:18 +00:00
|
|
|
return object->d();
|
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-01-13 20:49:09 +00:00
|
|
|
return ScopedString(scope, memoryManager->alloc<String>(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-01-15 10:36:57 +00:00
|
|
|
Heap::Object *ExecutionEngine::newStringObject(const Value &value)
|
2012-11-17 20:54:26 +00:00
|
|
|
{
|
2014-05-09 12:14:02 +00:00
|
|
|
Scope scope(this);
|
2014-06-13 12:30:03 +00:00
|
|
|
Scoped<StringObject> object(scope, memoryManager->alloc<StringObject>(this, value));
|
2014-11-11 12:34:18 +00:00
|
|
|
return object->d();
|
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
|
|
|
{
|
2014-05-09 12:14:02 +00:00
|
|
|
Scope scope(this);
|
2014-06-13 12:30:03 +00:00
|
|
|
Scoped<NumberObject> object(scope, memoryManager->alloc<NumberObject>(this, value));
|
2014-11-11 12:34:18 +00:00
|
|
|
return object->d();
|
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
|
|
|
{
|
2014-05-09 12:14:02 +00:00
|
|
|
Scope scope(this);
|
2015-01-15 20:54:12 +00:00
|
|
|
ScopedObject object(scope, memoryManager->alloc<BooleanObject>(this, b));
|
2014-11-11 12:34:18 +00:00
|
|
|
return object->d();
|
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);
|
2014-06-13 12:30:03 +00:00
|
|
|
ScopedArrayObject object(scope, memoryManager->alloc<ArrayObject>(this));
|
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
|
|
|
}
|
|
|
|
|
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);
|
2014-06-13 12:30:03 +00:00
|
|
|
ScopedArrayObject object(scope, memoryManager->alloc<ArrayObject>(this, list));
|
2014-11-11 12:34:18 +00:00
|
|
|
return object->d();
|
2012-11-17 20:54:26 +00:00
|
|
|
}
|
|
|
|
|
2014-11-24 14:38:41 +00:00
|
|
|
Heap::ArrayObject *ExecutionEngine::newArrayObject(InternalClass *ic, Object *prototype)
|
2013-09-02 12:25:15 +00:00
|
|
|
{
|
2014-05-09 12:14:02 +00:00
|
|
|
Scope scope(this);
|
2014-11-24 14:38:41 +00:00
|
|
|
ScopedArrayObject object(scope, memoryManager->alloc<ArrayObject>(ic, 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)
|
|
|
|
{
|
|
|
|
Scope scope(this);
|
2015-03-25 18:17:08 +00:00
|
|
|
Scoped<ArrayBuffer> object(scope, memoryManager->alloc<ArrayBuffer>(this, array));
|
2015-03-04 19:57:14 +00:00
|
|
|
return object->d();
|
|
|
|
}
|
|
|
|
|
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
|
|
|
{
|
2014-05-09 12:14:02 +00:00
|
|
|
Scope scope(this);
|
2014-06-13 12:30:03 +00:00
|
|
|
Scoped<DateObject> object(scope, memoryManager->alloc<DateObject>(this, value));
|
2014-11-11 12:34:18 +00:00
|
|
|
return object->d();
|
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);
|
2014-06-13 12:30:03 +00:00
|
|
|
Scoped<DateObject> object(scope, memoryManager->alloc<DateObject>(this, dt));
|
2014-11-11 12:34:18 +00:00
|
|
|
return object->d();
|
2013-05-02 20:33:47 +00:00
|
|
|
}
|
|
|
|
|
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
|
|
|
{
|
2014-02-14 12:58:40 +00:00
|
|
|
bool global = (flags & IR::RegExp::RegExp_Global);
|
2013-01-14 15:53:43 +00:00
|
|
|
bool ignoreCase = false;
|
|
|
|
bool multiline = false;
|
2014-02-14 12:58:40 +00:00
|
|
|
if (flags & IR::RegExp::RegExp_IgnoreCase)
|
2013-01-14 15:53:43 +00:00
|
|
|
ignoreCase = true;
|
2014-02-14 12:58:40 +00:00
|
|
|
if (flags & IR::RegExp::RegExp_Multiline)
|
2013-01-14 15:53:43 +00:00
|
|
|
multiline = true;
|
2012-11-17 20:54:26 +00:00
|
|
|
|
2013-10-15 13:00:24 +00:00
|
|
|
Scope scope(this);
|
|
|
|
Scoped<RegExp> re(scope, RegExp::create(this, pattern, ignoreCase, multiline));
|
|
|
|
return newRegExpObject(re, global);
|
2012-12-12 07:28:08 +00:00
|
|
|
}
|
|
|
|
|
2014-11-11 12:34:18 +00:00
|
|
|
Heap::RegExpObject *ExecutionEngine::newRegExpObject(RegExp *re, bool global)
|
2012-12-12 07:28:08 +00:00
|
|
|
{
|
2014-05-08 20:27:23 +00:00
|
|
|
Scope scope(this);
|
2014-06-13 12:30:03 +00:00
|
|
|
Scoped<RegExpObject> object(scope, memoryManager->alloc<RegExpObject>(this, re, global));
|
2014-11-11 12:34:18 +00:00
|
|
|
return object->d();
|
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
|
|
|
{
|
2014-05-08 20:27:23 +00:00
|
|
|
Scope scope(this);
|
2014-06-13 12:30:03 +00:00
|
|
|
Scoped<RegExpObject> object(scope, memoryManager->alloc<RegExpObject>(this, re));
|
2014-11-11 12:34:18 +00:00
|
|
|
return object->d();
|
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
|
|
|
{
|
2014-05-09 12:14:02 +00:00
|
|
|
Scope scope(this);
|
2015-02-13 12:39:20 +00:00
|
|
|
ScopedObject object(scope, memoryManager->alloc<ErrorObject>(emptyClass, errorPrototype.as<Object>(), value));
|
2014-11-11 12:34:18 +00:00
|
|
|
return object->d();
|
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
|
|
|
{
|
2013-09-25 20:42:58 +00:00
|
|
|
Scope scope(this);
|
|
|
|
ScopedString s(scope, newString(message));
|
2014-06-13 12:30:03 +00:00
|
|
|
ScopedObject error(scope, memoryManager->alloc<SyntaxErrorObject>(this, s));
|
2014-11-11 12:34:18 +00:00
|
|
|
return error->d();
|
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
|
|
|
{
|
2014-05-09 12:14:02 +00:00
|
|
|
Scope scope(this);
|
2014-06-13 12:30:03 +00:00
|
|
|
ScopedObject error(scope, memoryManager->alloc<SyntaxErrorObject>(this, message, fileName, line, column));
|
2014-11-11 12:34:18 +00:00
|
|
|
return error->d();
|
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
|
|
|
{
|
2014-05-09 12:14:02 +00:00
|
|
|
Scope scope(this);
|
2014-06-13 12:30:03 +00:00
|
|
|
ScopedObject o(scope, memoryManager->alloc<ReferenceErrorObject>(this, message));
|
2014-11-11 12:34:18 +00:00
|
|
|
return o->d();
|
2013-05-02 19:37:20 +00:00
|
|
|
}
|
|
|
|
|
2014-11-11 12:34:18 +00:00
|
|
|
Heap::Object *ExecutionEngine::newReferenceErrorObject(const QString &message, const QString &fileName, int lineNumber, int columnNumber)
|
2013-06-14 11:08:13 +00:00
|
|
|
{
|
2014-05-09 12:14:02 +00:00
|
|
|
Scope scope(this);
|
2014-06-13 12:30:03 +00:00
|
|
|
ScopedObject o(scope, memoryManager->alloc<ReferenceErrorObject>(this, message, fileName, lineNumber, columnNumber));
|
2014-11-11 12:34:18 +00:00
|
|
|
return o->d();
|
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
|
|
|
{
|
2014-05-09 12:14:02 +00:00
|
|
|
Scope scope(this);
|
2014-06-13 12:30:03 +00:00
|
|
|
ScopedObject o(scope, memoryManager->alloc<TypeErrorObject>(this, message));
|
2014-11-11 12:34:18 +00:00
|
|
|
return o->d();
|
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
|
|
|
{
|
2014-05-09 12:14:02 +00:00
|
|
|
Scope scope(this);
|
2014-06-13 12:30:03 +00:00
|
|
|
ScopedObject o(scope, memoryManager->alloc<RangeErrorObject>(this, message));
|
2014-11-11 12:34:18 +00:00
|
|
|
return o->d();
|
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
|
|
|
{
|
2014-05-09 12:14:02 +00:00
|
|
|
Scope scope(this);
|
2014-06-13 12:30:03 +00:00
|
|
|
ScopedObject o(scope, memoryManager->alloc<URIErrorObject>(this, message));
|
2014-11-11 12:34:18 +00:00
|
|
|
return o->d();
|
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
|
|
|
{
|
2014-05-09 12:32:59 +00:00
|
|
|
Scope scope(this);
|
2014-06-13 12:30:03 +00:00
|
|
|
ScopedObject o(scope, memoryManager->alloc<VariantObject>(this, v));
|
2014-11-11 12:34:18 +00:00
|
|
|
return o->d();
|
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);
|
2014-07-25 15:44:14 +00:00
|
|
|
ScopedObject obj(scope, memoryManager->alloc<ForEachIteratorObject>(this, o));
|
2014-11-11 12:34:18 +00:00
|
|
|
return obj->d();
|
2013-05-03 14:51:32 +00:00
|
|
|
}
|
|
|
|
|
2014-11-11 12:34:18 +00:00
|
|
|
Heap::Object *ExecutionEngine::qmlContextObject() const
|
2013-05-03 14:51:32 +00:00
|
|
|
{
|
2014-11-28 08:31:10 +00:00
|
|
|
Heap::ExecutionContext *ctx = currentContext();
|
2013-05-27 18:40:33 +00:00
|
|
|
|
2014-11-07 04:46:20 +00:00
|
|
|
if (ctx->type == Heap::ExecutionContext::Type_SimpleCallContext && !ctx->outer)
|
|
|
|
ctx = ctx->parent;
|
2013-05-27 18:40:33 +00:00
|
|
|
|
2014-11-07 04:46:20 +00:00
|
|
|
if (!ctx->outer)
|
2013-05-03 14:51:32 +00:00
|
|
|
return 0;
|
|
|
|
|
2014-11-07 04:46:20 +00:00
|
|
|
while (ctx->outer && ctx->outer->type != Heap::ExecutionContext::Type_GlobalContext)
|
|
|
|
ctx = ctx->outer;
|
2013-05-03 14:51:32 +00:00
|
|
|
|
2013-11-03 14:23:05 +00:00
|
|
|
Q_ASSERT(ctx);
|
2014-11-07 04:46:20 +00:00
|
|
|
if (ctx->type != Heap::ExecutionContext::Type_QmlContext)
|
2013-05-03 14:51:32 +00:00
|
|
|
return 0;
|
|
|
|
|
2014-11-11 12:34:18 +00:00
|
|
|
Q_ASSERT(static_cast<Heap::CallContext *>(ctx)->activation);
|
|
|
|
return static_cast<Heap::CallContext *>(ctx)->activation;
|
2012-11-17 20:54:26 +00:00
|
|
|
}
|
|
|
|
|
2013-09-11 11:23:21 +00:00
|
|
|
QVector<StackFrame> 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);
|
2013-05-22 08:47:36 +00:00
|
|
|
QVector<StackFrame> stack;
|
|
|
|
|
2014-12-31 18:43:46 +00:00
|
|
|
ScopedContext c(scope, currentContext());
|
2015-01-14 11:00:56 +00:00
|
|
|
ScopedFunctionObject function(scope);
|
2013-05-22 08:47:36 +00:00
|
|
|
while (c && frameLimit) {
|
2015-01-14 11:00:56 +00:00
|
|
|
function = c->getFunctionObject();
|
|
|
|
if (function) {
|
2013-05-22 08:47:36 +00:00
|
|
|
StackFrame frame;
|
2014-12-05 12:16:14 +00:00
|
|
|
if (const Function *f = function->function())
|
|
|
|
frame.source = f->sourceFile();
|
2014-11-07 04:24:24 +00:00
|
|
|
name = function->name();
|
2014-03-04 12:19:27 +00:00
|
|
|
frame.function = name->toQString();
|
2013-05-22 08:47:36 +00:00
|
|
|
frame.line = -1;
|
|
|
|
frame.column = -1;
|
2013-05-25 13:31:23 +00:00
|
|
|
|
2014-12-05 12:16:14 +00:00
|
|
|
if (function->function())
|
2014-03-06 08:09:05 +00:00
|
|
|
// line numbers can be negative for places where you can't set a real breakpoint
|
2014-12-05 12:16:14 +00:00
|
|
|
frame.line = qAbs(c->d()->lineNumber);
|
2013-05-25 13:31:23 +00:00
|
|
|
|
2013-05-22 08:47:36 +00:00
|
|
|
stack.append(frame);
|
|
|
|
--frameLimit;
|
|
|
|
}
|
2014-05-06 07:23:59 +00:00
|
|
|
c = c->d()->parent;
|
2013-05-22 08:47:36 +00:00
|
|
|
}
|
2013-05-25 13:31:23 +00:00
|
|
|
|
|
|
|
if (frameLimit && globalCode) {
|
|
|
|
StackFrame frame;
|
2013-08-14 14:02:56 +00:00
|
|
|
frame.source = globalCode->sourceFile();
|
2014-03-03 10:51:17 +00:00
|
|
|
frame.function = globalCode->name()->toQString();
|
2014-11-28 09:05:24 +00:00
|
|
|
frame.line = rootContext()->lineNumber;
|
2013-05-25 13:31:23 +00:00
|
|
|
frame.column = -1;
|
|
|
|
|
|
|
|
stack.append(frame);
|
|
|
|
}
|
2013-05-22 08:47:36 +00:00
|
|
|
return stack;
|
|
|
|
}
|
|
|
|
|
2013-09-11 11:23:21 +00:00
|
|
|
StackFrame ExecutionEngine::currentStackFrame() const
|
2013-05-22 08:47:36 +00:00
|
|
|
{
|
|
|
|
StackFrame frame;
|
|
|
|
frame.line = -1;
|
|
|
|
frame.column = -1;
|
|
|
|
|
2013-05-25 13:31:23 +00:00
|
|
|
QVector<StackFrame> trace = stackTrace(/*limit*/ 1);
|
|
|
|
if (!trace.isEmpty())
|
|
|
|
frame = trace.first();
|
|
|
|
|
2013-05-22 08:47:36 +00:00
|
|
|
return frame;
|
|
|
|
}
|
|
|
|
|
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=[";
|
2014-05-06 07:23:59 +00:00
|
|
|
if (context && context->d()->engine) {
|
|
|
|
const QVector<StackFrame> stackTrace = context->d()->engine->stackTrace(20);
|
2013-12-20 14:38:37 +00:00
|
|
|
for (int i = 0; i < stackTrace.size(); ++i) {
|
|
|
|
if (i)
|
|
|
|
str << ',';
|
|
|
|
const QUrl url(stackTrace.at(i).source);
|
|
|
|
const QString fileName = url.isLocalFile() ? url.toLocalFile() : url.toString();
|
|
|
|
str << "frame={level=\"" << i << "\",func=\"" << stackTrace.at(i).function
|
|
|
|
<< "\",file=\"" << fileName << "\",fullname=\"" << fileName
|
|
|
|
<< "\",line=\"" << stackTrace.at(i).line << "\",language=\"js\"}";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
str << ']';
|
|
|
|
return qstrdup(result.toLocal8Bit().constData());
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" Q_QML_EXPORT char *qt_v4StackTrace(void *executionContext)
|
|
|
|
{
|
|
|
|
return v4StackTrace(reinterpret_cast<const ExecutionContext *>(executionContext));
|
|
|
|
}
|
|
|
|
|
2013-05-29 07:59:40 +00:00
|
|
|
QUrl ExecutionEngine::resolvedUrl(const QString &file)
|
|
|
|
{
|
|
|
|
QUrl src(file);
|
|
|
|
if (!src.isRelative())
|
|
|
|
return src;
|
|
|
|
|
|
|
|
QUrl base;
|
2014-11-07 04:46:20 +00:00
|
|
|
Scope scope(this);
|
2014-12-31 18:43:46 +00:00
|
|
|
ScopedContext c(scope, currentContext());
|
2013-05-29 07:59:40 +00:00
|
|
|
while (c) {
|
2013-11-03 14:23:05 +00:00
|
|
|
CallContext *callCtx = c->asCallContext();
|
2014-05-09 14:50:17 +00:00
|
|
|
if (callCtx && callCtx->d()->function) {
|
2014-11-07 04:24:24 +00:00
|
|
|
if (callCtx->d()->function->function)
|
|
|
|
base.setUrl(callCtx->d()->function->function->sourceFile());
|
2013-05-29 07:59:40 +00:00
|
|
|
break;
|
|
|
|
}
|
2014-05-06 07:23:59 +00:00
|
|
|
c = c->d()->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;
|
|
|
|
}
|
2014-11-28 09:05:24 +00:00
|
|
|
ScopedContext global(scope, scope.engine->rootContext());
|
2014-03-10 14:18:54 +00:00
|
|
|
for (int i = oldSize; i < nArgumentsAccessors; ++i) {
|
2014-11-28 09:05:24 +00:00
|
|
|
argumentsAccessors[i].value = ScopedValue(scope, memoryManager->alloc<ArgumentsGetterFunction>(global, i));
|
|
|
|
argumentsAccessors[i].set = ScopedValue(scope, memoryManager->alloc<ArgumentsSetterFunction>(global, i));
|
2014-03-10 14:18:54 +00:00
|
|
|
}
|
2013-01-18 11:47:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-28 15:46:09 +00:00
|
|
|
void ExecutionEngine::markObjects()
|
|
|
|
{
|
2013-11-02 15:30:26 +00:00
|
|
|
identifierTable->mark(this);
|
2013-01-30 13:56:40 +00:00
|
|
|
|
2014-03-10 14:18:54 +00:00
|
|
|
for (int i = 0; i < nArgumentsAccessors; ++i) {
|
|
|
|
const Property &pd = argumentsAccessors[i];
|
2014-12-03 09:42:07 +00:00
|
|
|
if (Heap::FunctionObject *getter = pd.getter())
|
2013-11-02 15:30:26 +00:00
|
|
|
getter->mark(this);
|
2014-12-03 09:42:07 +00:00
|
|
|
if (Heap::FunctionObject *setter = pd.setter())
|
2013-11-02 15:30:26 +00:00
|
|
|
setter->mark(this);
|
2013-01-28 15:46:09 +00:00
|
|
|
}
|
|
|
|
|
2014-11-28 08:31:10 +00:00
|
|
|
Heap::ExecutionContext *c = currentContext();
|
2013-04-07 15:23:36 +00:00
|
|
|
while (c) {
|
2015-01-09 18:48:56 +00:00
|
|
|
Q_ASSERT(c->inUse());
|
2015-01-09 21:02:40 +00:00
|
|
|
if (!c->isMarked()) {
|
|
|
|
c->setMarkBit();
|
2015-01-10 16:55:29 +00:00
|
|
|
c->gcGetVtable()->markObjects(c, this);
|
2014-07-25 08:13:50 +00:00
|
|
|
}
|
2014-11-07 04:46:20 +00:00
|
|
|
c = c->parent;
|
2013-04-07 15:23:36 +00:00
|
|
|
}
|
2013-01-28 15:46:09 +00:00
|
|
|
|
2014-03-17 11:45:41 +00:00
|
|
|
id_empty->mark(this);
|
|
|
|
id_undefined->mark(this);
|
|
|
|
id_null->mark(this);
|
|
|
|
id_true->mark(this);
|
|
|
|
id_false->mark(this);
|
|
|
|
id_boolean->mark(this);
|
|
|
|
id_number->mark(this);
|
|
|
|
id_string->mark(this);
|
|
|
|
id_object->mark(this);
|
|
|
|
id_function->mark(this);
|
2013-11-02 15:30:26 +00:00
|
|
|
id_length->mark(this);
|
|
|
|
id_prototype->mark(this);
|
|
|
|
id_constructor->mark(this);
|
|
|
|
id_arguments->mark(this);
|
|
|
|
id_caller->mark(this);
|
2014-03-17 11:45:41 +00:00
|
|
|
id_callee->mark(this);
|
2013-11-02 15:30:26 +00:00
|
|
|
id_this->mark(this);
|
|
|
|
id___proto__->mark(this);
|
|
|
|
id_enumerable->mark(this);
|
|
|
|
id_configurable->mark(this);
|
|
|
|
id_writable->mark(this);
|
|
|
|
id_value->mark(this);
|
|
|
|
id_get->mark(this);
|
|
|
|
id_set->mark(this);
|
|
|
|
id_eval->mark(this);
|
|
|
|
id_uintMax->mark(this);
|
|
|
|
id_name->mark(this);
|
|
|
|
id_index->mark(this);
|
|
|
|
id_input->mark(this);
|
|
|
|
id_toString->mark(this);
|
2014-02-27 21:59:39 +00:00
|
|
|
id_destroy->mark(this);
|
2013-11-02 15:30:26 +00:00
|
|
|
id_valueOf->mark(this);
|
2014-09-10 12:50:28 +00:00
|
|
|
id_byteLength->mark(this);
|
2014-09-10 14:39:23 +00:00
|
|
|
id_byteOffset->mark(this);
|
|
|
|
id_buffer->mark(this);
|
2014-11-11 14:08:30 +00:00
|
|
|
id_lastIndex->mark(this);
|
2013-11-02 15:30:26 +00:00
|
|
|
|
|
|
|
objectCtor.mark(this);
|
|
|
|
stringCtor.mark(this);
|
|
|
|
numberCtor.mark(this);
|
|
|
|
booleanCtor.mark(this);
|
|
|
|
arrayCtor.mark(this);
|
|
|
|
functionCtor.mark(this);
|
|
|
|
dateCtor.mark(this);
|
|
|
|
regExpCtor.mark(this);
|
|
|
|
errorCtor.mark(this);
|
|
|
|
evalErrorCtor.mark(this);
|
|
|
|
rangeErrorCtor.mark(this);
|
|
|
|
referenceErrorCtor.mark(this);
|
|
|
|
syntaxErrorCtor.mark(this);
|
|
|
|
typeErrorCtor.mark(this);
|
|
|
|
uRIErrorCtor.mark(this);
|
2014-09-10 12:50:28 +00:00
|
|
|
arrayBufferCtor.mark(this);
|
2014-09-10 14:39:23 +00:00
|
|
|
dataViewCtor.mark(this);
|
2014-11-06 16:40:48 +00:00
|
|
|
for (int i = 0; i < Heap::TypedArray::NTypes; ++i)
|
2014-09-11 13:37:31 +00:00
|
|
|
typedArrayCtors[i].mark(this);
|
2014-11-24 14:38:41 +00:00
|
|
|
|
|
|
|
objectPrototype.mark(this);
|
|
|
|
arrayPrototype.mark(this);
|
|
|
|
stringPrototype.mark(this);
|
|
|
|
numberPrototype.mark(this);
|
|
|
|
booleanPrototype.mark(this);
|
|
|
|
datePrototype.mark(this);
|
|
|
|
functionPrototype.mark(this);
|
|
|
|
regExpPrototype.mark(this);
|
|
|
|
errorPrototype.mark(this);
|
|
|
|
evalErrorPrototype.mark(this);
|
|
|
|
rangeErrorPrototype.mark(this);
|
|
|
|
referenceErrorPrototype.mark(this);
|
|
|
|
syntaxErrorPrototype.mark(this);
|
|
|
|
typeErrorPrototype.mark(this);
|
|
|
|
uRIErrorPrototype.mark(this);
|
|
|
|
variantPrototype.mark(this);
|
2013-11-21 13:26:08 +00:00
|
|
|
sequencePrototype.mark(this);
|
2013-11-02 15:30:26 +00:00
|
|
|
|
2014-11-24 14:38:41 +00:00
|
|
|
arrayBufferPrototype.mark(this);
|
|
|
|
dataViewPrototype.mark(this);
|
|
|
|
for (int i = 0; i < Heap::TypedArray::NTypes; ++i)
|
|
|
|
typedArrayPrototype[i].mark(this);
|
|
|
|
|
2013-11-02 15:30:26 +00:00
|
|
|
thrower->mark(this);
|
2013-09-18 07:30:45 +00:00
|
|
|
|
2013-06-20 09:32:45 +00:00
|
|
|
if (m_qmlExtensions)
|
2013-11-02 15:30:26 +00:00
|
|
|
m_qmlExtensions->markObjects(this);
|
2013-08-15 12:11:19 +00:00
|
|
|
|
2014-04-16 07:36:38 +00:00
|
|
|
classPool->markObjects(this);
|
2013-08-29 11:24:38 +00:00
|
|
|
|
2013-08-15 12:11:19 +00:00
|
|
|
for (QSet<CompiledData::CompilationUnit*>::ConstIterator it = compilationUnits.constBegin(), end = compilationUnits.constEnd();
|
|
|
|
it != end; ++it)
|
2013-11-02 15:30:26 +00:00
|
|
|
(*it)->markObjects(this);
|
2013-01-28 15:46:09 +00:00
|
|
|
}
|
2013-05-25 13:31:23 +00:00
|
|
|
|
2013-06-20 09:32:45 +00:00
|
|
|
QmlExtensions *ExecutionEngine::qmlExtensions()
|
|
|
|
{
|
|
|
|
if (!m_qmlExtensions)
|
|
|
|
m_qmlExtensions = new QmlExtensions;
|
|
|
|
return m_qmlExtensions;
|
|
|
|
}
|
|
|
|
|
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)
|
2014-04-29 09:02:35 +00:00
|
|
|
exceptionStackTrace = error->d()->stackTrace;
|
2013-10-01 14:19:28 +00:00
|
|
|
else
|
|
|
|
exceptionStackTrace = stackTrace();
|
|
|
|
|
|
|
|
if (debugger)
|
2013-10-16 10:29:47 +00:00
|
|
|
debugger->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));
|
2014-07-28 08:07:57 +00:00
|
|
|
QString msg = s->toQString() + QStringLiteral(" 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));
|
2014-07-28 08:07:57 +00:00
|
|
|
QString msg = s->toQString() + QStringLiteral(" out of range");
|
|
|
|
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);
|
|
|
|
ScopedValue v(scope, newString(QStringLiteral("Unimplemented ") + message));
|
|
|
|
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()) {
|
|
|
|
QV4::StackFrame frame = trace.first();
|
|
|
|
error.setUrl(QUrl(frame.source));
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2013-11-11 10:22:24 +00:00
|
|
|
bool ExecutionEngine::recheckCStackLimits()
|
|
|
|
{
|
|
|
|
int dummy;
|
|
|
|
#ifdef Q_OS_WIN
|
|
|
|
// ### this is only required on windows, where we currently use heuristics to get the stack limit
|
|
|
|
if (cStackLimit - reinterpret_cast<quintptr>(&dummy) > 128*1024)
|
|
|
|
// we're more then 128k away from our stack limit, assume the thread has changed, and
|
|
|
|
// call getStackLimit
|
|
|
|
#endif
|
|
|
|
// this can happen after a thread change
|
|
|
|
cStackLimit = getStackLimit();
|
|
|
|
|
|
|
|
return (reinterpret_cast<quintptr>(&dummy) >= cStackLimit);
|
|
|
|
}
|
|
|
|
|
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-01-02 14:07:35 +00:00
|
|
|
static QVariant objectToVariant(QV4::ExecutionEngine *e, 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>())
|
2015-01-02 13:37:26 +00:00
|
|
|
return v->d()->data;
|
|
|
|
|
|
|
|
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
|
|
|
|
2015-02-13 12:39:20 +00:00
|
|
|
if (value.as<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());
|
|
|
|
} else if (object->as<QV4::QmlContextWrapper>()) {
|
|
|
|
return QVariant();
|
|
|
|
} else if (QV4::QmlTypeWrapper *w = object->as<QV4::QmlTypeWrapper>()) {
|
|
|
|
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())
|
2015-01-02 13:37:26 +00:00
|
|
|
return QVariant(QMetaType::VoidStar, (void *)0);
|
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();
|
|
|
|
if (value.isString())
|
|
|
|
return value.stringValue()->toQString();
|
2015-02-13 09:02:28 +00:00
|
|
|
if (const QV4::QQmlLocaleData *ld = value.as<QV4::QQmlLocaleData>())
|
2015-01-02 13:37:26 +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();
|
|
|
|
// 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-01-02 14:07:35 +00:00
|
|
|
static QVariant objectToVariant(QV4::ExecutionEngine *e, 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();
|
|
|
|
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-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:
|
2015-03-12 14:33:50 +00:00
|
|
|
return newString(QChar::fromLatin1(*reinterpret_cast<const char *>(ptr)))->asReturnedValue();
|
2015-01-02 13:37:26 +00:00
|
|
|
case QMetaType::UChar:
|
2015-03-12 14:33:50 +00:00
|
|
|
return newString(QChar::fromLatin1(*reinterpret_cast<const unsigned char *>(ptr)))->asReturnedValue();
|
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:
|
2015-01-02 14:07:35 +00:00
|
|
|
return QV4::Encode(newDateObject(QDateTime(QDate(1970,1,1), *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;
|
|
|
|
QDLRP *p = QDLRP::get((QQmlListReference*)ptr);
|
|
|
|
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*>?
|
|
|
|
const QList<QObject *> &list = *(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
|
|
|
}
|
|
|
|
|
|
|
|
QVariantMap ExecutionEngine::variantMapFromJS(Object *o)
|
|
|
|
{
|
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();
|
|
|
|
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-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-01-15 10:36:57 +00:00
|
|
|
bool ExecutionEngine::metaTypeFromJS(const QV4::Value &value, int type, void *data)
|
2015-01-02 13:37:26 +00:00
|
|
|
{
|
2015-01-02 14:07:35 +00:00
|
|
|
QV4::Scope scope(this);
|
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-01-15 10:36:57 +00:00
|
|
|
*reinterpret_cast<bool*>(data) = value.toBoolean();
|
2015-01-02 13:37:26 +00:00
|
|
|
return true;
|
|
|
|
case QMetaType::Int:
|
2015-01-15 10:36:57 +00:00
|
|
|
*reinterpret_cast<int*>(data) = value.toInt32();
|
2015-01-02 13:37:26 +00:00
|
|
|
return true;
|
|
|
|
case QMetaType::UInt:
|
2015-01-15 10:36:57 +00:00
|
|
|
*reinterpret_cast<uint*>(data) = value.toUInt32();
|
2015-01-02 13:37:26 +00:00
|
|
|
return true;
|
|
|
|
case QMetaType::LongLong:
|
2015-01-15 10:36:57 +00:00
|
|
|
*reinterpret_cast<qlonglong*>(data) = qlonglong(value.toInteger());
|
2015-01-02 13:37:26 +00:00
|
|
|
return true;
|
|
|
|
case QMetaType::ULongLong:
|
2015-01-15 10:36:57 +00:00
|
|
|
*reinterpret_cast<qulonglong*>(data) = qulonglong(value.toInteger());
|
2015-01-02 13:37:26 +00:00
|
|
|
return true;
|
|
|
|
case QMetaType::Double:
|
2015-01-15 10:36:57 +00:00
|
|
|
*reinterpret_cast<double*>(data) = value.toNumber();
|
2015-01-02 13:37:26 +00:00
|
|
|
return true;
|
|
|
|
case QMetaType::QString:
|
2015-01-15 10:36:57 +00:00
|
|
|
if (value.isUndefined() || value.isNull())
|
2015-01-02 13:37:26 +00:00
|
|
|
*reinterpret_cast<QString*>(data) = QString();
|
|
|
|
else
|
2015-01-15 10:36:57 +00:00
|
|
|
*reinterpret_cast<QString*>(data) = value.toQString();
|
2015-01-02 13:37:26 +00:00
|
|
|
return true;
|
|
|
|
case QMetaType::Float:
|
2015-01-15 10:36:57 +00:00
|
|
|
*reinterpret_cast<float*>(data) = value.toNumber();
|
2015-01-02 13:37:26 +00:00
|
|
|
return true;
|
|
|
|
case QMetaType::Short:
|
2015-01-15 10:36:57 +00:00
|
|
|
*reinterpret_cast<short*>(data) = short(value.toInt32());
|
2015-01-02 13:37:26 +00:00
|
|
|
return true;
|
|
|
|
case QMetaType::UShort:
|
2015-01-15 10:36:57 +00:00
|
|
|
*reinterpret_cast<unsigned short*>(data) = value.toUInt16();
|
2015-01-02 13:37:26 +00:00
|
|
|
return true;
|
|
|
|
case QMetaType::Char:
|
2015-01-15 10:36:57 +00:00
|
|
|
*reinterpret_cast<char*>(data) = char(value.toInt32());
|
2015-01-02 13:37:26 +00:00
|
|
|
return true;
|
|
|
|
case QMetaType::UChar:
|
2015-01-15 10:36:57 +00:00
|
|
|
*reinterpret_cast<unsigned char*>(data) = (unsigned char)(value.toInt32());
|
2015-01-02 13:37:26 +00:00
|
|
|
return true;
|
|
|
|
case QMetaType::QChar:
|
2015-01-15 10:36:57 +00:00
|
|
|
if (value.isString()) {
|
|
|
|
QString str = value.stringValue()->toQString();
|
2015-01-02 13:37:26 +00:00
|
|
|
*reinterpret_cast<QChar*>(data) = str.isEmpty() ? QChar() : str.at(0);
|
|
|
|
} else {
|
2015-01-15 10:36:57 +00:00
|
|
|
*reinterpret_cast<QChar*>(data) = QChar(ushort(value.toUInt16()));
|
2015-01-02 13:37:26 +00:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
case QMetaType::QDateTime:
|
2015-02-13 10:31:45 +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-02-13 10:31:45 +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-02-13 09:02:28 +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-02-13 09:02:28 +00:00
|
|
|
const QV4::QObjectWrapper *qobjectWrapper = value.as<QV4::QObjectWrapper>();
|
2015-01-15 10:36:57 +00:00
|
|
|
if (qobjectWrapper || value.isNull()) {
|
2015-01-02 13:37:26 +00:00
|
|
|
*reinterpret_cast<QObject* *>(data) = qtObjectFromJS(scope.engine, value);
|
|
|
|
return true;
|
|
|
|
} break;
|
|
|
|
}
|
|
|
|
case QMetaType::QStringList: {
|
|
|
|
QV4::ScopedArrayObject a(scope, value);
|
|
|
|
if (a) {
|
|
|
|
*reinterpret_cast<QStringList *>(data) = a->toQStringList();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case QMetaType::QVariantList: {
|
|
|
|
QV4::ScopedArrayObject a(scope, value);
|
|
|
|
if (a) {
|
2015-01-02 14:07:35 +00:00
|
|
|
*reinterpret_cast<QVariantList *>(data) = scope.engine->toVariant(a, /*typeHint*/-1, /*createJSValueForObjects*/false).toList();
|
2015-01-02 13:37:26 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case QMetaType::QVariantMap: {
|
|
|
|
QV4::ScopedObject o(scope, value);
|
|
|
|
if (o) {
|
|
|
|
*reinterpret_cast<QVariantMap *>(data) = variantMapFromJS(o);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case QMetaType::QVariant:
|
2015-01-02 14:07:35 +00:00
|
|
|
*reinterpret_cast<QVariant*>(data) = scope.engine->toVariant(value, /*typeHint*/-1, /*createJSValueForObjects*/false);
|
2015-01-02 13:37:26 +00:00
|
|
|
return true;
|
|
|
|
case QMetaType::QJsonValue:
|
|
|
|
*reinterpret_cast<QJsonValue *>(data) = QV4::JsonObject::toJsonValue(value);
|
|
|
|
return true;
|
|
|
|
case QMetaType::QJsonObject: {
|
|
|
|
QV4::ScopedObject o(scope, value);
|
|
|
|
*reinterpret_cast<QJsonObject *>(data) = QV4::JsonObject::toJsonObject(o);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case QMetaType::QJsonArray: {
|
|
|
|
QV4::ScopedArrayObject a(scope, value);
|
|
|
|
if (a) {
|
|
|
|
*reinterpret_cast<QJsonArray *>(data) = QV4::JsonObject::toJsonArray(a);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
;
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
QV4::Scoped<QV4::QQmlValueTypeWrapper> vtw(scope, value);
|
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-01-02 14:07:35 +00:00
|
|
|
if (convertToNativeQObject(this, value, name, reinterpret_cast<void* *>(data)))
|
2015-01-02 13:37:26 +00:00
|
|
|
return true;
|
2015-01-15 10:36:57 +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));
|
2015-01-15 10:36:57 +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;
|
2015-01-15 10:36:57 +00:00
|
|
|
} else if (value.isObject()) {
|
2015-01-02 13:37:26 +00:00
|
|
|
// Look in the prototype chain.
|
2015-01-15 10:36:57 +00:00
|
|
|
QV4::ScopedObject proto(scope, value.objectValue()->prototype());
|
2015-01-02 13:37:26 +00:00
|
|
|
while (proto) {
|
|
|
|
bool canCast = false;
|
|
|
|
if (QV4::VariantObject *vo = proto->as<QV4::VariantObject>()) {
|
|
|
|
const QVariant &v = vo->d()->data;
|
|
|
|
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());
|
|
|
|
if (QObject *qobject = qtObjectFromJS(scope.engine, p))
|
|
|
|
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-01-15 10:36:57 +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-01-14 11:50:34 +00:00
|
|
|
*reinterpret_cast<QJSValue*>(data) = QJSValue(this, value.asReturnedValue());
|
2015-01-02 13:37:26 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-01-15 10:36:57 +00:00
|
|
|
static bool convertToNativeQObject(QV4::ExecutionEngine *e, const 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;
|
|
|
|
}
|
|
|
|
|
2015-01-15 10:36:57 +00:00
|
|
|
static QObject *qtObjectFromJS(QV4::ExecutionEngine *engine, const 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) {
|
|
|
|
QVariant variant = v->d()->data;
|
|
|
|
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
|