diff options
Diffstat (limited to 'src/qml/qml/qqmljavascriptexpression.cpp')
-rw-r--r-- | src/qml/qml/qqmljavascriptexpression.cpp | 269 |
1 files changed, 119 insertions, 150 deletions
diff --git a/src/qml/qml/qqmljavascriptexpression.cpp b/src/qml/qml/qqmljavascriptexpression.cpp index 2a1ed1406a..3b3227cbbb 100644 --- a/src/qml/qml/qqmljavascriptexpression.cpp +++ b/src/qml/qml/qqmljavascriptexpression.cpp @@ -42,6 +42,11 @@ #include "qqmljavascriptexpression_p.h" #include <private/qqmlexpression_p.h> +#include <private/qqmlcontextwrapper_p.h> +#include <private/qv4value_p.h> +#include <private/qv4functionobject_p.h> +#include <private/qv4script_p.h> +#include <private/qv4errorobject_p.h> QT_BEGIN_NAMESPACE @@ -61,12 +66,6 @@ bool QQmlDelayedError::addError(QQmlEnginePrivate *e) return true; } -void QQmlDelayedError::setMessage(v8::Handle<v8::Message> message) -{ - qPersistentDispose(m_message); - m_message = qPersistentNew<v8::Message>(message); -} - void QQmlDelayedError::setErrorLocation(const QUrl &url, quint16 line, quint16 column) { m_error.setUrl(url); @@ -84,24 +83,21 @@ void QQmlDelayedError::setErrorObject(QObject *object) m_error.setObject(object); } -/* - Converting from a message to an error is relatively expensive. - - We don't want to do this work for transient exceptions (exceptions - that occur during startup because of the order of binding - execution, but have gone away by the time startup has finished), so we - delay conversion until it is required for displaying the error. -*/ -void QQmlDelayedError::convertMessageToError(QQmlEngine *engine) const +void QQmlDelayedError::setError(const QV4::Exception &e) { - if (!m_message.IsEmpty() && engine) { - v8::HandleScope handle_scope; - v8::Context::Scope context_scope(QQmlEnginePrivate::getV8Engine(engine)->context()); - QQmlExpressionPrivate::exceptionToError(m_message, m_error); - qPersistentDispose(m_message); + m_error.setDescription(e.value().toQString()); + QV4::ExecutionEngine::StackTrace trace = e.stackTrace(); + if (!trace.isEmpty()) { + QV4::ExecutionEngine::StackFrame frame = trace.first(); + m_error.setUrl(QUrl(frame.source)); + m_error.setLine(frame.line); + m_error.setColumn(frame.column); } + + m_error.setColumn(-1); } + QQmlJavaScriptExpression::QQmlJavaScriptExpression(VTable *v) : m_vtable(v) { @@ -125,24 +121,25 @@ void QQmlJavaScriptExpression::resetNotifyOnValueChanged() clearGuards(); } -v8::Local<v8::Value> +QV4::Value QQmlJavaScriptExpression::evaluate(QQmlContextData *context, - v8::Handle<v8::Function> function, bool *isUndefined) + const QV4::Value &function, bool *isUndefined) { return evaluate(context, function, 0, 0, isUndefined); } -v8::Local<v8::Value> +QV4::Value QQmlJavaScriptExpression::evaluate(QQmlContextData *context, - v8::Handle<v8::Function> function, - int argc, v8::Handle<v8::Value> args[], + const QV4::Value &function, + int argc, QV4::Value *args, bool *isUndefined) { Q_ASSERT(context && context->engine); - if (function.IsEmpty() || function->IsUndefined()) { - if (isUndefined) *isUndefined = true; - return v8::Local<v8::Value>(); + if (function.isEmpty() || function.isUndefined()) { + if (isUndefined) + *isUndefined = true; + return QV4::Value::emptyValue(); } QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context->engine); @@ -160,52 +157,41 @@ QQmlJavaScriptExpression::evaluate(QQmlContextData *context, QQmlContextData *lastSharedContext = 0; QObject *lastSharedScope = 0; - bool sharedContext = useSharedContext(); - // All code that follows must check with watcher before it accesses data members // incase we have been deleted. DeleteWatcher watcher(this); - if (sharedContext) { - lastSharedContext = ep->sharedContext; - lastSharedScope = ep->sharedScope; - ep->sharedContext = context; - ep->sharedScope = scopeObject(); - } - - v8::Local<v8::Value> result; - { - v8::TryCatch try_catch; - v8::Handle<v8::Object> This = ep->v8engine()->global(); + QV4::Value result = QV4::Value::undefinedValue(); + QV4::ExecutionEngine *v4 = QV8Engine::getV4(ep->v8engine()); + QV4::ExecutionContext *ctx = v4->current; + try { + QV4::Value 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); + QV4::Value value = QV4::QObjectWrapper::wrap(ctx->engine, scopeObject()); + if (value.isObject()) + This = value; } - result = function->Call(This, argc, args); + result = function.asFunctionObject()->call(This, args, argc); if (isUndefined) - *isUndefined = try_catch.HasCaught() || result->IsUndefined(); - - 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()) { - delayedError()->setMessage(message); + *isUndefined = result.isUndefined(); + + if (!watcher.wasDeleted() && hasDelayedError()) + delayedError()->clearError(); + } catch (QV4::Exception &e) { + e.accept(ctx); + if (isUndefined) + *isUndefined = true; + if (!watcher.wasDeleted()) { + if (!e.value().isEmpty()) { + delayedError()->setError(e); } else { if (hasDelayedError()) delayedError()->clearError(); } - } else { - if (hasDelayedError()) delayedError()->clearError(); } } - if (sharedContext) { - ep->sharedContext = lastSharedContext; - ep->sharedScope = lastSharedScope; - } - if (capture.errorString) { for (int ii = 0; ii < capture.errorString->count(); ++ii) qWarning("%s", qPrintable(capture.errorString->at(ii))); @@ -299,8 +285,10 @@ void QQmlJavaScriptExpression::clearError() QQmlError QQmlJavaScriptExpression::error(QQmlEngine *engine) const { - if (m_vtable.hasValue()) return m_vtable.constValue()->error(engine); - else return QQmlError(); + if (m_vtable.hasValue()) + return m_vtable.constValue()->error(); + else + return QQmlError(); } QQmlDelayedError *QQmlJavaScriptExpression::delayedError() @@ -308,119 +296,100 @@ QQmlDelayedError *QQmlJavaScriptExpression::delayedError() return &m_vtable.value(); } -void QQmlJavaScriptExpression::exceptionToError(v8::Handle<v8::Message> message, QQmlError &error) +void QQmlJavaScriptExpression::exceptionToError(const QV4::Exception &e, QQmlError &error) { - Q_ASSERT(!message.IsEmpty()); - - v8::Handle<v8::Value> name = message->GetScriptResourceName(); - v8::Handle<v8::String> description = message->Get(); - int lineNumber = message->GetLineNumber(); - - v8::Local<v8::String> file = name->IsString()?name->ToString():v8::Local<v8::String>(); - if (file.IsEmpty() || file->Length() == 0) - error.setUrl(QUrl()); - else - error.setUrl(QUrl(QV8Engine::toStringStatic(file))); - - 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); + QV4::ErrorObject *errorObj = e.value().asErrorObject(); + if (errorObj && errorObj->subtype == QV4::ErrorObject::SyntaxError) { + QV4::DiagnosticMessage *msg = static_cast<QV4::SyntaxErrorObject*>(errorObj)->message(); + error.setUrl(QUrl(msg->fileName)); + error.setLine(msg->startLine); + error.setColumn(msg->startColumn); + error.setDescription(msg->message); + // ### FIXME: support msg->next + } else { + QV4::ExecutionEngine::StackTrace trace = e.stackTrace(); + if (!trace.isEmpty()) { + QV4::ExecutionEngine::StackFrame frame = trace.first(); + error.setUrl(QUrl(frame.source)); + error.setLine(frame.line); + error.setColumn(frame.column); + } + error.setDescription(e.value().toQString()); + } } -// Callee owns the persistent handle -v8::Persistent<v8::Function> +QV4::PersistentValue QQmlJavaScriptExpression::evalFunction(QQmlContextData *ctxt, QObject *scope, - const char *code, int codeLength, - const QString &filename, quint16 line, - v8::Persistent<v8::Object> *qmlscope) + const QString &code, const QString &filename, quint16 line, + QV4::PersistentValue *qmlscope) { QQmlEngine *engine = ctxt->engine; QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine); - 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, codeLength, filename, line); - if (tc.HasCaught()) { - QQmlError error; - error.setDescription(QLatin1String("Exception occurred during function compilation")); - error.setLine(line); - error.setUrl(QUrl::fromLocalFile(filename)); - error.setObject(scope); - v8::Local<v8::Message> message = tc.Message(); - if (!message.IsEmpty()) - QQmlExpressionPrivate::exceptionToError(message, error); - ep->warning(error); - return v8::Persistent<v8::Function>(); - } - v8::Local<v8::Value> result = script->Run(scopeobject); - if (tc.HasCaught()) { + QV4::ExecutionEngine *v4 = QV8Engine::getV4(ep->v8engine()); + QV4::ExecutionContext *ctx = v4->current; + + QV4::Value scopeObject = QV4::QmlContextWrapper::qmlScope(ep->v8engine(), ctxt, scope); + QV4::Script script(v4, scopeObject.asObject(), code, filename, line); + QV4::Value result; + try { + script.parse(); + result = script.run(); + } catch (QV4::Exception &e) { + e.accept(ctx); QQmlError error; - error.setDescription(QLatin1String("Exception occurred during function evaluation")); - error.setLine(line); - error.setUrl(QUrl::fromLocalFile(filename)); + QQmlExpressionPrivate::exceptionToError(e, error); + if (error.description().isEmpty()) + error.setDescription(QLatin1String("Exception occurred during function evaluation")); + if (error.line() == -1) + error.setLine(line); + if (error.url().isEmpty()) + error.setUrl(QUrl::fromLocalFile(filename)); error.setObject(scope); - v8::Local<v8::Message> message = tc.Message(); - if (!message.IsEmpty()) - QQmlExpressionPrivate::exceptionToError(message, error); ep->warning(error); - return v8::Persistent<v8::Function>(); + return QV4::PersistentValue(); } - if (qmlscope) *qmlscope = qPersistentNew<v8::Object>(scopeobject); - return qPersistentNew<v8::Function>(v8::Local<v8::Function>::Cast(result)); + if (qmlscope) + *qmlscope = scopeObject; + return result; } -// Callee owns the persistent handle -v8::Persistent<v8::Function> -QQmlJavaScriptExpression::evalFunction(QQmlContextData *ctxt, QObject *scope, - const QString &code, const QString &filename, quint16 line, - v8::Persistent<v8::Object> *qmlscope) +QV4::PersistentValue QQmlJavaScriptExpression::qmlBinding(QQmlContextData *ctxt, QObject *scope, + const QString &code, const QString &filename, quint16 line, + QV4::PersistentValue *qmlscope) { QQmlEngine *engine = ctxt->engine; QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine); - 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()) { - QQmlError error; - error.setDescription(QLatin1String("Exception occurred during function compilation")); - error.setLine(line); - error.setUrl(QUrl::fromLocalFile(filename)); - error.setObject(scope); - v8::Local<v8::Message> message = tc.Message(); - if (!message.IsEmpty()) - QQmlExpressionPrivate::exceptionToError(message, error); - ep->warning(error); - return v8::Persistent<v8::Function>(); - } - v8::Local<v8::Value> result = script->Run(scopeobject); - if (tc.HasCaught()) { + QV4::ExecutionEngine *v4 = QV8Engine::getV4(ep->v8engine()); + QV4::ExecutionContext *ctx = v4->current; + + QV4::Value scopeObject = QV4::QmlContextWrapper::qmlScope(ep->v8engine(), ctxt, scope); + QV4::Script script(v4, scopeObject.asObject(), code, filename, line); + QV4::Value result; + try { + script.parse(); + result = script.qmlBinding(); + } catch (QV4::Exception &e) { + e.accept(ctx); QQmlError error; - error.setDescription(QLatin1String("Exception occurred during function evaluation")); - error.setLine(line); - error.setUrl(QUrl::fromLocalFile(filename)); + QQmlExpressionPrivate::exceptionToError(e, error); + if (error.description().isEmpty()) + error.setDescription(QLatin1String("Exception occurred during function evaluation")); + if (error.line() == -1) + error.setLine(line); + if (error.url().isEmpty()) + error.setUrl(QUrl::fromLocalFile(filename)); error.setObject(scope); - v8::Local<v8::Message> message = tc.Message(); - if (!message.IsEmpty()) - QQmlExpressionPrivate::exceptionToError(message, error); ep->warning(error); - return v8::Persistent<v8::Function>(); + return QV4::PersistentValue(); } - if (qmlscope) *qmlscope = qPersistentNew<v8::Object>(scopeobject); - return qPersistentNew<v8::Function>(v8::Local<v8::Function>::Cast(result)); + if (qmlscope) + *qmlscope = scopeObject; + return result; } + void QQmlJavaScriptExpression::clearGuards() { while (Guard *g = activeGuards.takeFirst()) |