Remove "All rights reserved" line from license headers.
[profile/ivi/qtdeclarative.git] / src / declarative / qml / qdeclarativeexpression.cpp
index 247bde9..25d85f4 100644 (file)
@@ -1,8 +1,7 @@
 /****************************************************************************
 **
-** 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_END_LICENSE$
 **
 ****************************************************************************/
 
 #include "qdeclarativeexpression.h"
-#include "private/qdeclarativeexpression_p.h"
+#include "qdeclarativeexpression_p.h"
 
-#include "private/qdeclarativeengine_p.h"
-#include "private/qdeclarativecontext_p.h"
-#include "private/qdeclarativerewrite_p.h"
-#include "private/qdeclarativecompiler_p.h"
-#include "private/qdeclarativeglobalscriptclass_p.h"
+#include "qdeclarativeengine_p.h"
+#include "qdeclarativecontext_p.h"
+#include "qdeclarativerewrite_p.h"
+#include "qdeclarativescriptstring_p.h"
+#include "qdeclarativecompiler_p.h"
 
 #include <QtCore/qdebug.h>
-#include <QtScript/qscriptprogram.h>
-
-#include <private/qscriptdeclarativeclass_p.h>
 
 QT_BEGIN_NAMESPACE
 
@@ -71,26 +68,30 @@ bool QDeclarativeDelayedError::addError(QDeclarativeEnginePrivate *e)
     return true;
 }
 
-QDeclarativeQtScriptExpression::QDeclarativeQtScriptExpression()
-: dataRef(0), expressionFunctionMode(ExplicitContext), scopeObject(0), trackChange(false), 
-  guardList(0), guardListLength(0), guardObject(0), guardObjectNotifyIndex(-1), deleted(0)
+QDeclarativeJavaScriptExpression::QDeclarativeJavaScriptExpression()
+: m_requiresThisObject(0), m_useSharedContext(0), m_notifyOnValueChanged(0), 
+  m_scopeObject(0), guardCapture(0)
 {
 }
 
-QDeclarativeQtScriptExpression::~QDeclarativeQtScriptExpression()
+QDeclarativeJavaScriptExpression::~QDeclarativeJavaScriptExpression()
 {
-    if (guardList) { delete [] guardList; guardList = 0; }
-    if (dataRef) dataRef->release();
-    if (deleted) *deleted = true;
+    if (guardCapture) guardCapture->expression = 0;
+    clearGuards();
 }
 
 QDeclarativeExpressionPrivate::QDeclarativeExpressionPrivate()
-: expressionFunctionValid(true), line(-1)
+: expressionFunctionValid(true), expressionFunctionRewritten(false),
+  extractExpressionFromFunction(false), line(-1), dataRef(0)
 {
 }
 
 QDeclarativeExpressionPrivate::~QDeclarativeExpressionPrivate()
 {
+    qPersistentDispose(v8qmlscope);
+    qPersistentDispose(v8function);
+    if (dataRef) dataRef->release();
+    dataRef = 0;
 }
 
 void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, const QString &expr, 
@@ -99,112 +100,69 @@ void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, const QS
     expression = expr;
 
     QDeclarativeAbstractExpression::setContext(ctxt);
-    scopeObject = me;
+    setScopeObject(me);
     expressionFunctionValid = false;
+    expressionFunctionRewritten = false;
 }
 
-void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, const QScriptValue &func,
+void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, v8::Handle<v8::Function> func,
                                          QObject *me)
 {
-    expression = func.toString();
-
     QDeclarativeAbstractExpression::setContext(ctxt);
-    scopeObject = me;
+    setScopeObject(me);
 
-    expressionFunction = func;
-    expressionFunctionMode = ExplicitContext;
+    v8function = qPersistentNew<v8::Function>(func);
+    setUseSharedContext(false);
     expressionFunctionValid = true;
+    expressionFunctionRewritten = false;
+    extractExpressionFromFunction = true;
 }
 
