Array::Array(const Array &other)
: len(other.len)
- , lengthProperty(0)
+ , arrayObject(0)
, values(other.values)
, sparse(0)
{
}
}
+void Array::setLengthUnchecked(uint l)
+{
+ len = l;
+ if (arrayObject) {
+ // length is always the first property of an array
+ PropertyDescriptor &lengthProperty = arrayObject->members->values[0];
+ lengthProperty.value = Value::fromUInt32(l);
+ }
+}
+
bool Array::setLength(uint newLen) {
+ const PropertyDescriptor *lengthProperty = arrayObject->members->values.constData();
if (lengthProperty && !lengthProperty->isWritable())
return false;
uint oldLen = length();
friend struct ArrayPrototype;
uint len;
- PropertyDescriptor *lengthProperty;
+ ArrayObject *arrayObject;
union {
uint freeList;
uint offset;
}
public:
- Array() : len(0), lengthProperty(0), offset(0), sparse(0) {}
+ Array() : len(0), arrayObject(0), offset(0), sparse(0) {}
Array(const Array &other);
~Array() { delete sparse; }
void initSparse();
uint length() const { return len; }
bool setLength(uint newLen);
- void setLengthProperty(PropertyDescriptor *pd) { lengthProperty = pd; }
- PropertyDescriptor *getLengthProperty() { return lengthProperty; }
+ void setArrayObject(ArrayObject *a) { arrayObject = a; }
- void setLengthUnchecked(uint l) {
- len = l;
- if (lengthProperty)
- lengthProperty->value = Value::fromUInt32(l);
- }
+ void setLengthUnchecked(uint l);
PropertyDescriptor *insert(uint index) {
PropertyDescriptor *pd;
Value thisArg = ctx->argument(1);
ArrayObject *a = ctx->engine->newArrayObject(ctx);
- a->array.setLength(len);
+ a->array.setLengthUnchecked(len);
for (uint k = 0; k < len; ++k) {
bool exists;
if (!(*it))
continue;
(*it)->name->mark();
- PropertyDescriptor &pd = (*it)->descriptor;
+ }
+ for (int i = 0; i < (uint)members->values.size(); ++i) {
+ const PropertyDescriptor &pd = members->values.at(i);
if (pd.isData()) {
if (Managed *m = pd.value.asManaged())
m->mark();
- } else if (pd.isAccessor()) {
+ } else if (pd.isAccessor()) {
if (pd.get)
pd.get->mark();
if (pd.set)
if (members) {
if (PropertyTableEntry *entry = members->findEntry(name)) {
- if (entry->descriptor.isConfigurable()) {
+ if (members->values[entry->valueIndex].isConfigurable()) {
members->remove(entry);
return true;
}
PropertyDescriptor *current;
if (isArrayObject() && name->isEqualTo(ctx->engine->id_length)) {
- PropertyDescriptor *lp = array.getLengthProperty();
+ PropertyDescriptor *lp = members->values.data(); // length is always the first property
+ assert(lp == members->find(ctx->engine->id_length));
if (desc->isEmpty() || desc->isSubset(lp))
return true;
if (!lp->isWritable() || desc->type == PropertyDescriptor::Accessor || desc->isConfigurable() || desc->isEnumerable())
PropertyDescriptor *current;
// 15.4.5.1, 4b
- if (isArrayObject() && index >= array.length() && !array.getLengthProperty()->isWritable())
+ if (isArrayObject() && index >= array.length() && !members->values.at(0).isWritable())
goto reject;
if (isNonStrictArgumentsObject)
pd->enumberable = PropertyDescriptor::Disabled;
pd->configurable = PropertyDescriptor::Disabled;
pd->value = Value::fromInt32(0);
- array.setLengthProperty(pd);
+ array.setArrayObject(this);
+ assert(pd = members->values.data());
}
PropertyTableEntry *pt = current->members->_properties[tableIndex];
++tableIndex;
// ### check that it's not a repeated attribute
- if (pt && (!(flags & EnumberableOnly) || pt->descriptor.isEnumerable())) {
- *name = pt->name;
- p = &pt->descriptor;
- return p;
+ if (pt) {
+ PropertyDescriptor *pd = current->members->values.data() + pt->valueIndex;
+ if (!(flags & EnumberableOnly) || pd->isEnumerable()) {
+ *name = pt->name;
+ p = pd;
+ return p;
+ }
}
}
return 0;
struct ObjectIterator;
struct PropertyTableEntry {
- PropertyDescriptor descriptor;
String *name;
+ uint valueIndex;
PropertyTableEntry *next;
int index;
inline PropertyTableEntry(String *name)
: name(name),
+ valueIndex(UINT_MAX),
next(0),
index(-1)
{ }
class PropertyTable
{
Q_DISABLE_COPY(PropertyTable)
+ friend class Array;
+ friend class ArrayObject;
public:
PropertyTable()
_properties[prop->index] = 0;
prop->next = _freeList;
_freeList = prop;
+ // ### empty space in value array
+ values[prop->valueIndex].type = PropertyDescriptor::Generic;
+ values[prop->valueIndex].writable = PropertyDescriptor::Undefined;
}
PropertyTableEntry *findEntry(String *name) const
return 0;
}
- PropertyDescriptor *find(String *name) const
+ PropertyDescriptor *find(String *name)
{
if (_properties) {
for (PropertyTableEntry *prop = _buckets[name->hashValue() % _bucketCount]; prop; prop = prop->next) {
if (prop && prop->name->isEqualTo(name))
- return &prop->descriptor;
+ return values.data() + prop->valueIndex;
}
}
PropertyDescriptor *insert(String *name)
{
if (PropertyTableEntry *prop = findEntry(name))
- return &prop->descriptor;
+ return values.data() + prop->valueIndex;
if (_propertyCount == _allocated) {
if (! _allocated)
bucket = prop;
}
- return &prop->descriptor;
+ prop->valueIndex = values.size();
+ values.resize(values.size() + 1);
+ return values.data() + prop->valueIndex;
}
private:
private:
friend struct ObjectIterator;
+ friend struct Object;
+
PropertyTableEntry **_properties;
PropertyTableEntry **_buckets;
PropertyTableEntry *_freeList;
int _bucketCount;
int _primeIdx: 5;
int _allocated: 27;
+ QVector<PropertyDescriptor> values;
};
} // namespace VM
if (!members)
members.reset(new PropertyTable());
- lastIndexProperty = members->insert(engine->newIdentifier(QStringLiteral("lastIndex")));
+ PropertyDescriptor *lastIndexProperty = members->insert(engine->newIdentifier(QStringLiteral("lastIndex")));
lastIndexProperty->type = PropertyDescriptor::Data;
lastIndexProperty->writable = PropertyDescriptor::Enabled;
lastIndexProperty->enumberable = PropertyDescriptor::Disabled;
defineReadonlyProperty(engine->newIdentifier(QStringLiteral("multiline")), Value::fromBoolean(this->value->multiLine()));
}
+PropertyDescriptor *RegExpObject::lastIndexProperty(ExecutionContext *ctx)
+{
+ return members->find(ctx->engine->newIdentifier(QStringLiteral("lastIndex")));
+}
+
+
RegExpCtor::RegExpCtor(ExecutionContext *scope)
: FunctionObject(scope)
arg = __qmljs_to_string(arg, ctx);
QString s = arg.stringValue()->toQString();
- int offset = r->global ? r->lastIndexProperty->value.toInt32(ctx) : 0;
+ int offset = r->global ? r->lastIndexProperty(ctx)->value.toInt32(ctx) : 0;
if (offset < 0 || offset > s.length()) {
- r->lastIndexProperty->value = Value::fromInt32(0);
+ r->lastIndexProperty(ctx)->value = Value::fromInt32(0);
return Value::nullValue();
}
uint* matchOffsets = (uint*)alloca(r->value->captureCount() * 2 * sizeof(uint));
int result = r->value->match(s, offset, matchOffsets);
if (result == -1) {
- r->lastIndexProperty->value = Value::fromInt32(0);
+ r->lastIndexProperty(ctx)->value = Value::fromInt32(0);
return Value::nullValue();
}
array->__put__(ctx, QLatin1String("input"), arg);
if (r->global)
- r->lastIndexProperty->value = Value::fromInt32(matchOffsets[1]);
+ r->lastIndexProperty(ctx)->value = Value::fromInt32(matchOffsets[1]);
return Value::fromObject(array);
}
struct RegExpObject: Object {
RefPtr<RegExp> value;
- PropertyDescriptor *lastIndexProperty;
+ PropertyDescriptor *lastIndexProperty(ExecutionContext *ctx);
bool global;
RegExpObject(ExecutionEngine *engine, PassRefPtr<RegExp> value, bool global);
};
offset = qMax(offset + 1, matchOffsets[oldSize + 1]);
}
if (regExp->global)
- regExp->lastIndexProperty->value = Value::fromUInt32(0);
+ regExp->lastIndexProperty(ctx)->value = Value::fromUInt32(0);
numStringMatches = matchOffsets.size() / (regExp->value->captureCount() * 2);
numCaptures = regExp->value->captureCount();
} else {