Remove "All rights reserved" line from license headers.
[profile/ivi/qtdeclarative.git] / src / declarative / qml / v8 / qv8engine_p.h
index d4b8730..f46a660 100644 (file)
@@ -1,34 +1,34 @@
 /****************************************************************************
 **
-** 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/qglobal.h>
 #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
 
+
+// Uncomment the following line to enable global handle debugging.  When enabled, all the persistent
+// handles allocated using qPersistentNew() (or registered with qPersistentRegsiter()) and disposed
+// with qPersistentDispose() are tracked.  If you try and do something illegal, like double disposing
+// a handle, qFatal() is called.
+// #define QML_GLOBAL_HANDLE_DEBUGGING
+
 #define V8_RESOURCE_TYPE(resourcetype) \
 public: \
     enum { V8ResourceType = QV8ObjectResource:: resourcetype }; \
@@ -78,11 +98,38 @@ private:
 
 #define V8ENGINE() ((QV8Engine *)v8::External::Unwrap(args.Data()))
 #define V8FUNCTION(function, engine) v8::FunctionTemplate::New(function, v8::External::Wrap((QV8Engine*)engine))->GetFunction()
-// XXX Are we mean to return a value here, or is an empty handle ok?
 #define V8THROW_ERROR(string) { \
     v8::ThrowException(v8::Exception::Error(v8::String::New(string))); \
     return v8::Handle<v8::Value>(); \
 }
+#define V8THROW_TYPE(string) { \
+    v8::ThrowException(v8::Exception::TypeError(v8::String::New(string))); \
+    return v8::Handle<v8::Value>(); \
+}
+#define V8ENGINE_ACCESSOR() ((QV8Engine *)v8::External::Unwrap(info.Data()));
+#define V8THROW_ERROR_SETTER(string) { \
+    v8::ThrowException(v8::Exception::Error(v8::String::New(string))); \
+    return; \
+}
+
+#define V8_DEFINE_EXTENSION(dataclass, datafunction) \
+    inline dataclass *datafunction(QV8Engine *engine) \
+    { \
+        static int extensionId = -1; \
+        if (extensionId == -1) { \
+            QV8Engine::registrationMutex()->lock(); \
+            if (extensionId == -1) \
+                extensionId = QV8Engine::registerExtension(); \
+            QV8Engine::registrationMutex()->unlock(); \
+        } \
+        dataclass *rv = (dataclass *)engine->extensionData(extensionId); \
+        if (!rv) { \
+            rv = new dataclass(engine); \
+            engine->setExtensionData(extensionId, rv); \
+        } \
+        return rv; \
+    } \
+
 
 class QV8Engine;
 class QV8ObjectResource : public v8::Object::ExternalResource
@@ -90,18 +137,28 @@ class QV8ObjectResource : public v8::Object::ExternalResource
 public:
     QV8ObjectResource(QV8Engine *engine) : engine(engine) { Q_ASSERT(engine); }
     enum ResourceType { ContextType, QObjectType, TypeType, ListType, VariantType, 
-                        ValueTypeType, XMLHttpRequestType, DOMNodeType, SQLDatabaseType };
+                        ValueTypeType, XMLHttpRequestType, DOMNodeType, SQLDatabaseType,
+                        ListModelType, Context2DType, Context2DStyleType, Context2DPixelArrayType, 
+                        ParticleDataType, SignalHandlerType, IncubatorType, VisualDataItemType,
+                        SequenceType, LocaleDataType };
     virtual ResourceType resourceType() const = 0;
 
     QV8Engine *engine;
 };
 
 template<class T>
-T *v8_resource_cast(v8::Handle<v8::Object> object) {
+inline T *v8_resource_cast(v8::Handle<v8::Object> object) {
     QV8ObjectResource *resource = static_cast<QV8ObjectResource *>(object->GetExternalResource());
     return (resource && (quint32)resource->resourceType() == (quint32)T::V8ResourceType)?static_cast<T *>(resource):0;
 }
 
+template<class T>
+inline T *v8_resource_check(v8::Handle<v8::Object> object) {
+    T *resource = static_cast<T *>(object->GetExternalResource());
+    Q_ASSERT(resource && resource->resourceType() == (quint32)T::V8ResourceType);
+    return resource;
+}
+
 // Used to allow a QObject method take and return raw V8 handles without having to expose
 // v8 in the public API.
 // Use like this:
@@ -150,12 +207,13 @@ public:
     QDeclarativeV8Handle &operator=(const QDeclarativeV8Handle &other) { d = other.d; return *this; }
 
     static QDeclarativeV8Handle fromHandle(v8::Handle<v8::Value> h) {
-        return reinterpret_cast<QDeclarativeV8Handle &>(h);
+        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) {}
     void *d;
 };
 
@@ -164,29 +222,101 @@ class QDeclarativeEngine;
 class QDeclarativeValueType;
 class QNetworkAccessManager;
 class QDeclarativeContextData;
-class Q_AUTOTEST_EXPORT QV8Engine 
+
+class Q_AUTOTEST_EXPORT QV8GCCallback
 {
+private:
+    class ThreadData;
 public:
-    QV8Engine();
-    ~QV8Engine();
+    static void garbageCollectorPrologueCallback(v8::GCType, v8::GCCallbackFlags);
+    static void registerGcPrologueCallback();
 
-    void init(QDeclarativeEngine *);
+    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:
+    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() {}
+    };
+
+    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; }
 
+    Deletable *listModelData() { return m_listModelData; }
+    void setListModelData(Deletable *d) { if (m_listModelData) delete m_listModelData; m_listModelData = d; }
+
     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);
     inline QString toString(v8::Handle<v8::String> string);
@@ -206,8 +336,12 @@ public:
     // 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 &regexp);
+    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>);
 
@@ -218,6 +352,9 @@ public:
     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 &);
@@ -228,11 +365,104 @@ public:
     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;
 
-private:
+    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 *);
+    static void releaseHandle(void *);
+#endif
+
+    static QMutex *registrationMutex();
+    static int registerExtension();
+
+    inline Deletable *extensionData(int) const;
+    void setExtensionData(int, Deletable *);
+
+    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;
@@ -241,47 +471,79 @@ private:
     QV8ListWrapper m_listWrapper;
     QV8VariantWrapper m_variantWrapper;
     QV8ValueTypeWrapper m_valueTypeWrapper;
+    QV8SequenceWrapper m_sequenceWrapper;
 
     v8::Persistent<v8::Function> m_getOwnPropertyNames;
+    v8::Persistent<v8::Function> m_freezeObject;
 
     void *m_xmlHttpRequestData;
     void *m_sqlDatabaseData;
 
-    QSet<QString> m_illegalNames;
+    QVector<Deletable *> m_extensionData;
+    Deletable *m_listModelData;
+
+    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>);
-    void freezeGlobal();
-
-    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);
 
     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
+// using this method.
+template<class T>
+v8::Persistent<T> qPersistentNew(v8::Handle<T> that)
+{
+    v8::Persistent<T> rv = v8::Persistent<T>::New(that);
+#ifdef QML_GLOBAL_HANDLE_DEBUGGING
+    QV8Engine::registerHandle(*rv);
+#endif
+    return rv;
+}
+
+// Register a Persistent handle that was returned to you by V8 (such as by
+// v8::Context::New). This allows us to do handle tracking on these handles too.
+template<class T>
+void qPersistentRegister(v8::Persistent<T> handle)
+{
+#ifdef QML_GLOBAL_HANDLE_DEBUGGING
+    QV8Engine::registerHandle(*handle);
+#else
+    Q_UNUSED(handle);
+#endif
+}
+
+// Dispose and clear a persistent handle.  *ALL* persistent handles in QML must be
+// disposed using this method.
+template<class T>
+void qPersistentDispose(v8::Persistent<T> &that)
+{
+#ifdef QML_GLOBAL_HANDLE_DEBUGGING
+    QV8Engine::releaseHandle(*that);
+#endif
+    that.Dispose();
+    that.Clear();
+}
+
 QString QV8Engine::toString(v8::Handle<v8::Value> string)
 {
     return m_stringWrapper.toString(string->ToString());
@@ -317,6 +579,20 @@ v8::Handle<v8::Value> QV8Engine::newQObject(QObject *object)
     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);
@@ -332,15 +608,26 @@ v8::Handle<v8::Value> QV8Engine::newValueType(const QVariant &value, QDeclarativ
     return m_valueTypeWrapper.newValueType(value, type);
 }
 
-// XXX perf?
+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)
 {
-    uint16_t buffer[2];
-    int written = string->Write(buffer, 0, 1);
-    if (written == 0) return false;
-    uint16_t c = buffer[0];
-    return ((c != '_' ) && (!(c >= 'a' && c <= 'z')) &&
-           ((c >= 'A' && c <= 'Z') || QChar::category(c) == QChar::Letter_Uppercase));
+    uint16_t c = string->GetCharacter(0);
+    return (c >= 'A' && c <= 'Z') || 
+           (c > 127 && QChar::category(c) == QChar::Letter_Uppercase);
+}
+
+QV8Engine::Deletable *QV8Engine::extensionData(int index) const
+{
+    if (index < m_extensionData.count())
+        return m_extensionData[index];
+    else
+        return 0;
 }
 
 QT_END_NAMESPACE