-void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, void *expr, 
-                                         QDeclarativeRefCount *rc, 
-                                         QObject *me, const QString &srcUrl, int lineNumber)
+void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, const QString &expr,
+                                         bool isRewritten, QObject *me, const QString &srcUrl,
+                                         int lineNumber, int columnNumber)
 {
     url = srcUrl;
     line = lineNumber;
+    column = columnNumber;
 
-    if (dataRef) dataRef->release();
-    dataRef = rc;
-    if (dataRef) dataRef->addref();
-
-    quint32 *exprData = (quint32 *)expr;
-    QDeclarativeCompiledData *dd = (QDeclarativeCompiledData *)rc;
-
-    expression = QString::fromRawData((QChar *)(exprData + 2), exprData[1]);
-
-    int progIdx = *(exprData);
-    bool isSharedProgram = progIdx & 0x80000000;
-    progIdx &= 0x7FFFFFFF;
-
-    QDeclarativeEngine *engine = ctxt->engine;
-    QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
-    QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
-
-    if (isSharedProgram) {
-
-        if (!dd->cachedClosures.at(progIdx)) {
-            QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(scriptEngine);
-            scriptContext->pushScope(ep->contextClass->newSharedContext());
-            scriptContext->pushScope(ep->globalClass->staticGlobalObject());
-            dd->cachedClosures[progIdx] = new QScriptValue(scriptEngine->evaluate(expression, url, line));
-            scriptEngine->popContext();
-        }
-
-        expressionFunction = *dd->cachedClosures.at(progIdx);
-        expressionFunctionMode = SharedContext;
-        expressionFunctionValid = true;
-
-    } else {
-
-        if (!dd->cachedPrograms.at(progIdx)) {
-            dd->cachedPrograms[progIdx] = new QScriptProgram(expression, url, line);
-        }
-
-        expressionFunction = evalInObjectScope(ctxt, me, *dd->cachedPrograms.at(progIdx), 
-                                                     &expressionContext);
+    expression = expr;
 
-        expressionFunctionMode = ExplicitContext;
-        expressionFunctionValid = true;
-    }
+    expressionFunctionValid = false;
+    expressionFunctionRewritten = isRewritten;
 
     QDeclarativeAbstractExpression::setContext(ctxt);
-    scopeObject = me;
+    setScopeObject(me);
 }
 
-QScriptValue QDeclarativeExpressionPrivate::evalInObjectScope(QDeclarativeContextData *context, QObject *object, 
-                                                              const QString &program, const QString &fileName,
-                                                              int lineNumber, QScriptValue *contextObject)
+// Callee owns the persistent handle
+v8::Persistent<v8::Function> 
+QDeclarativeExpressionPrivate::evalFunction(QDeclarativeContextData *ctxt, QObject *scope, 
+                                            const QString &code, const QString &filename, int line,
+                                            v8::Persistent<v8::Object> *qmlscope)
 {
-    QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context->engine);
-    QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(&ep->scriptEngine);
-    if (contextObject) {
-        *contextObject = ep->contextClass->newContext(context, object);
-        scriptContext->pushScope(*contextObject);
-    } else {
-        scriptContext->pushScope(ep->contextClass->newContext(context, object));
-    }
-    scriptContext->pushScope(ep->globalClass->staticGlobalObject());
-    QScriptValue rv = ep->scriptEngine.evaluate(program, fileName, lineNumber);
-    ep->scriptEngine.popContext();
-    return rv;
+    QDeclarativeEngine *engine = ctxt->engine;
+    QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
+
+    // XXX TODO: Implement script caching, like we used to do with QScriptProgram in the
+    // QtScript days
+    v8::HandleScope handle_scope;
+    v8::Context::Scope ctxtscope(ep->v8engine()->context());
+    
+    v8::TryCatch tc;
+    v8::Local<v8::Object> scopeobject = ep->v8engine()->qmlScope(ctxt, scope);
+    v8::Local<v8::Script> script = ep->v8engine()->qmlModeCompile(code, filename, line);
+    if (tc.HasCaught()) return v8::Persistent<v8::Function>();
+    v8::Local<v8::Value> result = script->Run(scopeobject);
+    if (tc.HasCaught()) return v8::Persistent<v8::Function>();
+    if (qmlscope) *qmlscope = qPersistentNew<v8::Object>(scopeobject);
+    return qPersistentNew<v8::Function>(v8::Local<v8::Function>::Cast(result));
 }
 
-QScriptValue QDeclarativeExpressionPrivate::evalInObjectScope(QDeclarativeContextData *context, QObject *object, 
-                                                              const QScriptProgram &program, 
-                                                              QScriptValue *contextObject)
+QDeclarativeExpression *QDeclarativeExpressionPrivate::create(QDeclarativeContextData *ctxt, QObject *object, const QString &expr, bool isRewritten,
+                                      const QString &url, int lineNumber, int columnNumber)
 {
-    QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context->engine);
-    QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(&ep->scriptEngine);
-    if (contextObject) {
-        *contextObject = ep->contextClass->newContext(context, object);
-        scriptContext->pushScope(*contextObject);
-    } else {
-        scriptContext->pushScope(ep->contextClass->newContext(context, object));
-    }
-    scriptContext->pushScope(ep->globalClass->staticGlobalObject());
-    QScriptValue rv = ep->scriptEngine.evaluate(program);
-    ep->scriptEngine.popContext();
-    return rv;
+    return new QDeclarativeExpression(ctxt, object, expr, isRewritten, url, lineNumber, columnNumber, *new QDeclarativeExpressionPrivate);
 }
 
 /*!
@@ -235,8 +193,6 @@ QScriptValue QDeclarativeExpressionPrivate::evalInObjectScope(QDeclarativeContex
     \endcode
 */
 
