aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@digia.com>2014-03-31 15:48:02 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2014-04-04 17:26:20 +0200
commit8e556778c8324c61ddf5842e457c873c1b5aac02 (patch)
treeca9dd1cd85510fdbd01221005cb0c096a844a762 /src
parentb02eeeee586abe343b8866385c1327ac009b3ef0 (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.pri2
-rw-r--r--src/qml/jsruntime/qv4argumentsobject.cpp14
-rw-r--r--src/qml/jsruntime/qv4argumentsobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4engine.cpp10
-rw-r--r--src/qml/jsruntime/qv4engine_p.h1
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp3
-rw-r--r--src/qml/jsruntime/qv4internalclass.cpp6
-rw-r--r--src/qml/jsruntime/qv4lookup.cpp6
-rw-r--r--src/qml/jsruntime/qv4memberdata.cpp86
-rw-r--r--src/qml/jsruntime/qv4memberdata_p.h82
-rw-r--r--src/qml/jsruntime/qv4object.cpp27
-rw-r--r--src/qml/jsruntime/qv4object_p.h11
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);