diff options
author | Lars Knoll <lars.knoll@digia.com> | 2013-09-23 15:52:10 +0200 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-09-26 09:05:16 +0200 |
commit | 12fd2ccd3fa2dc0133b5a3fb89f9fdf5cf721232 (patch) | |
tree | 880acb9c7c0d8289185b6aebe4339f439c707a0e /src/qml/jsruntime | |
parent | 2e4f66caa8a5f9e887dbdb4e3f2ae5c9be9a7005 (diff) |
Fix Persistent/WeakValue API
Don't use unprotected Values in the API anymore.
Change-Id: I8851628227fca374de24701bc8ee0908b5ae3923
Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
Diffstat (limited to 'src/qml/jsruntime')
-rw-r--r-- | src/qml/jsruntime/qv4engine.cpp | 4 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4engine_p.h | 2 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4exception.cpp | 3 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4exception_p.h | 3 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4include.cpp | 24 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4qobjectwrapper.cpp | 99 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4qobjectwrapper_p.h | 2 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4scopedvalue_p.h | 10 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4script.cpp | 14 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4script_p.h | 6 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4value.cpp | 73 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4value_p.h | 41 |
12 files changed, 153 insertions, 128 deletions
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index 821e88ee61..363f0a45c0 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -101,6 +101,8 @@ ExecutionEngine::ExecutionEngine(QQmlJS::EvalISelFactory *factory) { MemoryManager::GCBlocker gcBlocker(memoryManager); + exceptionValue = Encode::undefined(); + if (!factory) { #ifdef V4_ENABLE_JIT @@ -735,6 +737,8 @@ void ExecutionEngine::markObjects() typeErrorCtor.mark(); uRIErrorCtor.mark(); + exceptionValue.mark(); + thrower->mark(); if (m_qmlExtensions) diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index ec2c6f394d..90639d582c 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -236,6 +236,8 @@ struct Q_QML_EXPORT ExecutionEngine RegExpCache *regExpCache; + SafeValue exceptionValue; + // Scarce resources are "exceptionally high cost" QVariant types where allowing the // normal JavaScript GC to clean them up is likely to lead to out-of-memory or other // out-of-resource situations. When such a resource is passed into JavaScript we diff --git a/src/qml/jsruntime/qv4exception.cpp b/src/qml/jsruntime/qv4exception.cpp index 725a046b71..35a4f726e2 100644 --- a/src/qml/jsruntime/qv4exception.cpp +++ b/src/qml/jsruntime/qv4exception.cpp @@ -88,8 +88,8 @@ void Exception::throwException(ExecutionContext *context, const Value &value) Exception::Exception(ExecutionContext *throwingContext, const Value &exceptionValue) : e(throwingContext->engine) - , exception(exceptionValue) { + e->exceptionValue = exceptionValue; this->throwingContext = throwingContext->engine->current; accepted = false; if (ErrorObject *error = exceptionValue.asErrorObject()) @@ -101,6 +101,7 @@ Exception::Exception(ExecutionContext *throwingContext, const Value &exceptionVa Exception::~Exception() { assert(accepted); + e->exceptionValue = Value::undefinedValue(); } void Exception::accept(ExecutionContext *catchingContext) diff --git a/src/qml/jsruntime/qv4exception_p.h b/src/qml/jsruntime/qv4exception_p.h index 75246fa147..eaeebf7abd 100644 --- a/src/qml/jsruntime/qv4exception_p.h +++ b/src/qml/jsruntime/qv4exception_p.h @@ -58,7 +58,7 @@ struct Q_QML_EXPORT Exception { void partiallyUnwindContext(ExecutionContext *catchingContext); - ReturnedValue value() const { return exception.value().asReturnedValue(); } + ReturnedValue value() const { return e->exceptionValue.asReturnedValue(); } ExecutionEngine::StackTrace stackTrace() const { return m_stackTrace; } ExecutionEngine *engine() const { return e; } @@ -71,7 +71,6 @@ private: ExecutionEngine *e; ExecutionContext *throwingContext; bool accepted; - PersistentValue exception; ExecutionEngine::StackTrace m_stackTrace; static void throwInternal(ExecutionContext *throwingContext, const Value &exceptionValue); }; diff --git a/src/qml/jsruntime/qv4include.cpp b/src/qml/jsruntime/qv4include.cpp index 681ae5990d..d6f01bf369 100644 --- a/src/qml/jsruntime/qv4include.cpp +++ b/src/qml/jsruntime/qv4include.cpp @@ -62,9 +62,9 @@ QV4Include::QV4Include(const QUrl &url, QV8Engine *engine, QQmlContextData *cont const QV4::Value &qmlglobal, const QV4::Value &callback) : v4(QV8Engine::getV4(engine)), m_network(0), m_reply(0), m_url(url), m_redirectCount(0), m_context(context) { - m_qmlglobal = qmlglobal; + m_qmlglobal = qmlglobal.asReturnedValue(); if (callback.asFunctionObject()) - m_callbackFunction = callback; + m_callbackFunction = callback.asReturnedValue(); m_resultObject = resultValue(v4); @@ -119,7 +119,7 @@ void QV4Include::callback(const QV4::Value &callback, const QV4::Value &status) QV4::ReturnedValue QV4Include::result() { - return m_resultObject.value().asReturnedValue(); + return m_resultObject.value(); } #define INCLUDE_MAXIMUM_REDIRECT_RECURSION 15 @@ -143,32 +143,34 @@ void QV4Include::finished() } QV4::Scope scope(v4); + QV4::ScopedObject resultObj(scope, m_resultObject.value()); if (m_reply->error() == QNetworkReply::NoError) { QByteArray data = m_reply->readAll(); QString code = QString::fromUtf8(data); QQmlScript::Parser::extractPragmas(code); - QV4::Script script(v4, m_qmlglobal.value().asObject(), code, m_url.toString()); + QV4::ScopedObject qmlglobal(scope, m_qmlglobal.value()); + QV4::Script script(v4, qmlglobal, code, m_url.toString()); QV4::ExecutionContext *ctx = v4->current; - QV4::Scoped<QV4::Object> o(scope, m_resultObject.value()); QV4::ScopedString status(scope, v4->newString("status")); try { script.parse(); script.run(); - o->put(status, QV4::ScopedValue(scope, QV4::Value::fromInt32(Ok))); + resultObj->put(status, QV4::ScopedValue(scope, QV4::Value::fromInt32(Ok))); } catch (QV4::Exception &e) { e.accept(ctx); - o->put(status, QV4::ScopedValue(scope, QV4::Value::fromInt32(Exception))); + resultObj->put(status, QV4::ScopedValue(scope, QV4::Value::fromInt32(Exception))); QV4::ScopedValue ex(scope, e.value()); - o->put(QV4::ScopedString(scope, v4->newString("exception")), ex); + resultObj->put(QV4::ScopedString(scope, v4->newString("exception")), ex); } } else { - m_resultObject.value().asObject()->put(QV4::ScopedString(scope, v4->newString("status")), QV4::ScopedValue(scope, QV4::Value::fromInt32(NetworkError))); + resultObj->put(QV4::ScopedString(scope, v4->newString("status")), QV4::ScopedValue(scope, QV4::Value::fromInt32(NetworkError))); } - callback(m_callbackFunction.value(), m_resultObject.value()); + QV4::ScopedValue cb(scope, m_callbackFunction.value()); + callback(cb, resultObj.asValue()); disconnect(); deleteLater(); @@ -216,7 +218,7 @@ QV4::ReturnedValue QV4Include::method_include(QV4::SimpleCallContext *ctx) QString code = QString::fromUtf8(data); QQmlScript::Parser::extractPragmas(code); - QV4::Script script(v4, qmlcontextobject.getPointer(), code, url.toString()); + QV4::Script script(v4, qmlcontextobject, code, url.toString()); QV4::ExecutionContext *ctx = v4->current; try { diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index 7e31797627..c0c68bb6fd 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -400,11 +400,14 @@ ReturnedValue QObjectWrapper::getQmlProperty(ExecutionContext *ctx, QQmlContextD return wrapper->getQmlProperty(ctx, qmlContext, name, revisionMode, hasProperty); } -bool QObjectWrapper::setQmlProperty(ExecutionContext *ctx, QQmlContextData *qmlContext, QObject *object, String *name, QObjectWrapper::RevisionMode revisionMode, const Value &value) +bool QObjectWrapper::setQmlProperty(ExecutionContext *ctx, QQmlContextData *qmlContext, QObject *object, String *name, + QObjectWrapper::RevisionMode revisionMode, const ValueRef value) { if (QQmlData::wasDeleted(object)) return false; + QV4::Scope scope(ctx); + QQmlPropertyData local; QQmlPropertyData *result = 0; { @@ -427,7 +430,8 @@ bool QObjectWrapper::setQmlProperty(ExecutionContext *ctx, QQmlContextData *qmlC } QQmlBinding *newBinding = 0; - if (FunctionObject *f = value.asFunctionObject()) { + QV4::ScopedFunctionObject f(scope, value); + if (f) { if (!f->bindingKeyFlag) { if (!result->isVarProperty() && result->propType != qMetaTypeId<QJSValue>()) { // assigning a JS function to a non var or QJSValue property or is not allowed. @@ -461,7 +465,7 @@ bool QObjectWrapper::setQmlProperty(ExecutionContext *ctx, QQmlContextData *qmlC // allow assignment of "special" values (null, undefined, function) to var properties QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(object); Q_ASSERT(vmemo); - vmemo->setVMEProperty(result->coreIndex, value); + vmemo->setVMEProperty(result->coreIndex, *value); return true; } @@ -472,46 +476,46 @@ bool QObjectWrapper::setQmlProperty(ExecutionContext *ctx, QQmlContextData *qmlC void *argv[] = { &o, 0, &status, &flags }; \ QMetaObject::metacall(object, QMetaObject::WriteProperty, result->coreIndex, argv); - if (value.isNull() && result->isQObject()) { + if (value->isNull() && result->isQObject()) { PROPERTY_STORE(QObject*, 0); - } else if (value.isUndefined() && result->isResettable()) { + } else if (value->isUndefined() && result->isResettable()) { void *a[] = { 0 }; QMetaObject::metacall(object, QMetaObject::ResetProperty, result->coreIndex, a); - } else if (value.isUndefined() && result->propType == qMetaTypeId<QVariant>()) { + } else if (value->isUndefined() && result->propType == qMetaTypeId<QVariant>()) { PROPERTY_STORE(QVariant, QVariant()); - } else if (value.isUndefined() && result->propType == QMetaType::QJsonValue) { + } else if (value->isUndefined() && result->propType == QMetaType::QJsonValue) { PROPERTY_STORE(QJsonValue, QJsonValue(QJsonValue::Undefined)); } else if (!newBinding && result->propType == qMetaTypeId<QJSValue>()) { PROPERTY_STORE(QJSValue, new QJSValuePrivate(ctx->engine, value)); - } else if (value.isUndefined()) { + } else if (value->isUndefined()) { QString error = QLatin1String("Cannot assign [undefined] to "); if (!QMetaType::typeName(result->propType)) error += QLatin1String("[unknown property type]"); else error += QLatin1String(QMetaType::typeName(result->propType)); ctx->throwError(error); - } else if (value.asFunctionObject()) { + } else if (value->asFunctionObject()) { // this is handled by the binding creation above - } else if (result->propType == QMetaType::Int && value.isNumber()) { - PROPERTY_STORE(int, qRound(value.asDouble())); - } else if (result->propType == QMetaType::QReal && value.isNumber()) { - PROPERTY_STORE(qreal, qreal(value.asDouble())); - } else if (result->propType == QMetaType::Float && value.isNumber()) { - PROPERTY_STORE(float, float(value.asDouble())); - } else if (result->propType == QMetaType::Double && value.isNumber()) { - PROPERTY_STORE(double, double(value.asDouble())); - } else if (result->propType == QMetaType::QString && value.isString()) { - PROPERTY_STORE(QString, value.toQStringNoThrow()); + } else if (result->propType == QMetaType::Int && value->isNumber()) { + PROPERTY_STORE(int, qRound(value->asDouble())); + } else if (result->propType == QMetaType::QReal && value->isNumber()) { + PROPERTY_STORE(qreal, qreal(value->asDouble())); + } else if (result->propType == QMetaType::Float && value->isNumber()) { + PROPERTY_STORE(float, float(value->asDouble())); + } else if (result->propType == QMetaType::Double && value->isNumber()) { + PROPERTY_STORE(double, double(value->asDouble())); + } else if (result->propType == QMetaType::QString && value->isString()) { + PROPERTY_STORE(QString, value->toQStringNoThrow()); } else if (result->isVarProperty()) { QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(object); Q_ASSERT(vmemo); - vmemo->setVMEProperty(result->coreIndex, value); + vmemo->setVMEProperty(result->coreIndex, *value); } else { QVariant v; if (result->isQList()) - v = ctx->engine->v8Engine->toVariant(value, qMetaTypeId<QList<QObject *> >()); + v = ctx->engine->v8Engine->toVariant(*value, qMetaTypeId<QList<QObject *> >()); else - v = ctx->engine->v8Engine->toVariant(value, result->propType); + v = ctx->engine->v8Engine->toVariant(*value, result->propType); QQmlContextData *callingQmlContext = QV4::QmlContextWrapper::callingContext(ctx->engine); if (!QQmlPropertyPrivate::write(object, *result, v, callingQmlContext)) { @@ -547,7 +551,7 @@ ReturnedValue QObjectWrapper::wrap(ExecutionEngine *engine, QObject *object) if (ddata->jsEngineId == engine->m_engineId && !ddata->jsWrapper.isUndefined()) { // We own the JS object - return ddata->jsWrapper.value().asReturnedValue(); + return ddata->jsWrapper.value(); } else if (ddata->jsWrapper.isUndefined() && (ddata->jsEngineId == engine->m_engineId || // We own the QObject ddata->jsEngineId == 0 || // No one owns the QObject @@ -614,7 +618,7 @@ void QObjectWrapper::put(Managed *m, const StringRef name, const ValueRef value) return; QQmlContextData *qmlContext = QV4::QmlContextWrapper::callingContext(v4); - if (!setQmlProperty(v4->current, qmlContext, that->m_object, name.getPointer(), QV4::QObjectWrapper::IgnoreRevision, *value)) { + if (!setQmlProperty(v4->current, qmlContext, that->m_object, name.getPointer(), QV4::QObjectWrapper::IgnoreRevision, value)) { QString error = QLatin1String("Cannot assign to non-existent property \"") + name->toQString() + QLatin1Char('\"'); v4->current->throwError(error); @@ -697,13 +701,14 @@ struct QObjectSlotDispatcher : public QtPrivate::QSlotObjectBase int argCount = argsTypes ? argsTypes[0]:0; - QV4::FunctionObject *f = This->function.value().asFunctionObject(); - QV4::ExecutionEngine *v4 = f->internalClass->engine; + QV4::ExecutionEngine *v4 = This->function.engine(); + Q_ASSERT(v4); + QV4::Scope scope(v4); + QV4::ScopedFunctionObject f(scope, This->function.value()); QV4::ExecutionContext *ctx = v4->current; - Scope scope(v4); QV4::ScopedCallData callData(scope, argCount); - callData->thisObject = This->thisObject.isUndefined() ? Value::fromObject(v4->globalObject) : This->thisObject.value(); + callData->thisObject = This->thisObject.isUndefined() ? Value::fromObject(v4->globalObject) : Value::fromReturnedValue(This->thisObject.value()); for (int ii = 0; ii < argCount; ++ii) { int type = argsTypes[ii + 1]; if (type == qMetaTypeId<QVariant>()) { @@ -752,7 +757,8 @@ struct QObjectSlotDispatcher : public QtPrivate::QSlotObjectBase if (connection->thisObject.isUndefined() == thisObject->isUndefined() && (connection->thisObject.isUndefined() || __qmljs_strict_equal(connection->thisObject, thisObject))) { - QPair<QObject *, int> connectedFunctionData = extractQtMethod(connection->function.value().asFunctionObject()); + QV4::ScopedFunctionObject f(scope, connection->function.value()); + QPair<QObject *, int> connectedFunctionData = extractQtMethod(f.getPointer()); if (connectedFunctionData.first == receiverToDisconnect && connectedFunctionData.second == slotIndexToDisconnect) { *ret = true; @@ -798,22 +804,29 @@ ReturnedValue QObjectWrapper::method_connect(SimpleCallContext *ctx) if (signalObject->metaObject()->method(signalIndex).methodType() != QMetaMethod::Signal) V4THROW_ERROR("Function.prototype.connect: this object is not a signal"); - QV4::QObjectSlotDispatcher *slot = new QV4::QObjectSlotDispatcher; - slot->signalIndex = signalIndex; + QV4::Scope scope(ctx); + QV4::ScopedFunctionObject f(scope); + QV4::ScopedValue thisObject (scope, QV4::Encode::undefined()); if (ctx->argumentCount == 1) { - slot->function = ctx->arguments[0]; + f = ctx->arguments[0]; } else if (ctx->argumentCount >= 2) { - slot->thisObject = ctx->arguments[0]; - slot->function = ctx->arguments[1]; + thisObject = ctx->arguments[0]; + f = ctx->arguments[1]; } - if (!slot->function.value().asFunctionObject()) + if (!f) V4THROW_ERROR("Function.prototype.connect: target is not a function"); - if (!slot->thisObject.isUndefined() && !slot->thisObject.value().isObject()) + if (!thisObject->isUndefined() && !thisObject->isObject()) V4THROW_ERROR("Function.prototype.connect: target this is not an object"); + QV4::QObjectSlotDispatcher *slot = new QV4::QObjectSlotDispatcher; + slot->signalIndex = signalIndex; + + slot->thisObject = thisObject; + slot->function = f; + QObjectPrivate::connect(signalObject, signalIndex, slot, Qt::AutoConnection); return Encode::undefined(); @@ -1483,7 +1496,10 @@ void CallArgument::fromValue(int callType, QV8Engine *engine, const QV4::Value & if (type != 0) { cleanup(); type = 0; } if (callType == qMetaTypeId<QJSValue>()) { - qjsValuePtr = new (&allocData) QJSValue(new QJSValuePrivate(QV8Engine::getV4(engine), value)); + QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine); + QV4::Scope scope(v4); + QV4::ScopedValue v(scope, value); + qjsValuePtr = new (&allocData) QJSValue(new QJSValuePrivate(v4, v)); type = qMetaTypeId<QJSValue>(); } else if (callType == QMetaType::Int) { intValue = quint32(value.toInt32()); @@ -1647,10 +1663,10 @@ QObjectMethod::QObjectMethod(ExecutionContext *scope, QObject *object, int index : FunctionObject(scope) , m_object(object) , m_index(index) - , m_qmlGlobal(qmlGlobal) { vtbl = &static_vtbl; subtype = WrappedQtMethod; + m_qmlGlobal = qmlGlobal.asReturnedValue(); } QV4::ReturnedValue QObjectMethod::method_toString(QV4::ExecutionContext *ctx) @@ -1719,6 +1735,8 @@ ReturnedValue QObjectMethod::callInternal(CallData *callData) return Encode::undefined(); QV8Engine *v8Engine = context->engine->v8Engine; + QV4::ExecutionEngine *v4 = QV8Engine::getV4(v8Engine); + QV4::Scope scope(v4); QQmlPropertyData method; @@ -1741,8 +1759,9 @@ ReturnedValue QObjectMethod::callInternal(CallData *callData) if (method.isV4Function()) { QV4::Value rv = QV4::Value::undefinedValue(); - QQmlV4Function func(callData->argc, callData->args, &rv, m_qmlGlobal.value(), - QmlContextWrapper::getContext(m_qmlGlobal.value()), + QV4::ScopedValue qmlGlobal(scope, m_qmlGlobal.value()); + QQmlV4Function func(callData->argc, callData->args, &rv, qmlGlobal, + QmlContextWrapper::getContext(qmlGlobal), v8Engine); QQmlV4Function *funcptr = &func; diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h index 2fc0767bc8..ea2dccccbc 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper_p.h +++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h @@ -88,7 +88,7 @@ struct Q_QML_EXPORT QObjectWrapper : public QV4::Object ReturnedValue getQmlProperty(ExecutionContext *ctx, QQmlContextData *qmlContext, String *name, RevisionMode revisionMode, bool *hasProperty = 0, bool includeImports = false); static ReturnedValue getQmlProperty(ExecutionContext *ctx, QQmlContextData *qmlContext, QObject *object, String *name, RevisionMode revisionMode, bool *hasProperty = 0); - static bool setQmlProperty(ExecutionContext *ctx, QQmlContextData *qmlContext, QObject *object, String *name, RevisionMode revisionMode, const Value &value); + static bool setQmlProperty(ExecutionContext *ctx, QQmlContextData *qmlContext, QObject *object, String *name, RevisionMode revisionMode, const ValueRef value); static ReturnedValue wrap(ExecutionEngine *engine, QObject *object); diff --git a/src/qml/jsruntime/qv4scopedvalue_p.h b/src/qml/jsruntime/qv4scopedvalue_p.h index 09851af091..f11a982b65 100644 --- a/src/qml/jsruntime/qv4scopedvalue_p.h +++ b/src/qml/jsruntime/qv4scopedvalue_p.h @@ -439,6 +439,10 @@ struct Referenced { Referenced(const Scoped<T> &v) : ptr(v.ptr) {} Referenced(Safe<T> &v) { ptr = &v; } + Referenced(SafeValue &v) { + ptr = value_cast<T>(v) ? &v : 0; + } + Referenced &operator=(const Referenced &o) { *ptr = *o.ptr; return *this; } Referenced &operator=(T *t) @@ -465,7 +469,7 @@ struct Referenced { T *getPointer() const { return static_cast<T *>(ptr->managed()); } - ReturnedValue asReturnedValue() const { return ptr->val; } + ReturnedValue asReturnedValue() const { return ptr ? ptr->val : Value::undefinedValue().asReturnedValue(); } static Referenced null() { return Referenced(Null); } bool isNull() const { return !ptr; } @@ -643,7 +647,7 @@ PersistentValue::PersistentValue(Returned<T> *obj) } template<typename T> -inline PersistentValue::PersistentValue(const Scoped<T> &obj) +inline PersistentValue::PersistentValue(const Referenced<T> obj) : d(new PersistentValuePrivate(*obj.ptr)) { } @@ -655,7 +659,7 @@ inline PersistentValue &PersistentValue::operator=(Returned<T> *obj) } template<typename T> -inline PersistentValue &PersistentValue::operator=(const Scoped<T> &obj) +inline PersistentValue &PersistentValue::operator=(const Referenced<T> obj) { return operator=(*obj.ptr); } diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp index 1aa9d80a2d..a6cb40fff8 100644 --- a/src/qml/jsruntime/qv4script.cpp +++ b/src/qml/jsruntime/qv4script.cpp @@ -201,7 +201,8 @@ void Script::parse() isel->setUseFastLookups(false); QV4::CompiledData::CompilationUnit *compilationUnit = isel->compile(); vmFunction = compilationUnit->linkToEngine(v4); - compilationUnitHolder = Value::fromObject(new (v4->memoryManager) CompilationUnitHolder(v4, compilationUnit)); + ScopedValue holder(valueScope, Value::fromObject(new (v4->memoryManager) CompilationUnitHolder(v4, compilationUnit))); + compilationUnitHolder = holder; } if (!vmFunction) { @@ -256,7 +257,8 @@ ReturnedValue Script::run() return result.asReturnedValue(); } else { - FunctionObject *f = new (engine->memoryManager) QmlBindingWrapper(scope, vmFunction, qml.value().asObject()); + ScopedObject qmlObj(valueScope, qml.value()); + FunctionObject *f = new (engine->memoryManager) QmlBindingWrapper(scope, vmFunction, qmlObj.getPointer()); ScopedCallData callData(valueScope, 0); callData->thisObject = Value::undefinedValue(); return f->call(callData); @@ -274,11 +276,13 @@ ReturnedValue Script::qmlBinding() { if (!parsed) parse(); - QV4::ExecutionEngine *v4 = scope->engine; - return Value::fromObject(new (v4->memoryManager) QmlBindingWrapper(scope, vmFunction, qml.value().asObject())).asReturnedValue(); + ExecutionEngine *v4 = scope->engine; + Scope valueScope(v4); + ScopedObject qmlObj(valueScope, qml.value()); + return Value::fromObject(new (v4->memoryManager) QmlBindingWrapper(scope, vmFunction, qmlObj.getPointer())).asReturnedValue(); } -QV4::ReturnedValue Script::evaluate(ExecutionEngine *engine, const QString &script, Object *scopeObject) +QV4::ReturnedValue Script::evaluate(ExecutionEngine *engine, const QString &script, ObjectRef scopeObject) { QV4::Scope scope(engine); QV4::Script qmlScript(engine, scopeObject, script, QString()); diff --git a/src/qml/jsruntime/qv4script_p.h b/src/qml/jsruntime/qv4script_p.h index 752cb2ac53..030622cf72 100644 --- a/src/qml/jsruntime/qv4script_p.h +++ b/src/qml/jsruntime/qv4script_p.h @@ -73,10 +73,10 @@ struct Q_QML_EXPORT Script { : sourceFile(source), line(line), column(column), sourceCode(sourceCode) , scope(scope), strictMode(false), inheritContext(false), parsed(false) , vmFunction(0), parseAsBinding(false) {} - Script(ExecutionEngine *engine, Object *qml, const QString &sourceCode, const QString &source = QString(), int line = 1, int column = 0) + Script(ExecutionEngine *engine, ObjectRef qml, const QString &sourceCode, const QString &source = QString(), int line = 1, int column = 0) : sourceFile(source), line(line), column(column), sourceCode(sourceCode) , scope(engine->rootContext), strictMode(false), inheritContext(true), parsed(false) - , qml(Value::fromObject(qml)), vmFunction(0), parseAsBinding(true) {} + , qml(qml.asReturnedValue()), vmFunction(0), parseAsBinding(true) {} ~Script(); QString sourceFile; int line; @@ -98,7 +98,7 @@ struct Q_QML_EXPORT Script { Function *function(); - static ReturnedValue evaluate(ExecutionEngine *engine, const QString &script, Object *scopeObject); + static ReturnedValue evaluate(ExecutionEngine *engine, const QString &script, ObjectRef scopeObject); }; } diff --git a/src/qml/jsruntime/qv4value.cpp b/src/qml/jsruntime/qv4value.cpp index 197b1c2ee5..51f7fba6d3 100644 --- a/src/qml/jsruntime/qv4value.cpp +++ b/src/qml/jsruntime/qv4value.cpp @@ -285,18 +285,13 @@ Object *Value::toObject(ExecutionContext *ctx) const } -PersistentValue::PersistentValue(const Value &val) - : d(new PersistentValuePrivate(val)) -{ -} - -PersistentValue::PersistentValue(const ScopedValue &val) - : d(new PersistentValuePrivate(*val.operator ->())) +PersistentValue::PersistentValue(const ValueRef val) + : d(new PersistentValuePrivate(val.asReturnedValue())) { } PersistentValue::PersistentValue(ReturnedValue val) - : d(new PersistentValuePrivate(Value::fromReturnedValue(val))) + : d(new PersistentValuePrivate(val)) { } @@ -323,33 +318,23 @@ PersistentValue &PersistentValue::operator=(const PersistentValue &other) return *this; } -PersistentValue &PersistentValue::operator =(const Value &other) +PersistentValue &PersistentValue::operator =(const ValueRef other) { if (!d) { - d = new PersistentValuePrivate(other); + d = new PersistentValuePrivate(other.asReturnedValue()); return *this; } - d = d->detach(other); + d = d->detach(other.asReturnedValue()); return *this; } -PersistentValue &PersistentValue::operator =(const ScopedValue &other) -{ - return operator=(*other.operator ->()); -} - -PersistentValue &PersistentValue::operator =(const ValueRef other) -{ - return operator=(*other.operator ->()); -} - -PersistentValue &PersistentValue::operator =(const ReturnedValue &other) +PersistentValue &PersistentValue::operator =(ReturnedValue other) { if (!d) { - d = new PersistentValuePrivate(Value::fromReturnedValue(other)); + d = new PersistentValuePrivate(other); return *this; } - d = d->detach(Value::fromReturnedValue(other)); + d = d->detach(other); return *this; } @@ -359,8 +344,8 @@ PersistentValue::~PersistentValue() d->deref(); } -WeakValue::WeakValue(const Value &val) - : d(new PersistentValuePrivate(val, /*engine*/0, /*weak*/true)) +WeakValue::WeakValue(const ValueRef val) + : d(new PersistentValuePrivate(val.asReturnedValue(), /*engine*/0, /*weak*/true)) { } @@ -372,7 +357,7 @@ WeakValue::WeakValue(const WeakValue &other) } WeakValue::WeakValue(ReturnedValue val) - : d(new PersistentValuePrivate(Value::fromReturnedValue(val), /*engine*/0, /*weak*/true)) + : d(new PersistentValuePrivate(val, /*engine*/0, /*weak*/true)) { } @@ -392,23 +377,23 @@ WeakValue &WeakValue::operator=(const WeakValue &other) return *this; } -WeakValue &WeakValue::operator =(const Value &other) +WeakValue &WeakValue::operator =(const ValueRef other) { if (!d) { - d = new PersistentValuePrivate(other, /*engine*/0, /*weak*/true); + d = new PersistentValuePrivate(other.asReturnedValue(), /*engine*/0, /*weak*/true); return *this; } - d = d->detach(other, /*weak*/true); + d = d->detach(other.asReturnedValue(), /*weak*/true); return *this; } WeakValue &WeakValue::operator =(const ReturnedValue &other) { if (!d) { - d = new PersistentValuePrivate(Value::fromReturnedValue(other), /*engine*/0, /*weak*/true); + d = new PersistentValuePrivate(other, /*engine*/0, /*weak*/true); return *this; } - d = d->detach(Value::fromReturnedValue(other), /*weak*/true); + d = d->detach(other, /*weak*/true); return *this; } @@ -429,21 +414,27 @@ void WeakValue::markOnce() m->mark(); } -PersistentValuePrivate::PersistentValuePrivate(const Value &v, ExecutionEngine *e, bool weak) - : value(v) - , refcount(1) +PersistentValuePrivate::PersistentValuePrivate(ReturnedValue v, ExecutionEngine *e, bool weak) + : refcount(1) + , weak(weak) + , engine(e) , prev(0) , next(0) - , engine(e) +{ + value.val = v; + init(); +} + +void PersistentValuePrivate::init() { if (!engine) { - Managed *m = v.asManaged(); + Managed *m = value.asManaged(); if (!m) return; engine = m->engine(); } - if (engine) { + if (engine && !prev) { PersistentValuePrivate **listRoot = weak ? &engine->memoryManager->m_weakValues : &engine->memoryManager->m_persistentValues; prev = listRoot; @@ -479,10 +470,10 @@ void PersistentValuePrivate::deref() } } -PersistentValuePrivate *PersistentValuePrivate::detach(const QV4::Value &value, bool weak) +PersistentValuePrivate *PersistentValuePrivate::detach(const QV4::ReturnedValue val, bool weak) { if (refcount == 1) { - this->value = value; + value.val = val; Managed *m = value.asManaged(); if (!prev) { @@ -503,6 +494,6 @@ PersistentValuePrivate *PersistentValuePrivate::detach(const QV4::Value &value, return this; } --refcount; - return new PersistentValuePrivate(value, engine, weak); + return new PersistentValuePrivate(val, engine, weak); } diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h index ad884b6380..598d30f1f0 100644 --- a/src/qml/jsruntime/qv4value_p.h +++ b/src/qml/jsruntime/qv4value_p.h @@ -346,18 +346,20 @@ inline T *Value::as() const { Managed *m = isObject() ? managed() : 0; return m struct Q_QML_PRIVATE_EXPORT PersistentValuePrivate { - PersistentValuePrivate(const Value &v, ExecutionEngine *engine = 0, bool weak = false); + PersistentValuePrivate(ReturnedValue v, ExecutionEngine *engine = 0, bool weak = false); virtual ~PersistentValuePrivate(); Value value; uint refcount; + bool weak; QV4::ExecutionEngine *engine; PersistentValuePrivate **prev; PersistentValuePrivate *next; + void init(); void removeFromList(); void ref() { ++refcount; } void deref(); - PersistentValuePrivate *detach(const QV4::Value &value, bool weak = false); + PersistentValuePrivate *detach(const ReturnedValue value, bool weak = false); bool checkEngine(QV4::ExecutionEngine *otherEngine) { if (!engine) { @@ -372,39 +374,36 @@ class Q_QML_EXPORT PersistentValue { public: PersistentValue() : d(0) {} + PersistentValue(const PersistentValue &other); + PersistentValue &operator=(const PersistentValue &other); - PersistentValue(const Value &val); - PersistentValue(const ScopedValue &val); + PersistentValue(const ValueRef val); PersistentValue(ReturnedValue val); template<typename T> PersistentValue(Returned<T> *obj); template<typename T> - PersistentValue(const Scoped<T> &obj); - PersistentValue(const PersistentValue &other); - PersistentValue &operator=(const PersistentValue &other); - PersistentValue &operator=(const Value &other); - PersistentValue &operator=(const ScopedValue &other); + PersistentValue(const Referenced<T> obj); PersistentValue &operator=(const ValueRef other); - PersistentValue &operator =(const ReturnedValue &other); + PersistentValue &operator =(ReturnedValue other); template<typename T> PersistentValue &operator=(Returned<T> *obj); template<typename T> - PersistentValue &operator=(const Scoped<T> &obj); + PersistentValue &operator=(const Referenced<T> obj); ~PersistentValue(); - Value value() const { - return d ? d->value : Value::undefinedValue(); + ReturnedValue value() const { + return (d ? d->value : Value::undefinedValue()).asReturnedValue(); } ExecutionEngine *engine() { if (!d) return 0; + if (d->engine) + return d->engine; Managed *m = d->value.asManaged(); return m ? m->engine() : 0; } - operator Value() const { return value(); } - bool isUndefined() const { return !d || d->value.isUndefined(); } bool isNullOrUndefined() const { return !d || d->value.isNullOrUndefined(); } void clear() { @@ -420,32 +419,32 @@ class Q_QML_EXPORT WeakValue { public: WeakValue() : d(0) {} - WeakValue(const Value &val); + WeakValue(const ValueRef val); WeakValue(const WeakValue &other); WeakValue(ReturnedValue val); template<typename T> WeakValue(Returned<T> *obj); WeakValue &operator=(const WeakValue &other); - WeakValue &operator=(const Value &other); + WeakValue &operator=(const ValueRef other); WeakValue &operator =(const ReturnedValue &other); template<typename T> WeakValue &operator=(Returned<T> *obj); ~WeakValue(); - Value value() const { - return d ? d->value : Value::undefinedValue(); + ReturnedValue value() const { + return (d ? d->value : Value::undefinedValue()).asReturnedValue(); } ExecutionEngine *engine() { if (!d) return 0; + if (d->engine) + return d->engine; Managed *m = d->value.asManaged(); return m ? m->engine() : 0; } - operator Value() const { return value(); } - bool isUndefined() const { return !d || d->value.isUndefined(); } bool isNullOrUndefined() const { return !d || d->value.isNullOrUndefined(); } void clear() { |