-static int QDeclarativeExpression_notifyIdx = -1;
-
 /*!
     Create an invalid QDeclarativeExpression.
 
@@ -246,26 +202,67 @@ static int QDeclarativeExpression_notifyIdx = -1;
 QDeclarativeExpression::QDeclarativeExpression()
 : QObject(*new QDeclarativeExpressionPrivate, 0)
 {
-    Q_D(QDeclarativeExpression);
-
-    if (QDeclarativeExpression_notifyIdx == -1) 
-        QDeclarativeExpression_notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()");
-    d->setNotifyObject(this, QDeclarativeExpression_notifyIdx);
 }
 
 /*!  \internal */
-QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, void *expr,
-                                               QDeclarativeRefCount *rc, QObject *me, 
-                                               const QString &url, int lineNumber,
+QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, 
+                                               QObject *object, const QString &expr, bool isRewritten,
+                                               const QString &url, int lineNumber, int columnNumber,
                                                QDeclarativeExpressionPrivate &dd)
 : QObject(dd, 0)
 {
     Q_D(QDeclarativeExpression);
-    d->init(ctxt, expr, rc, me, url, lineNumber);
+    d->init(ctxt, expr, isRewritten, object, url, lineNumber, columnNumber);
+}
+
+/*!
+    Create a QDeclarativeExpression object that is a child of \a parent.
+
+    The \script provides the expression to be evaluated, the context to evaluate it in,
+    and the scope object to evaluate it with.
+
+    This constructor is functionally equivalent to the following, but in most cases
+    is more efficient.
+    \code
+    QDeclarativeExpression expression(script.context(), script.scopeObject(), script.script(), parent);
+    \endcode
+
+    \sa QDeclarativeScriptString
+*/
+QDeclarativeExpression::QDeclarativeExpression(const QDeclarativeScriptString &script, QObject *parent)
+: QObject(*new QDeclarativeExpressionPrivate, parent)
+{
+    Q_D(QDeclarativeExpression);
+    bool defaultConstruction = false;
+
+    int id = script.d.data()->bindingId;
+    if (id < 0) {
+        defaultConstruction = true;
+    } else {
+        QDeclarativeContextData *ctxtdata = QDeclarativeContextData::get(script.context());
+
+        QDeclarativeEnginePrivate *engine = QDeclarativeEnginePrivate::get(script.context()->engine());
+        QDeclarativeCompiledData *cdata = 0;
+        QDeclarativeTypeData *typeData = 0;
+        if (engine && ctxtdata && !ctxtdata->url.isEmpty()) {
+            typeData = engine->typeLoader.get(ctxtdata->url);
+            cdata = typeData->compiledData();
+        }
+
+        if (cdata)
+            d->init(ctxtdata, cdata->primitives.at(id), true, script.scopeObject(),
+                    cdata->name, script.d.data()->lineNumber, script.d.data()->columnNumber);
+        else
+           defaultConstruction = true;
 
-    if (QDeclarativeExpression_notifyIdx == -1) 
-        QDeclarativeExpression_notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()");
-    d->setNotifyObject(this, QDeclarativeExpression_notifyIdx);
+        if (cdata)
+            cdata->release();
+        if (typeData)
+            typeData->release();
+    }
+
+    if (defaultConstruction)
+        d->init(QDeclarativeContextData::get(script.context()), script.script(), script.scopeObject());
 }
 
 /*!
@@ -283,10 +280,6 @@ QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContext *ctxt,
 {
     Q_D(QDeclarativeExpression);
     d->init(QDeclarativeContextData::get(ctxt), expression, scope);
-
-    if (QDeclarativeExpression_notifyIdx == -1) 
-        QDeclarativeExpression_notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()");
-    d->setNotifyObject(this, QDeclarativeExpression_notifyIdx);
 }
 
 /*! 
@@ -298,10 +291,6 @@ QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, QO
 {
     Q_D(QDeclarativeExpression);
     d->init(ctxt, expression, scope);
-
-    if (QDeclarativeExpression_notifyIdx == -1) 
-        QDeclarativeExpression_notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()");
-    d->setNotifyObject(this, QDeclarativeExpression_notifyIdx);
 }
 
 /*!  \internal */
