Improve memory usage in QML/V4 engine.
authorMichael Brasser <michael.brasser@live.com>
Thu, 27 Feb 2014 21:59:39 +0000 (15:59 -0600)
committerThe Qt Project <gerrit-noreply@qt-project.org>
Fri, 28 Feb 2014 18:01:21 +0000 (19:01 +0100)
* Don't create prototype Object for bindings and
  signal handlers. It is inaccessible and not required.
  This saves one Object-sized allocation per binding.
* Shrink the size of QQmlContextWrapper by removing
  the v8 member variable.
* Shrink the size of QObjectWrapper by moving the destroy
  identifier to the engine.

Change-Id: I76e84e4c0581e97a19d2e959f814ac84d9c431fa
Task-number: QTBUG-37134
Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
src/qml/jsruntime/qv4engine.cpp
src/qml/jsruntime/qv4engine_p.h
src/qml/jsruntime/qv4functionobject.cpp
src/qml/jsruntime/qv4functionobject_p.h
src/qml/jsruntime/qv4qobjectwrapper.cpp
src/qml/jsruntime/qv4qobjectwrapper_p.h
src/qml/jsruntime/qv4runtime.cpp
src/qml/qml/qqmlcontextwrapper.cpp
src/qml/qml/qqmlcontextwrapper_p.h
src/qml/qml/qqmlobjectcreator.cpp
src/qml/qml/qqmlvme.cpp

index 885186e..56ca31c 100644 (file)
@@ -246,6 +246,7 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
     id_index = newIdentifier(QStringLiteral("index"));
     id_input = newIdentifier(QStringLiteral("input"));
     id_toString = newIdentifier(QStringLiteral("toString"));
+    id_destroy = newIdentifier(QStringLiteral("destroy"));
     id_valueOf = newIdentifier(QStringLiteral("valueOf"));
 
     ObjectPrototype *objectPrototype = new (memoryManager) ObjectPrototype(InternalClass::create(this, ObjectPrototype::staticVTable(), 0));
@@ -863,6 +864,7 @@ void ExecutionEngine::markObjects()
     id_index->mark(this);
     id_input->mark(this);
     id_toString->mark(this);
+    id_destroy->mark(this);
     id_valueOf->mark(this);
 
     objectCtor.mark(this);
index d8ac750..4bf95c4 100644 (file)
@@ -263,6 +263,7 @@ public:
     StringValue id_index;
     StringValue id_input;
     StringValue id_toString;
+    StringValue id_destroy;
     StringValue id_valueOf;
 
     QSet<CompiledData::CompilationUnit*> compilationUnits;
index 07ec94a..66e956e 100644 (file)
@@ -183,14 +183,14 @@ void FunctionObject::markObjects(Managed *that, ExecutionEngine *e)
     Object::markObjects(that, e);
 }
 
-FunctionObject *FunctionObject::creatScriptFunction(ExecutionContext *scope, Function *function)
+FunctionObject *FunctionObject::creatScriptFunction(ExecutionContext *scope, Function *function, bool createProto)
 {
     if (function->needsActivation() ||
         function->compiledFunction->flags & CompiledData::Function::HasCatchOrWith ||
         function->compiledFunction->nFormals > QV4::Global::ReservedArgumentCount ||
         function->isNamedExpression())
         return new (scope->engine->memoryManager) ScriptFunction(scope, function);
-    return new (scope->engine->memoryManager) SimpleScriptFunction(scope, function);
+    return new (scope->engine->memoryManager) SimpleScriptFunction(scope, function, createProto);
 }
 
 ReturnedValue FunctionObject::protoProperty()
@@ -482,8 +482,8 @@ ReturnedValue ScriptFunction::call(Managed *that, CallData *callData)
 
 DEFINE_OBJECT_VTABLE(SimpleScriptFunction);
 
