trace.event("writing binding result");
- bool needsErrorData = false;
+ bool needsErrorLocationData = false;
if (!watcher.wasDeleted() && !hasError())
- needsErrorData = !QQmlPropertyPrivate::writeBinding(*m_coreObject, m_core, context(),
+ needsErrorLocationData = !QQmlPropertyPrivate::writeBinding(*m_coreObject, m_core, context(),
this, result, isUndefined, flags);
if (!watcher.wasDeleted()) {
- if (needsErrorData) {
- QUrl url = QUrl(m_url);
-
- delayedError()->error.setUrl(url);
- delayedError()->error.setLine(m_lineNumber);
- delayedError()->error.setColumn(m_columnNumber);
- }
+ if (needsErrorLocationData)
+ delayedError()->setErrorLocation(QUrl(m_url), m_lineNumber, m_columnNumber);
if (hasError()) {
- if (!delayedError()->addError(ep)) ep->warning(this->error());
+ if (!delayedError()->addError(ep)) ep->warning(this->error(context()->engine));
} else {
clearError();
}
if (s->m_params) s->m_params->setValues(a);
if (s->m_expression && s->m_expression->engine()) {
s->m_expression->evaluate(s->m_params);
- if (s->m_expression && s->m_expression->hasError())
- QQmlEnginePrivate::warning(s->m_expression->engine(), s->m_expression->error());
+ if (s->m_expression && s->m_expression->hasError()) {
+ QQmlEngine *engine = s->m_expression->engine();
+ QQmlEnginePrivate::warning(engine, s->m_expression->error(engine));
+ }
}
if (s->m_params) s->m_params->clearValues();
if (0 == enginePriv->inProgressCreations) {
while (enginePriv->erroredBindings) {
- enginePriv->warning(enginePriv->erroredBindings->error);
+ enginePriv->warning(enginePriv->erroredBindings);
enginePriv->erroredBindings->removeError();
}
}
dumpwarning(errors);
}
+void QQmlEnginePrivate::warning(QQmlDelayedError *error)
+{
+ Q_Q(QQmlEngine);
+ warning(error->error(q));
+}
+
void QQmlEnginePrivate::warning(QQmlEngine *engine, const QQmlError &error)
{
if (engine)
dumpwarning(error);
}
+void QQmlEnginePrivate::warning(QQmlEngine *engine, QQmlDelayedError *error)
+{
+ if (engine)
+ QQmlEnginePrivate::get(engine)->warning(error);
+ else
+ dumpwarning(error->error(0));
+}
+
void QQmlEnginePrivate::warning(QQmlEnginePrivate *engine, const QQmlError &error)
{
if (engine)
void sendQuit();
void warning(const QQmlError &);
void warning(const QList<QQmlError> &);
+ void warning(QQmlDelayedError *);
static void warning(QQmlEngine *, const QQmlError &);
static void warning(QQmlEngine *, const QList<QQmlError> &);
+ static void warning(QQmlEngine *, QQmlDelayedError *);
static void warning(QQmlEnginePrivate *, const QQmlError &);
static void warning(QQmlEnginePrivate *, const QList<QQmlError> &);
QQmlError QQmlExpression::error() const
{
Q_D(const QQmlExpression);
- return d->error();
+ return d->error(engine());
}
/*!
if (0 == enginePriv->inProgressCreations) {
while (enginePriv->erroredBindings) {
- enginePriv->warning(enginePriv->erroredBindings->error);
+ enginePriv->warning(enginePriv->erroredBindings);
enginePriv->erroredBindings->removeError();
}
}
enginePriv->inProgressCreations--;
if (0 == enginePriv->inProgressCreations) {
while (enginePriv->erroredBindings) {
- enginePriv->warning(enginePriv->erroredBindings->error);
+ enginePriv->warning(enginePriv->erroredBindings);
enginePriv->erroredBindings->removeError();
}
}
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, int line, int column)
+{
+ m_error.setUrl(url);
+ m_error.setLine(line);
+ m_error.setColumn(column);
+}
+
+void QQmlDelayedError::setErrorDescription(const QString &description)
+{
+ m_error.setDescription(description);
+}
+
+/*
+ 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
+{
+ 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);
+ }
+}
+
QQmlJavaScriptExpression::QQmlJavaScriptExpression(VTable *v)
: m_vtable(v)
{
v8::Context::Scope scope(ep->v8engine()->context());
v8::Local<v8::Message> message = try_catch.Message();
if (!message.IsEmpty()) {
- QQmlExpressionPrivate::exceptionToError(message, delayedError()->error);
+ delayedError()->setMessage(message);
} else {
- if (hasDelayedError()) delayedError()->error = QQmlError();
+ if (hasDelayedError()) delayedError()->clearError();
}
} else {
- if (hasDelayedError()) delayedError()->error = QQmlError();
+ if (hasDelayedError()) delayedError()->clearError();
}
}
void QQmlJavaScriptExpression::clearError()
{
if (m_vtable.hasValue()) {
- m_vtable.value().error = QQmlError();
+ m_vtable.value().clearError();
m_vtable.value().removeError();
}
}
-QQmlError QQmlJavaScriptExpression::error() const
+QQmlError QQmlJavaScriptExpression::error(QQmlEngine *engine) const
{
- if (m_vtable.hasValue()) return m_vtable.constValue()->error;
+ if (m_vtable.hasValue()) return m_vtable.constValue()->error(engine);
else return QQmlError();
}
{
public:
inline QQmlDelayedError() : nextError(0), prevError(0) {}
- inline ~QQmlDelayedError() { removeError(); }
-
- QQmlError error;
+ inline ~QQmlDelayedError() { qPersistentDispose(m_message); removeError(); }
bool addError(QQmlEnginePrivate *);
prevError = 0;
}
+ inline bool isValid() const { return !m_message.IsEmpty() || m_error.isValid(); }
+ inline const QQmlError &error(QQmlEngine *engine) const { convertMessageToError(engine); return m_error; }
+ inline void clearError() { qPersistentDispose(m_message); m_error = QQmlError(); }
+
+ void setMessage(v8::Handle<v8::Message> message);
+ void setErrorLocation(const QUrl &url, int line, int column);
+ void setErrorDescription(const QString &description);
+
private:
+ void convertMessageToError(QQmlEngine *engine) const;
+
+ mutable QQmlError m_error;
+ mutable v8::Persistent<v8::Message> m_message;
+
QQmlDelayedError *nextError;
QQmlDelayedError **prevError;
};
inline bool hasError() const;
inline bool hasDelayedError() const;
- QQmlError error() const;
+ QQmlError error(QQmlEngine *) const;
void clearError();
QQmlDelayedError *delayedError();
bool QQmlJavaScriptExpression::hasError() const
{
- return m_vtable.hasValue() && m_vtable.constValue()->error.isValid();
+ return m_vtable.hasValue() && m_vtable.constValue()->isValid();
}
bool QQmlJavaScriptExpression::hasDelayedError() const
&& !result->ToObject()->GetHiddenValue(v8engine->bindingFlagKey()).IsEmpty()) {
// we explicitly disallow this case to avoid confusion. Users can still store one
// in an array in a var property if they need to, but the common case is user error.
- expression->delayedError()->error.setDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration."));
+ expression->delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration."));
return false;
}
} else if (type == qMetaTypeId<QJSValue>()) {
if (!result.IsEmpty() && result->IsFunction()
&& !result->ToObject()->GetHiddenValue(v8engine->bindingFlagKey()).IsEmpty()) {
- expression->delayedError()->error.setDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration."));
+ expression->delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration."));
return false;
}
writeValueProperty(object, engine, core, QVariant::fromValue(v8engine->scriptValueFromInternal(result)), context, flags);
errorStr += QLatin1String("[unknown property type]");
else
errorStr += QLatin1String(QMetaType::typeName(type));
- expression->delayedError()->error.setDescription(errorStr);
+ expression->delayedError()->setErrorDescription(errorStr);
return false;
} else if (result->IsFunction()) {
if (!result->ToObject()->GetHiddenValue(v8engine->bindingFlagKey()).IsEmpty())
- expression->delayedError()->error.setDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration."));
+ expression->delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration."));
else
- expression->delayedError()->error.setDescription(QLatin1String("Unable to assign a function to a property of any type other than var."));
+ expression->delayedError()->setErrorDescription(QLatin1String("Unable to assign a function to a property of any type other than var."));
return false;
} else if (!writeValueProperty(object, engine, core, value, context, flags)) {
if (!propertyType)
propertyType = "[unknown property type]";
- expression->delayedError()->error.setDescription(QLatin1String("Unable to assign ") +
- QLatin1String(valueType) +
- QLatin1String(" to ") +
- QLatin1String(propertyType));
+ expression->delayedError()->setErrorDescription(QLatin1String("Unable to assign ") +
+ QLatin1String(valueType) +
+ QLatin1String(" to ") +
+ QLatin1String(propertyType));
return false;
}
QV4Program *program, QQmlContextData *context,
const QString &description = QString())
{
- error->error.setUrl(context->url);
if (description.isEmpty())
- error->error.setDescription(QLatin1String("TypeError: Result of expression is not an object"));
+ error->setErrorDescription(QLatin1String("TypeError: Result of expression is not an object"));
else
- error->error.setDescription(description);
+ error->setErrorDescription(description);
if (id != 0xFF) {
quint64 e = *((quint64 *)(program->data() + program->exceptionDataOffset) + id);
- error->error.setLine((e >> 32) & 0xFFFFFFFF);
- error->error.setColumn(e & 0xFFFFFFFF);
+ error->setErrorLocation(context->url, (e >> 32) & 0xFFFFFFFF, e & 0xFFFFFFFF);
} else {
- error->error.setLine(-1);
- error->error.setColumn(-1);
+ error->setErrorLocation(context->url, -1, -1);
}
if (!context->engine || !error->addError(QQmlEnginePrivate::get(context->engine)))
- QQmlEnginePrivate::warning(context->engine, error->error);
+ QQmlEnginePrivate::warning(context->engine, error);
}
const double QV4Bindings::D32 = 4294967296.0;
&isUndefined);
trace.event("writing V8 result");
- bool needsErrorData = false;
+ bool needsErrorLocationData = false;
if (!watcher.wasDeleted() && !destroyedFlag() && !hasError()) {
typedef QQmlPropertyPrivate PP;
- needsErrorData = !PP::writeBinding(*target, instruction->property, context, this, result,
+ needsErrorLocationData = !PP::writeBinding(*target, instruction->property, context, this, result,
isUndefined, flags);
}
if (!watcher.wasDeleted() && !destroyedFlag()) {
- if (needsErrorData) {
- delayedError()->error.setUrl(parent->url());
- delayedError()->error.setLine(instruction->line);
- delayedError()->error.setColumn(-1);
- }
+ if (needsErrorLocationData)
+ delayedError()->setErrorLocation(parent->url(), instruction->line, -1);
if (hasError()) {
- if (!delayedError()->addError(ep)) ep->warning(delayedError()->error);
+ if (!delayedError()->addError(ep)) ep->warning(this->error(context->engine));
} else {
clearError();
}