identifierCache = new Identifiers(this);
+ emptyClass = new InternalClass(this);
rootContext = newContext();
rootContext->init(this);
current = rootContext;
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);
Object *ExecutionEngine::newObject()
{
- Object *object = new (memoryManager) Object();
+ Object *object = new (memoryManager) Object(this);
object->prototype = objectPrototype;
return object;
}
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;
}
Object *ExecutionEngine::newDateObject(const Value &value)
{
- Object *object = new (memoryManager) DateObject(value);
+ Object *object = new (memoryManager) DateObject(this, value);
object->prototype = datePrototype;
return object;
}
struct URIErrorPrototype;
struct EvalFunction;
struct Identifiers;
+struct InternalClass;
class RegExp;
QVector<Function *> functions;
+ InternalClass *emptyClass;
+
ExecutionEngine(EvalISelFactory *iselFactory);
~ExecutionEngine();
ArgumentsObject::ArgumentsObject(ExecutionContext *context, int formalParameterCount, int actualParameterCount)
- : context(context)
+ : Object(context->engine), context(context)
{
type = Type_ArgumentsObject;
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);
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);
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);
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
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);
using namespace QQmlJS::VM;
ErrorObject::ErrorObject(ExecutionEngine* engine, const Value &message)
+ : Object(engine)
{
type = Type_ErrorObject;
subtype = Error;
}
FunctionObject::FunctionObject(ExecutionContext *scope)
- : scope(scope)
+ : Object(scope->engine)
+ , scope(scope)
, name(0)
, formalParameterList(0)
, varList(0)
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)
#include "qv4isel_p.h"
#include "qv4managed.h"
#include "qv4propertydescriptor.h"
-#include "qv4propertytable.h"
#include "qv4objectiterator.h"
#include "qv4regexp.h"
str->stringIdentifier = currentIndex;
if (currentIndex <= USHRT_MAX) {
str->subtype = String::StringType_Identifier;
- ++currentIndex;
identifiers.insert(s, str);
+ ++currentIndex;
}
return str;
}
s->stringIdentifier = currentIndex;
if (currentIndex <= USHRT_MAX) {
s->subtype = String::StringType_Identifier;
- ++currentIndex;
identifiers.insert(s->toQString(), s);
+ ++currentIndex;
}
}
--- /dev/null
+/****************************************************************************
+**
+** 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 <qv4internalclass.h>
+#include <qv4string.h>
+#include <qmljs_engine.h>
+#include <qv4identifier.h>
+
+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<uint, uint>::const_iterator it = propertyTable.constFind(id);
+ if (it != propertyTable.constEnd())
+ return it.value();
+
+ // new member, need to transition to a new internal class
+
+ QHash<int, InternalClass *>::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<int, InternalClass *>::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<uint, uint>::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<uint, uint>::const_iterator it = propertyTable.constFind(id);
+ if (it != propertyTable.constEnd())
+ return it.value();
+
+ return UINT_MAX;
+}
+
+
+}
+}
--- /dev/null
+/****************************************************************************
+**
+** 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 <QHash>
+#include <QVector>
+
+QT_BEGIN_NAMESPACE
+
+namespace QQmlJS {
+namespace VM {
+
+struct String;
+struct ExecutionEngine;
+struct Object;
+
+struct InternalClass {
+ ExecutionEngine *engine;
+ QHash<uint, uint> propertyTable; // id to valueIndex
+ QVector<String *> nameMap;
+ QHash<int, InternalClass *> 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
bool Parser::parseMember(Object *o)
{
BEGIN << "parseMember";
- if (!o->members)
- o->members.reset(new PropertyTable());
QString key;
if (!parseString(&key))
JsonObject::JsonObject(ExecutionContext *context)
- : Object()
+ : Object(context->engine)
{
type = Type_JSONObject;
prototype = context->engine->objectPrototype;
static const double qt_PI = 2.0 * ::asin(1.0);
MathObject::MathObject(ExecutionContext *ctx)
+ : Object(ctx->engine)
{
type = Type_MathObject;
prototype = ctx->engine->objectPrototype;
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);
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;
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;
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;
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();
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
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;
}
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;
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;
}
cont:
- if (!members)
- members.reset(new PropertyTable());
-
// clause 4
if (!pd && prototype)
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;
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;
}
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())
return true;
}
- if (!members)
- members.reset(new PropertyTable());
-
// Clause 1
current = __getOwnProperty__(ctx, name);
if (!current) {
{
type = Type_ArrayObject;
- if (!members)
- members.reset(new PropertyTable());
PropertyDescriptor *pd = insertMember(context->engine->id_length);
assert(pd == memberData + LengthPropertyIndex);
pd->type = PropertyDescriptor::Data;
#include "qv4isel_p.h"
#include "qv4managed.h"
#include "qv4propertydescriptor.h"
-#include "qv4propertytable.h"
+#include "qv4internalclass.h"
#include "qv4objectiterator.h"
#include "qv4regexp.h"
struct Q_V4_EXPORT Object: Managed {
Object *prototype;
- QScopedPointer<PropertyTable> members;
- uint memberDataSize;
+ InternalClass *internalClass;
uint memberDataAlloc;
PropertyDescriptor *memberData;
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);
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(); }
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 {
LengthPropertyIndex = 0
};
- ArrayObject(ExecutionContext *ctx) { init(ctx); }
+ ArrayObject(ExecutionContext *ctx) : Object(ctx->engine) { init(ctx); }
void init(ExecutionContext *context);
};
#include "qv4objectiterator.h"
#include "qv4object.h"
#include "qv4stringobject.h"
+#include "qv4identifier.h"
namespace QQmlJS {
namespace VM {
, 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)
}
}
- if (!current->members || tableIndex >= (uint)current->members->_propertyCount) {
+ if (memberIndex == currentClass->size) {
if (flags & WithProtoChain)
current = current->prototype;
else
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;
#define QV4OBJECTITERATOR_H
#include "qmljs_value.h"
+#include <qv4internalclass.h>
QT_BEGIN_NAMESPACE
Object *current;
SparseArrayNode *arrayNode;
uint arrayIndex;
- uint tableIndex;
+ InternalClass *currentClass;
+ uint memberIndex;
uint flags;
ObjectIterator(ExecutionContext *context, Object *o, uint flags);
struct ObjectPrototype: Object
{
+ ObjectPrototype(ExecutionEngine *engine) : Object(engine) {}
+
void init(ExecutionContext *ctx, const Value &ctor);
static Value method_getPrototypeOf(ExecutionContext *ctx);
+++ /dev/null
-/****************************************************************************
-**
-** 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
RegExpObject::RegExpObject(ExecutionEngine *engine, PassRefPtr<RegExp> 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;
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];
}
#include "qv4isel_p.h"
#include "qv4managed.h"
#include "qv4propertydescriptor.h"
-#include "qv4propertytable.h"
#include "qv4objectiterator.h"
#include "qv4regexp.h"
using namespace QQmlJS::VM;
StringObject::StringObject(ExecutionContext *ctx, const Value &value)
- : value(value)
+ : Object(ctx->engine), value(value)
{
type = Type_StringObject;
debugging.cpp \
qv4mm.cpp \
qv4managed.cpp \
+ qv4internalclass.cpp \
qv4sparsearray.cpp \
qv4arrayobject.cpp \
qv4argumentsobject.cpp \
qv4identifier.h \
qv4mm.h \
qv4managed.h \
+ qv4internalclass.h \
qv4sparsearray.h \
qv4arrayobject.h \
qv4argumentsobject.h \
qv4stringobject.h \
qv4string.h \
qv4propertydescriptor.h \
- qv4propertytable.h \
qv4objectiterator.h \
qv4regexp.h