@@ -311,23 +300,24 @@ QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, QO
 {
     Q_D(QDeclarativeExpression);
     d->init(ctxt, expression, scope);
-
-    if (QDeclarativeExpression_notifyIdx == -1) 
-        QDeclarativeExpression_notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()");
-    d->setNotifyObject(this, QDeclarativeExpression_notifyIdx);
 }
 
-/*!  \internal */
-QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, QObject *scope, const QScriptValue &func,
-                       QDeclarativeExpressionPrivate &dd)
+/*!  
+    \internal 
+
+    To avoid exposing v8 in the public API, functionPtr must be a pointer to a v8::Handle<v8::Function>.  
+    For example:
+        v8::Handle<v8::Function> function;
+        new QDeclarativeExpression(ctxt, scope, &function, ...);
+ */
+QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, QObject *scope, void *functionPtr,
+                                               QDeclarativeExpressionPrivate &dd)
 : QObject(dd, 0)
 {
-    Q_D(QDeclarativeExpression);
-    d->init(ctxt, func, scope);
+    v8::Handle<v8::Function> function = *(v8::Handle<v8::Function> *)functionPtr;
 
-    if (QDeclarativeExpression_notifyIdx == -1)
-        QDeclarativeExpression_notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()");
-    d->setNotifyObject(this, QDeclarativeExpression_notifyIdx);
+    Q_D(QDeclarativeExpression);
+    d->init(ctxt, function, scope);
 }
 
 /*!
@@ -364,6 +354,13 @@ QDeclarativeContext *QDeclarativeExpression::context() const
 QString QDeclarativeExpression::expression() const
 {
     Q_D(const QDeclarativeExpression);
+    if (d->extractExpressionFromFunction && context()->engine()) {
+        QV8Engine *v8engine = QDeclarativeEnginePrivate::getV8Engine(context()->engine());
+        v8::HandleScope handle_scope;
+        v8::Context::Scope scope(v8engine->context());
+
+        return v8engine->toString(v8::Handle<v8::Value>(d->v8function));
+    }
     return d->expression;
 }
 
@@ -374,282 +371,235 @@ void QDeclarativeExpression::setExpression(const QString &expression)
 {
     Q_D(QDeclarativeExpression);
 
-    d->resetNotifyOnChange();
+    d->resetNotifyOnValueChanged();
     d->expression = expression;
     d->expressionFunctionValid = false;
-    d->expressionFunction = QScriptValue();
+    d->expressionFunctionRewritten = false;
+    qPersistentDispose(d->v8function);
+    qPersistentDispose(d->v8qmlscope);
 }
 
-void QDeclarativeExpressionPrivate::exceptionToError(QScriptEngine *scriptEngine, 
-                                            QDeclarativeError &error)
+void QDeclarativeExpressionPrivate::exceptionToError(v8::Handle<v8::Message> message, 
+                                                     QDeclarativeError &error)
 {
-    if (scriptEngine->hasUncaughtException() && 
-        scriptEngine->uncaughtException().isError()) {
+    Q_ASSERT(!message.IsEmpty());
 
-        QString fileName;
-        int lineNumber = scriptEngine->uncaughtExceptionLineNumber();
+    v8::Handle<v8::Value> name = message->GetScriptResourceName();
+    v8::Handle<v8::String> description = message->Get();
+    int lineNumber = message->GetLineNumber();
 
-        QScriptValue exception = scriptEngine->uncaughtException();
-        QLatin1String fileNameProp("fileName");
+    v8::Local<v8::String> file = name->IsString()?name->ToString():v8::Local<v8::String>();
+    if (file.IsEmpty() || file->Length() == 0) 
+        error.setUrl(QUrl(QLatin1String("<Unknown File>")));
+    else 
+        error.setUrl(QUrl(QV8Engine::toStringStatic(file)));
 
-        if (!exception.property(fileNameProp).toString().isEmpty()){
-            fileName = exception.property(fileNameProp).toString();
-        } else {
-            fileName = QLatin1String("<Unknown File>");
-        }
+    error.setLine(lineNumber);
+    error.setColumn(-1);
 
-        error.setUrl(QUrl(fileName));
-        error.setLine(lineNumber);
-        error.setColumn(-1);
-        error.setDescription(exception.toString());
-    } else {
-        error = QDeclarativeError();
-    }
-}
+    QString qDescription = QV8Engine::toStringStatic(description);
+    if (qDescription.startsWith(QLatin1String("Uncaught ")))
+        qDescription = qDescription.mid(9 /* strlen("Uncaught ") */);
 
