From: Lars Knoll Date: Sun, 10 Feb 2013 21:22:53 +0000 (+0100) Subject: Use internal classes to store the layout of members X-Git-Tag: upstream/5.2.1~669^2~659^2~281 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=b5333bdcf10662970185bd23f1ed10603f070159;p=platform%2Fupstream%2Fqtdeclarative.git Use internal classes to store the layout of members Add an internal class structure to Object that will allow us to do much more efficient property lookups in the future. Change-Id: I9ee72f6d73113a489f00ad7a31a20e91fbba18ed Reviewed-by: Simon Hausmann --- diff --git a/src/v4/qmljs_engine.cpp b/src/v4/qmljs_engine.cpp index 05a03f6..b71111a 100644 --- a/src/v4/qmljs_engine.cpp +++ b/src/v4/qmljs_engine.cpp @@ -75,6 +75,7 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) identifierCache = new Identifiers(this); + emptyClass = new InternalClass(this); rootContext = newContext(); rootContext->init(this); current = rootContext; @@ -94,12 +95,12 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory) id_set = newIdentifier(QStringLiteral("set")); id_eval = newIdentifier(QStringLiteral("eval")); - objectPrototype = new (memoryManager) ObjectPrototype(); + objectPrototype = new (memoryManager) ObjectPrototype(this); stringPrototype = new (memoryManager) StringPrototype(rootContext); - numberPrototype = new (memoryManager) NumberPrototype(); - booleanPrototype = new (memoryManager) BooleanPrototype(); + numberPrototype = new (memoryManager) NumberPrototype(this); + booleanPrototype = new (memoryManager) BooleanPrototype(this); arrayPrototype = new (memoryManager) ArrayPrototype(rootContext); - datePrototype = new (memoryManager) DatePrototype(); + datePrototype = new (memoryManager) DatePrototype(this); functionPrototype = new (memoryManager) FunctionPrototype(rootContext); regExpPrototype = new (memoryManager) RegExpPrototype(this); errorPrototype = new (memoryManager) ErrorPrototype(this); @@ -270,7 +271,7 @@ BoundFunction *ExecutionEngine::newBoundFunction(ExecutionContext *scope, Functi Object *ExecutionEngine::newObject() { - Object *object = new (memoryManager) Object(); + Object *object = new (memoryManager) Object(this); object->prototype = objectPrototype; return object; } @@ -294,14 +295,14 @@ Object *ExecutionEngine::newStringObject(ExecutionContext *ctx, const Value &val Object *ExecutionEngine::newNumberObject(const Value &value) { - NumberObject *object = new (memoryManager) NumberObject(value); + NumberObject *object = new (memoryManager) NumberObject(this, value); object->prototype = numberPrototype; return object; } Object *ExecutionEngine::newBooleanObject(const Value &value) { - Object *object = new (memoryManager) BooleanObject(value); + Object *object = new (memoryManager) BooleanObject(this, value); object->prototype = booleanPrototype; return object; } @@ -322,7 +323,7 @@ ArrayObject *ExecutionEngine::newArrayObject(ExecutionContext *ctx) Object *ExecutionEngine::newDateObject(const Value &value) { - Object *object = new (memoryManager) DateObject(value); + Object *object = new (memoryManager) DateObject(this, value); object->prototype = datePrototype; return object; } diff --git a/src/v4/qmljs_engine.h b/src/v4/qmljs_engine.h index e581beb..7aaefd4 100644 --- a/src/v4/qmljs_engine.h +++ b/src/v4/qmljs_engine.h @@ -94,6 +94,7 @@ struct TypeErrorPrototype; struct URIErrorPrototype; struct EvalFunction; struct Identifiers; +struct InternalClass; class RegExp; @@ -176,6 +177,8 @@ struct Q_V4_EXPORT ExecutionEngine QVector functions; + InternalClass *emptyClass; + ExecutionEngine(EvalISelFactory *iselFactory); ~ExecutionEngine(); diff --git a/src/v4/qv4argumentsobject.cpp b/src/v4/qv4argumentsobject.cpp index 8211ef2..404edbb 100644 --- a/src/v4/qv4argumentsobject.cpp +++ b/src/v4/qv4argumentsobject.cpp @@ -45,7 +45,7 @@ namespace VM { ArgumentsObject::ArgumentsObject(ExecutionContext *context, int formalParameterCount, int actualParameterCount) - : context(context) + : Object(context->engine), context(context) { type = Type_ArgumentsObject; diff --git a/src/v4/qv4arrayobject.cpp b/src/v4/qv4arrayobject.cpp index 3079c52..3f70029 100644 --- a/src/v4/qv4arrayobject.cpp +++ b/src/v4/qv4arrayobject.cpp @@ -78,8 +78,8 @@ Value ArrayCtor::call(ExecutionContext *ctx) void ArrayPrototype::init(ExecutionContext *ctx, const Value &ctor) { - ctor.objectValue()->defineReadonlyProperty(ctx->engine->id_prototype, Value::fromObject(this)); ctor.objectValue()->defineReadonlyProperty(ctx->engine->id_length, Value::fromInt32(1)); + ctor.objectValue()->defineReadonlyProperty(ctx->engine->id_prototype, Value::fromObject(this)); ctor.objectValue()->defineDefaultProperty(ctx, QStringLiteral("isArray"), method_isArray, 1); defineDefaultProperty(ctx, QStringLiteral("constructor"), ctor); defineDefaultProperty(ctx, QStringLiteral("toString"), method_toString, 0); diff --git a/src/v4/qv4booleanobject.cpp b/src/v4/qv4booleanobject.cpp index 640773d..748a695 100644 --- a/src/v4/qv4booleanobject.cpp +++ b/src/v4/qv4booleanobject.cpp @@ -62,8 +62,8 @@ Value BooleanCtor::call(ExecutionContext *parentCtx, Value thisObject, Value *ar void BooleanPrototype::init(ExecutionContext *ctx, const Value &ctor) { - ctor.objectValue()->defineReadonlyProperty(ctx->engine->id_prototype, Value::fromObject(this)); ctor.objectValue()->defineReadonlyProperty(ctx->engine->id_length, Value::fromInt32(1)); + ctor.objectValue()->defineReadonlyProperty(ctx->engine->id_prototype, Value::fromObject(this)); defineDefaultProperty(ctx, QStringLiteral("constructor"), ctor); defineDefaultProperty(ctx, QStringLiteral("toString"), method_toString); defineDefaultProperty(ctx, QStringLiteral("valueOf"), method_valueOf); diff --git a/src/v4/qv4booleanobject.h b/src/v4/qv4booleanobject.h index d0a7cda..c73ae9b 100644 --- a/src/v4/qv4booleanobject.h +++ b/src/v4/qv4booleanobject.h @@ -60,7 +60,7 @@ struct BooleanCtor: FunctionObject struct BooleanPrototype: BooleanObject { - BooleanPrototype(): BooleanObject(Value::fromBoolean(false)) {} + BooleanPrototype(ExecutionEngine *engine): BooleanObject(engine, Value::fromBoolean(false)) {} void init(ExecutionContext *ctx, const Value &ctor); static Value method_toString(ExecutionContext *ctx); diff --git a/src/v4/qv4dateobject.h b/src/v4/qv4dateobject.h index 2c09ad2..15bd99f 100644 --- a/src/v4/qv4dateobject.h +++ b/src/v4/qv4dateobject.h @@ -52,7 +52,7 @@ namespace VM { struct DateObject: Object { Value value; - DateObject(const Value &value): value(value) { type = Type_DateObject; } + DateObject(ExecutionEngine *engine, const Value &value): Object(engine), value(value) { type = Type_DateObject; } }; struct DateCtor: FunctionObject @@ -65,7 +65,7 @@ struct DateCtor: FunctionObject struct DatePrototype: DateObject { - DatePrototype(): DateObject(Value::fromDouble(qSNaN())) {} + DatePrototype(ExecutionEngine *engine): DateObject(engine, Value::fromDouble(qSNaN())) {} void init(ExecutionContext *ctx, const Value &ctor); static double getThisDate(ExecutionContext *ctx); diff --git a/src/v4/qv4errorobject.cpp b/src/v4/qv4errorobject.cpp index f381a78..c6b0a12 100644 --- a/src/v4/qv4errorobject.cpp +++ b/src/v4/qv4errorobject.cpp @@ -74,6 +74,7 @@ using namespace QQmlJS::VM; ErrorObject::ErrorObject(ExecutionEngine* engine, const Value &message) + : Object(engine) { type = Type_ErrorObject; subtype = Error; diff --git a/src/v4/qv4functionobject.cpp b/src/v4/qv4functionobject.cpp index bba00b8..67ba487 100644 --- a/src/v4/qv4functionobject.cpp +++ b/src/v4/qv4functionobject.cpp @@ -85,7 +85,8 @@ void Function::mark() } FunctionObject::FunctionObject(ExecutionContext *scope) - : scope(scope) + : Object(scope->engine) + , scope(scope) , name(0) , formalParameterList(0) , varList(0) @@ -258,15 +259,16 @@ Value FunctionCtor::call(ExecutionContext *ctx) void FunctionPrototype::init(ExecutionContext *ctx, const Value &ctor) { - ctor.objectValue()->defineReadonlyProperty(ctx->engine->id_prototype, Value::fromObject(this)); ctor.objectValue()->defineReadonlyProperty(ctx->engine->id_length, Value::fromInt32(1)); + ctor.objectValue()->defineReadonlyProperty(ctx->engine->id_prototype, Value::fromObject(this)); + + defineReadonlyProperty(ctx->engine->id_length, Value::fromInt32(0)); defineDefaultProperty(ctx, QStringLiteral("constructor"), ctor); defineDefaultProperty(ctx, QStringLiteral("toString"), method_toString, 0); defineDefaultProperty(ctx, QStringLiteral("apply"), method_apply, 2); defineDefaultProperty(ctx, QStringLiteral("call"), method_call, 1); defineDefaultProperty(ctx, QStringLiteral("bind"), method_bind, 1); - defineReadonlyProperty(ctx->engine->id_length, Value::fromInt32(0)); } Value FunctionPrototype::method_toString(ExecutionContext *ctx) diff --git a/src/v4/qv4functionobject.h b/src/v4/qv4functionobject.h index 900cb8f..87fb696 100644 --- a/src/v4/qv4functionobject.h +++ b/src/v4/qv4functionobject.h @@ -51,7 +51,6 @@ #include "qv4isel_p.h" #include "qv4managed.h" #include "qv4propertydescriptor.h" -#include "qv4propertytable.h" #include "qv4objectiterator.h" #include "qv4regexp.h" diff --git a/src/v4/qv4identifier.h b/src/v4/qv4identifier.h index 3fa84d2..fd4ca7a 100644 --- a/src/v4/qv4identifier.h +++ b/src/v4/qv4identifier.h @@ -73,8 +73,8 @@ public: str->stringIdentifier = currentIndex; if (currentIndex <= USHRT_MAX) { str->subtype = String::StringType_Identifier; - ++currentIndex; identifiers.insert(s, str); + ++currentIndex; } return str; } @@ -95,8 +95,8 @@ public: s->stringIdentifier = currentIndex; if (currentIndex <= USHRT_MAX) { s->subtype = String::StringType_Identifier; - ++currentIndex; identifiers.insert(s->toQString(), s); + ++currentIndex; } } diff --git a/src/v4/qv4internalclass.cpp b/src/v4/qv4internalclass.cpp new file mode 100644 index 0000000..5577f09 --- /dev/null +++ b/src/v4/qv4internalclass.cpp @@ -0,0 +1,129 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the V4VM 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 +#include +#include +#include + +namespace QQmlJS { +namespace VM { + + +InternalClass::InternalClass(const QQmlJS::VM::InternalClass &other) + : engine(other.engine) + , propertyTable(other.propertyTable) + , nameMap(other.nameMap) + , transitions() + , size(other.size) +{ +} + +uint InternalClass::getOrAddMember(Object *object, String *string) +{ + engine->identifierCache->toIdentifier(string); + uint id = string->stringIdentifier; + + QHash::const_iterator it = propertyTable.constFind(id); + if (it != propertyTable.constEnd()) + return it.value(); + + // new member, need to transition to a new internal class + + QHash::const_iterator tit = transitions.constFind(id); + + if (tit != transitions.constEnd()) { + object->internalClass = tit.value(); + } else { + // create a new class and add it to the tree + InternalClass *newClass = new InternalClass(*this); + newClass->propertyTable.insert(id, size); + newClass->nameMap.append(string); + ++newClass->size; + transitions.insert(id, newClass); + object->internalClass = newClass; + } + return size; +} + +void InternalClass::removeMember(Object *object, uint id) +{ + assert (propertyTable.constFind(id) != propertyTable.constEnd()); + int propIdx = propertyTable.constFind(id).value(); + assert(propIdx < size); + + int toRemove = - (int)id; + QHash::const_iterator tit = transitions.constFind(toRemove); + + if (tit != transitions.constEnd()) { + object->internalClass = tit.value(); + return; + } + + // create a new class and add it to the tree + InternalClass *newClass = new InternalClass(*this); + newClass->propertyTable.remove(id); + newClass->nameMap.remove(propIdx); + --newClass->size; + for (QHash::iterator it = newClass->propertyTable.begin(); it != newClass->propertyTable.end(); ++it) { + if ((*it) > propIdx) + --(*it); + } + + transitions.insert(toRemove, newClass); + object->internalClass = newClass; +} + +uint InternalClass::find(String *string) +{ + engine->identifierCache->toIdentifier(string); + uint id = string->stringIdentifier; + + QHash::const_iterator it = propertyTable.constFind(id); + if (it != propertyTable.constEnd()) + return it.value(); + + return UINT_MAX; +} + + +} +} diff --git a/src/v4/qv4internalclass.h b/src/v4/qv4internalclass.h new file mode 100644 index 0000000..d7da0ae --- /dev/null +++ b/src/v4/qv4internalclass.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the V4VM 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 QV4INTERNALCLASS_H +#define QV4INTERNALCLASS_H + +#include +#include + +QT_BEGIN_NAMESPACE + +namespace QQmlJS { +namespace VM { + +struct String; +struct ExecutionEngine; +struct Object; + +struct InternalClass { + ExecutionEngine *engine; + QHash propertyTable; // id to valueIndex + QVector nameMap; + QHash transitions; // id to next class, positive means add, negative delete + uint size; + + InternalClass(ExecutionEngine *engine) : engine(engine), size(0) {} + + uint getOrAddMember(Object *object, String *string); + void removeMember(Object *object, uint id); + uint find(String *s); + +private: + InternalClass(const InternalClass &other); +}; + + +} // namespace VM +} // namespace QQmlJS + +QT_END_NAMESPACE + +#endif diff --git a/src/v4/qv4jsonobject.cpp b/src/v4/qv4jsonobject.cpp index 241c3c8..74b25f3 100644 --- a/src/v4/qv4jsonobject.cpp +++ b/src/v4/qv4jsonobject.cpp @@ -268,8 +268,6 @@ Value Parser::parseObject() bool Parser::parseMember(Object *o) { BEGIN << "parseMember"; - if (!o->members) - o->members.reset(new PropertyTable()); QString key; if (!parseString(&key)) @@ -864,7 +862,7 @@ QString Stringify::JA(ArrayObject *a) JsonObject::JsonObject(ExecutionContext *context) - : Object() + : Object(context->engine) { type = Type_JSONObject; prototype = context->engine->objectPrototype; diff --git a/src/v4/qv4mathobject.cpp b/src/v4/qv4mathobject.cpp index f0523ba..e7c455a 100644 --- a/src/v4/qv4mathobject.cpp +++ b/src/v4/qv4mathobject.cpp @@ -51,6 +51,7 @@ using namespace QQmlJS::VM; static const double qt_PI = 2.0 * ::asin(1.0); MathObject::MathObject(ExecutionContext *ctx) + : Object(ctx->engine) { type = Type_MathObject; prototype = ctx->engine->objectPrototype; diff --git a/src/v4/qv4numberobject.h b/src/v4/qv4numberobject.h index aa2c9cf..b24e538 100644 --- a/src/v4/qv4numberobject.h +++ b/src/v4/qv4numberobject.h @@ -60,7 +60,7 @@ struct NumberCtor: FunctionObject struct NumberPrototype: NumberObject { - NumberPrototype(): NumberObject(Value::fromDouble(0)) {} + NumberPrototype(ExecutionEngine *engine): NumberObject(engine, Value::fromDouble(0)) {} void init(ExecutionContext *ctx, const Value &ctor); static Value method_toString(ExecutionContext *ctx); diff --git a/src/v4/qv4object.cpp b/src/v4/qv4object.cpp index f260762..31200bc 100644 --- a/src/v4/qv4object.cpp +++ b/src/v4/qv4object.cpp @@ -65,9 +65,16 @@ using namespace QQmlJS::VM; -// -// Object -// +Object::Object(ExecutionEngine *engine) + : prototype(0) + , internalClass(engine->emptyClass) + , memberDataAlloc(0), memberData(0) + , arrayOffset(0), arrayDataLen(0), arrayAlloc(0), sparseArray(0) +{ + type = Type_Object; +} + + Object::~Object() { delete [] memberData; @@ -130,8 +137,6 @@ void Object::inplaceBinOp(Value rhs, Value index, BinOp op, ExecutionContext *ct void Object::defineDefaultProperty(String *name, Value value) { - if (!members) - members.reset(new PropertyTable()); PropertyDescriptor *pd = insertMember(name); pd->type = PropertyDescriptor::Data; pd->writable = PropertyDescriptor::Enabled; @@ -170,8 +175,6 @@ void Object::defineReadonlyProperty(ExecutionEngine *engine, const QString &name void Object::defineReadonlyProperty(String *name, Value value) { - if (!members) - members.reset(new PropertyTable()); PropertyDescriptor *pd = insertMember(name); pd->type = PropertyDescriptor::Data; pd->writable = PropertyDescriptor::Disabled; @@ -185,23 +188,16 @@ void Object::markObjects() if (prototype) prototype->mark(); - if (members) { - for (PropertyTable::iterator it = members->begin(), eit = members->end(); it < eit; ++it) { - if (!(*it)) - continue; - (*it)->name->mark(); - } - for (int i = 0; i < memberDataSize; ++i) { - const PropertyDescriptor &pd = memberData[i]; - if (pd.isData()) { - if (Managed *m = pd.value.asManaged()) - m->mark(); - } else if (pd.isAccessor()) { - if (pd.get) - pd.get->mark(); - if (pd.set) - pd.set->mark(); - } + for (int i = 0; i < internalClass->size; ++i) { + const PropertyDescriptor &pd = memberData[i]; + if (pd.isData()) { + if (Managed *m = pd.value.asManaged()) + m->mark(); + } else if (pd.isAccessor()) { + if (pd.get) + pd.get->mark(); + if (pd.set) + pd.set->mark(); } } markArrayObjects(); @@ -209,22 +205,16 @@ void Object::markObjects() PropertyDescriptor *Object::insertMember(String *s) { - if (!members) - members.reset(new PropertyTable); - - PropertyTableEntry *e = members->insert(s); - if (e->valueIndex == UINT_MAX) { - if (memberDataSize == memberDataAlloc) { - memberDataAlloc = qMax((uint)8, 2*memberDataAlloc); - PropertyDescriptor *newMemberData = new PropertyDescriptor[memberDataAlloc]; - memcpy(newMemberData, memberData, sizeof(PropertyDescriptor)*memberDataSize); - delete [] memberData; - memberData = newMemberData; - } - e->valueIndex = memberDataSize; - ++memberDataSize; + uint idx = internalClass->getOrAddMember(this, s); + + if (idx >= memberDataAlloc) { + memberDataAlloc = qMax((uint)8, 2*memberDataAlloc); + PropertyDescriptor *newMemberData = new PropertyDescriptor[memberDataAlloc]; + memcpy(newMemberData, memberData, sizeof(PropertyDescriptor)*idx); + delete [] memberData; + memberData = newMemberData; } - return memberData + e->valueIndex; + return memberData + idx; } // Section 8.12.1 @@ -234,11 +224,10 @@ PropertyDescriptor *Object::__getOwnProperty__(ExecutionContext *ctx, String *na if (idx != String::InvalidArrayIndex) return __getOwnProperty__(ctx, idx); - if (members) { - uint idx = members->find(name); - if (idx < UINT_MAX) - return memberData + idx; - } + uint member = internalClass->find(name); + if (member < UINT_MAX) + return memberData + member; + return 0; } @@ -263,11 +252,10 @@ PropertyDescriptor *Object::__getPropertyDescriptor__(ExecutionContext *ctx, Str Object *o = this; while (o) { - if (o->members) { - uint idx = o->members->find(name); - if (idx < UINT_MAX) - return o->memberData + idx; - } + uint idx = o->internalClass->find(name); + if (idx < UINT_MAX) + return o->memberData + idx; + o = o->prototype; } return 0; @@ -307,14 +295,13 @@ Value Object::__get__(ExecutionContext *ctx, String *name, bool *hasProperty) Object *o = this; while (o) { - if (o->members) { - uint idx = o->members->find(name); - if (idx < UINT_MAX) { - if (hasProperty) - *hasProperty = true; - return getValue(ctx, o->memberData + idx); - } + uint idx = o->internalClass->find(name); + if (idx < UINT_MAX) { + if (hasProperty) + *hasProperty = true; + return getValue(ctx, o->memberData + idx); } + o = o->prototype; } @@ -407,9 +394,6 @@ void Object::__put__(ExecutionContext *ctx, String *name, Value value) cont: - if (!members) - members.reset(new PropertyTable()); - // clause 4 if (!pd && prototype) @@ -507,7 +491,7 @@ bool Object::__hasProperty__(const ExecutionContext *ctx, String *name) const name->makeIdentifier(ctx); - if (members && members->find(name) != UINT_MAX) + if (internalClass->find(name) != UINT_MAX) return true; return prototype ? prototype->__hasProperty__(ctx, name) : false; @@ -531,21 +515,19 @@ bool Object::__delete__(ExecutionContext *ctx, String *name) name->makeIdentifier(ctx); - if (members) { - if (PropertyTableEntry *entry = members->findEntry(name)) { - PropertyDescriptor &pd = memberData[entry->valueIndex]; - if (pd.isConfigurable()) { - members->remove(entry); - // ### leaves a hole in memberData - pd.type = PropertyDescriptor::Generic; - pd.writable = PropertyDescriptor::Undefined; - return true; - } - if (ctx->strictMode) - __qmljs_throw_type_error(ctx); - return false; + uint memberIdx = internalClass->find(name); + if (memberIdx != UINT_MAX) { + PropertyDescriptor &pd = memberData[memberIdx]; + if (pd.isConfigurable()) { + internalClass->removeMember(this, name->stringIdentifier); + memmove(memberData + memberIdx, memberData + memberIdx + 1, (internalClass->size - memberIdx)*sizeof(PropertyDescriptor)); + return true; } + if (ctx->strictMode) + __qmljs_throw_type_error(ctx); + return false; } + return true; } @@ -592,7 +574,7 @@ bool Object::__defineOwnProperty__(ExecutionContext *ctx, String *name, const Pr if (isArrayObject() && name->isEqualTo(ctx->engine->id_length)) { PropertyDescriptor *lp = memberData + ArrayObject::LengthPropertyIndex; - assert(0 == members->find(ctx->engine->id_length)); + assert(0 == internalClass->find(ctx->engine->id_length)); if (desc->isEmpty() || desc->isSubset(lp)) return true; if (!lp->isWritable() || desc->type == PropertyDescriptor::Accessor || desc->isConfigurable() || desc->isEnumerable()) @@ -612,9 +594,6 @@ bool Object::__defineOwnProperty__(ExecutionContext *ctx, String *name, const Pr return true; } - if (!members) - members.reset(new PropertyTable()); - // Clause 1 current = __getOwnProperty__(ctx, name); if (!current) { @@ -982,8 +961,6 @@ void ArrayObject::init(ExecutionContext *context) { type = Type_ArrayObject; - if (!members) - members.reset(new PropertyTable()); PropertyDescriptor *pd = insertMember(context->engine->id_length); assert(pd == memberData + LengthPropertyIndex); pd->type = PropertyDescriptor::Data; diff --git a/src/v4/qv4object.h b/src/v4/qv4object.h index 7f99668..964051f 100644 --- a/src/v4/qv4object.h +++ b/src/v4/qv4object.h @@ -51,7 +51,7 @@ #include "qv4isel_p.h" #include "qv4managed.h" #include "qv4propertydescriptor.h" -#include "qv4propertytable.h" +#include "qv4internalclass.h" #include "qv4objectiterator.h" #include "qv4regexp.h" @@ -102,8 +102,7 @@ struct URIErrorPrototype; struct Q_V4_EXPORT Object: Managed { Object *prototype; - QScopedPointer members; - uint memberDataSize; + InternalClass *internalClass; uint memberDataAlloc; PropertyDescriptor *memberData; @@ -116,11 +115,7 @@ struct Q_V4_EXPORT Object: Managed { PropertyDescriptor *arrayData; SparseArray *sparseArray; - Object() - : prototype(0) - , memberDataSize(0), memberDataAlloc(0), memberData(0) - , arrayOffset(0), arrayDataLen(0), arrayAlloc(0), sparseArray(0) { type = Type_Object; } - + Object(ExecutionEngine *engine); virtual ~Object(); PropertyDescriptor *__getOwnProperty__(ExecutionContext *ctx, String *name); @@ -315,7 +310,7 @@ protected: struct ForEachIteratorObject: Object { ObjectIterator it; ForEachIteratorObject(ExecutionContext *ctx, Object *o) - : it(ctx, o, ObjectIterator::EnumberableOnly|ObjectIterator::WithProtoChain) { type = Type_ForeachIteratorObject; } + : Object(ctx->engine), it(ctx, o, ObjectIterator::EnumberableOnly|ObjectIterator::WithProtoChain) { type = Type_ForeachIteratorObject; } Value nextPropertyName() { return it.nextPropertyNameAsString(); } @@ -325,12 +320,12 @@ protected: struct BooleanObject: Object { Value value; - BooleanObject(const Value &value): value(value) { type = Type_BooleanObject; } + BooleanObject(ExecutionEngine *engine, const Value &value): Object(engine), value(value) { type = Type_BooleanObject; } }; struct NumberObject: Object { Value value; - NumberObject(const Value &value): value(value) { type = Type_NumberObject; } + NumberObject(ExecutionEngine *engine, const Value &value): Object(engine), value(value) { type = Type_NumberObject; } }; struct ArrayObject: Object { @@ -338,7 +333,7 @@ struct ArrayObject: Object { LengthPropertyIndex = 0 }; - ArrayObject(ExecutionContext *ctx) { init(ctx); } + ArrayObject(ExecutionContext *ctx) : Object(ctx->engine) { init(ctx); } void init(ExecutionContext *context); }; diff --git a/src/v4/qv4objectiterator.cpp b/src/v4/qv4objectiterator.cpp index 7bcf872..d7c1a19 100644 --- a/src/v4/qv4objectiterator.cpp +++ b/src/v4/qv4objectiterator.cpp @@ -41,6 +41,7 @@ #include "qv4objectiterator.h" #include "qv4object.h" #include "qv4stringobject.h" +#include "qv4identifier.h" namespace QQmlJS { namespace VM { @@ -51,11 +52,15 @@ ObjectIterator::ObjectIterator(ExecutionContext *context, Object *o, uint flags) , current(o) , arrayNode(0) , arrayIndex(0) - , tableIndex(0) + , currentClass(0) + , memberIndex(0) , flags(flags) { - if (current && current->asStringObject()) - this->flags |= CurrentIsString; + if (current) { + currentClass = current->internalClass; + if (current->asStringObject()) + this->flags |= CurrentIsString; + } } PropertyDescriptor *ObjectIterator::next(String **name, uint *index) @@ -110,7 +115,7 @@ PropertyDescriptor *ObjectIterator::next(String **name, uint *index) } } - if (!current->members || tableIndex >= (uint)current->members->_propertyCount) { + if (memberIndex == currentClass->size) { if (flags & WithProtoChain) current = current->prototype; else @@ -122,19 +127,20 @@ PropertyDescriptor *ObjectIterator::next(String **name, uint *index) arrayIndex = 0; - tableIndex = 0; + memberIndex = 0; + if (current) + currentClass = current->internalClass; continue; } - PropertyTableEntry *pt = current->members->_properties[tableIndex]; - ++tableIndex; + String *n = currentClass->nameMap.at(memberIndex); + assert(n); // ### check that it's not a repeated attribute - if (pt) { - PropertyDescriptor *pd = current->memberData + pt->valueIndex; - if (!(flags & EnumberableOnly) || pd->isEnumerable()) { - *name = pt->name; - p = pd; - return p; - } + + p = current->memberData + memberIndex; + ++memberIndex; + if (!(flags & EnumberableOnly) || p->isEnumerable()) { + *name = n; + return p; } } return 0; diff --git a/src/v4/qv4objectiterator.h b/src/v4/qv4objectiterator.h index a463eb8..c2e61dc 100644 --- a/src/v4/qv4objectiterator.h +++ b/src/v4/qv4objectiterator.h @@ -42,6 +42,7 @@ #define QV4OBJECTITERATOR_H #include "qmljs_value.h" +#include QT_BEGIN_NAMESPACE @@ -66,7 +67,8 @@ struct ObjectIterator Object *current; SparseArrayNode *arrayNode; uint arrayIndex; - uint tableIndex; + InternalClass *currentClass; + uint memberIndex; uint flags; ObjectIterator(ExecutionContext *context, Object *o, uint flags); diff --git a/src/v4/qv4objectproto.h b/src/v4/qv4objectproto.h index 585ccb4..679c271 100644 --- a/src/v4/qv4objectproto.h +++ b/src/v4/qv4objectproto.h @@ -60,6 +60,8 @@ struct ObjectCtor: FunctionObject struct ObjectPrototype: Object { + ObjectPrototype(ExecutionEngine *engine) : Object(engine) {} + void init(ExecutionContext *ctx, const Value &ctor); static Value method_getPrototypeOf(ExecutionContext *ctx); diff --git a/src/v4/qv4propertytable.h b/src/v4/qv4propertytable.h deleted file mode 100644 index 79e4c77..0000000 --- a/src/v4/qv4propertytable.h +++ /dev/null @@ -1,234 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the V4VM 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 QV4PROPERTYTABLE_H -#define QV4PROPERTYTABLE_H - -#include "qmljs_value.h" -#include "qv4propertydescriptor.h" - -QT_BEGIN_NAMESPACE - -namespace QQmlJS { -namespace VM { - -struct ObjectIterator; - -struct PropertyTableEntry { - String *name; - uint valueIndex; - PropertyTableEntry *next; - int index; - - inline PropertyTableEntry(String *name) - : name(name), - valueIndex(UINT_MAX), - next(0), - index(-1) - { } - - inline unsigned hashValue() const { return name->hashValue(); } -}; - -class PropertyTable -{ - Q_DISABLE_COPY(PropertyTable) - friend struct ArrayObject; - -public: - PropertyTable() - : _properties(0) - , _buckets(0) - , _freeList(0) - , _propertyCount(0) - , _bucketCount(0) - , _primeIdx(-1) - , _allocated(0) - {} - - ~PropertyTable() - { - qDeleteAll(_properties, _properties + _propertyCount); - delete[] _properties; - delete[] _buckets; - } - - typedef PropertyTableEntry **iterator; - inline iterator begin() const { return _properties; } - inline iterator end() const { return _properties + _propertyCount; } - - void remove(PropertyTableEntry *prop) - { - PropertyTableEntry **bucket = _buckets + (prop->hashValue() % _bucketCount); - if (*bucket == prop) { - *bucket = prop->next; - } else { - for (PropertyTableEntry *it = *bucket; it; it = it->next) { - if (it->next == prop) { - it->next = it->next->next; - break; - } - } - } - - _properties[prop->index] = 0; - prop->next = _freeList; - _freeList = prop; - } - - PropertyTableEntry *findEntry(String *name) const - { - if (_properties) { - for (PropertyTableEntry *prop = _buckets[name->hashValue() % _bucketCount]; prop; prop = prop->next) { - if (prop && prop->name->isEqualTo(name)) - return prop; - } - } - - return 0; - } - - uint find(String *name) - { - if (_properties) { - for (PropertyTableEntry *prop = _buckets[name->hashValue() % _bucketCount]; prop; prop = prop->next) { - if (prop && prop->name->isEqualTo(name)) - return prop->valueIndex; - } - } - - return UINT_MAX; - } - - PropertyTableEntry *insert(String *name) - { - if (PropertyTableEntry *prop = findEntry(name)) - return prop; - - if (_propertyCount == _allocated) { - if (! _allocated) - _allocated = 4; - else - _allocated *= 2; - - PropertyTableEntry **properties = new PropertyTableEntry*[_allocated]; - std::copy(_properties, _properties + _propertyCount, properties); - delete[] _properties; - _properties = properties; - } - - PropertyTableEntry *prop; - if (_freeList) { - prop = _freeList; - prop->name = name; - _freeList = _freeList->next; - } else { - prop = new PropertyTableEntry(name); - } - - prop->index = _propertyCount; - _properties[_propertyCount] = prop; - ++_propertyCount; - - if (! _buckets || 3 * _propertyCount >= 2 * _bucketCount) { - rehash(); - } else { - PropertyTableEntry *&bucket = _buckets[prop->hashValue() % _bucketCount]; - prop->next = bucket; - bucket = prop; - } - - return prop; -// prop->valueIndex = values.size(); -// values.resize(values.size() + 1); -// return values.data() + prop->valueIndex; - } - -private: - void rehash() - { - _bucketCount = nextPrime(); - - delete[] _buckets; - _buckets = new PropertyTableEntry *[_bucketCount]; - std::fill(_buckets, _buckets + _bucketCount, (PropertyTableEntry *) 0); - - for (int i = 0; i < _propertyCount; ++i) { - PropertyTableEntry *prop = _properties[i]; - if (prop) { - PropertyTableEntry *&bucket = _buckets[prop->hashValue() % _bucketCount]; - prop->next = bucket; - bucket = prop; - } - } - } - - inline int nextPrime() - { - // IMPORTANT: do not add more primes without checking if _primeIdx needs more bits! - static const int primes[] = { - 11, 23, 47, 97, 197, 397, 797, 1597, 3203, 6421, 12853, 25717, 51437, 102877 - }; - - if (_primeIdx < (int) (sizeof(primes)/sizeof(int))) - return primes[++_primeIdx]; - else - return _bucketCount * 2 + 1; // Yes, we're degrading here. But who needs more than about 68000 properties? - } - -private: - friend struct ObjectIterator; - friend struct Object; - - PropertyTableEntry **_properties; - PropertyTableEntry **_buckets; - PropertyTableEntry *_freeList; - int _propertyCount; - int _bucketCount; - int _primeIdx: 5; - int _allocated: 27; -}; - -} // namespace VM -} // namespace QQmlJS - -QT_END_NAMESPACE - -#endif diff --git a/src/v4/qv4regexpobject.cpp b/src/v4/qv4regexpobject.cpp index 8319a0c..2762c98 100644 --- a/src/v4/qv4regexpobject.cpp +++ b/src/v4/qv4regexpobject.cpp @@ -65,13 +65,12 @@ using namespace QQmlJS::VM; RegExpObject::RegExpObject(ExecutionEngine *engine, PassRefPtr value, bool global) - : value(value) + : Object(engine) + , value(value) , global(global) { type = Type_RegExpObject; - if (!members) - members.reset(new PropertyTable()); PropertyDescriptor *lastIndexProperty = insertMember(engine->newIdentifier(QStringLiteral("lastIndex"))); lastIndexProperty->type = PropertyDescriptor::Data; lastIndexProperty->writable = PropertyDescriptor::Enabled; @@ -88,7 +87,7 @@ RegExpObject::RegExpObject(ExecutionEngine *engine, PassRefPtr value, bo PropertyDescriptor *RegExpObject::lastIndexProperty(ExecutionContext *ctx) { - assert(0 == members->find(ctx->engine->newIdentifier(QStringLiteral("lastIndex")))); + assert(0 == internalClass->find(ctx->engine->newIdentifier(QStringLiteral("lastIndex")))); return &memberData[0]; } diff --git a/src/v4/qv4regexpobject.h b/src/v4/qv4regexpobject.h index 6c7f583..dcf6120 100644 --- a/src/v4/qv4regexpobject.h +++ b/src/v4/qv4regexpobject.h @@ -50,7 +50,6 @@ #include "qv4isel_p.h" #include "qv4managed.h" #include "qv4propertydescriptor.h" -#include "qv4propertytable.h" #include "qv4objectiterator.h" #include "qv4regexp.h" diff --git a/src/v4/qv4stringobject.cpp b/src/v4/qv4stringobject.cpp index dee5dae..1e226b1 100644 --- a/src/v4/qv4stringobject.cpp +++ b/src/v4/qv4stringobject.cpp @@ -76,7 +76,7 @@ using namespace QQmlJS::VM; StringObject::StringObject(ExecutionContext *ctx, const Value &value) - : value(value) + : Object(ctx->engine), value(value) { type = Type_StringObject; diff --git a/src/v4/v4.pro b/src/v4/v4.pro index 79b3316..2197ae3 100644 --- a/src/v4/v4.pro +++ b/src/v4/v4.pro @@ -29,6 +29,7 @@ SOURCES += \ debugging.cpp \ qv4mm.cpp \ qv4managed.cpp \ + qv4internalclass.cpp \ qv4sparsearray.cpp \ qv4arrayobject.cpp \ qv4argumentsobject.cpp \ @@ -65,6 +66,7 @@ HEADERS += \ qv4identifier.h \ qv4mm.h \ qv4managed.h \ + qv4internalclass.h \ qv4sparsearray.h \ qv4arrayobject.h \ qv4argumentsobject.h \ @@ -82,7 +84,6 @@ HEADERS += \ qv4stringobject.h \ qv4string.h \ qv4propertydescriptor.h \ - qv4propertytable.h \ qv4objectiterator.h \ qv4regexp.h