aboutsummaryrefslogtreecommitdiffstats
path: root/src/declarative/qml/qdeclarativeexpression.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/declarative/qml/qdeclarativeexpression.cpp')
-rw-r--r--src/declarative/qml/qdeclarativeexpression.cpp245
1 files changed, 134 insertions, 111 deletions
diff --git a/src/declarative/qml/qdeclarativeexpression.cpp b/src/declarative/qml/qdeclarativeexpression.cpp
index afd1be1025..a210e4e1d7 100644
--- a/src/declarative/qml/qdeclarativeexpression.cpp
+++ b/src/declarative/qml/qdeclarativeexpression.cpp
@@ -46,7 +46,6 @@
#include "private/qdeclarativecontext_p.h"
#include "private/qdeclarativerewrite_p.h"
#include "private/qdeclarativecompiler_p.h"
-#include "private/qdeclarativeglobalscriptclass_p.h"
#include <QtCore/qdebug.h>
#include <QtScript/qscriptprogram.h>
@@ -79,6 +78,11 @@ QDeclarativeQtScriptExpression::QDeclarativeQtScriptExpression()
QDeclarativeQtScriptExpression::~QDeclarativeQtScriptExpression()
{
+ v8function.Dispose();
+ v8qmlscope.Dispose();
+ v8function = v8::Persistent<v8::Function>();
+ v8qmlscope = v8::Persistent<v8::Function>();
+
if (guardList) { delete [] guardList; guardList = 0; }
if (dataRef) dataRef->release();
if (deleted) *deleted = true;
@@ -103,15 +107,16 @@ void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, const QS
expressionFunctionValid = false;
}
-void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, const QScriptValue &func,
+void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, v8::Handle<v8::Function> func,
QObject *me)
{
- expression = func.toString();
+ // XXX aakenned
+ // expression = func.toString();
QDeclarativeAbstractExpression::setContext(ctxt);
scopeObject = me;
- expressionFunction = func;
+ v8function = v8::Persistent<v8::Function>::New(func);
expressionFunctionMode = ExplicitContext;
expressionFunctionValid = true;
}
@@ -123,7 +128,8 @@ void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, void *ex
url = srcUrl;
line = lineNumber;
- if (dataRef) dataRef->release();
+ Q_ASSERT(!dataRef);
+
dataRef = rc;
if (dataRef) dataRef->addref();
@@ -136,45 +142,42 @@ void QDeclarativeExpressionPrivate::init(QDeclarativeContextData *ctxt, void *ex
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;
+ v8function = evalFunction(ctxt, me, expression, url, line, &v8qmlscope);
- } else {
+ expressionFunctionMode = ExplicitContext;
+ expressionFunctionValid = true;
- if (!dd->cachedPrograms.at(progIdx)) {
- dd->cachedPrograms[progIdx] = new QScriptProgram(expression, url, line);
- }
+ QDeclarativeAbstractExpression::setContext(ctxt);
+ scopeObject = me;
+}
- expressionFunction = evalInObjectScope(ctxt, me, *dd->cachedPrograms.at(progIdx),
- &expressionContext);
+// 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)
+{
+ QDeclarativeEngine *engine = ctxt->engine;
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
- expressionFunctionMode = ExplicitContext;
- expressionFunctionValid = true;
- }
+ // XXX aakenned optimize
+ v8::HandleScope handle_scope;
+ v8::Context::Scope ctxtscope(ep->v8engine.context());
+
+ // XXX try/catch?
- QDeclarativeAbstractExpression::setContext(ctxt);
- scopeObject = me;
+ v8::Local<v8::Object> scopeobject = ep->v8engine.qmlScope(ctxt, scope);
+ v8::Local<v8::Script> script = ep->v8engine.qmlModeCompile(code, filename, line);
+ v8::Local<v8::Value> result = script->Run(scopeobject);
+ if (qmlscope) *qmlscope = v8::Persistent<v8::Object>::New(scopeobject);
+ return v8::Persistent<v8::Function>::New(v8::Local<v8::Function>::Cast(result));
}
QScriptValue QDeclarativeExpressionPrivate::evalInObjectScope(QDeclarativeContextData *context, QObject *object,
const QString &program, const QString &fileName,
int lineNumber, QScriptValue *contextObject)
{
+#if 0
QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context->engine);
QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(&ep->scriptEngine);
if (contextObject) {
@@ -187,12 +190,16 @@ QScriptValue QDeclarativeExpressionPrivate::evalInObjectScope(QDeclarativeContex
QScriptValue rv = ep->scriptEngine.evaluate(program, fileName, lineNumber);
ep->scriptEngine.popContext();
return rv;
+#else
+ qFatal("Not impl");
+#endif
}
QScriptValue QDeclarativeExpressionPrivate::evalInObjectScope(QDeclarativeContextData *context, QObject *object,
const QScriptProgram &program,
QScriptValue *contextObject)
{
+#if 0
QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(context->engine);
QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(&ep->scriptEngine);
if (contextObject) {
@@ -205,6 +212,9 @@ QScriptValue QDeclarativeExpressionPrivate::evalInObjectScope(QDeclarativeContex
QScriptValue rv = ep->scriptEngine.evaluate(program);
ep->scriptEngine.popContext();
return rv;
+#else
+ qFatal("Not impl");
+#endif
}
/*!
@@ -317,16 +327,26 @@ QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, QO
d->setNotifyObject(this, QDeclarativeExpression_notifyIdx);
}
-/*! \internal */
-QDeclarativeExpression::QDeclarativeExpression(QDeclarativeContextData *ctxt, QObject *scope, const QScriptValue &func,
+/*!
+ \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)
{
+ v8::Handle<v8::Function> function = *(v8::Handle<v8::Function> *)functionPtr;
+
Q_D(QDeclarativeExpression);
- d->init(ctxt, func, scope);
+ d->init(ctxt, function, scope);
if (QDeclarativeExpression_notifyIdx == -1)
QDeclarativeExpression_notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("_q_notify()");
+
d->setNotifyObject(this, QDeclarativeExpression_notifyIdx);
}
@@ -377,34 +397,43 @@ void QDeclarativeExpression::setExpression(const QString &expression)
d->resetNotifyOnChange();
d->expression = expression;
d->expressionFunctionValid = false;
- d->expressionFunction = QScriptValue();
+ d->v8function.Dispose();
+ d->v8qmlscope.Dispose();
+ d->v8function = v8::Persistent<v8::Function>();
+ d->v8qmlscope = v8::Persistent<v8::Function>();
}
-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");
+ Q_ASSERT(name->IsString());
- if (!exception.property(fileNameProp).toString().isEmpty()){
- fileName = exception.property(fileNameProp).toString();
- } else {
- fileName = QLatin1String("<Unknown File>");
- }
+ v8::Local<v8::String> file = name->ToString();
+ if (file->Length() == 0)
+ error.setUrl(QUrl(QLatin1String("<Unknown File>")));
+ else
+ error.setUrl(QUrl(QV8Engine::toStringStatic(file)));
- error.setUrl(QUrl(fileName));
- error.setLine(lineNumber);
- error.setColumn(-1);
- error.setDescription(exception.toString());
- } else {
- error = QDeclarativeError();
- }
+ error.setLine(lineNumber);
+ error.setColumn(-1);
+
+ QString qDescription = QV8Engine::toStringStatic(description);
+ if (qDescription.startsWith(QLatin1String("Uncaught ")))
+ qDescription = qDescription.mid(9 /* strlen("Uncaught ") */);
+
+ error.setDescription(qDescription);
+}
+
+void QDeclarativeExpressionPrivate::exceptionToError(QScriptEngine *scriptEngine,
+ QDeclarativeError &error)
+{
+ qFatal("Not implemented - we use v8 now");
}
bool QDeclarativeQtScriptExpression::notifyOnValueChange() const
@@ -448,14 +477,14 @@ QDeclarativeQtScriptExpression::EvaluateFlags QDeclarativeQtScriptExpression::ev
return evalFlags;
}
-QScriptValue QDeclarativeQtScriptExpression::scriptValue(QObject *secondaryScope, bool *isUndefined)
+v8::Local<v8::Value> QDeclarativeQtScriptExpression::v8value(QObject *secondaryScope, bool *isUndefined)
{
Q_ASSERT(context() && context()->engine);
Q_ASSERT(!trackChange || (guardObject && guardObjectNotifyIndex != -1));
- if (!expressionFunction.isValid()) {
+ if (v8function.IsEmpty() || v8function->IsUndefined()) {
if (isUndefined) *isUndefined = true;
- return QScriptValue();
+ return v8::Local<v8::Value>();
}
DeleteWatcher watcher(this);
@@ -467,7 +496,7 @@ QScriptValue QDeclarativeQtScriptExpression::scriptValue(QObject *secondaryScope
ep->captureProperties = trackChange;
ep->capturedProperties.copyAndClear(lastCapturedProperties);
- QScriptValue value = eval(secondaryScope, isUndefined);
+ v8::Local<v8::Value> value = eval(secondaryScope, isUndefined);
if (!watcher.wasDeleted() && trackChange) {
if (ep->capturedProperties.count() == 0) {
@@ -487,59 +516,52 @@ QScriptValue QDeclarativeQtScriptExpression::scriptValue(QObject *secondaryScope
return value;
}
-QScriptValue QDeclarativeQtScriptExpression::eval(QObject *secondaryScope, bool *isUndefined)
+v8::Local<v8::Value> QDeclarativeQtScriptExpression::eval(QObject *secondaryScope, bool *isUndefined)
{
Q_ASSERT(context() && context()->engine);
-
DeleteWatcher watcher(this);
QDeclarativeEngine *engine = context()->engine;
QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
+ QObject *restoreSecondaryScope = 0;
+ if (secondaryScope)
+ restoreSecondaryScope = ep->v8engine.contextWrapper()->setSecondaryScope(v8qmlscope, secondaryScope);
- QDeclarativeContextData *oldSharedContext = 0;
- QObject *oldSharedScope = 0;
- QObject *oldOverride = 0;
- bool isShared = (expressionFunctionMode == SharedContext);
+ v8::TryCatch try_catch;
+ v8::Context::Scope scope(ep->v8engine.context()); // XXX is this needed?
- if (isShared) {
- oldSharedContext = ep->sharedContext;
- oldSharedScope = ep->sharedScope;
- ep->sharedContext = context();
- ep->sharedScope = scopeObject;
- } else {
- oldOverride = ep->contextClass->setOverrideObject(expressionContext, secondaryScope);
+ v8::Handle<v8::Object> This;
+
+ if (evaluateFlags() & RequiresThisObject) {
+ v8::Handle<v8::Value> value = ep->v8engine.newQObject(scopeObject);
+ if (value->IsObject()) This = v8::Handle<v8::Object>::Cast(value);
+ }
+ if (This.IsEmpty()) {
+ This = ep->v8engine.global();
}
- QScriptValue thisObject;
- if (evalFlags & RequiresThisObject)
- thisObject = ep->objectClass->newQObject(scopeObject);
- QScriptValue svalue = expressionFunction.call(thisObject); // This could cause this c++ object to be deleted
+ v8::Local<v8::Value> result = v8function->Call(This, 0, 0);
- if (isShared) {
- ep->sharedContext = oldSharedContext;
- ep->sharedScope = oldSharedScope;
- } else if (!watcher.wasDeleted()) {
- ep->contextClass->setOverrideObject(expressionContext, oldOverride);
- }
+ if (secondaryScope)
+ ep->v8engine.contextWrapper()->setSecondaryScope(v8qmlscope, restoreSecondaryScope);
if (isUndefined)
- *isUndefined = svalue.isUndefined() || scriptEngine->hasUncaughtException();
+ *isUndefined = try_catch.HasCaught() || result->IsUndefined();
- // Handle exception
- if (scriptEngine->hasUncaughtException()) {
- if (!watcher.wasDeleted())
- QDeclarativeExpressionPrivate::exceptionToError(scriptEngine, error);
-
- scriptEngine->clearExceptions();
- return QScriptValue();
- } else {
- if (!watcher.wasDeleted())
+ if (watcher.wasDeleted()) {
+ } else if (try_catch.HasCaught()) {
+ v8::Local<v8::Message> message = try_catch.Message();
+ if (!message.IsEmpty()) {
+ QDeclarativeExpressionPrivate::exceptionToError(message, error);
+ } else {
error = QDeclarativeError();
-
- return svalue;
+ }
+ } else {
+ error = QDeclarativeError();
}
+
+ return result;
}
void QDeclarativeQtScriptExpression::updateGuards(const QPODVector<QDeclarativeEnginePrivate::CapturedProperty> &properties)
@@ -625,31 +647,23 @@ void QDeclarativeQtScriptExpression::updateGuards(const QPODVector<QDeclarativeE
}
}
-QScriptValue QDeclarativeExpressionPrivate::scriptValue(QObject *secondaryScope, bool *isUndefined)
+// Must be called with a valid handle scope
+v8::Local<v8::Value> QDeclarativeExpressionPrivate::v8value(QObject *secondaryScope, bool *isUndefined)
{
if (!expressionFunctionValid) {
QDeclarativeEngine *engine = context()->engine;
QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
- QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine);
-
- QScriptContext *scriptContext = QScriptDeclarativeClass::pushCleanContext(scriptEngine);
- expressionContext = ep->contextClass->newContext(context(), scopeObject);
- scriptContext->pushScope(expressionContext);
- scriptContext->pushScope(ep->globalClass->staticGlobalObject());
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();
+ if (ok) v8function = evalFunction(context(), scopeObject, code, url, line, &v8qmlscope);
expressionFunctionMode = ExplicitContext;
expressionFunctionValid = true;
}
- return QDeclarativeQtScriptExpression::scriptValue(secondaryScope, isUndefined);
+ return QDeclarativeQtScriptExpression::v8value(secondaryScope, isUndefined);
}
QVariant QDeclarativeExpressionPrivate::value(QObject *secondaryScope, bool *isUndefined)
@@ -662,10 +676,19 @@ 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::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;
}
/*!