-bool QDeclarativeQtScriptExpression::notifyOnValueChange() const
-{
-    return trackChange;
+    error.setDescription(qDescription);
 }
 
-void QDeclarativeQtScriptExpression::setNotifyOnValueChange(bool notify)
+void QDeclarativeJavaScriptExpression::setNotifyOnValueChanged(bool v)
 {
-    trackChange = notify;
-    if (!notify && guardList) 
-        clearGuards();
+    m_notifyOnValueChanged = v;
+    if (!v) clearGuards();
 }
 
-void QDeclarativeQtScriptExpression::resetNotifyOnChange()
+void QDeclarativeJavaScriptExpression::resetNotifyOnValueChanged()
 {
     clearGuards();
 }
 
-void QDeclarativeQtScriptExpression::setNotifyObject(QObject *object, int notifyIndex)
-{
-    if (guardList) clearGuards();
-
-    if (!object || notifyIndex == -1) {
-        guardObject = 0;
-        notifyIndex = -1;
-    } else {
-        guardObject = object;
-        guardObjectNotifyIndex = notifyIndex;
-
-    }
-}
-
-void QDeclarativeQtScriptExpression::setEvaluateFlags(EvaluateFlags flags)
-{
-    evalFlags = flags;
-}
-
-QDeclarativeQtScriptExpression::EvaluateFlags QDeclarativeQtScriptExpression::evaluateFlags() const
-{
-    return evalFlags;
-}
-
-QScriptValue QDeclarativeQtScriptExpression::scriptValue(QObject *secondaryScope, bool *isUndefined)
+v8::Local<v8::Value> QDeclarativeJavaScriptExpression::evaluate(v8::Handle<v8::Function> function, bool *isUndefined)
 {
     Q_ASSERT(context() && context()->engine);
-    Q_ASSERT(!trackChange || (guardObject && guardObjectNotifyIndex != -1));
 
-    if (!expressionFunction.isValid()) {
+    if (function.IsEmpty() || function->IsUndefined()) {
         if (isUndefined) *isUndefined = true;
-        return QScriptValue();
+        return v8::Local<v8::Value>();
     }
 
-    DeleteWatcher watcher(this);
-
     QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context()->engine);
 
-    bool lastCaptureProperties = ep->captureProperties;
-    QPODVector<QDeclarativeEnginePrivate::CapturedProperty> lastCapturedProperties;
-    ep->captureProperties = trackChange;
-    ep->capturedProperties.copyAndClear(lastCapturedProperties);
-
-    QScriptValue value = eval(secondaryScope, isUndefined);
-
-    if (!watcher.wasDeleted() && trackChange) {
-        if (ep->capturedProperties.count() == 0) {
+    Q_ASSERT(notifyOnValueChanged() || activeGuards.isEmpty());
+    GuardCapture capture(this);
 
-            if (guardList) clearGuards();
-
-        } else {
+    QDeclarativeEnginePrivate::PropertyCapture *lastPropertyCapture = ep->propertyCapture;
+    ep->propertyCapture = notifyOnValueChanged()?&capture:0;
 
-            updateGuards(ep->capturedProperties);
 
-        }
-    }
+    if (notifyOnValueChanged())
+        capture.guards.copyAndClear(activeGuards);
 
-    lastCapturedProperties.copyAndClear(ep->capturedProperties);
-    ep->captureProperties = lastCaptureProperties;
+    QDeclarativeContextData *lastSharedContext = 0;
+    QObject *lastSharedScope = 0;
 
-    return value;
-}
+    bool sharedContext = useSharedContext();
 
