diff options
author | Lars Knoll <lars.knoll@digia.com> | 2014-03-31 15:48:02 +0200 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2014-04-04 17:26:20 +0200 |
commit | 8e556778c8324c61ddf5842e457c873c1b5aac02 (patch) | |
tree | ca9dd1cd85510fdbd01221005cb0c096a844a762 /src | |
parent | b02eeeee586abe343b8866385c1327ac009b3ef0 (diff) |
Garbage collect member data
Move the allocated member data into the garbage collected
area, so that we can avoid using malloc/free for it.
Change-Id: I20625efa67ecd60238568742b74854b0c8cb2e3e
Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/qml/jsruntime/jsruntime.pri | 2 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4argumentsobject.cpp | 14 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4argumentsobject_p.h | 2 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4engine.cpp | 10 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4engine_p.h | 1 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4functionobject.cpp | 3 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4internalclass.cpp | 6 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4lookup.cpp | 6 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4memberdata.cpp | 86 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4memberdata_p.h | 82 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4object.cpp | 27 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4object_p.h | 11 |
12 files changed, 207 insertions, 43 deletions
diff --git a/src/qml/jsruntime/jsruntime.pri b/src/qml/jsruntime/jsruntime.pri index ac26794506..9d5757b5a0 100644 --- a/src/qml/jsruntime/jsruntime.pri +++ b/src/qml/jsruntime/jsruntime.pri @@ -26,6 +26,7 @@ SOURCES += \ $$PWD/qv4globalobject.cpp \ $$PWD/qv4jsonobject.cpp \ $$PWD/qv4mathobject.cpp \ + $$PWD/qv4memberdata.cpp \ $$PWD/qv4numberobject.cpp \ $$PWD/qv4object.cpp \ $$PWD/qv4objectproto.cpp \ @@ -73,6 +74,7 @@ HEADERS += \ $$PWD/qv4globalobject_p.h \ $$PWD/qv4jsonobject_p.h \ $$PWD/qv4mathobject_p.h \ + $$PWD/qv4memberdata_p.h \ $$PWD/qv4numberobject_p.h \ $$PWD/qv4object_p.h \ $$PWD/qv4objectproto_p.h \ diff --git a/src/qml/jsruntime/qv4argumentsobject.cpp b/src/qml/jsruntime/qv4argumentsobject.cpp index c8ba2c4037..1c210b53b6 100644 --- a/src/qml/jsruntime/qv4argumentsobject.cpp +++ b/src/qml/jsruntime/qv4argumentsobject.cpp @@ -93,8 +93,9 @@ void ArgumentsObject::fullyCreate() uint argCount = qMin(context->realArgumentCount, context->callData->argc); ArrayData::realloc(this, ArrayData::Sparse, 0, argCount, true); context->engine->requireArgumentsAccessors(numAccessors); + mappedArguments.ensureIndex(engine(), numAccessors); for (uint i = 0; i < (uint)numAccessors; ++i) { - mappedArguments.append(context->callData->args[i]); + mappedArguments[i] = context->callData->args[i]; arraySet(i, context->engine->argumentsAccessors[i], Attr_Accessor); } arrayPut(numAccessors, context->callData->args + numAccessors, argCount - numAccessors); @@ -113,7 +114,8 @@ bool ArgumentsObject::defineOwnProperty(ExecutionContext *ctx, uint index, const Property map; PropertyAttributes mapAttrs; bool isMapped = false; - if (pd && index < (uint)mappedArguments.size()) + uint numAccessors = qMin((int)context->function->formalParameterCount(), context->realArgumentCount); + if (pd && index < (uint)numAccessors) isMapped = arrayData->attributes(index).isAccessor() && pd->getter() == context->engine->argumentsAccessors[index].getter(); if (isMapped) { @@ -121,7 +123,7 @@ bool ArgumentsObject::defineOwnProperty(ExecutionContext *ctx, uint index, const map.copy(*pd, mapAttrs); setArrayAttributes(index, Attr_Data); pd = arrayData->getProperty(index); - pd->value = mappedArguments.at(index); + pd->value = mappedArguments[index]; } bool strict = ctx->strictMode; @@ -232,9 +234,9 @@ ReturnedValue ArgumentsSetterFunction::call(Managed *setter, CallData *callData) void ArgumentsObject::markObjects(Managed *that, ExecutionEngine *e) { ArgumentsObject *o = static_cast<ArgumentsObject *>(that); - o->context->mark(e); - for (int i = 0; i < o->mappedArguments.size(); ++i) - o->mappedArguments.at(i).mark(e); + if (o->context) + o->context->mark(e); + o->mappedArguments.mark(e); Object::markObjects(that, e); } diff --git a/src/qml/jsruntime/qv4argumentsobject_p.h b/src/qml/jsruntime/qv4argumentsobject_p.h index a7904105e4..80c2a70501 100644 --- a/src/qml/jsruntime/qv4argumentsobject_p.h +++ b/src/qml/jsruntime/qv4argumentsobject_p.h @@ -80,7 +80,7 @@ struct ArgumentsObject: Object { Q_MANAGED_TYPE(ArgumentsObject) CallContext *context; bool fullyCreated; - QVector<Value> mappedArguments; + Members mappedArguments; ArgumentsObject(CallContext *context); ~ArgumentsObject() {} diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index 5372ef8f07..b95197e16b 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -68,6 +68,7 @@ #include "qv4sequenceobject_p.h" #include "qv4qobjectwrapper_p.h" #include "qv4qmlextensions_p.h" +#include "qv4memberdata_p.h" #include <QtCore/QTextStream> @@ -253,6 +254,8 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) id_destroy = newIdentifier(QStringLiteral("destroy")); id_valueOf = newIdentifier(QStringLiteral("valueOf")); + memberDataClass = InternalClass::create(this, MemberData::staticVTable(), 0); + ObjectPrototype *objectPrototype = new (memoryManager) ObjectPrototype(InternalClass::create(this, ObjectPrototype::staticVTable(), 0)); objectClass = InternalClass::create(this, Object::staticVTable(), objectPrototype); Q_ASSERT(objectClass->vtable == Object::staticVTable()); @@ -286,9 +289,12 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) DatePrototype *datePrototype = new (memoryManager) DatePrototype(InternalClass::create(this, DatePrototype::staticVTable(), objectPrototype)); dateClass = InternalClass::create(this, DateObject::staticVTable(), datePrototype); - FunctionPrototype *functionPrototype = new (memoryManager) FunctionPrototype(InternalClass::create(this, FunctionPrototype::staticVTable(), objectPrototype)); - functionClass = InternalClass::create(this, FunctionObject::staticVTable(), functionPrototype); + InternalClass *functionProtoClass = InternalClass::create(this, FunctionObject::staticVTable(), objectPrototype); uint index; + functionProtoClass = functionProtoClass->addMember(id_prototype, Attr_NotEnumerable, &index); + Q_ASSERT(index == FunctionObject::Index_Prototype); + FunctionPrototype *functionPrototype = new (memoryManager) FunctionPrototype(functionProtoClass); + functionClass = InternalClass::create(this, FunctionObject::staticVTable(), functionPrototype); functionClass = functionClass->addMember(id_prototype, Attr_NotEnumerable|Attr_NotConfigurable, &index); Q_ASSERT(index == FunctionObject::Index_Prototype); protoClass = objectClass->addMember(id_constructor, Attr_NotEnumerable, &index); diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index 8620913ae8..b93af514b1 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -229,6 +229,7 @@ public: InternalClass *strictArgumentsObjectClass; InternalClass *variantClass; + InternalClass *memberDataClass; EvalFunction *evalFunction; FunctionObject *thrower; diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp index 00c13a1a35..8e943fa6ef 100644 --- a/src/qml/jsruntime/qv4functionobject.cpp +++ b/src/qml/jsruntime/qv4functionobject.cpp @@ -167,7 +167,8 @@ ReturnedValue FunctionObject::call(Managed *, CallData *) void FunctionObject::markObjects(Managed *that, ExecutionEngine *e) { FunctionObject *o = static_cast<FunctionObject *>(that); - o->scope->mark(e); + if (o->scope) + o->scope->mark(e); Object::markObjects(that, e); } diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp index 4fe8f0bd44..61608b4cba 100644 --- a/src/qml/jsruntime/qv4internalclass.cpp +++ b/src/qml/jsruntime/qv4internalclass.cpp @@ -160,10 +160,10 @@ void InternalClass::changeMember(Object *object, String *string, PropertyAttribu if (newClass->size > object->internalClass->size) { Q_ASSERT(newClass->size == object->internalClass->size + 1); - memmove(object->memberData + idx + 2, object->memberData + idx + 1, (object->internalClass->size - idx - 1)*sizeof(Value)); + memmove(object->memberData.data() + idx + 2, object->memberData.data() + idx + 1, (object->internalClass->size - idx - 1)*sizeof(Value)); } else if (newClass->size < object->internalClass->size) { Q_ASSERT(newClass->size == object->internalClass->size - 1); - memmove(object->memberData + idx + 1, object->memberData + idx + 2, (object->internalClass->size - idx - 2)*sizeof(Value)); + memmove(object->memberData.data() + idx + 1, object->memberData.data() + idx + 2, (object->internalClass->size - idx - 2)*sizeof(Value)); } object->internalClass = newClass; } @@ -368,7 +368,7 @@ void InternalClass::removeMember(Object *object, Identifier *id) } // remove the entry in memberdata - memmove(object->memberData + propIdx, object->memberData + propIdx + 1, (object->internalClass->size - propIdx)*sizeof(Value)); + memmove(object->memberData.data() + propIdx, object->memberData.data() + propIdx + 1, (object->internalClass->size - propIdx)*sizeof(Value)); oldClass->transitions.insert(t, object->internalClass); } diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp index 875a02732f..1155bbf9e9 100644 --- a/src/qml/jsruntime/qv4lookup.cpp +++ b/src/qml/jsruntime/qv4lookup.cpp @@ -763,7 +763,7 @@ void Lookup::setterInsert0(Lookup *l, const ValueRef object, const ValueRef valu Object *o = static_cast<Object *>(object->asManaged()); if (o && o->internalClass == l->classList[0]) { if (!o->prototype()) { - if (l->index >= o->memberDataAlloc) + if (l->index >= o->memberData.size()) o->ensureMemberIndex(l->index); o->memberData[l->index] = *value; o->internalClass = l->classList[3]; @@ -781,7 +781,7 @@ void Lookup::setterInsert1(Lookup *l, const ValueRef object, const ValueRef valu if (o && o->internalClass == l->classList[0]) { Object *p = o->prototype(); if (p && p->internalClass == l->classList[1]) { - if (l->index >= o->memberDataAlloc) + if (l->index >= o->memberData.size()) o->ensureMemberIndex(l->index); o->memberData[l->index] = *value; o->internalClass = l->classList[3]; @@ -801,7 +801,7 @@ void Lookup::setterInsert2(Lookup *l, const ValueRef object, const ValueRef valu if (p && p->internalClass == l->classList[1]) { p = p->prototype(); if (p && p->internalClass == l->classList[2]) { - if (l->index >= o->memberDataAlloc) + if (l->index >= o->memberData.size()) o->ensureMemberIndex(l->index); o->memberData[l->index] = *value; o->internalClass = l->classList[3]; diff --git a/src/qml/jsruntime/qv4memberdata.cpp b/src/qml/jsruntime/qv4memberdata.cpp new file mode 100644 index 0000000000..aeb4c38a8e --- /dev/null +++ b/src/qml/jsruntime/qv4memberdata.cpp @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qv4memberdata_p.h" +#include "qv4mm_p.h" + +using namespace QV4; + +const ManagedVTable MemberData::static_vtbl = +{ + MemberData::IsExecutionContext, + MemberData::IsString, + MemberData::IsObject, + MemberData::IsFunctionObject, + MemberData::IsErrorObject, + MemberData::IsArrayData, + 0, + MemberData::MyType, + "MemberData", + destroy, + markObjects, + isEqualTo +}; + + + +void MemberData::markObjects(Managed *that, ExecutionEngine *e) +{ + MemberData *m = static_cast<MemberData *>(that); + for (uint i = 0; i < m->size; ++i) + m->data[i].mark(e); +} + +void Members::ensureIndex(QV4::ExecutionEngine *e, uint idx) +{ + uint s = size(); + if (idx >= s) { + int newAlloc = qMax((uint)4, 2*idx); + uint alloc = sizeof(MemberData) + (newAlloc)*sizeof(Value); + MemberData *newMemberData = reinterpret_cast<MemberData *>(e->memoryManager->allocManaged(alloc)); + if (d()) + memcpy(newMemberData, d(), sizeof(MemberData) + s*sizeof(Value)); + else + new (newMemberData) MemberData(e->memberDataClass); + newMemberData->size = newAlloc; + m = newMemberData; + } +} diff --git a/src/qml/jsruntime/qv4memberdata_p.h b/src/qml/jsruntime/qv4memberdata_p.h new file mode 100644 index 0000000000..03aa75a365 --- /dev/null +++ b/src/qml/jsruntime/qv4memberdata_p.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef QV4MEMBERDATA_H +#define QV4MEMBERDATA_H + +#include "qv4global_p.h" +#include "qv4managed_p.h" + +QT_BEGIN_NAMESPACE + +namespace QV4 { + +struct MemberData : Managed +{ + V4_MANAGED + uint size; + Value data[1]; + + MemberData(QV4::InternalClass *ic) : Managed(ic) {} + Value &operator[] (uint idx) { return data[idx]; } + + static void markObjects(Managed *that, ExecutionEngine *e); +}; + +struct Members : Value +{ + void ensureIndex(QV4::ExecutionEngine *e, uint idx); + Value &operator[] (uint idx) const { return static_cast<MemberData *>(managed())->data[idx]; } + inline uint size() const { return d() ? d()->size : 0; } + inline MemberData *d() const { return static_cast<MemberData *>(managed()); } + Value *data() const { return static_cast<MemberData *>(managed())->data; } + + void mark(ExecutionEngine *e) const { + MemberData *m = d(); + if (m) + m->mark(e); + } +}; + +} + +QT_END_NAMESPACE + +#endif diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index 37dc0a8bfb..c8d360d511 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -48,6 +48,7 @@ #include "qv4mm_p.h" #include "qv4lookup_p.h" #include "qv4scopedvalue_p.h" +#include "qv4memberdata_p.h" #include <private/qqmljsengine_p.h> #include <private/qqmljslexer_p.h> @@ -71,26 +72,24 @@ DEFINE_OBJECT_VTABLE(Object); Object::Object(ExecutionEngine *engine) : Managed(engine->objectClass) - , memberDataAlloc(InlinePropertySize), memberData(inlineProperties) { } Object::Object(InternalClass *ic) : Managed(ic) - , memberDataAlloc(InlinePropertySize), memberData(inlineProperties) { Q_ASSERT(internalClass->vtable && internalClass->vtable != &Managed::static_vtbl); - if (internalClass->size >= memberDataAlloc) { - memberDataAlloc = internalClass->size; - memberData = new Value[memberDataAlloc]; + Q_ASSERT(!memberData.d()); + if (internalClass->size) { + Scope scope(engine()); + ScopedObject protectThis(scope, this); + memberData.ensureIndex(engine(), internalClass->size); } } Object::~Object() { - if (memberData != inlineProperties) - delete [] memberData; _data = 0; } @@ -222,24 +221,14 @@ void Object::markObjects(Managed *that, ExecutionEngine *e) { Object *o = static_cast<Object *>(that); - for (uint i = 0; i < o->internalClass->size; ++i) - o->memberData[i].mark(e); + o->memberData.mark(e); if (o->arrayData) o->arrayData->mark(e); } void Object::ensureMemberIndex(uint idx) { - if (idx >= memberDataAlloc) { - int newAlloc = qMax((uint)8, 2*memberDataAlloc); - Value *newMemberData = new Value[newAlloc]; - memcpy(newMemberData, memberData, sizeof(Value)*memberDataAlloc); - memset(newMemberData + memberDataAlloc, 0, sizeof(Value)*(newAlloc - memberDataAlloc)); - memberDataAlloc = newAlloc; - if (memberData != inlineProperties) - delete [] memberData; - memberData = newMemberData; - } + memberData.ensureIndex(engine(), idx); } void Object::insertMember(const StringRef s, const Property &p, PropertyAttributes attributes) diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index 89dbde5c82..0dfaffc132 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -50,6 +50,7 @@ #include "qv4property_p.h" #include "qv4internalclass_p.h" #include "qv4arraydata_p.h" +#include "qv4memberdata_p.h" #include <QtCore/QString> #include <QtCore/QHash> @@ -107,17 +108,11 @@ struct Q_QML_EXPORT Object: Managed { enum { IsObject = true }; - uint memberDataAlloc; - Value *memberData; + Members memberData; ArrayData *arrayData; - enum { - InlinePropertySize = 4 - }; - Value inlineProperties[InlinePropertySize]; - - Property *propertyAt(uint index) const { return reinterpret_cast<Property *>(memberData + index); } + Property *propertyAt(uint index) const { return reinterpret_cast<Property *>(memberData.data() + index); } Object(ExecutionEngine *engine); Object(InternalClass *internalClass); |