-SimpleScriptFunction::SimpleScriptFunction(ExecutionContext *scope, Function *function)
-    : FunctionObject(scope, function->name, true)
+SimpleScriptFunction::SimpleScriptFunction(ExecutionContext *scope, Function *function, bool createProto)
+    : FunctionObject(scope, function->name, createProto)
 {
     setVTable(staticVTable());
 
index af4ec02..1f5bced 100644 (file)
@@ -137,7 +137,7 @@ struct Q_QML_EXPORT FunctionObject: Object {
         return v.asFunctionObject();
     }
 
-    static FunctionObject *creatScriptFunction(ExecutionContext *scope, Function *function);
+    static FunctionObject *creatScriptFunction(ExecutionContext *scope, Function *function, bool createProto = true);
 
     ReturnedValue protoProperty();
     InternalClass *internalClassForConstructor();
@@ -221,7 +221,7 @@ struct ScriptFunction: FunctionObject {
 
 struct SimpleScriptFunction: FunctionObject {
     V4_OBJECT
-    SimpleScriptFunction(ExecutionContext *scope, Function *function);
+    SimpleScriptFunction(ExecutionContext *scope, Function *function, bool createProto);
 
     static ReturnedValue construct(Managed *, CallData *callData);
     static ReturnedValue call(Managed *that, CallData *callData);
index 7f4ac22..1453394 100644 (file)
@@ -245,8 +245,6 @@ QObjectWrapper::QObjectWrapper(ExecutionEngine *engine, QObject *object)
 
     Scope scope(engine);
     ScopedObject protectThis(scope, this);
-
-    m_destroy = engine->newIdentifier(QStringLiteral("destroy"));
 }
 
 void QObjectWrapper::initializeBindings(ExecutionEngine *engine)
@@ -282,8 +280,8 @@ ReturnedValue QObjectWrapper::getQmlProperty(ExecutionContext *ctx, QQmlContextD
     QV4::Scope scope(ctx);
     QV4::ScopedString name(scope, n);
 
-    if (name->equals(m_destroy) || name->equals(scope.engine->id_toString)) {
-        int index = name->equals(m_destroy) ? QV4::QObjectMethod::DestroyMethod : QV4::QObjectMethod::ToStringMethod;
+    if (name->equals(scope.engine->id_destroy) || name->equals(scope.engine->id_toString)) {
+        int index = name->equals(scope.engine->id_destroy) ? QV4::QObjectMethod::DestroyMethod : QV4::QObjectMethod::ToStringMethod;
         QV4::ScopedValue method(scope, QV4::QObjectMethod::create(ctx->engine->rootContext, m_object, index));
         if (hasProperty)
             *hasProperty = true;
@@ -695,7 +693,7 @@ PropertyAttributes QObjectWrapper::query(const Managed *m, StringRef name)
     QQmlContextData *qmlContext = QV4::QmlContextWrapper::callingContext(engine);
     QQmlPropertyData local;
     if (that->findProperty(engine, qmlContext, name, IgnoreRevision, &local)
-        || name->equals(const_cast<StringValue &>(that->m_destroy)) || name->equals(engine->id_toString))
+        || name->equals(engine->id_destroy) || name->equals(engine->id_toString))
         return QV4::Attr_Data;
     else
         return QV4::Object::query(m, name);
index ca38c5b..b11f0af 100644 (file)
@@ -111,7 +111,6 @@ private:
     QQmlPropertyData *findProperty(ExecutionEngine *engine, QQmlContextData *qmlContext, String *name, RevisionMode revisionMode, QQmlPropertyData *local) const;
 
     QPointer<QObject> m_object;
-    StringValue m_destroy;
 
     static ReturnedValue get(Managed *m, const StringRef name, bool *hasProperty);
     static void put(Managed *m, const StringRef name, const ValueRef value);
index a3ba4b0..2b63632 100644 (file)
@@ -1297,7 +1297,7 @@ ReturnedValue __qmljs_get_imported_scripts(NoThrowContext *ctx)
 
 QV4::ReturnedValue __qmljs_get_qml_singleton(QV4::NoThrowContext *ctx, const QV4::StringRef name)
 {
-    return ctx->engine->qmlContextObject()->getPointer()->as<QmlContextWrapper>()->qmlSingletonWrapper(name);
+    return ctx->engine->qmlContextObject()->getPointer()->as<QmlContextWrapper>()->qmlSingletonWrapper(ctx->engine->v8Engine, name);
 }
 
 void __qmljs_builtin_convert_this_to_object(ExecutionContext *ctx)
index d221e07..1660e3a 100644 (file)
@@ -63,7 +63,7 @@ DEFINE_OBJECT_VTABLE(QmlContextWrapper);
 
 QmlContextWrapper::QmlContextWrapper(QV8Engine *engine, QQmlContextData *context, QObject *scopeObject, bool ownsContext)
     : Object(QV8Engine::getV4(engine)),
-      v8(engine), readOnly(true), ownsContext(ownsContext), isNullWrapper(false),
+      readOnly(true), ownsContext(ownsContext), isNullWrapper(false),
       context(context), scopeObject(scopeObject), idObjectsWrapper(0)
 {
     setVTable(staticVTable());
@@ -181,7 +181,7 @@ ReturnedValue QmlContextWrapper::get(Managed *m, const StringRef name, bool *has
     //     context = context->parent
     // }
 
-    QV8Engine *engine = resource->v8;
+    QV8Engine *engine = v4->v8Engine;
 
     QObject *scopeObject = resource->getScopeObject();
 
@@ -413,7 +413,7 @@ ReturnedValue QmlContextWrapper::idObjectsArray()
     return idObjectsWrapper->asReturnedValue();
 }
 
-ReturnedValue QmlContextWrapper::qmlSingletonWrapper(const StringRef &name)
+ReturnedValue QmlContextWrapper::qmlSingletonWrapper(QV8Engine *v8, const StringRef &name)
 {
     if (!context->imports)
         return Encode::undefined();
@@ -423,6 +423,7 @@ ReturnedValue QmlContextWrapper::qmlSingletonWrapper(const StringRef &name)
     Q_ASSERT(r.isValid());
     Q_ASSERT(r.type);
     Q_ASSERT(r.type->isSingleton());
+    Q_ASSERT(v8);
 
     QQmlEngine *e = v8->engine();
     QQmlType::SingletonInstanceInfo *siinfo = r.type->singletonInstanceInfo();
index 0ecec93..3facf71 100644 (file)
@@ -97,9 +97,8 @@ struct Q_QML_EXPORT QmlContextWrapper : Object
     static void registerQmlDependencies(ExecutionEngine *context, const CompiledData::Function *compiledFunction);
 
     ReturnedValue idObjectsArray();
-    ReturnedValue qmlSingletonWrapper(const StringRef &name);
+    ReturnedValue qmlSingletonWrapper(QV8Engine *e, const StringRef &name);
 
-    QV8Engine *v8; // ### temporary, remove
     bool readOnly;
     bool ownsContext;
     bool isNullWrapper;
index 7085915..32f3fe7 100644 (file)
@@ -743,7 +743,7 @@ bool QQmlObjectCreator::setPropertyBinding(QQmlPropertyData *property, const QV4
         QV4::Function *runtimeFunction = compiledData->compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex];
 
         QV4::Scope scope(_qmlContext);
-        QV4::ScopedFunctionObject function(scope, QV4::FunctionObject::creatScriptFunction(_qmlContext, runtimeFunction));
+        QV4::ScopedFunctionObject function(scope, QV4::FunctionObject::creatScriptFunction(_qmlContext, runtimeFunction, /*createProto*/ false));
 
         if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression) {
             int signalIndex = _propertyCache->methodIndexToSignalIndex(property->coreIndex);
index ce4997f..83c1f65 100644 (file)
@@ -800,7 +800,7 @@ QObject *QQmlVME::run(QList<QQmlError> *errors,
 
             QV4::Function *runtimeFunction = COMP->compilationUnit->runtimeFunctions[instr.runtimeFunctionIndex];
 
-            tmpValue = QV4::FunctionObject::creatScriptFunction(qmlContext, runtimeFunction);
+            tmpValue = QV4::FunctionObject::creatScriptFunction(qmlContext, runtimeFunction, /*createProto*/ false);
 
             QQmlBoundSignal *bs = new QQmlBoundSignal(target, instr.signalIndex, target, engine);
             QQmlBoundSignalExpression *expr =
@@ -862,7 +862,7 @@ QObject *QQmlVME::run(QList<QQmlError> *errors,
 
             QV4::Function *runtimeFunction = COMP->compilationUnit->runtimeFunctions[instr.functionIndex];
 
-            tmpValue = QV4::FunctionObject::creatScriptFunction(qmlContext, runtimeFunction);
+            tmpValue = QV4::FunctionObject::creatScriptFunction(qmlContext, runtimeFunction, /*createProto*/ false);
 
             QQmlBinding *bind = new QQmlBinding(tmpValue, context, CTXT, COMP->name, instr.line, instr.column);
             bindValues.push(bind);