-QScriptValue QDeclarativeQtScriptExpression::eval(QObject *secondaryScope, bool *isUndefined)
-{
-    Q_ASSERT(context() && context()->engine);
+    // All code that follows must check with watcher before it accesses data members 
+    // incase we have been deleted.
+    QDeleteWatcher watcher(this);
 
-    DeleteWatcher watcher(this);
+    if (sharedContext) {
+        lastSharedContext = ep->sharedContext;
+        lastSharedScope = ep->sharedScope;
+        ep->sharedContext = context();
+        ep->sharedScope = scopeObject();
+    }
 
-    QDeclarativeEngine *engine = context()->engine;
-    QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
+    v8::Local<v8::Value> result;
+    {
+        v8::TryCatch try_catch;
+        v8::Handle<v8::Object> This = ep->v8engine()->global();
+        if (scopeObject() && requiresThisObject()) {
+            v8::Handle<v8::Value> value = ep->v8engine()->newQObject(scopeObject());
+            if (value->IsObject()) This = v8::Handle<v8::Object>::Cast(value);
+        }
 
-    QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
+        result = function->Call(This, 0, 0);
 
-    QDeclarativeContextData *oldSharedContext = 0;
-    QObject *oldSharedScope = 0;
-    QObject *oldOverride = 0;
-    bool isShared = (expressionFunctionMode == SharedContext);
+        if (isUndefined)
+            *isUndefined = try_catch.HasCaught() || result->IsUndefined();
 
-    if (isShared) {
-        oldSharedContext = ep->sharedContext;
-        oldSharedScope = ep->sharedScope;
-        ep->sharedContext = context();
-        ep->sharedScope = scopeObject;
-    } else {
-        oldOverride = ep->contextClass->setOverrideObject(expressionContext, secondaryScope);
+        if (watcher.wasDeleted()) {
+        } else if (try_catch.HasCaught()) {
+            v8::Context::Scope scope(ep->v8engine()->context());
+            v8::Local<v8::Message> message = try_catch.Message();
+            if (!message.IsEmpty()) {
+                QDeclarativeExpressionPrivate::exceptionToError(message, error);
+            } else {
+                error = QDeclarativeError();
+            }
+        } else {
+            error = QDeclarativeError();
+        }
     }
 
-    QScriptValue thisObject;
-    if (evalFlags & RequiresThisObject)
-        thisObject = ep->objectClass->newQObject(scopeObject);
-    QScriptValue svalue = expressionFunction.call(thisObject); // This could cause this c++ object to be deleted
-
-    if (isShared) {
-        ep->sharedContext = oldSharedContext;
-        ep->sharedScope = oldSharedScope;
-    } else if (!watcher.wasDeleted()) {
-        ep->contextClass->setOverrideObject(expressionContext, oldOverride);
+    if (sharedContext) {
+        ep->sharedContext = lastSharedContext;
+        ep->sharedScope = lastSharedScope;
     }
 
-    if (isUndefined)
-        *isUndefined = svalue.isUndefined() || scriptEngine->hasUncaughtException();
+    if (capture.errorString) {
+        for (int ii = 0; ii < capture.errorString->count(); ++ii)
+            qWarning("%s", qPrintable(capture.errorString->at(ii)));
+        delete capture.errorString;
+        capture.errorString = 0;
+    }
 
-    // Handle exception
-    if (scriptEngine->hasUncaughtException()) {
-        if (!watcher.wasDeleted()) 
-           QDeclarativeExpressionPrivate::exceptionToError(scriptEngine, error);
+    while (Guard *g = capture.guards.takeFirst())
+        g->Delete();
 
-       scriptEngine->clearExceptions();
-       return QScriptValue();
-    } else {
-        if (!watcher.wasDeleted())
-            error = QDeclarativeError();
+    ep->propertyCapture = lastPropertyCapture;
 
-        return svalue;
-    }
+    return result;
 }
 
-void QDeclarativeQtScriptExpression::updateGuards(const QPODVector<QDeclarativeEnginePrivate::CapturedProperty> &properties)
+void QDeclarativeJavaScriptExpression::GuardCapture::captureProperty(QDeclarativeNotifier *n)
 {
-    Q_ASSERT(guardObject);
-    Q_ASSERT(guardObjectNotifyIndex != -1);
+    if (expression) {
 
-    if (properties.count() != guardListLength) {
-        QDeclarativeNotifierEndpoint *newGuardList = new QDeclarativeNotifierEndpoint[properties.count()];
+        // Try and find a matching guard
+        while (!guards.isEmpty() && !guards.first()->isConnected(n))
+            guards.takeFirst()->Delete();
 
-        for (int ii = 0; ii < qMin(guardListLength, properties.count()); ++ii) 
-           guardList[ii].copyAndClear(newGuardList[ii]);
+        Guard *g = 0;
+        if (!guards.isEmpty()) {
+            g = guards.takeFirst();
+            g->cancelNotify();
+            Q_ASSERT(g->isConnected(n));
+        } else {
+            g = Guard::New(expression);
+            g->connect(n);
+        }
 
-        delete [] guardList;
-        guardList = newGuardList;
-        guardListLength = properties.count();
+        expression->activeGuards.append(g);
     }
+}
 
-    bool outputWarningHeader = false;
-    bool noChanges = true;
-    for (int ii = 0; ii < properties.count(); ++ii) {
-        QDeclarativeNotifierEndpoint &guard = guardList[ii];
-        const QDeclarativeEnginePrivate::CapturedProperty &property = properties.at(ii);
-
-        guard.target = guardObject;
-        guard.targetMethod = guardObjectNotifyIndex;
-
-        if (property.notifier != 0) {
-
-            if (!noChanges && guard.isConnected(property.notifier)) {
-                // Nothing to do
-
-            } else {
-                noChanges = false;
-
-                bool existing = false;
-                for (int jj = 0; !existing && jj < ii; ++jj) 
-                    if (guardList[jj].isConnected(property.notifier)) 
-                        existing = true;
-
-                if (existing) {
-                    // duplicate
-                    guard.disconnect();
-                } else {
-                    guard.connect(property.notifier);
-                }
+void QDeclarativeJavaScriptExpression::GuardCapture::captureProperty(QObject *o, int c, int n)
+{
+    if (expression) {
+        if (n == -1) {
+            if (!errorString) {
+                errorString = new QStringList;
+                QString preamble = QLatin1String("QDeclarativeExpression: Expression ") +
+                                   expression->expressionIdentifier() +
+                                   QLatin1String(" depends on non-NOTIFYable properties:");
+                errorString->append(preamble);
             }
 
+            const QMetaObject *metaObj = o->metaObject();
+            QMetaProperty metaProp = metaObj->property(c);
 
-        } else if (property.notifyIndex != -1) {
+            QString error = QLatin1String("    ") +
+                            QString::fromUtf8(metaObj->className()) +
+                            QLatin1String("::") +
+                            QString::fromUtf8(metaProp.name());
+            errorString->append(error);
+        } else {
 
-            if (!noChanges && guard.isConnected(property.object, property.notifyIndex)) {
-                // Nothing to do
+            // Try and find a matching guard
+            while (!guards.isEmpty() && !guards.first()->isConnected(o, n))
+                guards.takeFirst()->Delete();
 
+            Guard *g = 0;
+            if (!guards.isEmpty()) {
+                g = guards.takeFirst();
+                g->cancelNotify();
+                Q_ASSERT(g->isConnected(o, n));
             } else {
-                noChanges = false;
-
-                bool existing = false;
-                for (int jj = 0; !existing && jj < ii; ++jj) 
-                    if (guardList[jj].isConnected(property.object, property.notifyIndex)) 
-                        existing = true;
-
-                if (existing) {
-                    // duplicate
-                    guard.disconnect();
-                } else {
-                    guard.connect(property.object, property.notifyIndex);
-                }
+                g = Guard::New(expression);
+                g->connect(o, n);
             }
 
-        } else {
-            if (!outputWarningHeader) {
-                outputWarningHeader = true;
-                qWarning() << "QDeclarativeExpression: Expression" << expression
-                           << "depends on non-NOTIFYable properties:";
-            }
-
-            const QMetaObject *metaObj = property.object->metaObject();
-            QMetaProperty metaProp = metaObj->property(property.coreIndex);
-
-            qWarning().nospace() << "    " << metaObj->className() << "::" << metaProp.name();
+            expression->activeGuards.append(g);
         }
     }
 }
 
-QScriptValue QDeclarativeExpressionPrivate::scriptValue(QObject *secondaryScope, bool *isUndefined)
+void QDeclarativeJavaScriptExpression::clearGuards()
 {
-    if (!expressionFunctionValid) {
-        QDeclarativeEngine *engine = context()->engine;
-        QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
-        QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
+    while (Guard *g = activeGuards.takeFirst())
+        g->Delete();
+}
 
-        QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(scriptEngine);
-        expressionContext = ep->contextClass->newContext(context(), scopeObject);
-        scriptContext->pushScope(expressionContext);
-        scriptContext->pushScope(ep->globalClass->staticGlobalObject());
+// Must be called with a valid handle scope
+v8::Local<v8::Value> QDeclarativeExpressionPrivate::v8value(QObject *secondaryScope, bool *isUndefined)
+{
+    if (!expressionFunctionValid) {
+        bool ok = true;
 
         QDeclarativeRewrite::RewriteBinding rewriteBinding;
         rewriteBinding.setName(name);
-        bool ok = true;
-        const QString code = rewriteBinding(expression, &ok);
-        if (ok) 
-            expressionFunction = scriptEngine->evaluate(code, url, line);
-
-        scriptEngine->popContext();
-        expressionFunctionMode = ExplicitContext;
+        QString code;
+        if (expressionFunctionRewritten)
+            code = expression;
+        else
+            code = rewriteBinding(expression, &ok);
+
+        if (ok) v8function = evalFunction(context(), scopeObject(), code, url, line, &v8qmlscope);
+        setUseSharedContext(false);
         expressionFunctionValid = true;
     }
 
-    return QDeclarativeQtScriptExpression::scriptValue(secondaryScope, isUndefined);
+
+    if (secondaryScope) {
+        v8::Local<v8::Value> result;
+        QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context()->engine);
+        QObject *restoreSecondaryScope = 0;
+        restoreSecondaryScope = ep->v8engine()->contextWrapper()->setSecondaryScope(v8qmlscope, secondaryScope);
+        result = evaluate(v8function, isUndefined);
+        ep->v8engine()->contextWrapper()->setSecondaryScope(v8qmlscope, restoreSecondaryScope);
+        return result;
+    } else {
+        return evaluate(v8function, isUndefined);
+    }
 }
 
 QVariant QDeclarativeExpressionPrivate::value(QObject *secondaryScope, bool *isUndefined)
@@ -662,10 +612,20 @@ QVariant QDeclarativeExpressionPrivate::value(QObject *secondaryScope, bool *isU
     }
 
     QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(q->engine());
+    QVariant rv;
+
     ep->referenceScarceResources(); // "hold" scarce resources in memory during evaluation.
-    QVariant retn(ep->scriptValueToVariant(scriptValue(secondaryScope, isUndefined), qMetaTypeId<QList<QObject*> >()));
+
+    {
+        v8::HandleScope handle_scope;
+        v8::Context::Scope context_scope(ep->v8engine()->context());
+        v8::Local<v8::Value> result = v8value(secondaryScope, isUndefined);
+        rv = ep->v8engine()->toVariant(result, qMetaTypeId<QList<QObject*> >());
+    }
+
     ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
-    return retn;
+
+    return rv;
 }
 
 /*!
@@ -690,7 +650,7 @@ value changes.
 bool QDeclarativeExpression::notifyOnValueChanged() const
 {
     Q_D(const QDeclarativeExpression);
-    return d->notifyOnValueChange();
+    return d->notifyOnValueChanged();
 }
 
 /*!
@@ -712,7 +672,7 @@ bool QDeclarativeExpression::notifyOnValueChanged() const
 void QDeclarativeExpression::setNotifyOnValueChanged(bool notifyOnChange)
 {
     Q_D(QDeclarativeExpression);
-    d->setNotifyOnValueChange(notifyOnChange);
+    d->setNotifyOnValueChanged(notifyOnChange);
 }
 
 /*!
@@ -736,14 +696,25 @@ int QDeclarativeExpression::lineNumber() const
 }
 
 /*!
+    Returns the source file column number for this expression.  The source location
+    must have been previously set by calling setSourceLocation().
+*/
+int QDeclarativeExpression::columnNumber() const
+{
+    Q_D(const QDeclarativeExpression);
+    return d->column;
+}
+
+/*!
     Set the location of this expression to \a line of \a url. This information
     is used by the script engine.
 */
-void QDeclarativeExpression::setSourceLocation(const QString &url, int line)
+void QDeclarativeExpression::setSourceLocation(const QString &url, int line, int column)
 {
     Q_D(QDeclarativeExpression);
     d->url = url;
     d->line = line;
+    d->column = column;
 }
 
 /*!
@@ -755,7 +726,7 @@ void QDeclarativeExpression::setSourceLocation(const QString &url, int line)
 QObject *QDeclarativeExpression::scopeObject() const
 {
     Q_D(const QDeclarativeExpression);
-    return d->scopeObject;
+    return d->scopeObject();
 }
 
 /*!
@@ -795,19 +766,6 @@ QDeclarativeError QDeclarativeExpression::error() const
     return d->error;
 }
 
-/*! \internal */
-void QDeclarativeExpressionPrivate::_q_notify()
-{
-    emitValueChanged();
-}
-
-void QDeclarativeQtScriptExpression::clearGuards()
-{
-    delete [] guardList; 
-    guardList = 0; 
-    guardListLength = 0;
-}
-
 /*!
     \fn void QDeclarativeExpression::valueChanged()
 
@@ -816,7 +774,7 @@ void QDeclarativeQtScriptExpression::clearGuards()
     calling QDeclarativeExpression::evaluate()) before this signal will be emitted.
 */
 
-void QDeclarativeExpressionPrivate::emitValueChanged()
+void QDeclarativeExpressionPrivate::expressionChanged()
 {
     Q_Q(QDeclarativeExpression);
     emit q->valueChanged();