aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@digia.com>2013-04-10 10:46:23 +0200
committerSimon Hausmann <simon.hausmann@digia.com>2013-04-12 15:19:02 +0200
commitd0af8986b32aa4cccdc2ff7d8dc5e66e9d53ed77 (patch)
tree1385c3f8bad78b71d0f2c83518976bc86bc7f3cb /src
parent9bd0895c277150aa51ee0ce55ce492c41346b18e (diff)
Move property attributes out of the property arrays
Rather large change that fully separates the property attributes from the property data. This saves quite some memory. Since the property data for members is saves in the class structure it'll also allow optimizations to the lookup code. Change-Id: I9ba1d372bb756695bef8188d1b86275562a1b219 Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
Diffstat (limited to 'src')
-rw-r--r--src/v4/debugging.cpp5
-rw-r--r--src/v4/qv4argumentsobject.cpp42
-rw-r--r--src/v4/qv4argumentsobject.h2
-rw-r--r--src/v4/qv4arrayobject.cpp34
-rw-r--r--src/v4/qv4context.cpp17
-rw-r--r--src/v4/qv4engine.cpp12
-rw-r--r--src/v4/qv4engine.h3
-rw-r--r--src/v4/qv4functionobject.cpp13
-rw-r--r--src/v4/qv4functionobject.h18
-rw-r--r--src/v4/qv4global.h38
-rw-r--r--src/v4/qv4internalclass.cpp87
-rw-r--r--src/v4/qv4internalclass.h10
-rw-r--r--src/v4/qv4isel_util_p.h10
-rw-r--r--src/v4/qv4jsir.cpp3
-rw-r--r--src/v4/qv4jsonobject.cpp8
-rw-r--r--src/v4/qv4object.cpp626
-rw-r--r--src/v4/qv4object.h142
-rw-r--r--src/v4/qv4objectiterator.cpp36
-rw-r--r--src/v4/qv4objectiterator.h5
-rw-r--r--src/v4/qv4objectproto.cpp186
-rw-r--r--src/v4/qv4objectproto.h4
-rw-r--r--src/v4/qv4propertydescriptor.h84
-rw-r--r--src/v4/qv4regexpobject.cpp5
-rw-r--r--src/v4/qv4regexpobject.h2
-rw-r--r--src/v4/qv4runtime.cpp78
-rw-r--r--src/v4/qv4runtime.h1
-rw-r--r--src/v4/qv4sparsearray.cpp10
-rw-r--r--src/v4/qv4sparsearray.h2
-rw-r--r--src/v4/qv4string.cpp14
-rw-r--r--src/v4/qv4stringobject.cpp3
-rw-r--r--src/v4/qv4stringobject.h4
-rw-r--r--src/v4/qv4v8.cpp23
-rw-r--r--src/v4/qv4value.h18
33 files changed, 907 insertions, 638 deletions
diff --git a/src/v4/debugging.cpp b/src/v4/debugging.cpp
index e41dba2086..30ab4a1ed9 100644
--- a/src/v4/debugging.cpp
+++ b/src/v4/debugging.cpp
@@ -294,8 +294,9 @@ static void realDumpValue(VM::Value v, VM::ExecutionContext *ctx, std::string pr
ForEachIteratorObject it(ctx, o);
for (Value name = it.nextPropertyName(); !name.isNull(); name = it.nextPropertyName()) {
cout << prefix << "\t\"" << qPrintable(name.stringValue()->toQString()) << "\"" << endl;
- PropertyDescriptor *d = o->__getOwnProperty__(ctx, name.stringValue());
- Value pval = o->getValue(ctx, d);
+ PropertyAttributes attrs;
+ Property *d = o->__getOwnProperty__(ctx, name.stringValue(), &attrs);
+ Value pval = o->getValue(ctx, d, attrs);
cout << prefix << "\tvalue:" << endl;
realDumpValue(pval, ctx, prefix + "\t");
}
diff --git a/src/v4/qv4argumentsobject.cpp b/src/v4/qv4argumentsobject.cpp
index 0378112356..21c72be460 100644
--- a/src/v4/qv4argumentsobject.cpp
+++ b/src/v4/qv4argumentsobject.cpp
@@ -63,22 +63,19 @@ ArgumentsObject::ArgumentsObject(CallContext *context, int formalParameterCount,
for (uint i = 0; i < context->argumentCount; ++i)
Object::put(context, QString::number(i), context->arguments[i]);
FunctionObject *thrower = context->engine->newBuiltinFunction(context, 0, throwTypeError);
- PropertyDescriptor pd = PropertyDescriptor::fromAccessor(thrower, thrower);
- pd.attrs = Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable;
- __defineOwnProperty__(context, QStringLiteral("callee"), &pd);
- __defineOwnProperty__(context, QStringLiteral("caller"), &pd);
+ Property pd = Property::fromAccessor(thrower, thrower);
+ __defineOwnProperty__(context, QStringLiteral("callee"), pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
+ __defineOwnProperty__(context, QStringLiteral("caller"), pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
} else {
uint numAccessors = qMin(formalParameterCount, actualParameterCount);
context->engine->requireArgumentsAccessors(numAccessors);
for (uint i = 0; i < (uint)numAccessors; ++i) {
mappedArguments.append(context->argument(i));
- __defineOwnProperty__(context, i, &context->engine->argumentsAccessors.at(i));
+ __defineOwnProperty__(context, i, context->engine->argumentsAccessors.at(i), Attr_Accessor);
}
- PropertyDescriptor pd;
- pd.attrs = Attr_Data;
for (uint i = numAccessors; i < qMin((uint)actualParameterCount, context->argumentCount); ++i) {
- pd.value = context->argument(i);
- __defineOwnProperty__(context, i, &pd);
+ Property pd = Property::fromValue(context->argument(i));
+ __defineOwnProperty__(context, i, pd, Attr_Data);
}
defineDefaultProperty(context, QStringLiteral("callee"), Value::fromObject(context->function));
isNonStrictArgumentsObject = true;
@@ -90,34 +87,39 @@ void ArgumentsObject::destroy(Managed *that)
static_cast<ArgumentsObject *>(that)->~ArgumentsObject();
}
-bool ArgumentsObject::defineOwnProperty(ExecutionContext *ctx, uint index, const PropertyDescriptor *desc)
+bool ArgumentsObject::defineOwnProperty(ExecutionContext *ctx, uint index, const Property &desc, PropertyAttributes attrs)
{
- PropertyDescriptor *pd = arrayAt(index);
- PropertyDescriptor map;
+ uint pidx = propertyIndexFromArrayIndex(index);
+ Property *pd = arrayData + pidx;
+ Property map;
+ PropertyAttributes mapAttrs;
bool isMapped = false;
if (pd && index < (uint)mappedArguments.size())
- isMapped = pd->attrs.isAccessor() && pd->get == context->engine->argumentsAccessors.at(index).get;
+ isMapped = arrayAttributes && arrayAttributes[pidx].isAccessor() && pd->getter() == context->engine->argumentsAccessors.at(index).getter();
if (isMapped) {
map = *pd;
- pd->attrs = Attr_Data;
+ mapAttrs = arrayAttributes[pidx];
+ arrayAttributes[pidx] = Attr_Data;
pd->value = mappedArguments.at(index);
}
isNonStrictArgumentsObject = false;
bool strict = ctx->strictMode;
ctx->strictMode = false;
- bool result = Object::__defineOwnProperty__(ctx, index, desc);
+ bool result = Object::__defineOwnProperty__(ctx, index, desc, attrs);
ctx->strictMode = strict;
isNonStrictArgumentsObject = true;
- if (isMapped && desc->attrs.isData()) {
- if (desc->attrs.type() != PropertyAttributes::Generic) {
- Value arg = desc->value;
- map.set->call(ctx, Value::fromObject(this), &arg, 1);
+ if (isMapped && attrs.isData()) {
+ if (!attrs.isGeneric()) {
+ Value arg = desc.value;
+ map.setter()->call(ctx, Value::fromObject(this), &arg, 1);
}
- if (desc->attrs.isWritable())
+ if (attrs.isWritable()) {
*pd = map;
+ arrayAttributes[pidx] = mapAttrs;
+ }
}
if (ctx->strictMode && !result)
diff --git a/src/v4/qv4argumentsobject.h b/src/v4/qv4argumentsobject.h
index 4dcdadd2d8..6727d8759b 100644
--- a/src/v4/qv4argumentsobject.h
+++ b/src/v4/qv4argumentsobject.h
@@ -82,7 +82,7 @@ struct ArgumentsObject: Object {
ArgumentsObject(CallContext *context, int formalParameterCount, int actualParameterCount);
~ArgumentsObject() {}
- bool defineOwnProperty(ExecutionContext *ctx, uint index, const PropertyDescriptor *desc);
+ bool defineOwnProperty(ExecutionContext *ctx, uint index, const Property &desc, PropertyAttributes attrs);
static void markObjects(Managed *that);
protected:
diff --git a/src/v4/qv4arrayobject.cpp b/src/v4/qv4arrayobject.cpp
index 1ca9cf947c..39492ef099 100644
--- a/src/v4/qv4arrayobject.cpp
+++ b/src/v4/qv4arrayobject.cpp
@@ -69,7 +69,7 @@ Value ArrayCtor::construct(Managed *, ExecutionContext *ctx, Value *argv, int ar
len = argc;
a->arrayReserve(len);
for (unsigned int i = 0; i < len; ++i)
- fillDescriptor(a->arrayData + i, argv[i]);
+ a->arrayData[i].value = argv[i];
a->arrayDataLen = len;
}
a->setArrayLengthUnchecked(len);
@@ -270,7 +270,9 @@ Value ArrayPrototype::method_push(SimpleCallContext *ctx)
if (!instance->sparseArray) {
if (len >= instance->arrayAlloc)
instance->arrayReserve(len + 1);
- fillDescriptor(instance->arrayData + len, v);
+ instance->arrayData[len].value = v;
+ if (instance->arrayAttributes)
+ instance->arrayAttributes[len] = Attr_Data;
instance->arrayDataLen = len + 1;
} else {
uint i = instance->allocArrayValue(v);
@@ -328,19 +330,12 @@ Value ArrayPrototype::method_shift(SimpleCallContext *ctx)
return Value::undefinedValue();
}
- PropertyDescriptor *front = 0;
- if (!instance->sparseArray) {
- if (instance->arrayDataLen)
- front = instance->arrayData;
- } else {
- SparseArrayNode *n = instance->sparseArray->findNode(0);
- if (n)
- front = instance->arrayDecriptor(n->value);
- }
- if (front && front->attrs.type() == PropertyAttributes::Generic)
- front = 0;
+ Property *front = 0;
+ uint pidx = instance->propertyIndexFromArrayIndex(0);
+ if (pidx < UINT_MAX && (!instance->arrayAttributes || !instance->arrayAttributes[0].isGeneric()))
+ front = instance->arrayData + pidx;
- Value result = instance->getValueChecked(ctx, front);
+ Value result = front ? instance->getValue(ctx, front, instance->arrayAttributes ? instance->arrayAttributes[pidx] : Attr_Data) : Value::undefinedValue();
bool protoHasArray = false;
Object *p = instance;
@@ -355,6 +350,8 @@ Value ArrayPrototype::method_shift(SimpleCallContext *ctx)
++instance->arrayData;
--instance->arrayDataLen;
--instance->arrayAlloc;
+ if (instance->arrayAttributes)
+ ++instance->arrayAttributes;
}
} else {
uint idx = instance->sparseArray->pop_front();
@@ -445,9 +442,8 @@ Value ArrayPrototype::method_splice(SimpleCallContext *ctx)
uint deleteCount = (uint)qMin(qMax(ctx->argument(1).toInteger(ctx), 0.), (double)(len - start));
newArray->arrayReserve(deleteCount);
- PropertyDescriptor *pd = newArray->arrayData;
+ Property *pd = newArray->arrayData;
for (uint i = 0; i < deleteCount; ++i) {
- pd->attrs = Attr_Data;
pd->value = instance->getIndexed(ctx, start + i);
++pd;
}
@@ -511,7 +507,11 @@ Value ArrayPrototype::method_unshift(SimpleCallContext *ctx)
--instance->arrayOffset;
--instance->arrayData;
++instance->arrayDataLen;
- fillDescriptor(instance->arrayData, v);
+ if (instance->arrayAttributes) {
+ --instance->arrayAttributes;
+ *instance->arrayAttributes = Attr_Data;
+ }
+ instance->arrayData->value = v;
} else {
uint idx = instance->allocArrayValue(v);
instance->sparseArray->push_front(idx);
diff --git a/src/v4/qv4context.cpp b/src/v4/qv4context.cpp
index 97038090b2..24a8563c14 100644
--- a/src/v4/qv4context.cpp
+++ b/src/v4/qv4context.cpp
@@ -98,13 +98,10 @@ void ExecutionContext::createMutableBinding(String *name, bool deletable)
if (activation->__hasProperty__(this, name))
return;
- PropertyDescriptor desc;
- desc.value = Value::undefinedValue();
- desc.attrs.setType(PropertyAttributes::Data);
- desc.attrs.setConfigurable(deletable);
- desc.attrs.setWritable(true);
- desc.attrs.setEnumerable(true);
- activation->__defineOwnProperty__(this, name, &desc);
+ Property desc = Property::fromValue(Value::undefinedValue());
+ PropertyAttributes attrs(Attr_Data);
+ attrs.setConfigurable(deletable);
+ activation->__defineOwnProperty__(this, name, desc, attrs);
}
String * const *ExecutionContext::formals() const
@@ -205,10 +202,8 @@ void CallContext::initCallContext(ExecutionEngine *engine)
args->prototype = engine->objectPrototype;
Value arguments = Value::fromObject(args);
activation = engine->newObject();
- PropertyDescriptor desc;
- desc.value = Value::fromObject(args);
- desc.attrs = PropertyAttributes(Attr_NotConfigurable);
- activation->__defineOwnProperty__(this, engine->id_arguments, &desc);
+ Property desc = Property::fromValue(Value::fromObject(args));
+ activation->__defineOwnProperty__(this, engine->id_arguments, desc, Attr_NotConfigurable);
}
}
diff --git a/src/v4/qv4engine.cpp b/src/v4/qv4engine.cpp
index 54ddf4325a..7d5c79f333 100644
--- a/src/v4/qv4engine.cpp
+++ b/src/v4/qv4engine.cpp
@@ -109,7 +109,7 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
id_eval = newIdentifier(QStringLiteral("eval"));
emptyClass = new InternalClass(this);
- arrayClass = emptyClass->addMember(id_length, Attr_ReadOnly);
+ arrayClass = emptyClass->addMember(id_length, Attr_NotConfigurable|Attr_NotEnumerable);
initRootContext();
objectPrototype = new (memoryManager) ObjectPrototype(this);
@@ -482,9 +482,7 @@ void ExecutionEngine::requireArgumentsAccessors(int n)
get->prototype = functionPrototype;
FunctionObject *set = new (memoryManager) ArgumentsSetterFunction(rootContext, i);
set->prototype = functionPrototype;
- PropertyDescriptor pd = PropertyDescriptor::fromAccessor(get, set);
- pd.attrs.setConfigurable(true);
- pd.attrs.setEnumerable(true);
+ Property pd = Property::fromAccessor(get, set);
argumentsAccessors[i] = pd;
}
}
@@ -499,9 +497,9 @@ void ExecutionEngine::markObjects()
globalCode->mark();
for (int i = 0; i < argumentsAccessors.size(); ++i) {
- const PropertyDescriptor &pd = argumentsAccessors.at(i);
- pd.get->mark();
- pd.set->mark();
+ const Property &pd = argumentsAccessors.at(i);
+ pd.getter()->mark();
+ pd.setter()->mark();
}
ExecutionContext *c = current;
diff --git a/src/v4/qv4engine.h b/src/v4/qv4engine.h
index 6170c082ad..9cf36d408d 100644
--- a/src/v4/qv4engine.h
+++ b/src/v4/qv4engine.h
@@ -46,6 +46,7 @@
#include "qv4object.h"
#include "qv4util.h"
#include "qv4context.h"
+#include "qv4propertydescriptor.h"
#include <setjmp.h>
#include <wtf/BumpPointerAllocator.h>
@@ -159,7 +160,7 @@ struct Q_V4_EXPORT ExecutionEngine
EvalFunction *evalFunction;
- QVector<PropertyDescriptor> argumentsAccessors;
+ QVector<Property> argumentsAccessors;
String *id_undefined;
String *id_null;
diff --git a/src/v4/qv4functionobject.cpp b/src/v4/qv4functionobject.cpp
index 8393ec9de4..cff0b59f68 100644
--- a/src/v4/qv4functionobject.cpp
+++ b/src/v4/qv4functionobject.cpp
@@ -341,16 +341,14 @@ ScriptFunction::ScriptFunction(ExecutionContext *scope, Function *function)
Object *proto = scope->engine->newObject();
proto->defineDefaultProperty(scope->engine->id_constructor, Value::fromObject(this));
- PropertyDescriptor *pd = insertMember(scope->engine->id_prototype, Attr_NotEnumerable|Attr_NotConfigurable);
- pd->attrs = Attr_Data|Attr_NotEnumerable|Attr_NotConfigurable;
+ Property *pd = insertMember(scope->engine->id_prototype, Attr_NotEnumerable|Attr_NotConfigurable);
pd->value = Value::fromObject(proto);
if (scope->strictMode) {
FunctionObject *thrower = scope->engine->newBuiltinFunction(scope, 0, throwTypeError);
- PropertyDescriptor pd = PropertyDescriptor::fromAccessor(thrower, thrower);
- pd.attrs = Attr_Accessor|Attr_NotEnumerable|Attr_NotConfigurable;
- __defineOwnProperty__(scope, QStringLiteral("caller"), &pd);
- __defineOwnProperty__(scope, QStringLiteral("arguments"), &pd);
+ Property pd = Property::fromAccessor(thrower, thrower);
+ __defineOwnProperty__(scope, QStringLiteral("caller"), pd, Attr_Accessor|Attr_NotEnumerable|Attr_NotConfigurable);
+ __defineOwnProperty__(scope, QStringLiteral("arguments"), pd, Attr_Accessor|Attr_NotEnumerable|Attr_NotConfigurable);
}
}
@@ -475,8 +473,7 @@ BoundFunction::BoundFunction(ExecutionContext *scope, FunctionObject *target, Va
defineReadonlyProperty(scope->engine->id_length, Value::fromInt32(len));
FunctionObject *thrower = scope->engine->newBuiltinFunction(scope, 0, throwTypeError);
- PropertyDescriptor pd = PropertyDescriptor::fromAccessor(thrower, thrower);
- pd.attrs = Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable;
+ Property pd = Property::fromAccessor(thrower, thrower);
*insertMember(scope->engine->id_arguments, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable) = pd;
*insertMember(scope->engine->id_caller, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable) = pd;
}
diff --git a/src/v4/qv4functionobject.h b/src/v4/qv4functionobject.h
index c20eb69ee8..1be3dd5e6f 100644
--- a/src/v4/qv4functionobject.h
+++ b/src/v4/qv4functionobject.h
@@ -109,15 +109,17 @@ struct Lookup {
uint index;
String *name;
- PropertyDescriptor *lookup(Object *obj) {
+ Property *lookup(Object *obj, PropertyAttributes *attrs) {
int i = 0;
while (i < level && obj && obj->internalClass == classList[i]) {
obj = obj->prototype;
++i;
}
- if (index != UINT_MAX && obj->internalClass == classList[i])
+ if (index != UINT_MAX && obj->internalClass == classList[i]) {
+ *attrs = obj->internalClass->propertyData.at(index);
return obj->memberData + index;
+ }
while (i < Size && obj) {
classList[i] = obj->internalClass;
@@ -125,6 +127,7 @@ struct Lookup {
index = obj->internalClass->find(name);
if (index != UINT_MAX) {
level = i;
+ *attrs = obj->internalClass->propertyData.at(index);
return obj->memberData + index;
}
@@ -135,22 +138,27 @@ struct Lookup {
while (obj) {
index = obj->internalClass->find(name);
- if (index != UINT_MAX)
+ if (index != UINT_MAX) {
+ *attrs = obj->internalClass->propertyData.at(index);
return obj->memberData + index;
+ }
obj = obj->prototype;
}
return 0;
}
- PropertyDescriptor *setterLookup(Object *o) {
- if (o->internalClass == classList[0])
+ Property *setterLookup(Object *o, bool *writable) {
+ if (o->internalClass == classList[0]) {
+ *writable = o->internalClass->propertyData[index].isWritable();
return o->memberData + index;
+ }
uint idx = o->internalClass->find(name);
if (idx != UINT_MAX) {
classList[0] = o->internalClass;
index = idx;
+ *writable = o->internalClass->propertyData[index].isWritable();
return o->memberData + index;
}
return 0;
diff --git a/src/v4/qv4global.h b/src/v4/qv4global.h
index 928664de0a..5f3f1b6d17 100644
--- a/src/v4/qv4global.h
+++ b/src/v4/qv4global.h
@@ -101,18 +101,22 @@ struct PropertyAttributes
PropertyAttributes() : m_all(0) {}
PropertyAttributes(PropertyFlag f) : m_all(0) {
- setType(f & Attr_Accessor ? Accessor : Data);
- if (!(f & Attr_Accessor))
- setWritable(!(f & Attr_NotWritable));
- setEnumerable(!(f & Attr_NotEnumerable));
- setConfigurable(!(f & Attr_NotConfigurable));
+ if (f != Attr_Invalid) {
+ setType(f & Attr_Accessor ? Accessor : Data);
+ if (!(f & Attr_Accessor))
+ setWritable(!(f & Attr_NotWritable));
+ setEnumerable(!(f & Attr_NotEnumerable));
+ setConfigurable(!(f & Attr_NotConfigurable));
+ }
}
PropertyAttributes(PropertyFlags f) : m_all(0) {
- setType(f & Attr_Accessor ? Accessor : Data);
- if (!(f & Attr_Accessor))
- setWritable(!(f & Attr_NotWritable));
- setEnumerable(!(f & Attr_NotEnumerable));
- setConfigurable(!(f & Attr_NotConfigurable));
+ if (f != Attr_Invalid) {
+ setType(f & Attr_Accessor ? Accessor : Data);
+ if (!(f & Attr_Accessor))
+ setWritable(!(f & Attr_NotWritable));
+ setEnumerable(!(f & Attr_NotEnumerable));
+ setConfigurable(!(f & Attr_NotConfigurable));
+ }
}
PropertyAttributes(const PropertyAttributes &other) : m_all(other.m_all) {}
PropertyAttributes & operator=(const PropertyAttributes &other) { m_all = other.m_all; return *this; }
@@ -133,12 +137,9 @@ struct PropertyAttributes
void setConfigurable(bool b) { m_configurable = b; configurable_set = true; }
void setEnumerable(bool b) { m_enumerable = b; enumerable_set = true; }
- void resolveType() { type_set = true; }
- void resolveWritable() { writable_set = true; }
- void resolveConfigurable() { configurable_set = true; }
- void resolveEnumerable() { enumerable_set = true; }
+ void resolve() { m_mask = 0xf; if (m_type == Accessor) { m_writable = false; writable_set = false; } }
- bool isWritable() const { return m_writable; }
+ bool isWritable() const { return m_type != Data || m_writable; }
bool isEnumerable() const { return m_enumerable; }
bool isConfigurable() const { return m_configurable; }
@@ -151,6 +152,13 @@ struct PropertyAttributes
bool isEmpty() const { return !m_all; }
uint flags() const { return m_flags; }
+
+ bool operator==(PropertyAttributes other) {
+ return m_all == other.m_all;
+ }
+ bool operator!=(PropertyAttributes other) {
+ return m_all != other.m_all;
+ }
};
}
diff --git a/src/v4/qv4internalclass.cpp b/src/v4/qv4internalclass.cpp
index 00e891b205..4d9bb93d0d 100644
--- a/src/v4/qv4internalclass.cpp
+++ b/src/v4/qv4internalclass.cpp
@@ -54,14 +54,45 @@ InternalClass::InternalClass(const QQmlJS::VM::InternalClass &other)
, nameMap(other.nameMap)
, propertyData(other.propertyData)
, transitions()
+ , m_sealed(0)
+ , m_frozen(0)
, size(other.size)
{
}
+// ### Should we build this up from the empty class to avoid duplication?
+InternalClass *InternalClass::changeMember(String *string, PropertyAttributes data, uint *index)
+{
+// qDebug() << "InternalClass::changeMember()" << string->toQString() << hex << (uint)data.m_all;
+ data.resolve();
+ uint idx = find(string);
+ if (index)
+ *index = idx;
+
+ assert(idx != UINT_MAX);
+
+ if (data == propertyData[idx])
+ return this;
+
+ uint tid = string->identifier | (data.flags() << 27);
+
+ QHash<int, InternalClass *>::const_iterator tit = transitions.constFind(tid);
+ if (tit != transitions.constEnd())
+ return tit.value();
+
+ // create a new class and add it to the tree
+ InternalClass *newClass = new InternalClass(*this);
+ newClass->propertyData[idx] = data;
+ return newClass;
+
+}
+
InternalClass *InternalClass::addMember(String *string, PropertyAttributes data, uint *index)
{
+// qDebug() << "InternalClass::addMember()" << string->toQString() << size << hex << (uint)data.m_all << data.type();
+ data.resolve();
engine->identifierCache->toIdentifier(string);
- uint id = string->identifier | (data.flags() << 24);
+ uint id = string->identifier | (data.flags() << 27);
assert(propertyTable.constFind(id) == propertyTable.constEnd());
@@ -69,18 +100,17 @@ InternalClass *InternalClass::addMember(String *string, PropertyAttributes data,
if (index)
*index = size;
- if (tit != transitions.constEnd()) {
+ if (tit != transitions.constEnd())
return tit.value();
- } else {
- // create a new class and add it to the tree
- InternalClass *newClass = new InternalClass(*this);
- newClass->propertyTable.insert(string->identifier, size);
- newClass->nameMap.append(string);
- newClass->propertyData.append(data);
- ++newClass->size;
- transitions.insert(id, newClass);
- return newClass;
- }
+
+ // create a new class and add it to the tree
+ InternalClass *newClass = new InternalClass(*this);
+ newClass->propertyTable.insert(string->identifier, size);
+ newClass->nameMap.append(string);
+ newClass->propertyData.append(data);
+ ++newClass->size;
+ transitions.insert(id, newClass);
+ return newClass;
}
void InternalClass::removeMember(Object *object, uint id)
@@ -120,6 +150,39 @@ uint InternalClass::find(String *string)
return UINT_MAX;
}
+InternalClass *InternalClass::sealed()
+{
+ if (m_sealed)
+ return m_sealed;
+
+ m_sealed = engine->emptyClass;
+ for (int i = 0; i < nameMap.size(); ++i) {
+ PropertyAttributes attrs = propertyData.at(i);
+ attrs.setConfigurable(false);
+ m_sealed = m_sealed->addMember(nameMap.at(i), attrs);
+ }
+
+ m_sealed->m_sealed = m_sealed;
+ return m_sealed;
+}
+
+InternalClass *InternalClass::frozen()
+{
+ if (m_frozen)
+ return m_frozen;
+
+ m_frozen = engine->emptyClass;
+ for (int i = 0; i < nameMap.size(); ++i) {
+ PropertyAttributes attrs = propertyData.at(i);
+ attrs.setWritable(false);
+ attrs.setConfigurable(false);
+ m_frozen = m_frozen->addMember(nameMap.at(i), attrs);
+ }
+
+ m_frozen->m_frozen = m_frozen;
+ return m_frozen;
+}
+
}
}
diff --git a/src/v4/qv4internalclass.h b/src/v4/qv4internalclass.h
index 92bf19a741..cc3b03190b 100644
--- a/src/v4/qv4internalclass.h
+++ b/src/v4/qv4internalclass.h
@@ -62,14 +62,22 @@ struct InternalClass {
QVector<PropertyAttributes> propertyData;
QHash<int, InternalClass *> transitions; // id to next class, positive means add, negative delete
+
+ InternalClass *m_sealed;
+ InternalClass *m_frozen;
+
uint size;
- InternalClass(ExecutionEngine *engine) : engine(engine), size(0) {}
+ InternalClass(ExecutionEngine *engine) : engine(engine), m_sealed(0), m_frozen(0), size(0) {}
InternalClass *addMember(String *string, PropertyAttributes data, uint *index = 0);
+ InternalClass *changeMember(String *string, PropertyAttributes data, uint *index = 0);
void removeMember(Object *object, uint id);
uint find(String *s);
+ InternalClass *sealed();
+ InternalClass *frozen();
+
private:
InternalClass(const InternalClass &other);
};
diff --git a/src/v4/qv4isel_util_p.h b/src/v4/qv4isel_util_p.h
index 0960e17f51..e10a9658f2 100644
--- a/src/v4/qv4isel_util_p.h
+++ b/src/v4/qv4isel_util_p.h
@@ -47,19 +47,11 @@
namespace QQmlJS {
-inline VM::Value nonExistantValue()
-{
- VM::Value v;
- v.tag = VM::Value::Undefined_Type;
- v.uint_32 = UINT_MAX;
- return v;
-}
-
inline VM::Value convertToValue(V4IR::Const *c)
{
switch (c->type) {
case V4IR::MissingType:
- return nonExistantValue();
+ return VM::Value::deletedValue();
case V4IR::NullType:
return VM::Value::nullValue();
case V4IR::UndefinedType:
diff --git a/src/v4/qv4jsir.cpp b/src/v4/qv4jsir.cpp
index 88f566861d..ddf6509f27 100644
--- a/src/v4/qv4jsir.cpp
+++ b/src/v4/qv4jsir.cpp
@@ -278,6 +278,9 @@ void Const::dump(QTextStream &out)
case QQmlJS::V4IR::BoolType:
out << (value ? "true" : "false");
break;
+ case QQmlJS::V4IR::MissingType:
+ out << "missing";
+ break;
default:
out << QString::number(value, 'g', 16);
break;
diff --git a/src/v4/qv4jsonobject.cpp b/src/v4/qv4jsonobject.cpp
index d3a71acff9..22cd8ea8d5 100644
--- a/src/v4/qv4jsonobject.cpp
+++ b/src/v4/qv4jsonobject.cpp
@@ -281,8 +281,7 @@ bool Parser::parseMember(Object *o)
if (!parseValue(&val))
return false;
- PropertyDescriptor *p = o->insertMember(context->engine->newIdentifier(key), Attr_Data);
- p->attrs = Attr_Data;
+ Property *p = o->insertMember(context->engine->newIdentifier(key), Attr_Data);
p->value = val;
END;
@@ -782,10 +781,11 @@ QString Stringify::JO(Object *o)
while (1) {
String *name;
uint index;
- PropertyDescriptor *pd = it.next(&name, &index);
+ PropertyAttributes attrs;
+ Property *pd = it.next(&name, &index, &attrs);
if (!pd)
break;
- Value v = o->getValueChecked(ctx, pd);
+ Value v = o->getValueChecked(ctx, pd, attrs);
QString key;
if (name)
key = name->toQString();
diff --git a/src/v4/qv4object.cpp b/src/v4/qv4object.cpp
index 105af27517..45ce45e595 100644
--- a/src/v4/qv4object.cpp
+++ b/src/v4/qv4object.cpp
@@ -70,7 +70,7 @@ Object::Object(ExecutionEngine *engine)
: prototype(0)
, internalClass(engine->emptyClass)
, memberDataAlloc(0), memberData(0)
- , arrayOffset(0), arrayDataLen(0), arrayAlloc(0), arrayData(0), sparseArray(0)
+ , arrayOffset(0), arrayDataLen(0), arrayAlloc(0), arrayAttributes(0), arrayData(0), sparseArray(0)
, externalResource(0)
{
vtbl = &static_vtbl;
@@ -81,7 +81,7 @@ Object::Object(ExecutionContext *context)
: prototype(0)
, internalClass(context->engine->emptyClass)
, memberDataAlloc(0), memberData(0)
- , arrayOffset(0), arrayDataLen(0), arrayAlloc(0), arrayData(0), sparseArray(0)
+ , arrayOffset(0), arrayDataLen(0), arrayAlloc(0), arrayAttributes(0), arrayData(0), sparseArray(0)
, externalResource(0)
{
vtbl = &static_vtbl;
@@ -93,6 +93,8 @@ Object::~Object()
delete externalResource;
delete [] memberData;
delete [] (arrayData - (sparseArray ? 0 : arrayOffset));
+ if (arrayAttributes)
+ delete [] (arrayAttributes - (sparseArray ? 0 : arrayOffset));
delete sparseArray;
_data = 0;
}
@@ -107,54 +109,30 @@ void Object::put(ExecutionContext *ctx, const QString &name, const Value &value)
put(ctx, ctx->engine->newString(name), value);
}
-Value Object::getValue(const Value &thisObject, ExecutionContext *ctx, const PropertyDescriptor *p)
+Value Object::getValue(const Value &thisObject, ExecutionContext *ctx, const Property *p, PropertyAttributes attrs)
{
- assert(p->attrs.type() != PropertyAttributes::Generic);
- if (p->attrs.isData())
+ if (!attrs.isAccessor())
return p->value;
- if (!p->get)
+ FunctionObject *getter = p->getter();
+ if (!getter)
return Value::undefinedValue();
- return p->get->call(ctx, thisObject, 0, 0);
+ return getter->call(ctx, thisObject, 0, 0);
}
-void Object::putValue(ExecutionContext *ctx, PropertyDescriptor *pd, const Value &value)
+void Object::putValue(ExecutionContext *ctx, Property *pd, PropertyAttributes attrs, const Value &value)
{
- if (pd->attrs.isAccessor()) {
- if (pd->set) {
- Value args[1];
- args[0] = value;
- pd->set->call(ctx, Value::fromObject(this), args, 1);
- return;
- }
- goto reject;
- }
-
- if (!pd->attrs.isWritable())
+ if (attrs.isAccessor()) {
+ if (pd->set) {
+ Value args[1];
+ args[0] = value;
+ pd->set->call(ctx, Value::fromObject(this), args, 1);
+ return;
+ }
goto reject;
-
- pd->value = value;
- return;
-
- reject:
- if (ctx->strictMode)
- ctx->throwTypeError();
-
-}
-
-void Object::putValue(ExecutionContext *ctx, PropertyDescriptor *pd, const Value &thisObject, const Value &value)
-{
- if (pd->attrs.isAccessor()) {
- if (pd->set) {
- Value args[1];
- args[0] = value;
- pd->set->call(ctx, thisObject, args, 1);
- return;
- }
- goto reject;
}
- if (!pd->attrs.isWritable())
+ if (!attrs.isWritable())
goto reject;
pd->value = value;
@@ -192,8 +170,7 @@ void Object::inplaceBinOp(ExecutionContext *ctx, BinOp op, const Value &index, c
void Object::defineDefaultProperty(String *name, Value value)
{
- PropertyDescriptor *pd = insertMember(name, Attr_Data|Attr_NotEnumerable);
- pd->attrs = Attr_Data|Attr_NotEnumerable;
+ Property *pd = insertMember(name, Attr_Data|Attr_NotEnumerable);
pd->value = value;
}
@@ -218,8 +195,7 @@ void Object::defineReadonlyProperty(ExecutionEngine *engine, const QString &name
void Object::defineReadonlyProperty(String *name, Value value)
{
- PropertyDescriptor *pd = insertMember(name, Attr_ReadOnly);
- pd->attrs = Attr_ReadOnly;
+ Property *pd = insertMember(name, Attr_ReadOnly);
pd->value = value;
}
@@ -230,29 +206,29 @@ void Object::markObjects(Managed *that)
o->prototype->mark();
for (int i = 0; i < o->internalClass->size; ++i) {
- const PropertyDescriptor &pd = o->memberData[i];
- if (pd.attrs.isData()) {
+ const Property &pd = o->memberData[i];
+ if (o->internalClass->propertyData[i].isData()) {
if (Managed *m = pd.value.asManaged())
m->mark();
- } else if (pd.attrs.isAccessor()) {
- if (pd.get)
- pd.get->mark();
- if (pd.set)
- pd.set->mark();
+ } else {
+ if (pd.getter())
+ pd.getter()->mark();
+ if (pd.setter())
+ pd.setter()->mark();
}
}
o->markArrayObjects();
}
-PropertyDescriptor *Object::insertMember(String *s, PropertyAttributes attributes)
+Property *Object::insertMember(String *s, PropertyAttributes attributes)
{
uint idx;
internalClass = internalClass->addMember(s, attributes, &idx);
if (idx >= memberDataAlloc) {
memberDataAlloc = qMax((uint)8, 2*memberDataAlloc);
- PropertyDescriptor *newMemberData = new PropertyDescriptor[memberDataAlloc];
- memcpy(newMemberData, memberData, sizeof(PropertyDescriptor)*idx);
+ Property *newMemberData = new Property[memberDataAlloc];
+ memcpy(newMemberData, memberData, sizeof(Property)*idx);
delete [] memberData;
memberData = newMemberData;
}
@@ -260,32 +236,52 @@ PropertyDescriptor *Object::insertMember(String *s, PropertyAttributes attribute
}
// Section 8.12.1
-PropertyDescriptor *Object::__getOwnProperty__(ExecutionContext *ctx, String *name)
+Property *Object::__getOwnProperty__(ExecutionContext *ctx, String *name, PropertyAttributes *attrs)
{
uint idx = name->asArrayIndex();
if (idx != UINT_MAX)
- return __getOwnProperty__(ctx, idx);
+ return __getOwnProperty__(ctx, idx, attrs);
uint member = internalClass->find(name);
- if (member < UINT_MAX)
+ if (member < UINT_MAX) {
+ if (attrs)
+ *attrs = internalClass->propertyData[member];
return memberData + member;
+ }
+ if (attrs)
+ *attrs = Attr_Invalid;
return 0;
}
-PropertyDescriptor *Object::__getOwnProperty__(ExecutionContext *ctx, uint index)
+Property *Object::__getOwnProperty__(ExecutionContext *ctx, uint index, PropertyAttributes *attrs)
{
- PropertyDescriptor *p = arrayAt(index);
- if (p && p->attrs.type() != PropertyAttributes::Generic)
- return p;
- if (isStringObject())
+ uint pidx = propertyIndexFromArrayIndex(index);
+ if (pidx < UINT_MAX) {
+ Property *p = arrayData + pidx;
+ if (!arrayAttributes || arrayAttributes[pidx].isData()) {
+ if (attrs)
+ *attrs = arrayAttributes ? arrayAttributes[pidx] : PropertyAttributes(Attr_Data);
+ return p;
+ } else if (arrayAttributes[pidx].isAccessor()) {
+ if (attrs)
+ *attrs = arrayAttributes ? arrayAttributes[pidx] : PropertyAttributes(Attr_Accessor);
+ return p;
+ }
+ }
+ if (isStringObject()) {
+ if (attrs)
+ *attrs = Attr_NotConfigurable|Attr_NotWritable;
return static_cast<StringObject *>(this)->getIndex(ctx, index);
+ }
+ if (attrs)
+ *attrs = Attr_Invalid;
return 0;
}
// Section 8.12.2
-PropertyDescriptor *Object::__getPropertyDescriptor__(const ExecutionContext *ctx, String *name) const
+Property *Object::__getPropertyDescriptor__(const ExecutionContext *ctx, String *name, PropertyAttributes *attrs) const
{
uint idx = name->asArrayIndex();
if (idx != UINT_MAX)
@@ -295,28 +291,44 @@ PropertyDescriptor *Object::__getPropertyDescriptor__(const ExecutionContext *ct
const Object *o = this;
while (o) {
uint idx = o->internalClass->find(name);
- if (idx < UINT_MAX)
+ if (idx < UINT_MAX) {
+ if (attrs)
+ *attrs = o->internalClass->propertyData[idx];
return o->memberData + idx;
+ }
o = o->prototype;
}
+ if (attrs)
+ *attrs = Attr_Invalid;
return 0;
}
-PropertyDescriptor *Object::__getPropertyDescriptor__(const ExecutionContext *ctx, uint index) const
+Property *Object::__getPropertyDescriptor__(const ExecutionContext *ctx, uint index, PropertyAttributes *attrs) const
{
const Object *o = this;
while (o) {
- PropertyDescriptor *p = o->arrayAt(index);
- if (p && p->attrs.type() != PropertyAttributes::Generic)
- return p;
+ uint pidx = o->propertyIndexFromArrayIndex(index);
+ if (pidx < UINT_MAX) {
+ Property *p = o->arrayData + pidx;
+ if (!o->arrayAttributes || !o->arrayAttributes[pidx].isGeneric()) {
+ if (attrs)
+ *attrs = o->arrayAttributes ? o->arrayAttributes[pidx] : PropertyAttributes(Attr_Data);
+ return p;
+ }
+ }
if (o->isStringObject()) {
- p = static_cast<const StringObject *>(o)->getIndex(ctx, index);
- if (p)
+ Property *p = static_cast<const StringObject *>(o)->getIndex(ctx, index);
+ if (p) {
+ if (attrs)
+ *attrs = (Attr_NotWritable|Attr_NotConfigurable);
return p;
+ }
}
o = o->prototype;
}
+ if (attrs)
+ *attrs = Attr_Invalid;
return 0;
}
@@ -342,20 +354,39 @@ void Object::putIndexed(Managed *m, ExecutionContext *ctx, uint index, const Val
PropertyAttributes Object::query(Managed *m, ExecutionContext *ctx, String *name)
{
- Object *that = static_cast<Object *>(m);
- PropertyDescriptor *pd = that->__getPropertyDescriptor__(ctx, name);
- if (!pd || pd->attrs.type() == PropertyAttributes::Generic)
- return Attr_Invalid;
- return pd->attrs;
+ uint idx = name->asArrayIndex();
+ if (idx != UINT_MAX)
+ return queryIndexed(m, ctx, idx);
+
+ const Object *o = static_cast<Object *>(m);
+ while (o) {
+ uint idx = o->internalClass->find(name);
+ if (idx < UINT_MAX)
+ return o->internalClass->propertyData[idx];
+
+ o = o->prototype;
+ }
+ return Attr_Invalid;
}
PropertyAttributes Object::queryIndexed(Managed *m, ExecutionContext *ctx, uint index)
{
- Object *that = static_cast<Object *>(m);
- PropertyDescriptor *pd = that->__getPropertyDescriptor__(ctx, index);
- if (!pd || pd->attrs.type() == PropertyAttributes::Generic)
- return Attr_Invalid;
- return pd->attrs;
+ const Object *o = static_cast<Object *>(m);
+ while (o) {
+ uint pidx = o->propertyIndexFromArrayIndex(index);
+ if (pidx < UINT_MAX) {
+ if (o->arrayAttributes)
+ return o->arrayAttributes[pidx];
+ return Attr_Data;
+ }
+ if (o->isStringObject()) {
+ Property *p = static_cast<const StringObject *>(o)->getIndex(ctx, index);
+ if (p)
+ return Attr_Data;
+ }
+ o = o->prototype;
+ }
+ return Attr_Invalid;
}
bool Object::deleteProperty(Managed *m, ExecutionContext *ctx, String *name)
@@ -390,7 +421,7 @@ Value Object::internalGet(ExecutionContext *ctx, String *name, bool *hasProperty
if (idx < UINT_MAX) {
if (hasProperty)
*hasProperty = true;
- return getValue(ctx, o->memberData + idx);
+ return getValue(ctx, o->memberData + idx, o->internalClass->propertyData.at(idx));
}
o = o->prototype;
@@ -403,18 +434,23 @@ Value Object::internalGet(ExecutionContext *ctx, String *name, bool *hasProperty
Value Object::internalGetIndexed(ExecutionContext *ctx, uint index, bool *hasProperty)
{
- PropertyDescriptor *pd = 0;
+ Property *pd = 0;
+ PropertyAttributes attrs = Attr_Data;
Object *o = this;
while (o) {
- PropertyDescriptor *p = o->arrayAt(index);
- if (p && p->attrs.type() != PropertyAttributes::Generic) {
- pd = p;
- break;
+ uint pidx = o->propertyIndexFromArrayIndex(index);
+ if (pidx < UINT_MAX) {
+ if (!o->arrayAttributes || !o->arrayAttributes[pidx].isGeneric()) {
+ pd = o->arrayData + pidx;
+ if (o->arrayAttributes)
+ attrs = o->arrayAttributes[pidx];
+ break;
+ }
}
if (o->isStringObject()) {
- p = static_cast<StringObject *>(o)->getIndex(ctx, index);
- if (p) {
- pd = p;
+ pd = static_cast<StringObject *>(o)->getIndex(ctx, index);
+ if (pd) {
+ attrs = (Attr_NotWritable|Attr_NotConfigurable);
break;
}
}
@@ -424,7 +460,7 @@ Value Object::internalGetIndexed(ExecutionContext *ctx, uint index, bool *hasPro
if (pd) {
if (hasProperty)
*hasProperty = true;
- return getValue(ctx, pd);
+ return getValue(ctx, pd, attrs);
}
if (hasProperty)
@@ -443,15 +479,20 @@ void Object::internalPut(ExecutionContext *ctx, String *name, const Value &value
name->makeIdentifier(ctx);
uint member = internalClass->find(name);
- PropertyDescriptor *pd = (member < UINT_MAX) ? memberData + member : 0;
+ Property *pd = 0;
+ PropertyAttributes attrs;
+ if (member < UINT_MAX) {
+ pd = memberData + member;
+ attrs = internalClass->propertyData[member];
+ }
// clause 1
if (pd) {
- if (pd->attrs.isAccessor()) {
- if (pd->set)
- goto cont;
- goto reject;
- } else if (!pd->attrs.isWritable())
+ if (attrs.isAccessor()) {
+ if (pd->setter())
+ goto cont;
+ goto reject;
+ } else if (!attrs.isWritable())
goto reject;
else if (isArrayObject() && name->isEqualTo(ctx->engine->id_length)) {
bool ok;
@@ -469,15 +510,16 @@ void Object::internalPut(ExecutionContext *ctx, String *name, const Value &value
if (!extensible)
goto reject;
} else {
- if (PropertyDescriptor *p = prototype->__getPropertyDescriptor__(ctx, name)) {
- if (p->attrs.isAccessor()) {
- if (p->set)
+ PropertyAttributes attrs;
+ if (Property *p = prototype->__getPropertyDescriptor__(ctx, name, &attrs)) {
+ if (attrs.isAccessor()) {
+ if (p->setter())
goto cont;
goto reject;
}
if (!extensible)
goto reject;
- if (!p->attrs.isWritable())
+ if (!attrs.isWritable())
goto reject;
} else {
if (!extensible)
@@ -489,22 +531,22 @@ void Object::internalPut(ExecutionContext *ctx, String *name, const Value &value
// clause 4
+ // ### should be able to remove these two lines (see call 15 lines above)
if (!pd && prototype)
- pd = prototype->__getPropertyDescriptor__(ctx, name);
+ pd = prototype->__getPropertyDescriptor__(ctx, name, &attrs);
// Clause 5
- if (pd && pd->attrs.isAccessor()) {
- assert(pd->set != 0);
+ if (pd && attrs.isAccessor()) {
+ assert(pd->setter() != 0);
Value args[1];
args[0] = value;
- pd->set->call(ctx, Value::fromObject(this), args, 1);
+ pd->setter()->call(ctx, Value::fromObject(this), args, 1);
return;
}
{
- PropertyDescriptor *p = insertMember(name, Attr_Data);
- p->attrs = Attr_Data;
+ Property *p = insertMember(name, Attr_Data);
p->value = value;
return;
}
@@ -516,19 +558,33 @@ void Object::internalPut(ExecutionContext *ctx, String *name, const Value &value
void Object::internalPutIndexed(ExecutionContext *ctx, uint index, const Value &value)
{
- PropertyDescriptor *pd = arrayAt(index);
- if (pd && pd->attrs.type() == PropertyAttributes::Generic)
- pd = 0;
- if (!pd && isStringObject())
+ Property *pd = 0;
+ PropertyAttributes attrs;
+
+ uint pidx = propertyIndexFromArrayIndex(index);
+ if (pidx < UINT_MAX) {
+ if (arrayAttributes && arrayAttributes[pidx].isGeneric()) {
+ pidx = UINT_MAX;
+ } else {
+ pd = arrayData + pidx;
+ attrs = arrayAttributes ? arrayAttributes[pidx] : PropertyAttributes(Attr_Data);
+ }
+ }
+
+ if (!pd && isStringObject()) {
pd = static_cast<StringObject *>(this)->getIndex(ctx, index);
+ if (pd)
+ // not writable
+ goto reject;
+ }
// clause 1
if (pd) {
- if (pd->attrs.isAccessor()) {
- if (pd->set)
- goto cont;
- goto reject;
- } else if (!pd->attrs.isWritable())
+ if (attrs.isAccessor()) {
+ if (pd->setter())
+ goto cont;
+ goto reject;
+ } else if (!attrs.isWritable())
goto reject;
else
pd->value = value;
@@ -537,15 +593,16 @@ void Object::internalPutIndexed(ExecutionContext *ctx, uint index, const Value &
if (!extensible)
goto reject;
} else {
- if (PropertyDescriptor *p = prototype->__getPropertyDescriptor__(ctx, index)) {
- if (p->attrs.isAccessor()) {
- if (p->set)
+ PropertyAttributes attrs;
+ if (Property *p = prototype->__getPropertyDescriptor__(ctx, index, &attrs)) {
+ if (attrs.isAccessor()) {
+ if (p->setter())
goto cont;
goto reject;
}
if (!extensible)
goto reject;
- if (!p->attrs.isWritable())
+ if (!attrs.isWritable())
goto reject;
} else {
if (!extensible)
@@ -556,16 +613,17 @@ void Object::internalPutIndexed(ExecutionContext *ctx, uint index, const Value &
cont:
// clause 4
+ // ### remove and replace with 15 lines above...
if (!pd && prototype)
- pd = prototype->__getPropertyDescriptor__(ctx, index);
+ pd = prototype->__getPropertyDescriptor__(ctx, index, &attrs);
// Clause 5
- if (pd && pd->attrs.isAccessor()) {
- assert(pd->set != 0);
+ if (pd && attrs.isAccessor()) {
+ assert(pd->setter() != 0);
Value args[1];
args[0] = value;
- pd->set->call(ctx, Value::fromObject(this), args, 1);
+ pd->setter()->call(ctx, Value::fromObject(this), args, 1);
return;
}
@@ -588,10 +646,9 @@ bool Object::internalDeleteProperty(ExecutionContext *ctx, String *name)
uint memberIdx = internalClass->find(name);
if (memberIdx != UINT_MAX) {
- PropertyDescriptor &pd = memberData[memberIdx];
- if (pd.attrs.isConfigurable()) {
+ if (internalClass->propertyData[memberIdx].isConfigurable()) {
internalClass->removeMember(this, name->identifier);
- memmove(memberData + memberIdx, memberData + memberIdx + 1, (internalClass->size - memberIdx)*sizeof(PropertyDescriptor));
+ memmove(memberData + memberIdx, memberData + memberIdx + 1, (internalClass->size - memberIdx)*sizeof(Property));
return true;
}
if (ctx->strictMode)
@@ -604,25 +661,20 @@ bool Object::internalDeleteProperty(ExecutionContext *ctx, String *name)
bool Object::internalDeleteIndexedProperty(ExecutionContext *ctx, uint index)
{
- PropertyDescriptor *pd = 0;
- if (!sparseArray) {
- if (index >= arrayDataLen)
- return true;
- pd = arrayAt(index);
- } else {
- SparseArrayNode *n = sparseArray->findNode(index);
- if (n)
- pd = arrayDecriptor(n->value);
- }
- if (!pd || pd->attrs.type() == PropertyAttributes::Generic)
+ uint pidx = propertyIndexFromArrayIndex(index);
+ if (pidx == UINT_MAX)
+ return true;
+ if (arrayAttributes && arrayAttributes[pidx].isGeneric())
return true;
- if (pd->attrs.isConfigurable()) {
- pd->attrs.clear();
- pd->value = Value::undefinedValue();
+ if (!arrayAttributes || arrayAttributes[pidx].isConfigurable()) {
+ arrayData[pidx].value = Value::undefinedValue();
+ if (!arrayAttributes)
+ ensureArrayAttributes();
+ arrayAttributes[pidx].clear();
if (sparseArray) {
- pd->value.int_32 = arrayFreeList;
- arrayFreeList = pd - arrayData;
+ arrayData[pidx].value.int_32 = arrayFreeList;
+ arrayFreeList = pidx;
}
return true;
}
@@ -633,33 +685,35 @@ bool Object::internalDeleteIndexedProperty(ExecutionContext *ctx, uint index)
}
// Section 8.12.9
-bool Object::__defineOwnProperty__(ExecutionContext *ctx, String *name, const PropertyDescriptor *desc)
+bool Object::__defineOwnProperty__(ExecutionContext *ctx, String *name, const Property &p, PropertyAttributes attrs)
{
uint idx = name->asArrayIndex();
if (idx != UINT_MAX)
- return __defineOwnProperty__(ctx, idx, desc);
+ return __defineOwnProperty__(ctx, idx, p, attrs);
name->makeIdentifier(ctx);
- PropertyDescriptor *current;
+ Property *current;
+ PropertyAttributes *cattrs;
if (isArrayObject() && name->isEqualTo(ctx->engine->id_length)) {
- PropertyDescriptor *lp = memberData + ArrayObject::LengthPropertyIndex;
- assert(0 == internalClass->find(ctx->engine->id_length));
- if (desc->attrs.isEmpty() || desc->isSubset(desc->attrs, lp))
+ assert(ArrayObject::LengthPropertyIndex == internalClass->find(ctx->engine->id_length));
+ Property *lp = memberData + ArrayObject::LengthPropertyIndex;
+ cattrs = internalClass->propertyData.data() + ArrayObject::LengthPropertyIndex;
+ if (attrs.isEmpty() || p.isSubset(attrs, *lp, *cattrs))
return true;
- if (!lp->attrs.isWritable() || desc->attrs.type() == PropertyAttributes::Accessor || desc->attrs.isConfigurable() || desc->attrs.isEnumerable())
+ if (!cattrs->isWritable() || attrs.type() == PropertyAttributes::Accessor || attrs.isConfigurable() || attrs.isEnumerable())
goto reject;
bool succeeded = true;
- if (desc->attrs.type() == PropertyAttributes::Data) {
+ if (attrs.type() == PropertyAttributes::Data) {
bool ok;
- uint l = desc->value.asArrayLength(ctx, &ok);
+ uint l = p.value.asArrayLength(ctx, &ok);
if (!ok)
- ctx->throwRangeError(desc->value);
+ ctx->throwRangeError(p.value);
succeeded = setArrayLength(l);
}
- if (desc->attrs.hasWritable() && !desc->attrs.isWritable())
- lp->attrs.setWritable(false);
+ if (attrs.hasWritable() && !attrs.isWritable())
+ cattrs->setWritable(false);
if (!succeeded)
goto reject;
return true;
@@ -669,6 +723,7 @@ bool Object::__defineOwnProperty__(ExecutionContext *ctx, String *name, const Pr
{
uint member = internalClass->find(name);
current = (member < UINT_MAX) ? memberData + member : 0;
+ cattrs = internalClass->propertyData.data() + member;
}
if (!current) {
@@ -676,112 +731,128 @@ bool Object::__defineOwnProperty__(ExecutionContext *ctx, String *name, const Pr
if (!extensible)
goto reject;
// clause 4
- PropertyDescriptor *pd = insertMember(name, desc->attrs);
- *pd = *desc;
- pd->fullyPopulated(&pd->attrs);
+ Property *pd = insertMember(name, attrs);
+ *pd = p;
+ pd->fullyPopulated(&attrs);
return true;
}
- return __defineOwnProperty__(ctx, current, desc);
+ return __defineOwnProperty__(ctx, current, name, p, attrs);
reject:
if (ctx->strictMode)
ctx->throwTypeError();
return false;
}
-bool Object::__defineOwnProperty__(ExecutionContext *ctx, uint index, const PropertyDescriptor *desc)
+bool Object::__defineOwnProperty__(ExecutionContext *ctx, uint index, const Property &p, PropertyAttributes attrs)
{
- PropertyDescriptor *current;
+ Property *current = 0;
// 15.4.5.1, 4b
- if (isArrayObject() && index >= arrayLength() && !memberData[ArrayObject::LengthPropertyIndex].attrs.isWritable())
+ if (isArrayObject() && index >= arrayLength() && !internalClass->propertyData[ArrayObject::LengthPropertyIndex].isWritable())
goto reject;
if (isNonStrictArgumentsObject)
- return static_cast<ArgumentsObject *>(this)->defineOwnProperty(ctx, index, desc);
+ return static_cast<ArgumentsObject *>(this)->defineOwnProperty(ctx, index, p, attrs);
// Clause 1
- current = arrayAt(index);
- if (current && current->attrs.type() == PropertyAttributes::Generic)
- current = 0;
- if (!current && isStringObject())
- current = static_cast<StringObject *>(this)->getIndex(ctx, index);
+ {
+ uint pidx = propertyIndexFromArrayIndex(index);
+ if (pidx < UINT_MAX && (!arrayAttributes || !arrayAttributes[pidx].isGeneric()))
+ current = arrayData + pidx;
+ if (!current && isStringObject())
+ current = static_cast<StringObject *>(this)->getIndex(ctx, index);
+ }
if (!current) {
// clause 3
if (!extensible)
goto reject;
// clause 4
- PropertyDescriptor *pd = arrayInsert(index);
- *pd = *desc;
- pd->fullyPopulated(&pd->attrs);
+ Property *pd = arrayInsert(index, attrs);
+ *pd = p;
+ pd->fullyPopulated(&attrs);
return true;
}
- return __defineOwnProperty__(ctx, current, desc);
+ return __defineOwnProperty__(ctx, current, 0 /*member*/, p, attrs);
reject:
if (ctx->strictMode)
ctx->throwTypeError();
return false;
}
-bool Object::__defineOwnProperty__(ExecutionContext *ctx, PropertyDescriptor *current, const PropertyDescriptor *desc)
+bool Object::__defineOwnProperty__(ExecutionContext *ctx, Property *current, String *member, const Property &p, PropertyAttributes attrs)
{
// clause 5
- if (desc->attrs.isEmpty())
+ if (attrs.isEmpty())
return true;
+ PropertyAttributes cattrs = Attr_Data;
+ if (member)
+ cattrs = internalClass->propertyData[current - memberData];
+ else if (arrayAttributes)
+ cattrs = arrayAttributes[current - arrayData];
+
// clause 6
- if (desc->isSubset(desc->attrs, current))
+ if (p.isSubset(attrs, *current, cattrs))
return true;
// clause 7
- if (!current->attrs.isConfigurable()) {
- if (desc->attrs.isConfigurable())
+ if (!cattrs.isConfigurable()) {
+ if (attrs.isConfigurable())
goto reject;
- if (desc->attrs.hasEnumerable() && desc->attrs.isEnumerable() != current->attrs.isEnumerable())
+ if (attrs.hasEnumerable() && attrs.isEnumerable() != cattrs.isEnumerable())
goto reject;
}
// clause 8
- if (desc->attrs.isGeneric())
+ if (attrs.isGeneric())
goto accept;
// clause 9
- if (current->attrs.isData() != desc->attrs.isData()) {
+ if (cattrs.isData() != attrs.isData()) {
// 9a
- if (!current->attrs.isConfigurable())
+ if (!cattrs.isConfigurable())
goto reject;
- if (current->attrs.isData()) {
+ if (cattrs.isData()) {
// 9b
- current->attrs.setType(PropertyAttributes::Accessor);
- current->attrs.clearWritable();
- current->get = 0;
- current->set = 0;
+ cattrs.setType(PropertyAttributes::Accessor);
+ cattrs.clearWritable();
+ current->setGetter(0);
+ current->setSetter(0);
} else {
// 9c
- current->attrs.setType(PropertyAttributes::Data);
- current->attrs.setWritable(false);
+ cattrs.setType(PropertyAttributes::Data);
+ cattrs.setWritable(false);
current->value = Value::undefinedValue();
}
- } else if (current->attrs.isData() && desc->attrs.isData()) { // clause 10
- if (!current->attrs.isConfigurable() && !current->attrs.isWritable()) {
- if (desc->attrs.isWritable() || !current->value.sameValue(desc->value))
+ } else if (cattrs.isData() && attrs.isData()) { // clause 10
+ if (!cattrs.isConfigurable() && !cattrs.isWritable()) {
+ if (attrs.isWritable() || !current->value.sameValue(p.value))
goto reject;
}
} else { // clause 10
- assert(current->attrs.isAccessor() && desc->attrs.isAccessor());
- if (!current->attrs.isConfigurable()) {
- if (desc->get && !(current->get == desc->get || (!current->get && (quintptr)desc->get == 0x1)))
+ assert(cattrs.isAccessor() && attrs.isAccessor());
+ if (!cattrs.isConfigurable()) {
+ if (p.getter() && !(current->getter() == p.getter() || (!current->getter() && (quintptr)p.getter() == 0x1)))
goto reject;
- if (desc->set && !(current->set == desc->set || (!current->set && (quintptr)desc->set == 0x1)))
+ if (p.setter() && !(current->setter() == p.setter() || (!current->setter() && (quintptr)p.setter() == 0x1)))
goto reject;
}
}
accept:
- current->merge(current->attrs, *desc);
+ current->merge(cattrs, p, attrs);
+ if (member) {
+ internalClass = internalClass->changeMember(member, cattrs);
+ } else {
+ if (cattrs != Attr_Data)
+ ensureArrayAttributes();
+ if (arrayAttributes)
+ arrayAttributes[current - arrayData] = cattrs;
+ }
return true;
reject:
if (ctx->strictMode)
@@ -790,9 +861,9 @@ bool Object::__defineOwnProperty__(ExecutionContext *ctx, PropertyDescriptor *cu
}
-bool Object::__defineOwnProperty__(ExecutionContext *ctx, const QString &name, const PropertyDescriptor *desc)
+bool Object::__defineOwnProperty__(ExecutionContext *ctx, const QString &name, const Property &p, PropertyAttributes attrs)
{
- return __defineOwnProperty__(ctx, ctx->engine->newString(name), desc);
+ return __defineOwnProperty__(ctx, ctx->engine->newString(name), p, attrs);
}
@@ -800,7 +871,7 @@ void Object::copyArrayData(Object *other)
{
arrayReserve(other->arrayDataLen);
arrayDataLen = other->arrayDataLen;
- memcpy(arrayData, other->arrayData, arrayDataLen*sizeof(PropertyDescriptor));
+ memcpy(arrayData, other->arrayData, arrayDataLen*sizeof(Property));
arrayOffset = 0;
if (other->sparseArray) {
sparseArray = new SparseArray(*other->sparseArray);
@@ -819,7 +890,7 @@ Value Object::arrayIndexOf(Value v, uint fromIndex, uint endIndex, ExecutionCont
if (p->arrayDataLen)
protoHasArray = true;
- if (protoHasArray) {
+ if (protoHasArray || o->arrayAttributes) {
// lets be safe and slow
for (uint i = fromIndex; i < endIndex; ++i) {
bool exists;
@@ -830,19 +901,19 @@ Value Object::arrayIndexOf(Value v, uint fromIndex, uint endIndex, ExecutionCont
} else if (sparseArray) {
for (SparseArrayNode *n = sparseArray->lowerBound(fromIndex); n != sparseArray->end() && n->key() < endIndex; n = n->nextNode()) {
bool exists;
- Value value = o->getValueChecked(ctx, arrayDecriptor(n->value), &exists);
+ Value value = o->getValueChecked(ctx, arrayData + n->value, arrayAttributes ? arrayAttributes[n->value] : Attr_Data, &exists);
if (exists && __qmljs_strict_equal(value, v, ctx))
return Value::fromDouble(n->key());
}
} else {
if ((int) endIndex > arrayDataLen)
endIndex = arrayDataLen;
- PropertyDescriptor *pd = arrayData;
- PropertyDescriptor *end = pd + endIndex;
+ Property *pd = arrayData;
+ Property *end = pd + endIndex;
pd += fromIndex;
while (pd < end) {
bool exists;
- Value value = o->getValueChecked(ctx, pd, &exists);
+ Value value = o->getValueChecked(ctx, pd, arrayAttributes ? arrayAttributes[pd - arrayData] : Attr_Data, &exists);
if (exists && __qmljs_strict_equal(value, v, ctx))
return Value::fromDouble(pd - arrayData);
++pd;
@@ -856,14 +927,17 @@ void Object::arrayConcat(const ArrayObject *other)
int newLen = arrayDataLen + other->arrayLength();
if (other->sparseArray)
initSparse();
+ // ### copy attributes as well!
if (sparseArray) {
if (other->sparseArray) {
for (const SparseArrayNode *it = other->sparseArray->begin(); it != other->sparseArray->end(); it = it->nextNode())
- arraySet(arrayDataLen + it->key(), other->arrayDecriptor(it->value));
+ arraySet(arrayDataLen + it->key(), other->arrayData + it->value);
} else {
int oldSize = arrayDataLen;
arrayReserve(oldSize + other->arrayLength());
- memcpy(arrayData + oldSize, other->arrayData, other->arrayLength()*sizeof(PropertyDescriptor));
+ memcpy(arrayData + oldSize, other->arrayData, other->arrayLength()*sizeof(Property));
+ if (arrayAttributes)
+ std::fill(arrayAttributes + oldSize, arrayAttributes + oldSize + other->arrayLength(), PropertyAttributes(Attr_Data));
for (uint i = 0; i < other->arrayLength(); ++i) {
SparseArrayNode *n = sparseArray->insert(arrayDataLen + i);
n->value = oldSize + i;
@@ -873,13 +947,26 @@ void Object::arrayConcat(const ArrayObject *other)
int oldSize = arrayLength();
arrayReserve(oldSize + other->arrayDataLen);
if (oldSize > arrayDataLen) {
- PropertyDescriptor generic;
- generic.attrs.clear();
- generic.value = Value::undefinedValue();
- std::fill(arrayData + arrayDataLen, arrayData + oldSize, generic);
+ ensureArrayAttributes();
+ std::fill(arrayAttributes + arrayDataLen, arrayAttributes + oldSize, PropertyAttributes());
}
arrayDataLen = oldSize + other->arrayDataLen;
- memcpy(arrayData + oldSize, other->arrayData, other->arrayDataLen*sizeof(PropertyDescriptor));
+ if (other->arrayAttributes) {
+ for (int i = 0; i < arrayDataLen; ++i) {
+ bool exists;
+ arrayData[oldSize + i].value = const_cast<ArrayObject *>(other)->getIndexed(internalClass->engine->current, i, &exists);
+ if (arrayAttributes)
+ arrayAttributes[oldSize + i] = Attr_Data;
+ if (!exists) {
+ ensureArrayAttributes();
+ arrayAttributes[oldSize + i].clear();
+ }
+ }
+ } else {
+ memcpy(arrayData + oldSize, other->arrayData, other->arrayDataLen*sizeof(Property));
+ if (arrayAttributes)
+ std::fill(arrayAttributes + oldSize, arrayAttributes + oldSize + other->arrayDataLen, PropertyAttributes(Attr_Data));
+ }
}
setArrayLengthUnchecked(newLen);
}
@@ -892,14 +979,34 @@ void Object::arraySort(ExecutionContext *context, Object *thisObject, const Valu
if (sparseArray) {
context->throwUnimplemented("Object::sort unimplemented for sparse arrays");
return;
- delete sparseArray;
}
- ArrayElementLessThan lessThan(context, thisObject, comparefn);
if (len > arrayDataLen)
len = arrayDataLen;
- PropertyDescriptor *begin = arrayData;
+ // The spec says the sorting goes through a series of get,put and delete operations.
+ // this implies that the attributes don't get sorted around.
+ // behavior of accessor properties is implementation defined. We simply turn them all
+ // into data properties and then sort. This is in line with the sentence above.
+ if (arrayAttributes) {
+ for (uint i = 0; i < len; i++) {
+ if (arrayAttributes[i].isGeneric()) {
+ while (--len > i)
+ if (!arrayAttributes[len].isGeneric())
+ break;
+ arrayData[i].value = getValue(context, arrayData + len, arrayAttributes[len]);
+ arrayAttributes[i] = Attr_Data;
+ arrayAttributes[len].clear();
+ } else if (arrayAttributes[i].isAccessor()) {
+ arrayData[i].value = getValue(context, arrayData + i, arrayAttributes[i]);
+ arrayAttributes[i] = Attr_Data;
+ }
+ }
+ }
+
+ ArrayElementLessThan lessThan(context, thisObject, comparefn);
+
+ Property *begin = arrayData;
std::sort(begin, begin + len, lessThan);
}
@@ -909,7 +1016,7 @@ void Object::initSparse()
if (!sparseArray) {
sparseArray = new SparseArray;
for (int i = 0; i < arrayDataLen; ++i) {
- if (arrayData[i].attrs.type() != PropertyAttributes::Generic) {
+ if (!arrayAttributes || !arrayAttributes[i].isGeneric()) {
SparseArrayNode *n = sparseArray->insert(i);
n->value = i + arrayOffset;
}
@@ -924,14 +1031,11 @@ void Object::initSparse()
arrayAlloc += off;
int o = off;
for (int i = 0; i < o - 1; ++i) {
- arrayData[i].attrs.clear();
arrayData[i].value = Value::fromInt32(i + 1);
}
- arrayData[o - 1].attrs.clear();
arrayData[o - 1].value = Value::fromInt32(arrayDataLen + off);
}
for (int i = arrayDataLen + off; i < arrayAlloc; ++i) {
- arrayData[i].attrs.clear();
arrayData[i].value = Value::fromInt32(i + 1);
}
}
@@ -952,28 +1056,52 @@ void Object::arrayReserve(uint n)
off = arrayOffset;
}
arrayAlloc = qMax(n, 2*arrayAlloc);
- PropertyDescriptor *newArrayData = new PropertyDescriptor[arrayAlloc];
+ Property *newArrayData = new Property[arrayAlloc];
if (arrayData) {
- memcpy(newArrayData, arrayData, sizeof(PropertyDescriptor)*arrayDataLen);
+ memcpy(newArrayData, arrayData, sizeof(Property)*arrayDataLen);
delete [] (arrayData - off);
}
arrayData = newArrayData;
if (sparseArray) {
for (uint i = arrayFreeList; i < arrayAlloc; ++i) {
- arrayData[i].attrs.clear();
+ arrayData[i].value = Value::deletedValue();
arrayData[i].value = Value::fromInt32(i + 1);
}
} else {
arrayOffset = 0;
}
+
+ if (arrayAttributes) {
+ PropertyAttributes *newAttrs = new PropertyAttributes[arrayAlloc];
+ memcpy(newAttrs, arrayAttributes, sizeof(PropertyAttributes)*arrayDataLen);
+ delete [] (arrayAttributes - off);
+
+ arrayAttributes = newAttrs;
+ if (sparseArray) {
+ for (uint i = arrayFreeList; i < arrayAlloc; ++i)
+ arrayAttributes[i] = Attr_Invalid;
+ }
+ }
}
}
+void Object::ensureArrayAttributes()
+{
+ if (arrayAttributes)
+ return;
+
+ arrayAttributes = new PropertyAttributes[arrayAlloc];
+ for (uint i = 0; i < arrayDataLen; ++i)
+ arrayAttributes[i] = Attr_Data;
+ for (uint i = arrayDataLen; i < arrayAlloc; ++i)
+ arrayAttributes[i] = Attr_Invalid;
+}
+
bool Object::setArrayLength(uint newLen) {
assert(isArrayObject());
- const PropertyDescriptor *lengthProperty = memberData + ArrayObject::LengthPropertyIndex;
- if (lengthProperty && !lengthProperty->attrs.isWritable())
+ const Property *lengthProperty = memberData + ArrayObject::LengthPropertyIndex;
+ if (lengthProperty && !internalClass->propertyData[ArrayObject::LengthPropertyIndex].isWritable())
return false;
uint oldLen = arrayLength();
bool ok = true;
@@ -983,14 +1111,17 @@ bool Object::setArrayLength(uint newLen) {
if (begin != sparseArray->end()) {
SparseArrayNode *it = sparseArray->end()->previousNode();
while (1) {
- PropertyDescriptor &pd = arrayData[it->value];
- if (pd.attrs.type() != PropertyAttributes::Generic && !pd.attrs.isConfigurable()) {
- ok = false;
- newLen = it->key() + 1;
- break;
+ Property &pd = arrayData[it->value];
+ if (arrayAttributes) {
+ if (!arrayAttributes[it->value].isConfigurable()) {
+ ok = false;
+ newLen = it->key() + 1;
+ break;
+ } else {
+ arrayAttributes[it->value].clear();
+ }
}
- pd.attrs.clear();
- pd.value.tag = Value::_Undefined_Type;
+ pd.value.tag = Value::_Deleted_Type;
pd.value.int_32 = arrayFreeList;
arrayFreeList = it->value;
bool brk = (it == begin);
@@ -1002,13 +1133,18 @@ bool Object::setArrayLength(uint newLen) {
}
}
} else {
- PropertyDescriptor *it = arrayData + arrayDataLen;
- const PropertyDescriptor *begin = arrayData + newLen;
+ Property *it = arrayData + arrayDataLen;
+ const Property *begin = arrayData + newLen;
while (--it >= begin) {
- if (it->attrs.type() != PropertyAttributes::Generic && !it->attrs.isConfigurable()) {
- ok = false;
- newLen = it - arrayData + 1;
- break;
+ if (arrayAttributes) {
+ if (!arrayAttributes[it - arrayData].isEmpty() && !arrayAttributes[it - arrayData].isConfigurable()) {
+ ok = false;
+ newLen = it - arrayData + 1;
+ break;
+ } else {
+ arrayAttributes[it - arrayData].clear();
+ }
+ it->value = Value::deletedValue();
}
}
arrayDataLen = newLen;
@@ -1024,15 +1160,15 @@ bool Object::setArrayLength(uint newLen) {
void Object::markArrayObjects() const
{
for (uint i = 0; i < arrayDataLen; ++i) {
- const PropertyDescriptor &pd = arrayData[i];
- if (pd.attrs.isData()) {
+ const Property &pd = arrayData[i];
+ if (!arrayAttributes || arrayAttributes[i].isData()) {
if (Managed *m = pd.value.asManaged())
m->mark();
- } else if (pd.attrs.isAccessor()) {
- if (pd.get)
- pd.get->mark();
- if (pd.set)
- pd.set->mark();
+ } else if (arrayAttributes[i].isAccessor()) {
+ if (pd.getter())
+ pd.getter()->mark();
+ if (pd.setter())
+ pd.setter()->mark();
}
}
}
@@ -1042,10 +1178,8 @@ void ArrayObject::init(ExecutionContext *context)
type = Type_ArrayObject;
internalClass = context->engine->arrayClass;
- memberData = new PropertyDescriptor[4];
- PropertyDescriptor *pd = memberData + LengthPropertyIndex;
- pd->attrs = Attr_NotEnumerable|Attr_NotConfigurable;
- pd->value = Value::fromInt32(0);
+ memberData = new Property[4];
+ memberData[LengthPropertyIndex].value = Value::fromInt32(0);
}
diff --git a/src/v4/qv4object.h b/src/v4/qv4object.h
index 8c35a5a0cc..9919ce3ade 100644
--- a/src/v4/qv4object.h
+++ b/src/v4/qv4object.h
@@ -111,7 +111,7 @@ struct Q_V4_EXPORT Object: Managed {
Object *prototype;
InternalClass *internalClass;
uint memberDataAlloc;
- PropertyDescriptor *memberData;
+ Property *memberData;
union {
uint arrayFreeList;
@@ -119,7 +119,8 @@ struct Q_V4_EXPORT Object: Managed {
};
uint arrayDataLen;
uint arrayAlloc;
- PropertyDescriptor *arrayData;
+ PropertyAttributes *arrayAttributes;
+ Property *arrayData;
SparseArray *sparseArray;
ExternalResource *externalResource;
@@ -127,50 +128,46 @@ struct Q_V4_EXPORT Object: Managed {
Object(ExecutionContext *context);
~Object();
- PropertyDescriptor *__getOwnProperty__(ExecutionContext *ctx, String *name);
- PropertyDescriptor *__getOwnProperty__(ExecutionContext *ctx, uint index);
+ Property *__getOwnProperty__(ExecutionContext *ctx, String *name, PropertyAttributes *attrs = 0);
+ Property *__getOwnProperty__(ExecutionContext *ctx, uint index, PropertyAttributes *attrs = 0);
- PropertyDescriptor *__getPropertyDescriptor__(const ExecutionContext *ctx, String *name) const;
- PropertyDescriptor *__getPropertyDescriptor__(const ExecutionContext *ctx, uint index) const;
+ Property *__getPropertyDescriptor__(const ExecutionContext *ctx, String *name, PropertyAttributes *attrs = 0) const;
+ Property *__getPropertyDescriptor__(const ExecutionContext *ctx, uint index, PropertyAttributes *attrs = 0) const;
bool __hasProperty__(const ExecutionContext *ctx, String *name) const {
- PropertyDescriptor *pd = __getPropertyDescriptor__(ctx, name);
- return pd && pd->attrs.type() != PropertyAttributes::Generic;
+ return __getPropertyDescriptor__(ctx, name);
}
bool __hasProperty__(const ExecutionContext *ctx, uint index) const {
- PropertyDescriptor *pd = __getPropertyDescriptor__(ctx, index);
- return pd && pd->attrs.type() != PropertyAttributes::Generic;
+ return __getPropertyDescriptor__(ctx, index);
}
- bool __defineOwnProperty__(ExecutionContext *ctx, PropertyDescriptor *current, const PropertyDescriptor *desc);
- bool __defineOwnProperty__(ExecutionContext *ctx, String *name, const PropertyDescriptor *desc);
- bool __defineOwnProperty__(ExecutionContext *ctx, uint index, const PropertyDescriptor *desc);
- bool __defineOwnProperty__(ExecutionContext *ctx, const QString &name, const PropertyDescriptor *desc);
+ bool __defineOwnProperty__(ExecutionContext *ctx, Property *current, String *member, const Property &p, PropertyAttributes attrs);
+ bool __defineOwnProperty__(ExecutionContext *ctx, String *name, const Property &p, PropertyAttributes attrs);
+ bool __defineOwnProperty__(ExecutionContext *ctx, uint index, const Property &p, PropertyAttributes attrs);
+ bool __defineOwnProperty__(ExecutionContext *ctx, const QString &name, const Property &p, PropertyAttributes attrs);
//
// helpers
//
void put(ExecutionContext *ctx, const QString &name, const Value &value);
- static Value getValue(const Value &thisObject, ExecutionContext *ctx, const PropertyDescriptor *p);
- Value getValue(ExecutionContext *ctx, const PropertyDescriptor *p) const {
- return getValue(Value::fromObject(const_cast<Object *>(this)), ctx, p);
+ static Value getValue(const Value &thisObject, ExecutionContext *ctx, const Property *p, PropertyAttributes attrs);
+ Value getValue(ExecutionContext *ctx, const Property *p, PropertyAttributes attrs) const {
+ return getValue(Value::fromObject(const_cast<Object *>(this)), ctx, p, attrs);
}
- Value getValueChecked(ExecutionContext *ctx, const PropertyDescriptor *p) const {
- if (!p || p->attrs.type() == PropertyAttributes::Generic)
+ Value getValueChecked(ExecutionContext *ctx, const Property *p, PropertyAttributes attrs) const {
+ if (!p || attrs.isGeneric())
return Value::undefinedValue();
- return getValue(Value::fromObject(const_cast<Object *>(this)), ctx, p);
+ return getValue(Value::fromObject(const_cast<Object *>(this)), ctx, p, attrs);
}
- Value getValueChecked(ExecutionContext *ctx, const PropertyDescriptor *p, bool *exists) const {
- *exists = p && p->attrs.type() != PropertyAttributes::Generic;
+ Value getValueChecked(ExecutionContext *ctx, const Property *p, PropertyAttributes attrs, bool *exists) const {
+ *exists = p && !attrs.isGeneric();
if (!*exists)
return Value::undefinedValue();
- return getValue(Value::fromObject(const_cast<Object *>(this)), ctx, p);
+ return getValue(Value::fromObject(const_cast<Object *>(this)), ctx, p, attrs);
}
-
- void putValue(ExecutionContext *ctx, PropertyDescriptor *pd, const Value &value);
- void putValue(ExecutionContext *ctx, PropertyDescriptor *pd, const Value &thisObject, const Value &value);
+ void putValue(ExecutionContext *ctx, Property *pd, PropertyAttributes attrs, const Value &value);
void inplaceBinOp(ExecutionContext *ctx, BinOp op, String *name, const Value &rhs);
void inplaceBinOp(ExecutionContext *ctx, BinOp op, const Value &index, const Value &rhs);
@@ -183,52 +180,48 @@ struct Q_V4_EXPORT Object: Managed {
void defineReadonlyProperty(ExecutionEngine *engine, const QString &name, Value value);
void defineReadonlyProperty(String *name, Value value);
- PropertyDescriptor *insertMember(String *s, PropertyAttributes attributes);
+ Property *insertMember(String *s, PropertyAttributes attributes);
// Array handling
- static void fillDescriptor(PropertyDescriptor *pd, Value v)
- {
- pd->attrs = PropertyAttributes(Attr_Data);
- pd->value = v;
- }
-
uint allocArrayValue() {
uint idx = arrayFreeList;
if (arrayAlloc <= arrayFreeList)
arrayReserve(arrayAlloc + 1);
- arrayFreeList = arrayData[arrayFreeList].value.integerValue();
+ arrayFreeList = arrayData[arrayFreeList].value.uint_32;
+ if (arrayAttributes)
+ arrayAttributes[idx].setType(PropertyAttributes::Data);
return idx;
}
uint allocArrayValue(Value v) {
uint idx = allocArrayValue();
- PropertyDescriptor *pd = &arrayData[idx];
- fillDescriptor(pd, v);
+ Property *pd = &arrayData[idx];
+ pd->value = v;
return idx;
}
void freeArrayValue(int idx) {
- PropertyDescriptor &pd = arrayData[idx];
- pd.attrs.clear();
- pd.value.tag = Value::_Undefined_Type;
+ Property &pd = arrayData[idx];
+ pd.value.tag = Value::_Deleted_Type;
pd.value.int_32 = arrayFreeList;
arrayFreeList = idx;
- }
-
- PropertyDescriptor *arrayDecriptor(uint index) {
- return arrayData + index;
- }
- const PropertyDescriptor *arrayDecriptor(uint index) const {
- return arrayData + index;
+ if (arrayAttributes)
+ arrayAttributes[idx].clear();
}
void getArrayHeadRoom() {
assert(!sparseArray && !arrayOffset);
arrayOffset = qMax(arrayDataLen >> 2, (uint)16);
- PropertyDescriptor *newArray = new PropertyDescriptor[arrayOffset + arrayAlloc];
- memcpy(newArray + arrayOffset, arrayData, arrayDataLen*sizeof(PropertyDescriptor));
+ Property *newArray = new Property[arrayOffset + arrayAlloc];
+ memcpy(newArray + arrayOffset, arrayData, arrayDataLen*sizeof(Property));
delete [] arrayData;
arrayData = newArray + arrayOffset;
+ if (arrayAttributes) {
+ PropertyAttributes *newAttrs = new PropertyAttributes[arrayOffset + arrayAlloc];
+ memcpy(newAttrs + arrayOffset, arrayAttributes, arrayDataLen*sizeof(PropertyAttributes));
+ delete [] arrayAttributes;
+ arrayAttributes = newAttrs + arrayOffset;
+ }
}
public:
@@ -240,54 +233,68 @@ public:
void setArrayLengthUnchecked(uint l);
- PropertyDescriptor *arrayInsert(uint index) {
- PropertyDescriptor *pd;
+ Property *arrayInsert(uint index, PropertyAttributes attributes = Attr_Data) {
+
+ Property *pd;
if (!sparseArray && (index < 0x1000 || index < arrayDataLen + (arrayDataLen >> 2))) {
if (index >= arrayAlloc)
arrayReserve(index + 1);
if (index >= arrayDataLen) {
- for (uint i = arrayDataLen; i < index; ++i) {
- arrayData[i].attrs.clear();
- arrayData[i].value.tag = Value::_Undefined_Type;
- }
+ ensureArrayAttributes();
+ for (uint i = arrayDataLen; i < index; ++i)
+ arrayAttributes[i].clear();
arrayDataLen = index + 1;
}
- pd = arrayDecriptor(index);
+ pd = arrayData + index;
} else {
initSparse();
SparseArrayNode *n = sparseArray->insert(index);
if (n->value == UINT_MAX)
n->value = allocArrayValue();
- pd = arrayDecriptor(n->value);
+ pd = arrayData + n->value;
}
if (index >= arrayLength())
setArrayLengthUnchecked(index + 1);
+ if (arrayAttributes || attributes != Attr_Data) {
+ if (!arrayAttributes)
+ ensureArrayAttributes();
+ attributes.resolve();
+ arrayAttributes[pd - arrayData] = attributes;
+ }
return pd;
}
- void arraySet(uint index, const PropertyDescriptor *pd) {
+ void arraySet(uint index, const Property *pd) {
*arrayInsert(index) = *pd;
}
void arraySet(uint index, Value value) {
- PropertyDescriptor *pd = arrayInsert(index);
- fillDescriptor(pd, value);
+ Property *pd = arrayInsert(index);
+ pd->value = value;
}
- PropertyDescriptor *arrayAt(uint index) const {
+ uint propertyIndexFromArrayIndex(uint index) const
+ {
if (!sparseArray) {
if (index >= arrayDataLen)
- return 0;
- return arrayData + index;
+ return UINT_MAX;
+ return index;
} else {
SparseArrayNode *n = sparseArray->findNode(index);
if (!n)
- return 0;
- return arrayData + n->value;
+ return UINT_MAX;
+ return n->value;
}
}
- PropertyDescriptor *nonSparseArrayAt(uint index) const {
+ Property *arrayAt(uint index) const {
+ uint pidx = propertyIndexFromArrayIndex(index);
+ if (pidx == UINT_MAX)
+ return 0;
+ return arrayData + pidx;
+ }
+
+ Property *nonSparseArrayAt(uint index) const {
if (sparseArray)
return 0;
if (index >= arrayDataLen)
@@ -302,7 +309,7 @@ public:
if (!sparseArray) {
if (idx >= arrayAlloc)
arrayReserve(idx + 1);
- fillDescriptor(arrayData + idx, v);
+ arrayData[idx].value = v;
arrayDataLen = idx + 1;
} else {
uint idx = allocArrayValue(v);
@@ -319,6 +326,7 @@ public:
Value arrayIndexOf(Value v, uint fromIndex, uint arrayDataLen, ExecutionContext *ctx, Object *o);
void arrayReserve(uint n);
+ void ensureArrayAttributes();
using Managed::get;
using Managed::getIndexed;
@@ -401,7 +409,7 @@ inline void Object::setArrayLengthUnchecked(uint l)
{
if (isArrayObject()) {
// length is always the first property of an array
- PropertyDescriptor &lengthProperty = memberData[ArrayObject::LengthPropertyIndex];
+ Property &lengthProperty = memberData[ArrayObject::LengthPropertyIndex];
lengthProperty.value = Value::fromUInt32(l);
}
}
diff --git a/src/v4/qv4objectiterator.cpp b/src/v4/qv4objectiterator.cpp
index 29b0c96482..f7c211365e 100644
--- a/src/v4/qv4objectiterator.cpp
+++ b/src/v4/qv4objectiterator.cpp
@@ -52,20 +52,18 @@ ObjectIterator::ObjectIterator(ExecutionContext *context, Object *o, uint flags)
, current(o)
, arrayNode(0)
, arrayIndex(0)
- , currentClass(0)
, memberIndex(0)
, flags(flags)
{
if (current) {
- currentClass = current->internalClass;
if (current->asStringObject())
this->flags |= CurrentIsString;
}
}
-PropertyDescriptor *ObjectIterator::next(String **name, uint *index)
+Property *ObjectIterator::next(String **name, uint *index, PropertyAttributes *attrs)
{
- PropertyDescriptor *p = 0;
+ Property *p = 0;
*name = 0;
*index = UINT_MAX;
while (1) {
@@ -78,6 +76,8 @@ PropertyDescriptor *ObjectIterator::next(String **name, uint *index)
while (arrayIndex < slen) {
*index = arrayIndex;
++arrayIndex;
+ if (attrs)
+ *attrs = s->arrayAttributes ? s->arrayAttributes[arrayIndex] : PropertyAttributes(Attr_NotWritable|Attr_NotConfigurable);
return s->__getOwnProperty__(context, *index);
}
flags &= ~CurrentIsString;
@@ -94,11 +94,15 @@ PropertyDescriptor *ObjectIterator::next(String **name, uint *index)
if (arrayNode) {
while (arrayNode != current->sparseArrayEnd()) {
int k = arrayNode->key();
- p = current->arrayAt(k);
+ uint pidx = arrayNode->value;
+ p = current->arrayData + pidx;
arrayNode = arrayNode->nextNode();
- if (p && (!(flags & EnumberableOnly) || p->attrs.isEnumerable())) {
+ PropertyAttributes a = current->arrayAttributes ? current->arrayAttributes[pidx] : PropertyAttributes(Attr_Data);
+ if (!(flags & EnumberableOnly) || a.isEnumerable()) {
arrayIndex = k + 1;
*index = k;
+ if (attrs)
+ *attrs = a;
return p;
}
}
@@ -107,15 +111,20 @@ PropertyDescriptor *ObjectIterator::next(String **name, uint *index)
}
// dense arrays
while (arrayIndex < current->arrayDataLen) {
- p = current->arrayAt(arrayIndex);
+ uint pidx = current->propertyIndexFromArrayIndex(arrayIndex);
+ p = current->arrayData + pidx;
+ PropertyAttributes a = current->arrayAttributes ? current->arrayAttributes[pidx] : PropertyAttributes(Attr_Data);
++arrayIndex;
- if (p && p->attrs.type() != PropertyAttributes::Generic && (!(flags & EnumberableOnly) || p->attrs.isEnumerable())) {
+ if ((!current->arrayAttributes || !current->arrayAttributes[pidx].isGeneric())
+ && (!(flags & EnumberableOnly) || a.isEnumerable())) {
*index = arrayIndex - 1;
+ if (attrs)
+ *attrs = a;
return p;
}
}
- if (memberIndex == currentClass->size) {
+ if (memberIndex == current->internalClass->size) {
if (flags & WithProtoChain)
current = current->prototype;
else
@@ -128,18 +137,19 @@ PropertyDescriptor *ObjectIterator::next(String **name, uint *index)
arrayIndex = 0;
memberIndex = 0;
- if (current)
- currentClass = current->internalClass;
continue;
}
- String *n = currentClass->nameMap.at(memberIndex);
+ String *n = current->internalClass->nameMap.at(memberIndex);
assert(n);
// ### check that it's not a repeated attribute
p = current->memberData + memberIndex;
+ PropertyAttributes a = current->internalClass->propertyData[memberIndex];
++memberIndex;
- if (!(flags & EnumberableOnly) || p->attrs.isEnumerable()) {
+ if (!(flags & EnumberableOnly) || a.isEnumerable()) {
*name = n;
+ if (attrs)
+ *attrs = a;
return p;
}
}
diff --git a/src/v4/qv4objectiterator.h b/src/v4/qv4objectiterator.h
index 4f23b7e417..06c6ee80ab 100644
--- a/src/v4/qv4objectiterator.h
+++ b/src/v4/qv4objectiterator.h
@@ -43,6 +43,7 @@
#include "qv4value.h"
#include <qv4internalclass.h>
+#include <qv4propertydescriptor.h>
QT_BEGIN_NAMESPACE
@@ -51,7 +52,6 @@ namespace VM {
struct SparseArrayNode;
struct Object;
-struct PropertyDescriptor;
struct ObjectIterator
{
@@ -67,12 +67,11 @@ struct ObjectIterator
Object *current;
SparseArrayNode *arrayNode;
uint arrayIndex;
- InternalClass *currentClass;
uint memberIndex;
uint flags;
ObjectIterator(ExecutionContext *context, Object *o, uint flags);
- PropertyDescriptor *next(String **name, uint *index);
+ Property *next(String **name, uint *index, PropertyAttributes *attributes = 0);
Value nextPropertyName();
Value nextPropertyNameAsString();
};
diff --git a/src/v4/qv4objectproto.cpp b/src/v4/qv4objectproto.cpp
index 0721aa1b4a..b818d28821 100644
--- a/src/v4/qv4objectproto.cpp
+++ b/src/v4/qv4objectproto.cpp
@@ -145,8 +145,9 @@ Value ObjectPrototype::method_getOwnPropertyDescriptor(SimpleCallContext *ctx)
ctx->throwTypeError();
String *name = ctx->argument(1).toString(ctx);
- PropertyDescriptor *desc = O.objectValue()->__getOwnProperty__(ctx, name);
- return fromPropertyDescriptor(ctx, desc);
+ PropertyAttributes attrs;
+ Property *desc = O.objectValue()->__getOwnProperty__(ctx, name, &attrs);
+ return fromPropertyDescriptor(ctx, desc, attrs);
}
Value ObjectPrototype::method_getOwnPropertyNames(SimpleCallContext *context)
@@ -193,10 +194,11 @@ Value ObjectPrototype::method_defineProperty(SimpleCallContext *ctx)
String *name = ctx->argument(1).toString(ctx);
Value attributes = ctx->argument(2);
- PropertyDescriptor pd;
- toPropertyDescriptor(ctx, attributes, &pd);
+ Property pd;
+ PropertyAttributes attrs;
+ toPropertyDescriptor(ctx, attributes, &pd, &attrs);
- if (!O.objectValue()->__defineOwnProperty__(ctx, name, &pd))
+ if (!O.objectValue()->__defineOwnProperty__(ctx, name, pd, attrs))
ctx->throwTypeError();
return O;
@@ -214,16 +216,18 @@ Value ObjectPrototype::method_defineProperties(SimpleCallContext *ctx)
while (1) {
uint index;
String *name;
- PropertyDescriptor *pd = it.next(&name, &index);
+ PropertyAttributes attrs;
+ Property *pd = it.next(&name, &index, &attrs);
if (!pd)
break;
- PropertyDescriptor n;
- toPropertyDescriptor(ctx, o->getValue(ctx, pd), &n);
+ Property n;
+ PropertyAttributes nattrs;
+ toPropertyDescriptor(ctx, o->getValue(ctx, pd, attrs), &n, &nattrs);
bool ok;
if (name)
- ok = O.objectValue()->__defineOwnProperty__(ctx, name, &n);
+ ok = O.objectValue()->__defineOwnProperty__(ctx, name, n, nattrs);
else
- ok = O.objectValue()->__defineOwnProperty__(ctx, index, &n);
+ ok = O.objectValue()->__defineOwnProperty__(ctx, index, n, nattrs);
if (!ok)
ctx->throwTypeError();
}
@@ -239,15 +243,14 @@ Value ObjectPrototype::method_seal(SimpleCallContext *ctx)
Object *o = ctx->argument(0).objectValue();
o->extensible = false;
- ObjectIterator it(ctx, o, ObjectIterator::NoFlags);
- while (1) {
- uint index;
- String *name;
- PropertyDescriptor *pd = it.next(&name, &index);
- if (!pd)
- break;
- pd->attrs.setConfigurable(false);
+ o->internalClass = o->internalClass->sealed();
+
+ o->ensureArrayAttributes();
+ for (uint i = 0; i < o->arrayDataLen; ++i) {
+ if (!o->arrayAttributes[i].isGeneric())
+ o->arrayAttributes[i].setConfigurable(false);
}
+
return ctx->argument(0);
}
@@ -259,16 +262,14 @@ Value ObjectPrototype::method_freeze(SimpleCallContext *ctx)
Object *o = ctx->argument(0).objectValue();
o->extensible = false;
- ObjectIterator it(ctx, o, ObjectIterator::NoFlags);
- while (1) {
- uint index;
- String *name;
- PropertyDescriptor *pd = it.next(&name, &index);
- if (!pd)
- break;
- if (pd->attrs.type() == PropertyAttributes::Data)
- pd->attrs.setWritable(false);
- pd->attrs.setConfigurable(false);
+ o->internalClass = o->internalClass->frozen();
+
+ o->ensureArrayAttributes();
+ for (uint i = 0; i < o->arrayDataLen; ++i) {
+ if (!o->arrayAttributes[i].isGeneric())
+ o->arrayAttributes[i].setConfigurable(false);
+ if (o->arrayAttributes[i].isData())
+ o->arrayAttributes[i].setWritable(false);
}
return ctx->argument(0);
}
@@ -292,16 +293,21 @@ Value ObjectPrototype::method_isSealed(SimpleCallContext *ctx)
if (o->extensible)
return Value::fromBoolean(false);
- ObjectIterator it(ctx, o, ObjectIterator::NoFlags);
- while (1) {
- uint index;
- String *name;
- PropertyDescriptor *pd = it.next(&name, &index);
- if (!pd)
- break;
- if (pd->attrs.isConfigurable())
- return Value::fromBoolean(false);
+ if (o->internalClass != o->internalClass->sealed())
+ return Value::fromBoolean(false);
+
+ if (!o->arrayDataLen)
+ return Value::fromBoolean(true);
+
+ if (!o->arrayAttributes)
+ return Value::fromBoolean(false);
+
+ for (uint i = 0; i < o->arrayDataLen; ++i) {
+ if (!o->arrayAttributes[i].isGeneric())
+ if (o->arrayAttributes[i].isConfigurable())
+ return Value::fromBoolean(false);
}
+
return Value::fromBoolean(true);
}
@@ -314,16 +320,21 @@ Value ObjectPrototype::method_isFrozen(SimpleCallContext *ctx)
if (o->extensible)
return Value::fromBoolean(false);
- ObjectIterator it(ctx, o, ObjectIterator::NoFlags);
- while (1) {
- uint index;
- String *name;
- PropertyDescriptor *pd = it.next(&name, &index);
- if (!pd)
- break;
- if (pd->attrs.isWritable() || pd->attrs.isConfigurable())
- return Value::fromBoolean(false);
+ if (o->internalClass != o->internalClass->frozen())
+ return Value::fromBoolean(false);
+
+ if (!o->arrayDataLen)
+ return Value::fromBoolean(true);
+
+ if (!o->arrayAttributes)
+ return Value::fromBoolean(false);
+
+ for (uint i = 0; i < o->arrayDataLen; ++i) {
+ if (!o->arrayAttributes[i].isGeneric())
+ if (o->arrayAttributes[i].isConfigurable() || o->arrayAttributes[i].isWritable())
+ return Value::fromBoolean(false);
}
+
return Value::fromBoolean(true);
}
@@ -349,7 +360,7 @@ Value ObjectPrototype::method_keys(SimpleCallContext *ctx)
while (1) {
uint index;
String *name;
- PropertyDescriptor *pd = it.next(&name, &index);
+ Property *pd = it.next(&name, &index);
if (!pd)
break;
Value key;
@@ -422,8 +433,9 @@ Value ObjectPrototype::method_propertyIsEnumerable(SimpleCallContext *ctx)
String *p = ctx->argument(0).toString(ctx);
Object *o = ctx->thisObject.toObject(ctx);
- PropertyDescriptor *pd = o->__getOwnProperty__(ctx, p);
- return Value::fromBoolean(pd && pd->attrs.isEnumerable());
+ PropertyAttributes attrs;
+ o->__getOwnProperty__(ctx, p, &attrs);
+ return Value::fromBoolean(attrs.isEnumerable());
}
Value ObjectPrototype::method_defineGetter(SimpleCallContext *ctx)
@@ -438,10 +450,8 @@ Value ObjectPrototype::method_defineGetter(SimpleCallContext *ctx)
Object *o = ctx->thisObject.toObject(ctx);
- PropertyDescriptor pd = PropertyDescriptor::fromAccessor(f, 0);
- pd.attrs.setConfigurable(true);
- pd.attrs.setEnumerable(true);
- o->__defineOwnProperty__(ctx, prop, &pd);
+ Property pd = Property::fromAccessor(f, 0);
+ o->__defineOwnProperty__(ctx, prop, pd, Attr_Accessor);
return Value::undefinedValue();
}
@@ -457,75 +467,75 @@ Value ObjectPrototype::method_defineSetter(SimpleCallContext *ctx)
Object *o = ctx->thisObject.toObject(ctx);
- PropertyDescriptor pd = PropertyDescriptor::fromAccessor(0, f);
- pd.attrs.setConfigurable(true);
- pd.attrs.setEnumerable(true);
- o->__defineOwnProperty__(ctx, prop, &pd);
+ Property pd = Property::fromAccessor(0, f);
+ o->__defineOwnProperty__(ctx, prop, pd, Attr_Accessor);
return Value::undefinedValue();
}
-void ObjectPrototype::toPropertyDescriptor(ExecutionContext *ctx, Value v, PropertyDescriptor *desc)
+void ObjectPrototype::toPropertyDescriptor(ExecutionContext *ctx, Value v, Property *desc, PropertyAttributes *attrs)
{
if (!v.isObject())
ctx->throwTypeError();
Object *o = v.objectValue();
- desc->attrs.clear();
- desc->get = 0;
- desc->set = 0;
+ attrs->clear();
+ desc->setGetter(0);
+ desc->setSetter(0);
if (o->__hasProperty__(ctx, ctx->engine->id_enumerable))
- desc->attrs.setEnumerable(o->get(ctx, ctx->engine->id_enumerable).toBoolean());
+ attrs->setEnumerable(o->get(ctx, ctx->engine->id_enumerable).toBoolean());
if (o->__hasProperty__(ctx, ctx->engine->id_configurable))
- desc->attrs.setConfigurable(o->get(ctx, ctx->engine->id_configurable).toBoolean());
+ attrs->setConfigurable(o->get(ctx, ctx->engine->id_configurable).toBoolean());
if (o->__hasProperty__(ctx, ctx->engine->id_get)) {
Value get = o->get(ctx, ctx->engine->id_get);
FunctionObject *f = get.asFunctionObject();
if (f) {
- desc->get = f;
+ desc->setGetter(f);
} else if (get.isUndefined()) {
- desc->get = (FunctionObject *)0x1;
+ desc->setGetter((FunctionObject *)0x1);
} else {
ctx->throwTypeError();
}
- desc->attrs.setType(PropertyAttributes::Accessor);
+ attrs->setType(PropertyAttributes::Accessor);
}
if (o->__hasProperty__(ctx, ctx->engine->id_set)) {
Value set = o->get(ctx, ctx->engine->id_set);
FunctionObject *f = set.asFunctionObject();
if (f) {
- desc->set = f;
+ desc->setSetter(f);
} else if (set.isUndefined()) {
- desc->set = (FunctionObject *)0x1;
+ desc->setSetter((FunctionObject *)0x1);
} else {
ctx->throwTypeError();
}
- desc->attrs.setType(PropertyAttributes::Accessor);
+ attrs->setType(PropertyAttributes::Accessor);
}
if (o->__hasProperty__(ctx, ctx->engine->id_writable)) {
- if (desc->attrs.isAccessor())
+ if (attrs->isAccessor())
ctx->throwTypeError();
- desc->attrs.setWritable(o->get(ctx, ctx->engine->id_writable).toBoolean());
+ attrs->setWritable(o->get(ctx, ctx->engine->id_writable).toBoolean());
// writable forces it to be a data descriptor
desc->value = Value::undefinedValue();
}
if (o->__hasProperty__(ctx, ctx->engine->id_value)) {
- if (desc->attrs.isAccessor())
+ if (attrs->isAccessor())
ctx->throwTypeError();
desc->value = o->get(ctx, ctx->engine->id_value);
- desc->attrs.setType(PropertyAttributes::Data);
+ attrs->setType(PropertyAttributes::Data);
}
+ if (attrs->isGeneric())
+ desc->value = Value::deletedValue();
}
-Value ObjectPrototype::fromPropertyDescriptor(ExecutionContext *ctx, const PropertyDescriptor *desc)
+Value ObjectPrototype::fromPropertyDescriptor(ExecutionContext *ctx, const Property *desc, PropertyAttributes attrs)
{
if (!desc)
return Value::undefinedValue();
@@ -534,24 +544,22 @@ Value ObjectPrototype::fromPropertyDescriptor(ExecutionContext *ctx, const Prope
// Let obj be the result of creating a new object as if by the expression new Object() where Object is the standard built-in constructor with that name.
Object *o = engine->newObject();
- PropertyDescriptor pd;
- pd.attrs = Attr_Data;
-
- if (desc->attrs.isData()) {
+ Property pd;
+ if (attrs.isData()) {
pd.value = desc->value;
- o->__defineOwnProperty__(ctx, engine->newString(QStringLiteral("value")), &pd);
- pd.value = Value::fromBoolean(desc->attrs.isWritable());
- o->__defineOwnProperty__(ctx, engine->newString(QStringLiteral("writable")), &pd);
+ o->__defineOwnProperty__(ctx, engine->newString(QStringLiteral("value")), pd, Attr_Data);
+ pd.value = Value::fromBoolean(attrs.isWritable());
+ o->__defineOwnProperty__(ctx, engine->newString(QStringLiteral("writable")), pd, Attr_Data);
} else {
- pd.value = desc->get ? Value::fromObject(desc->get) : Value::undefinedValue();
- o->__defineOwnProperty__(ctx, engine->newString(QStringLiteral("get")), &pd);
- pd.value = desc->set ? Value::fromObject(desc->set) : Value::undefinedValue();
- o->__defineOwnProperty__(ctx, engine->newString(QStringLiteral("set")), &pd);
+ pd.value = desc->getter() ? Value::fromObject(desc->getter()) : Value::undefinedValue();
+ o->__defineOwnProperty__(ctx, engine->newString(QStringLiteral("get")), pd, Attr_Data);
+ pd.value = desc->setter() ? Value::fromObject(desc->setter()) : Value::undefinedValue();
+ o->__defineOwnProperty__(ctx, engine->newString(QStringLiteral("set")), pd, Attr_Data);
}
- pd.value = Value::fromBoolean(desc->attrs.isEnumerable());
- o->__defineOwnProperty__(ctx, engine->newString(QStringLiteral("enumerable")), &pd);
- pd.value = Value::fromBoolean(desc->attrs.isConfigurable());
- o->__defineOwnProperty__(ctx, engine->newString(QStringLiteral("configurable")), &pd);
+ pd.value = Value::fromBoolean(attrs.isEnumerable());
+ o->__defineOwnProperty__(ctx, engine->newString(QStringLiteral("enumerable")), pd, Attr_Data);
+ pd.value = Value::fromBoolean(attrs.isConfigurable());
+ o->__defineOwnProperty__(ctx, engine->newString(QStringLiteral("configurable")), pd, Attr_Data);
return Value::fromObject(o);
}
diff --git a/src/v4/qv4objectproto.h b/src/v4/qv4objectproto.h
index 1abd8d13a6..0a19f45b06 100644
--- a/src/v4/qv4objectproto.h
+++ b/src/v4/qv4objectproto.h
@@ -91,8 +91,8 @@ struct ObjectPrototype: Object
static Value method_defineGetter(SimpleCallContext *ctx);
static Value method_defineSetter(SimpleCallContext *ctx);
- static void toPropertyDescriptor(ExecutionContext *ctx, Value v, PropertyDescriptor *desc);
- static Value fromPropertyDescriptor(ExecutionContext *ctx, const PropertyDescriptor *desc);
+ static void toPropertyDescriptor(ExecutionContext *ctx, Value v, Property *desc, PropertyAttributes *attrs);
+ static Value fromPropertyDescriptor(ExecutionContext *ctx, const Property *desc, PropertyAttributes attrs);
};
diff --git a/src/v4/qv4propertydescriptor.h b/src/v4/qv4propertydescriptor.h
index 0d77067743..afb5ede277 100644
--- a/src/v4/qv4propertydescriptor.h
+++ b/src/v4/qv4propertydescriptor.h
@@ -51,7 +51,6 @@ namespace QQmlJS {
namespace VM {
struct FunctionObject;
-struct PropertyDescriptor;
struct Property {
union {
@@ -65,87 +64,86 @@ struct Property {
// Section 8.10
inline void fullyPopulated(PropertyAttributes *attrs) {
if (!attrs->hasType()) {
- attrs->setType(PropertyAttributes::Data);
value = Value::undefinedValue();
}
- if (attrs->type() == PropertyAttributes::Data) {
- attrs->resolveWritable();
- } else {
+ if (attrs->type() == PropertyAttributes::Accessor) {
attrs->clearWritable();
- if ((quintptr)get == 0x1)
+ if (get == (FunctionObject *)0x1)
get = 0;
- if ((quintptr)set == 0x1)
+ if (set == (FunctionObject *)0x1)
set = 0;
}
- attrs->resolveEnumerable();
- attrs->resolveConfigurable();
+ attrs->resolve();
}
- inline bool isSubset(const PropertyAttributes &attrs, PropertyDescriptor *other) const;
- inline void merge(PropertyAttributes &attrs, const PropertyDescriptor &other);
-};
-
-struct PropertyDescriptor : public Property
-{
- PropertyAttributes attrs;
-
- static inline PropertyDescriptor fromValue(Value v) {
- PropertyDescriptor pd;
+ static inline Property fromValue(Value v) {
+ Property pd;
pd.value = v;
- pd.attrs.setType(PropertyAttributes::Data);
return pd;
}
- static inline PropertyDescriptor fromAccessor(FunctionObject *getter, FunctionObject *setter) {
- PropertyDescriptor pd;
+ static inline Property fromAccessor(FunctionObject *getter, FunctionObject *setter) {
+ Property pd;
pd.get = getter;
pd.set = setter;
- pd.attrs.setType(PropertyAttributes::Accessor);
return pd;
}
+
+ static Property genericDescriptor() {
+ Property pd;
+ pd.value = Value::deletedValue();
+ return pd;
+ }
+
+ inline bool isSubset(const PropertyAttributes &attrs, const Property &other, PropertyAttributes otherAttrs) const;
+ inline void merge(PropertyAttributes &attrs, const Property &other, PropertyAttributes otherAttrs);
+
+ inline FunctionObject *getter() const { return get; }
+ inline FunctionObject *setter() const { return set; }
+ inline void setGetter(FunctionObject *g) { get = g; }
+ inline void setSetter(FunctionObject *s) { set = s; }
};
-inline bool Property::isSubset(const PropertyAttributes &attrs, PropertyDescriptor *other) const
+inline bool Property::isSubset(const PropertyAttributes &attrs, const Property &other, PropertyAttributes otherAttrs) const
{
- if (attrs.type() != PropertyAttributes::Generic && attrs.type() != other->attrs.type())
+ if (attrs.type() != PropertyAttributes::Generic && attrs.type() != otherAttrs.type())
return false;
- if (attrs.hasEnumerable() && attrs.isEnumerable() != other->attrs.isEnumerable())
+ if (attrs.hasEnumerable() && attrs.isEnumerable() != otherAttrs.isEnumerable())
return false;
- if (attrs.hasConfigurable() && attrs.isConfigurable() != other->attrs.isConfigurable())
+ if (attrs.hasConfigurable() && attrs.isConfigurable() != otherAttrs.isConfigurable())
return false;
- if (attrs.hasWritable() && attrs.isWritable() != other->attrs.isWritable())
+ if (attrs.hasWritable() && attrs.isWritable() != otherAttrs.isWritable())
return false;
- if (attrs.type() == PropertyAttributes::Data && !value.sameValue(other->value))
+ if (attrs.type() == PropertyAttributes::Data && !value.sameValue(other.value))
return false;
if (attrs.type() == PropertyAttributes::Accessor) {
- if (get != other->get)
+ if (get != other.get)
return false;
- if (set != other->set)
+ if (set != other.set)
return false;
}
return true;
}
-inline void Property::merge(PropertyAttributes &attrs, const PropertyDescriptor &other)
+inline void Property::merge(PropertyAttributes &attrs, const Property &other, PropertyAttributes otherAttrs)
{
- if (other.attrs.hasEnumerable())
- attrs.setEnumerable(other.attrs.isEnumerable());
- if (other.attrs.hasConfigurable())
- attrs.setConfigurable(other.attrs.isConfigurable());
- if (other.attrs.hasWritable())
- attrs.setWritable(other.attrs.isWritable());
- if (other.attrs.type() == PropertyAttributes::Accessor) {
+ if (otherAttrs.hasEnumerable())
+ attrs.setEnumerable(otherAttrs.isEnumerable());
+ if (otherAttrs.hasConfigurable())
+ attrs.setConfigurable(otherAttrs.isConfigurable());
+ if (otherAttrs.hasWritable())
+ attrs.setWritable(otherAttrs.isWritable());
+ if (otherAttrs.type() == PropertyAttributes::Accessor) {
attrs.setType(PropertyAttributes::Accessor);
if (other.get)
- get = ((quintptr)other.get == 0x1) ? 0 : other.get;
+ get = (other.get == (FunctionObject *)0x1) ? 0 : other.get;
if (other.set)
- set = ((quintptr)other.set == 0x1) ? 0 : other.set;
- } else if (other.attrs.type() == PropertyAttributes::Data){
+ set = (other.set == (FunctionObject *)0x1) ? 0 : other.set;
+ } else if (otherAttrs.type() == PropertyAttributes::Data){
attrs.setType(PropertyAttributes::Data);
value = other.value;
}
}
-
} // namespace VM
} // namespace QQmlJS
diff --git a/src/v4/qv4regexpobject.cpp b/src/v4/qv4regexpobject.cpp
index 3717da6e57..cc1d84747a 100644
--- a/src/v4/qv4regexpobject.cpp
+++ b/src/v4/qv4regexpobject.cpp
@@ -73,9 +73,8 @@ RegExpObject::RegExpObject(ExecutionEngine *engine, RegExp* value, bool global)
vtbl = &static_vtbl;
type = Type_RegExpObject;
- PropertyDescriptor *lastIndexProperty = insertMember(engine->newIdentifier(QStringLiteral("lastIndex")),
+ Property *lastIndexProperty = insertMember(engine->newIdentifier(QStringLiteral("lastIndex")),
Attr_NotEnumerable|Attr_NotConfigurable);
- lastIndexProperty->attrs = Attr_NotEnumerable|Attr_NotConfigurable;
lastIndexProperty->value = Value::fromInt32(0);
if (!this->value)
return;
@@ -98,7 +97,7 @@ void RegExpObject::markObjects(Managed *that)
Object::markObjects(that);
}
-PropertyDescriptor *RegExpObject::lastIndexProperty(ExecutionContext *ctx)
+Property *RegExpObject::lastIndexProperty(ExecutionContext *ctx)
{
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 b949953504..9447c0516a 100644
--- a/src/v4/qv4regexpobject.h
+++ b/src/v4/qv4regexpobject.h
@@ -66,7 +66,7 @@ namespace VM {
struct RegExpObject: Object {
RegExp* value;
- PropertyDescriptor *lastIndexProperty(ExecutionContext *ctx);
+ Property *lastIndexProperty(ExecutionContext *ctx);
bool global;
RegExpObject(ExecutionEngine *engine, RegExp* value, bool global);
~RegExpObject() {}
diff --git a/src/v4/qv4runtime.cpp b/src/v4/qv4runtime.cpp
index 083bfea206..fcc2b4f5a1 100644
--- a/src/v4/qv4runtime.cpp
+++ b/src/v4/qv4runtime.cpp
@@ -613,11 +613,13 @@ void __qmljs_get_element(ExecutionContext *ctx, Value *result, const Value &obje
}
if (idx < UINT_MAX) {
- const PropertyDescriptor *p = o->nonSparseArrayAt(idx);
- if (p && p->attrs.type() == PropertyAttributes::Data) {
- if (result)
- *result = p->value;
- return;
+ uint pidx = o->propertyIndexFromArrayIndex(idx);
+ if (pidx < UINT_MAX) {
+ if (!o->arrayAttributes || o->arrayAttributes[pidx].isData()) {
+ if (result)
+ *result = o->arrayData[pidx].value;
+ return;
+ }
}
Value res = o->getIndexed(ctx, idx);
@@ -638,10 +640,33 @@ void __qmljs_set_element(ExecutionContext *ctx, const Value &object, const Value
uint idx = index.asArrayIndex();
if (idx < UINT_MAX) {
- PropertyDescriptor *p = o->nonSparseArrayAt(idx);
- if (p && p->attrs.type() == PropertyAttributes::Data && p->attrs.isWritable()) {
- p->value = value;
- return;
+ uint pidx = o->propertyIndexFromArrayIndex(idx);
+ if (pidx < UINT_MAX) {
+ if (o->arrayAttributes && !o->arrayAttributes[pidx].isEmpty() && !o->arrayAttributes[pidx].isWritable()) {
+ if (ctx->strictMode)
+ ctx->throwTypeError();
+ return;
+ }
+
+ Property *p = o->arrayData + pidx;
+ if (!o->arrayAttributes || o->arrayAttributes[pidx].isData()) {
+ p->value = value;
+ return;
+ }
+
+ if (o->arrayAttributes[pidx].isAccessor()) {
+ FunctionObject *setter = p->setter();
+ if (!setter) {
+ if (ctx->strictMode)
+ ctx->throwTypeError();
+ return;
+ }
+
+ Value args[1];
+ args[0] = value;
+ setter->call(ctx, Value::fromObject(o), args, 1);
+ return;
+ }
}
o->putIndexed(ctx, idx, value);
return;
@@ -700,9 +725,10 @@ void __qmljs_get_property_lookup(ExecutionContext *ctx, Value *result, const Val
Value res;
Lookup *l = ctx->lookups + lookupIndex;
if (Object *o = object.asObject()) {
- PropertyDescriptor *p = l->lookup(o);
+ PropertyAttributes attrs;
+ Property *p = l->lookup(o, &attrs);
if (p)
- res = p->attrs.type() == PropertyAttributes::Data ? p->value : o->getValue(ctx, p);
+ res = attrs.isData() ? p->value : o->getValue(ctx, p, attrs);
else
res = Value::undefinedValue();
} else {
@@ -722,9 +748,10 @@ void __qmljs_set_property_lookup(ExecutionContext *ctx, const Value &object, int
Object *o = object.toObject(ctx);
Lookup *l = ctx->lookups + lookupIndex;
- PropertyDescriptor *p = l->setterLookup(o);
+ bool writable;
+ Property *p = l->setterLookup(o, &writable);
if (p && (l->index != ArrayObject::LengthPropertyIndex || !o->isArrayObject())) {
- o->putValue(ctx, p, value);
+ o->putValue(ctx, p, o->internalClass->propertyData[l->index], value);
return;
}
@@ -861,10 +888,11 @@ void __qmljs_call_property_lookup(ExecutionContext *context, Value *result, cons
else
baseObject = __qmljs_convert_to_object(context, thisObject);
- PropertyDescriptor *p = l->lookup(baseObject);
+ PropertyAttributes attrs;
+ Property *p = l->lookup(baseObject, &attrs);
if (!p)
context->throwTypeError();
- Value func = p->attrs.type() == PropertyAttributes::Data ? p->value : baseObject->getValue(context, p);
+ Value func = attrs.isData() ? p->value : baseObject->getValue(context, p, attrs);
FunctionObject *o = func.asFunctionObject();
if (!o)
context->throwTypeError();
@@ -1210,9 +1238,8 @@ void __qmljs_builtin_define_property(ExecutionContext *ctx, const Value &object,
assert(o);
uint idx = name->asArrayIndex();
- PropertyDescriptor *pd = (idx != UINT_MAX) ? o->arrayInsert(idx) : o->insertMember(name, Attr_Data);
+ Property *pd = (idx != UINT_MAX) ? o->arrayInsert(idx) : o->insertMember(name, Attr_Data);
pd->value = val ? *val : Value::undefinedValue();
- pd->attrs = PropertyAttributes(Attr_Data);
}
void __qmljs_builtin_define_array(ExecutionContext *ctx, Value *array, Value *values, uint length)
@@ -1223,18 +1250,18 @@ void __qmljs_builtin_define_array(ExecutionContext *ctx, Value *array, Value *va
// This should rather be done when required
a->arrayReserve(length);
if (length) {
- PropertyDescriptor *pd = a->arrayData;
+ a->arrayDataLen = length;
+ Property *pd = a->arrayData;
for (uint i = 0; i < length; ++i) {
- if (values[i].isUndefined() && values[i].uint_32 == UINT_MAX) {
+ if (values[i].isDeleted()) {
+ a->ensureArrayAttributes();
pd->value = Value::undefinedValue();
- pd->attrs.clear();
+ a->arrayAttributes[i].clear();
} else {
pd->value = values[i];
- pd->attrs = PropertyAttributes(Attr_Data);
}
++pd;
}
- a->arrayDataLen = length;
a->setArrayLengthUnchecked(length);
}
*array = Value::fromObject(a);
@@ -1246,10 +1273,9 @@ void __qmljs_builtin_define_getter_setter(ExecutionContext *ctx, const Value &ob
assert(o);
uint idx = name->asArrayIndex();
- PropertyDescriptor *pd = (idx != UINT_MAX) ? o->arrayInsert(idx) : o->insertMember(name, Attr_Accessor);
- pd->get = getter ? getter->asFunctionObject() : 0;
- pd->set = setter ? setter->asFunctionObject() : 0;
- pd->attrs = Attr_Accessor;
+ Property *pd = (idx != UINT_MAX) ? o->arrayInsert(idx, Attr_Accessor) : o->insertMember(name, Attr_Accessor);
+ pd->setGetter(getter ? getter->asFunctionObject() : 0);
+ pd->setSetter(setter ? setter->asFunctionObject() : 0);
}
void __qmljs_increment(ExecutionContext *ctx, Value *result, const Value &value)
diff --git a/src/v4/qv4runtime.h b/src/v4/qv4runtime.h
index 09581c9f4f..8640c829df 100644
--- a/src/v4/qv4runtime.h
+++ b/src/v4/qv4runtime.h
@@ -77,7 +77,6 @@ enum TypeHint {
struct Function;
struct Object;
struct String;
-struct PropertyDescriptor;
struct ExecutionContext;
struct FunctionObject;
struct BooleanObject;
diff --git a/src/v4/qv4sparsearray.cpp b/src/v4/qv4sparsearray.cpp
index 33aab75b1c..b1ac830010 100644
--- a/src/v4/qv4sparsearray.cpp
+++ b/src/v4/qv4sparsearray.cpp
@@ -53,14 +53,10 @@
namespace QQmlJS {
namespace VM {
-bool ArrayElementLessThan::operator()(const PropertyDescriptor &p1, const PropertyDescriptor &p2) const
+bool ArrayElementLessThan::operator()(const Property &p1, const Property &p2) const
{
- if (p1.attrs.type() == PropertyAttributes::Generic)
- return false;
- if (p2.attrs.type() == PropertyAttributes::Generic)
- return true;
- Value v1 = thisObject->getValue(m_context, &p1);
- Value v2 = thisObject->getValue(m_context, &p2);
+ Value v1 = p1.value;
+ Value v2 = p2.value;
if (v1.isUndefined())
return false;
diff --git a/src/v4/qv4sparsearray.h b/src/v4/qv4sparsearray.h
index 40ee7ba06c..c0a79b20a0 100644
--- a/src/v4/qv4sparsearray.h
+++ b/src/v4/qv4sparsearray.h
@@ -67,7 +67,7 @@ public:
inline ArrayElementLessThan(ExecutionContext *context, Object *thisObject, const Value &comparefn)
: m_context(context), thisObject(thisObject), m_comparefn(comparefn) {}
- bool operator()(const PropertyDescriptor &v1, const PropertyDescriptor &v2) const;
+ bool operator()(const Property &v1, const Property &v2) const;
private:
ExecutionContext *m_context;
diff --git a/src/v4/qv4string.cpp b/src/v4/qv4string.cpp
index 382359fd35..1fd50f4eab 100644
--- a/src/v4/qv4string.cpp
+++ b/src/v4/qv4string.cpp
@@ -106,15 +106,16 @@ Value String::get(Managed *m, ExecutionContext *ctx, String *name, bool *hasProp
*hasProperty = true;
return Value::fromInt32(that->_text.length());
}
- PropertyDescriptor *pd = ctx->engine->stringPrototype->__getPropertyDescriptor__(ctx, name);
- if (!pd || pd->attrs.type() == PropertyAttributes::Generic) {
+ PropertyAttributes attrs;
+ Property *pd = ctx->engine->stringPrototype->__getPropertyDescriptor__(ctx, name, &attrs);
+ if (!pd || attrs.isGeneric()) {
if (hasProperty)
*hasProperty = false;
return Value::undefinedValue();
}
if (hasProperty)
*hasProperty = true;
- return ctx->engine->stringPrototype->getValue(Value::fromString(that), ctx, pd);
+ return ctx->engine->stringPrototype->getValue(Value::fromString(that), ctx, pd, attrs);
}
Value String::getIndexed(Managed *m, ExecutionContext *ctx, uint index, bool *hasProperty)
@@ -125,15 +126,16 @@ Value String::getIndexed(Managed *m, ExecutionContext *ctx, uint index, bool *ha
*hasProperty = true;
return Value::fromString(ctx, that->toQString().mid(index, 1));
}
- PropertyDescriptor *pd = ctx->engine->stringPrototype->__getPropertyDescriptor__(ctx, index);
- if (!pd || pd->attrs.type() == PropertyAttributes::Generic) {
+ PropertyAttributes attrs;
+ Property *pd = ctx->engine->stringPrototype->__getPropertyDescriptor__(ctx, index, &attrs);
+ if (!pd || attrs.isGeneric()) {
if (hasProperty)
*hasProperty = false;
return Value::undefinedValue();
}
if (hasProperty)
*hasProperty = true;
- return ctx->engine->stringPrototype->getValue(Value::fromString(that), ctx, pd);
+ return ctx->engine->stringPrototype->getValue(Value::fromString(that), ctx, pd, attrs);
}
void String::put(Managed *m, ExecutionContext *ctx, String *name, const Value &value)
diff --git a/src/v4/qv4stringobject.cpp b/src/v4/qv4stringobject.cpp
index 129c806f77..6003f4a4e3 100644
--- a/src/v4/qv4stringobject.cpp
+++ b/src/v4/qv4stringobject.cpp
@@ -83,14 +83,13 @@ StringObject::StringObject(ExecutionContext *ctx, const Value &value)
vtbl = &static_vtbl;
type = Type_StringObject;
- tmpProperty.attrs = Attr_NotWritable|Attr_NotConfigurable;
tmpProperty.value = Value::undefinedValue();
assert(value.isString());
defineReadonlyProperty(ctx->engine->id_length, Value::fromUInt32(value.stringValue()->toQString().length()));
}
-PropertyDescriptor *StringObject::getIndex(const ExecutionContext *ctx, uint index) const
+Property *StringObject::getIndex(const ExecutionContext *ctx, uint index) const
{
QString str = value.stringValue()->toQString();
if (index >= (uint)str.length())
diff --git a/src/v4/qv4stringobject.h b/src/v4/qv4stringobject.h
index 73dc740d0c..54f9130a49 100644
--- a/src/v4/qv4stringobject.h
+++ b/src/v4/qv4stringobject.h
@@ -52,10 +52,10 @@ namespace VM {
struct StringObject: Object {
Value value;
- mutable PropertyDescriptor tmpProperty;
+ mutable Property tmpProperty;
StringObject(ExecutionContext *ctx, const Value &value);
- PropertyDescriptor *getIndex(const ExecutionContext *ctx, uint index) const;
+ Property *getIndex(const ExecutionContext *ctx, uint index) const;
protected:
static const ManagedVTable static_vtbl;
diff --git a/src/v4/qv4v8.cpp b/src/v4/qv4v8.cpp
index e4ed24a0e8..db4c84e041 100644
--- a/src/v4/qv4v8.cpp
+++ b/src/v4/qv4v8.cpp
@@ -923,9 +923,9 @@ bool Object::SetAccessor(Handle<String> name, AccessorGetter getter, AccessorSet
PropertyAttributes attrs = Attr_Accessor;
attrs.setConfigurable(!(attribute & DontDelete));
attrs.setEnumerable(!(attribute & DontEnum));
- VM::PropertyDescriptor *pd = o->insertMember(name->asVMString(), attrs);
- *pd = VM::PropertyDescriptor::fromAccessor(wrappedGetter, wrappedSetter);
- pd->attrs = attrs;
+ VM::Property *pd = o->insertMember(name->asVMString(), attrs);
+ pd->setGetter(wrappedGetter);
+ pd->setSetter(wrappedSetter);
return true;
}
@@ -1428,10 +1428,9 @@ public:
PropertyAttributes attrs = Attr_Accessor;
attrs.setConfigurable(!(acc.attribute & DontDelete));
attrs.setEnumerable(!(acc.attribute & DontEnum));
- VM::PropertyDescriptor *pd = this->insertMember(acc.name->asVMString(), attrs);
- *pd = VM::PropertyDescriptor::fromAccessor(acc.getter->vmValue().asFunctionObject(),
- acc.setter->vmValue().asFunctionObject());
- pd->attrs = attrs;
+ VM::Property *pd = this->insertMember(acc.name->asVMString(), attrs);
+ *pd = VM::Property::fromAccessor(acc.getter->vmValue().asFunctionObject(),
+ acc.setter->vmValue().asFunctionObject());
}
initProperties(m_template.get());
@@ -1444,9 +1443,8 @@ public:
attrs.setConfigurable(!(p.attributes & DontDelete));
attrs.setEnumerable(!(p.attributes & DontEnum));
attrs.setWritable(!(p.attributes & ReadOnly));
- VM::PropertyDescriptor *pd = this->insertMember(p.name->asVMString(), attrs);
- *pd = VM::PropertyDescriptor::fromValue(p.value->vmValue());
- pd->attrs = attrs;
+ VM::Property *pd = this->insertMember(p.name->asVMString(), attrs);
+ *pd = VM::Property::fromValue(p.value->vmValue());
}
}
@@ -1523,9 +1521,10 @@ protected:
if (!result.IsEmpty())
return;
}
- PropertyDescriptor *pd = that->__getOwnProperty__(ctx, name);
+ PropertyAttributes attrs;
+ Property *pd = that->__getOwnProperty__(ctx, name, &attrs);
if (pd)
- that->putValue(ctx, pd, value);
+ that->putValue(ctx, pd, attrs, value);
else if (that->m_template->m_fallbackPropertySetter)
that->m_template->m_fallbackPropertySetter(String::New(name), v8Value, that->fallbackAccessorInfo());
else
diff --git a/src/v4/qv4value.h b/src/v4/qv4value.h
index 0fb3464c02..929e4561b4 100644
--- a/src/v4/qv4value.h
+++ b/src/v4/qv4value.h
@@ -97,6 +97,7 @@ struct Q_V4_EXPORT Value
NotDouble_Mask = 0xfffc0000,
Type_Mask = 0xffff8000,
Immediate_Mask = NotDouble_Mask | 0x00008000,
+ Special_Mask = Immediate_Mask | 0x20000,
Tag_Shift = 32
};
enum ValueType {
@@ -105,7 +106,8 @@ struct Q_V4_EXPORT Value
Boolean_Type = Immediate_Mask | 0x20000,
Integer_Type = Immediate_Mask | 0x30000,
Object_Type = NotDouble_Mask | 0x00000,
- String_Type = NotDouble_Mask | 0x10000
+ String_Type = NotDouble_Mask | 0x10000,
+ Deleted_Type = NotDouble_Mask | 0x30000,
};
enum ImmediateFlags {
@@ -114,6 +116,7 @@ struct Q_V4_EXPORT Value
enum ValueTypeInternal {
_Undefined_Type = Undefined_Type,
+ _Deleted_Type = Deleted_Type,
_Null_Type = Null_Type | ConvertibleToInt,
_Boolean_Type = Boolean_Type | ConvertibleToInt,
_Integer_Type = Integer_Type | ConvertibleToInt,
@@ -126,6 +129,9 @@ struct Q_V4_EXPORT Value
return tag & Type_Mask;
}
+ // used internally in property
+ inline bool isDeleted() const { return tag == _Deleted_Type; }
+
inline bool isUndefined() const { return tag == _Undefined_Type; }
inline bool isNull() const { return tag == _Null_Type; }
inline bool isBoolean() const { return tag == _Boolean_Type; }
@@ -185,6 +191,7 @@ struct Q_V4_EXPORT Value
return val;
}
+ static Value deletedValue();
static Value undefinedValue();
static Value nullValue();
static Value fromBoolean(Bool b);
@@ -294,6 +301,15 @@ inline Value Value::nullValue()
return v;
}
+inline VM::Value Value::deletedValue()
+{
+ VM::Value v;
+ v.tag = VM::Value::_Deleted_Type;
+ v.uint_32 = 0;
+ return v;
+}
+
+
inline Value Value::fromBoolean(Bool b)
{
Value v;