/****************************************************************************
**
-** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
**
** This file is part of the QtDeclarative module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
-** No Commercial Usage
-** This file contains pre-release code and may not be distributed.
-** You may use this file in accordance with the terms and conditions
-** contained in the Technology Preview License Agreement accompanying
-** this package.
-**
** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
+** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
-** If you have questions regarding the use of this file, please contact
-** Nokia at qt-info@nokia.com.
-**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
**
**
**
#include <QtCore/qvariant.h>
#include <QtCore/qset.h>
#include <QtCore/qmutex.h>
+#include <QtCore/qstack.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/QElapsedTimer>
+#include <QtCore/QThreadStorage>
+
#include <private/qv8_p.h>
+#include <qjsengine.h>
+#include <qjsvalue.h>
+#include "qjsvalue_p.h"
+#include "qjsvalueiterator_p.h"
+#include "qscriptoriginalglobalobject_p.h"
+#include "qscripttools_p.h"
#include <private/qdeclarativepropertycache_p.h>
#include "qv8listwrapper_p.h"
#include "qv8variantwrapper_p.h"
#include "qv8valuetypewrapper_p.h"
+#include "qv8sequencewrapper_p.h"
QT_BEGIN_NAMESPACE
return rv; \
} \
+
class QV8Engine;
class QV8ObjectResource : public v8::Object::ExternalResource
{
QV8ObjectResource(QV8Engine *engine) : engine(engine) { Q_ASSERT(engine); }
enum ResourceType { ContextType, QObjectType, TypeType, ListType, VariantType,
ValueTypeType, XMLHttpRequestType, DOMNodeType, SQLDatabaseType,
- ListModelType, Context2DType, ParticleDataType };
+ ListModelType, Context2DType, Context2DStyleType, Context2DPixelArrayType,
+ ParticleDataType, SignalHandlerType, IncubatorType, VisualDataItemType,
+ SequenceType, LocaleDataType };
virtual ResourceType resourceType() const = 0;
QV8Engine *engine;
return QDeclarativeV8Handle(*h);
}
v8::Handle<v8::Value> toHandle() const {
- return reinterpret_cast<const v8::Handle<v8::Value> &>(*this);
+ return v8::Handle<v8::Value>((v8::Value *)d);
}
private:
QDeclarativeV8Handle(void *d) : d(d) {}
class QDeclarativeValueType;
class QNetworkAccessManager;
class QDeclarativeContextData;
+
+class Q_AUTOTEST_EXPORT QV8GCCallback
+{
+private:
+ class ThreadData;
+public:
+ static void garbageCollectorPrologueCallback(v8::GCType, v8::GCCallbackFlags);
+ static void registerGcPrologueCallback();
+
+ class Q_AUTOTEST_EXPORT Node {
+ public:
+ typedef void (*PrologueCallback)(Node *node);
+ Node(PrologueCallback callback);
+ ~Node();
+
+ QIntrusiveListNode node;
+ PrologueCallback prologueCallback;
+ };
+
+ static void addGcCallbackNode(Node *node);
+};
+
class Q_DECLARATIVE_EXPORT QV8Engine
{
public:
- QV8Engine();
+ static QV8Engine* get(QJSEngine* q) { Q_ASSERT(q); return q->handle(); }
+ static QJSEngine* get(QV8Engine* d) { Q_ASSERT(d); return d->q; }
+
+ QV8Engine(QJSEngine* qq,QJSEngine::ContextOwnership ownership = QJSEngine::CreateNewContext);
~QV8Engine();
+ // ### TODO get rid of it, do we really need CppOwnership?
+ // This enum should be in sync with QDeclarativeEngine::ObjectOwnership
+ enum ObjectOwnership { CppOwnership, JavaScriptOwnership };
+
struct Deletable {
virtual ~Deletable() {}
};
- void init(QDeclarativeEngine *);
+ class Exception
+ {
+ typedef QPair<v8::Persistent<v8::Value>, v8::Persistent<v8::Message> > ValueMessagePair;
+
+ v8::Persistent<v8::Value> m_value;
+ v8::Persistent<v8::Message> m_message;
+ QStack<ValueMessagePair> m_stack;
+
+ Q_DISABLE_COPY(Exception)
+ public:
+ inline Exception();
+ inline ~Exception();
+ inline void set(v8::Handle<v8::Value> value, v8::Handle<v8::Message> message);
+ inline void clear();
+ inline operator bool() const;
+ inline operator v8::Handle<v8::Value>() const;
+ inline int lineNumber() const;
+ inline QStringList backtrace() const;
+
+ inline void push();
+ inline void pop();
+ };
+ void initDeclarativeGlobalObject();
+ void setEngine(QDeclarativeEngine *engine);
QDeclarativeEngine *engine() { return m_engine; }
v8::Local<v8::Object> global() { return m_context->Global(); }
- v8::Handle<v8::Context> context() { return m_context; }
+ v8::Handle<v8::Context> context() const { return m_context; }
+
+ inline void registerValue(QJSValuePrivate *data);
+ inline void unregisterValue(QJSValuePrivate *data);
+ inline void invalidateAllValues();
+
+ inline void registerValueIterator(QJSValueIteratorPrivate *data);
+ inline void unregisterValueIterator(QJSValueIteratorPrivate *data);
+ inline void invalidateAllIterators();
+
QV8ContextWrapper *contextWrapper() { return &m_contextWrapper; }
QV8QObjectWrapper *qobjectWrapper() { return &m_qobjectWrapper; }
QV8TypeWrapper *typeWrapper() { return &m_typeWrapper; }
QV8ListWrapper *listWrapper() { return &m_listWrapper; }
QV8VariantWrapper *variantWrapper() { return &m_variantWrapper; }
+ QV8ValueTypeWrapper *valueTypeWrapper() { return &m_valueTypeWrapper; }
+ QV8SequenceWrapper *sequenceWrapper() { return &m_sequenceWrapper; }
void *xmlHttpRequestData() { return m_xmlHttpRequestData; }
void *sqlDatabaseData() { return m_sqlDatabaseData; }
QDeclarativeContextData *callingContext();
v8::Local<v8::Array> getOwnPropertyNames(v8::Handle<v8::Object>);
+ inline QJSValue::PropertyFlags getPropertyFlags(v8::Handle<v8::Object> object, v8::Handle<v8::Value> property);
void freezeObject(v8::Handle<v8::Value>);
inline QString toString(v8::Handle<v8::Value> string);
// Return the QML global "scope" object for the \a ctxt context and \a scope object.
inline v8::Local<v8::Object> qmlScope(QDeclarativeContextData *ctxt, QObject *scope);
+ QScriptPassPointer<QJSValuePrivate> newRegExp(const QRegExp ®exp);
+ QScriptPassPointer<QJSValuePrivate> newRegExp(const QString &pattern, const QString &flags);
+
// Return a JS wrapper for the given QObject \a object
inline v8::Handle<v8::Value> newQObject(QObject *object);
+ inline v8::Handle<v8::Value> newQObject(QObject *object, const ObjectOwnership ownership);
inline bool isQObject(v8::Handle<v8::Value>);
inline QObject *toQObject(v8::Handle<v8::Value>);
inline v8::Handle<v8::Value> newValueType(QObject *, int coreIndex, QDeclarativeValueType *);
inline v8::Handle<v8::Value> newValueType(const QVariant &, QDeclarativeValueType *);
+ // Create a new sequence type object
+ inline v8::Handle<v8::Value> newSequence(int sequenceType, QObject *, int coreIndex, bool *succeeded);
+
// Create a new QVariant object. This doesn't examine the type of the variant, but always returns
// a QVariant wrapper
inline v8::Handle<v8::Value> newQVariant(const QVariant &);
virtual QNetworkAccessManager *networkAccessManager();
// Return the list of illegal id names (the names of the properties on the global object)
- const QSet<QString> &illegalNames() const;
+ const QStringHash<bool> &illegalNames() const;
+ inline void collectGarbage() { gc(); }
static void gc();
+ void clearExceptions();
+ void setException(v8::Handle<v8::Value> value, v8::Handle<v8::Message> message = v8::Handle<v8::Message>());
+ v8::Handle<v8::Value> throwException(v8::Handle<v8::Value> value);
+ bool hasUncaughtException() const;
+ int uncaughtExceptionLineNumber() const;
+ QStringList uncaughtExceptionBacktrace() const;
+ v8::Handle<v8::Value> uncaughtException() const;
+ void saveException();
+ void restoreException();
+
#ifdef QML_GLOBAL_HANDLE_DEBUGGING
// Used for handle debugging
static void registerHandle(void *);
inline Deletable *extensionData(int) const;
void setExtensionData(int, Deletable *);
-private:
+ inline v8::Handle<v8::Value> makeJSValue(bool value);
+ inline v8::Local<v8::Value> makeJSValue(int value);
+ inline v8::Local<v8::Value> makeJSValue(uint value);
+ inline v8::Local<v8::Value> makeJSValue(double value);
+ inline v8::Handle<v8::Value> makeJSValue(QJSValue::SpecialValue value);
+ inline v8::Local<v8::Value> makeJSValue(const QString &value);
+
+ inline QScriptPassPointer<QJSValuePrivate> evaluate(const QString &program, const QString &fileName = QString(), int lineNumber = 1);
+ QScriptPassPointer<QJSValuePrivate> evaluate(v8::Handle<v8::Script> script, v8::TryCatch& tryCatch);
+
+ QScriptPassPointer<QJSValuePrivate> newArray(uint length);
+ v8::Local<v8::Object> newVariant(const QVariant &variant);
+ QScriptPassPointer<QJSValuePrivate> newVariant(QJSValuePrivate* value, const QVariant &variant);
+
+ v8::Local<v8::Array> variantListToJS(const QVariantList &lst);
+ QVariantList variantListFromJS(v8::Handle<v8::Array> jsArray);
+
+ v8::Local<v8::Object> variantMapToJS(const QVariantMap &vmap);
+ QVariantMap variantMapFromJS(v8::Handle<v8::Object> jsObject);
+
+ v8::Handle<v8::Value> variantToJS(const QVariant &value);
+ QVariant variantFromJS(v8::Handle<v8::Value> value);
+
+ v8::Handle<v8::Value> metaTypeToJS(int type, const void *data);
+ bool metaTypeFromJS(v8::Handle<v8::Value> value, int type, void *data);
+
+ bool convertToNativeQObject(v8::Handle<v8::Value> value,
+ const QByteArray &targetType,
+ void **result);
+
+ QVariant &variantValue(v8::Handle<v8::Value> value);
+
+ QJSValue scriptValueFromInternal(v8::Handle<v8::Value>) const;
+
+ void emitSignalHandlerException();
+
+ // used for console.time(), console.timeEnd()
+ void startTimer(const QString &timerName);
+ qint64 stopTimer(const QString &timerName, bool *wasRunning);
+
+ // used for console.count()
+ int consoleCountHelper(const QString &file, int line, int column);
+
+ QObject *qtObjectFromJS(v8::Handle<v8::Value> value);
+ QSet<int> visitedConversionObjects;
+
+ static QDateTime qtDateTimeFromJsDate(double jsDate);
+
+ void addRelationshipForGC(QObject *object, v8::Persistent<v8::Value> handle);
+ void addRelationshipForGC(QObject *object, QObject *other);
+
+ struct ThreadData {
+ ThreadData();
+ ~ThreadData();
+ v8::Isolate* isolate;
+ bool gcPrologueCallbackRegistered;
+ QIntrusiveList<QV8GCCallback::Node, &QV8GCCallback::Node::node> gcCallbackNodes;
+ };
+
+ static bool hasThreadData();
+ static ThreadData* threadData();
+ static void ensurePerThreadIsolate();
+
+ v8::Persistent<v8::Object> m_strongReferencer;
+
+protected:
+ QJSEngine* q;
QDeclarativeEngine *m_engine;
+ bool m_ownsV8Context;
v8::Persistent<v8::Context> m_context;
+ QScriptOriginalGlobalObject m_originalGlobalObject;
QV8StringWrapper m_stringWrapper;
QV8ContextWrapper m_contextWrapper;
QV8ListWrapper m_listWrapper;
QV8VariantWrapper m_variantWrapper;
QV8ValueTypeWrapper m_valueTypeWrapper;
+ QV8SequenceWrapper m_sequenceWrapper;
v8::Persistent<v8::Function> m_getOwnPropertyNames;
v8::Persistent<v8::Function> m_freezeObject;
QVector<Deletable *> m_extensionData;
Deletable *m_listModelData;
- QSet<QString> m_illegalNames;
+ QStringHash<bool> m_illegalNames;
+
+ Exception m_exception;
+
+ QElapsedTimer m_time;
+ QHash<QString, qint64> m_startedTimers;
+
+ QHash<QString, quint32> m_consoleCount;
QVariant toBasicVariant(v8::Handle<v8::Value>);
void initializeGlobal(v8::Handle<v8::Object>);
- static v8::Handle<v8::Value> gc(const v8::Arguments &args);
- static v8::Handle<v8::Value> print(const v8::Arguments &args);
- static v8::Handle<v8::Value> isQtObject(const v8::Arguments &args);
- static v8::Handle<v8::Value> rgba(const v8::Arguments &args);
- static v8::Handle<v8::Value> hsla(const v8::Arguments &args);
- static v8::Handle<v8::Value> rect(const v8::Arguments &args);
- static v8::Handle<v8::Value> point(const v8::Arguments &args);
- static v8::Handle<v8::Value> size(const v8::Arguments &args);
- static v8::Handle<v8::Value> vector3d(const v8::Arguments &args);
- static v8::Handle<v8::Value> lighter(const v8::Arguments &args);
- static v8::Handle<v8::Value> darker(const v8::Arguments &args);
- static v8::Handle<v8::Value> tint(const v8::Arguments &args);
- static v8::Handle<v8::Value> formatDate(const v8::Arguments &args);
- static v8::Handle<v8::Value> formatTime(const v8::Arguments &args);
- static v8::Handle<v8::Value> formatDateTime(const v8::Arguments &args);
- static v8::Handle<v8::Value> openUrlExternally(const v8::Arguments &args);
- static v8::Handle<v8::Value> fontFamilies(const v8::Arguments &args);
- static v8::Handle<v8::Value> md5(const v8::Arguments &args);
- static v8::Handle<v8::Value> btoa(const v8::Arguments &args);
- static v8::Handle<v8::Value> atob(const v8::Arguments &args);
- static v8::Handle<v8::Value> quit(const v8::Arguments &args);
- static v8::Handle<v8::Value> resolvedUrl(const v8::Arguments &args);
- static v8::Handle<v8::Value> createQmlObject(const v8::Arguments &args);
- static v8::Handle<v8::Value> createComponent(const v8::Arguments &args);
- static v8::Handle<v8::Value> qsTranslate(const v8::Arguments &args);
- static v8::Handle<v8::Value> qsTranslateNoOp(const v8::Arguments &args);
- static v8::Handle<v8::Value> qsTr(const v8::Arguments &args);
- static v8::Handle<v8::Value> qsTrNoOp(const v8::Arguments &args);
- static v8::Handle<v8::Value> qsTrId(const v8::Arguments &args);
- static v8::Handle<v8::Value> qsTrIdNoOp(const v8::Arguments &args);
- static v8::Handle<v8::Value> stringArg(const v8::Arguments &args);
-
double qtDateTimeToJsDate(const QDateTime &dt);
- QDateTime qtDateTimeFromJsDate(double jsDate);
+
+private:
+ static v8::Persistent<v8::Object> *findOwnerAndStrength(QObject *object, bool *shouldBeStrong);
+
+ typedef QScriptIntrusiveList<QJSValuePrivate, &QJSValuePrivate::m_node> ValueList;
+ ValueList m_values;
+ typedef QScriptIntrusiveList<QJSValueIteratorPrivate, &QJSValueIteratorPrivate::m_node> ValueIteratorList;
+ ValueIteratorList m_valueIterators;
+
+ Q_DISABLE_COPY(QV8Engine)
};
// Allocate a new Persistent handle. *ALL* persistent handles in QML must be allocated
return m_qobjectWrapper.newQObject(object);
}
+v8::Handle<v8::Value> QV8Engine::newQObject(QObject *object, const ObjectOwnership ownership)
+{
+ if (!object)
+ return v8::Null();
+
+ v8::Handle<v8::Value> result = newQObject(object);
+ QDeclarativeData *ddata = QDeclarativeData::get(object, true);
+ if (ownership == JavaScriptOwnership && ddata) {
+ ddata->indestructible = false;
+ ddata->explicitIndestructibleSet = true;
+ }
+ return result;
+}
+
v8::Local<v8::String> QV8Engine::toString(const QString &string)
{
return m_stringWrapper.toString(string);
return m_valueTypeWrapper.newValueType(value, type);
}
+v8::Handle<v8::Value> QV8Engine::newSequence(int sequenceType, QObject *object, int property, bool *succeeded)
+{
+ return m_sequenceWrapper.newSequence(sequenceType, object, property, succeeded);
+}
+
// XXX Can this be made more optimal? It is called prior to resolving each and every
// unqualified name in QV8ContextWrapper.
bool QV8Engine::startsWithUpper(v8::Handle<v8::String> string)