aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
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;