PropertyDescriptor map;
bool isMapped = false;
if (pd && index < (uint)mappedArguments.size())
- isMapped = pd->isAccessor() && pd->get == context->engine->argumentsAccessors.at(index).get;
+ isMapped = pd->attrs.isAccessor() && pd->get == context->engine->argumentsAccessors.at(index).get;
if (isMapped) {
map = *pd;
ctx->strictMode = strict;
isNonStrictArgumentsObject = true;
- if (isMapped && desc->isData()) {
+ 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 (desc->attrs.writable())
+ if (desc->attrs.isWritable())
*pd = map;
}
void resolveConfigurable() { configurable_set = true; }
void resolveEnumerable() { enumerable_set = true; }
- bool writable() const { return m_writable; }
- bool enumerable() const { return m_enumerable; }
- bool configurable() const { return m_configurable; }
+ bool isWritable() const { return m_writable; }
+ bool isEnumerable() const { return m_enumerable; }
+ bool isConfigurable() const { return m_configurable; }
void clearType() { m_type = Data; type_set = false; }
void clearWritable() { m_writable = false; writable_set = false; }
Value Object::getValue(const Value &thisObject, ExecutionContext *ctx, const PropertyDescriptor *p)
{
assert(p->attrs.type() != PropertyAttributes::Generic);
- if (p->isData())
+ if (p->attrs.isData())
return p->value;
if (!p->get)
return Value::undefinedValue();
void Object::putValue(ExecutionContext *ctx, PropertyDescriptor *pd, const Value &value)
{
- if (pd->isAccessor()) {
+ if (pd->attrs.isAccessor()) {
if (pd->set) {
Value args[1];
args[0] = value;
goto reject;
}
- if (!pd->isWritable())
+ if (!pd->attrs.isWritable())
goto reject;
pd->value = value;
void Object::putValue(ExecutionContext *ctx, PropertyDescriptor *pd, const Value &thisObject, const Value &value)
{
- if (pd->isAccessor()) {
+ if (pd->attrs.isAccessor()) {
if (pd->set) {
Value args[1];
args[0] = value;
goto reject;
}
- if (!pd->isWritable())
+ if (!pd->attrs.isWritable())
goto reject;
pd->value = value;
for (int i = 0; i < o->internalClass->size; ++i) {
const PropertyDescriptor &pd = o->memberData[i];
- if (pd.isData()) {
+ if (pd.attrs.isData()) {
if (Managed *m = pd.value.asManaged())
m->mark();
- } else if (pd.isAccessor()) {
+ } else if (pd.attrs.isAccessor()) {
if (pd.get)
pd.get->mark();
if (pd.set)
PropertyDescriptor *pd = that->__getPropertyDescriptor__(ctx, name);
if (!pd || pd->attrs.type() == PropertyAttributes::Generic)
return Attr_Invalid;
- return pd->toPropertyAttributes();
+ return pd->attrs;
}
PropertyAttributes Object::queryIndexed(Managed *m, ExecutionContext *ctx, uint index)
PropertyDescriptor *pd = that->__getPropertyDescriptor__(ctx, index);
if (!pd || pd->attrs.type() == PropertyAttributes::Generic)
return Attr_Invalid;
- return pd->toPropertyAttributes();
+ return pd->attrs;
}
bool Object::deleteProperty(Managed *m, ExecutionContext *ctx, String *name)
// clause 1
if (pd) {
- if (pd->isAccessor()) {
+ if (pd->attrs.isAccessor()) {
if (pd->set)
goto cont;
goto reject;
- } else if (!pd->isWritable())
+ } else if (!pd->attrs.isWritable())
goto reject;
else if (isArrayObject() && name->isEqualTo(ctx->engine->id_length)) {
bool ok;
goto reject;
} else {
if (PropertyDescriptor *p = prototype->__getPropertyDescriptor__(ctx, name)) {
- if (p->isAccessor()) {
+ if (p->attrs.isAccessor()) {
if (p->set)
goto cont;
goto reject;
}
if (!extensible)
goto reject;
- if (!p->isWritable())
+ if (!p->attrs.isWritable())
goto reject;
} else {
if (!extensible)
pd = prototype->__getPropertyDescriptor__(ctx, name);
// Clause 5
- if (pd && pd->isAccessor()) {
+ if (pd && pd->attrs.isAccessor()) {
assert(pd->set != 0);
Value args[1];
// clause 1
if (pd) {
- if (pd->isAccessor()) {
+ if (pd->attrs.isAccessor()) {
if (pd->set)
goto cont;
goto reject;
- } else if (!pd->isWritable())
+ } else if (!pd->attrs.isWritable())
goto reject;
else
pd->value = value;
goto reject;
} else {
if (PropertyDescriptor *p = prototype->__getPropertyDescriptor__(ctx, index)) {
- if (p->isAccessor()) {
+ if (p->attrs.isAccessor()) {
if (p->set)
goto cont;
goto reject;
}
if (!extensible)
goto reject;
- if (!p->isWritable())
+ if (!p->attrs.isWritable())
goto reject;
} else {
if (!extensible)
pd = prototype->__getPropertyDescriptor__(ctx, index);
// Clause 5
- if (pd && pd->isAccessor()) {
+ if (pd && pd->attrs.isAccessor()) {
assert(pd->set != 0);
Value args[1];
uint memberIdx = internalClass->find(name);
if (memberIdx != UINT_MAX) {
PropertyDescriptor &pd = memberData[memberIdx];
- if (pd.isConfigurable()) {
+ if (pd.attrs.isConfigurable()) {
internalClass->removeMember(this, name->identifier);
memmove(memberData + memberIdx, memberData + memberIdx + 1, (internalClass->size - memberIdx)*sizeof(PropertyDescriptor));
return true;
if (!pd || pd->attrs.type() == PropertyAttributes::Generic)
return true;
- if (pd->isConfigurable()) {
+ if (pd->attrs.isConfigurable()) {
pd->attrs.clear();
pd->value = Value::undefinedValue();
if (sparseArray) {
if (isArrayObject() && name->isEqualTo(ctx->engine->id_length)) {
PropertyDescriptor *lp = memberData + ArrayObject::LengthPropertyIndex;
assert(0 == internalClass->find(ctx->engine->id_length));
- if (desc->isEmpty() || desc->isSubset(lp))
+ if (desc->attrs.isEmpty() || desc->isSubset(desc->attrs, lp))
return true;
- if (!lp->isWritable() || desc->attrs.type() == PropertyAttributes::Accessor || desc->isConfigurable() || desc->isEnumerable())
+ if (!lp->attrs.isWritable() || desc->attrs.type() == PropertyAttributes::Accessor || desc->attrs.isConfigurable() || desc->attrs.isEnumerable())
goto reject;
bool succeeded = true;
if (desc->attrs.type() == PropertyAttributes::Data) {
succeeded = setArrayLength(l);
}
if (desc->attrs.hasWritable())
- lp->attrs.setWritable(desc->attrs.writable());
+ lp->attrs.setWritable(desc->attrs.isWritable());
if (!succeeded)
goto reject;
return true;
if (!extensible)
goto reject;
// clause 4
- PropertyDescriptor *pd = insertMember(name, desc->toPropertyAttributes());
+ PropertyDescriptor *pd = insertMember(name, desc->attrs);
*pd = *desc;
- pd->fullyPopulated();
+ pd->fullyPopulated(&pd->attrs);
return true;
}
PropertyDescriptor *current;
// 15.4.5.1, 4b
- if (isArrayObject() && index >= arrayLength() && !memberData[ArrayObject::LengthPropertyIndex].isWritable())
+ if (isArrayObject() && index >= arrayLength() && !memberData[ArrayObject::LengthPropertyIndex].attrs.isWritable())
goto reject;
if (isNonStrictArgumentsObject)
// clause 4
PropertyDescriptor *pd = arrayInsert(index);
*pd = *desc;
- pd->fullyPopulated();
+ pd->fullyPopulated(&pd->attrs);
return true;
}
bool Object::__defineOwnProperty__(ExecutionContext *ctx, PropertyDescriptor *current, const PropertyDescriptor *desc)
{
// clause 5
- if (desc->isEmpty())
+ if (desc->attrs.isEmpty())
return true;
// clause 6
- if (desc->isSubset(current))
+ if (desc->isSubset(desc->attrs, current))
return true;
// clause 7
- if (!current->isConfigurable()) {
- if (desc->isConfigurable())
+ if (!current->attrs.isConfigurable()) {
+ if (desc->attrs.isConfigurable())
goto reject;
- if (desc->attrs.hasEnumerable() && desc->attrs.enumerable() != current->attrs.enumerable())
+ if (desc->attrs.hasEnumerable() && desc->attrs.isEnumerable() != current->attrs.isEnumerable())
goto reject;
}
// clause 8
- if (desc->isGeneric())
+ if (desc->attrs.isGeneric())
goto accept;
// clause 9
- if (current->isData() != desc->isData()) {
+ if (current->attrs.isData() != desc->attrs.isData()) {
// 9a
- if (!current->isConfigurable())
+ if (!current->attrs.isConfigurable())
goto reject;
- if (current->isData()) {
+ if (current->attrs.isData()) {
// 9b
current->attrs.setType(PropertyAttributes::Accessor);
current->attrs.clearWritable();
current->attrs.setWritable(false);
current->value = Value::undefinedValue();
}
- } else if (current->isData() && desc->isData()) { // clause 10
- if (!current->isConfigurable() && !current->isWritable()) {
- if (desc->isWritable() || !current->value.sameValue(desc->value))
+ } 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))
goto reject;
}
} else { // clause 10
- assert(current->isAccessor() && desc->isAccessor());
- if (!current->isConfigurable()) {
+ assert(current->attrs.isAccessor() && desc->attrs.isAccessor());
+ if (!current->attrs.isConfigurable()) {
if (desc->get && !(current->get == desc->get || (!current->get && (quintptr)desc->get == 0x1)))
goto reject;
if (desc->set && !(current->set == desc->set || (!current->set && (quintptr)desc->set == 0x1)))
accept:
- *current += *desc;
+ current->merge(current->attrs, *desc);
return true;
reject:
if (ctx->strictMode)
bool Object::setArrayLength(uint newLen) {
assert(isArrayObject());
const PropertyDescriptor *lengthProperty = memberData + ArrayObject::LengthPropertyIndex;
- if (lengthProperty && !lengthProperty->isWritable())
+ if (lengthProperty && !lengthProperty->attrs.isWritable())
return false;
uint oldLen = arrayLength();
bool ok = true;
SparseArrayNode *it = sparseArray->end()->previousNode();
while (1) {
PropertyDescriptor &pd = arrayData[it->value];
- if (pd.attrs.type() != PropertyAttributes::Generic && !pd.isConfigurable()) {
+ if (pd.attrs.type() != PropertyAttributes::Generic && !pd.attrs.isConfigurable()) {
ok = false;
newLen = it->key() + 1;
break;
PropertyDescriptor *it = arrayData + arrayDataLen;
const PropertyDescriptor *begin = arrayData + newLen;
while (--it >= begin) {
- if (it->attrs.type() != PropertyAttributes::Generic && !it->isConfigurable()) {
+ if (it->attrs.type() != PropertyAttributes::Generic && !it->attrs.isConfigurable()) {
ok = false;
newLen = it - arrayData + 1;
break;
{
for (uint i = 0; i < arrayDataLen; ++i) {
const PropertyDescriptor &pd = arrayData[i];
- if (pd.isData()) {
+ if (pd.attrs.isData()) {
if (Managed *m = pd.value.asManaged())
m->mark();
- } else if (pd.isAccessor()) {
+ } else if (pd.attrs.isAccessor()) {
if (pd.get)
pd.get->mark();
if (pd.set)
int k = arrayNode->key();
p = current->arrayAt(k);
arrayNode = arrayNode->nextNode();
- if (p && (!(flags & EnumberableOnly) || p->isEnumerable())) {
+ if (p && (!(flags & EnumberableOnly) || p->attrs.isEnumerable())) {
arrayIndex = k + 1;
*index = k;
return p;
while (arrayIndex < current->arrayDataLen) {
p = current->arrayAt(arrayIndex);
++arrayIndex;
- if (p && p->attrs.type() != PropertyAttributes::Generic && (!(flags & EnumberableOnly) || p->isEnumerable())) {
+ if (p && p->attrs.type() != PropertyAttributes::Generic && (!(flags & EnumberableOnly) || p->attrs.isEnumerable())) {
*index = arrayIndex - 1;
return p;
}
p = current->memberData + memberIndex;
++memberIndex;
- if (!(flags & EnumberableOnly) || p->isEnumerable()) {
+ if (!(flags & EnumberableOnly) || p->attrs.isEnumerable()) {
*name = n;
return p;
}
PropertyDescriptor *pd = it.next(&name, &index);
if (!pd)
break;
- if (pd->attrs.configurable())
+ if (pd->attrs.isConfigurable())
return Value::fromBoolean(false);
}
return Value::fromBoolean(true);
PropertyDescriptor *pd = it.next(&name, &index);
if (!pd)
break;
- if (pd->isWritable() || pd->isConfigurable())
+ if (pd->attrs.isWritable() || pd->attrs.isConfigurable())
return Value::fromBoolean(false);
}
return Value::fromBoolean(true);
Object *o = ctx->thisObject.toObject(ctx);
PropertyDescriptor *pd = o->__getOwnProperty__(ctx, p);
- return Value::fromBoolean(pd && pd->isEnumerable());
+ return Value::fromBoolean(pd && pd->attrs.isEnumerable());
}
Value ObjectPrototype::method_defineGetter(SimpleCallContext *ctx)
}
if (o->__hasProperty__(ctx, ctx->engine->id_writable)) {
- if (desc->isAccessor())
+ if (desc->attrs.isAccessor())
ctx->throwTypeError();
desc->attrs.setWritable(o->get(ctx, ctx->engine->id_writable).toBoolean());
// writable forces it to be a data descriptor
}
if (o->__hasProperty__(ctx, ctx->engine->id_value)) {
- if (desc->isAccessor())
+ if (desc->attrs.isAccessor())
ctx->throwTypeError();
desc->value = o->get(ctx, ctx->engine->id_value);
desc->attrs.setType(PropertyAttributes::Data);
PropertyDescriptor pd;
pd.attrs = Attr_Data;
- if (desc->isData()) {
+ if (desc->attrs.isData()) {
pd.value = desc->value;
o->__defineOwnProperty__(ctx, engine->newString(QStringLiteral("value")), &pd);
- pd.value = Value::fromBoolean(desc->attrs.writable());
+ pd.value = Value::fromBoolean(desc->attrs.isWritable());
o->__defineOwnProperty__(ctx, engine->newString(QStringLiteral("writable")), &pd);
} else {
pd.value = desc->get ? Value::fromObject(desc->get) : Value::undefinedValue();
pd.value = desc->set ? Value::fromObject(desc->set) : Value::undefinedValue();
o->__defineOwnProperty__(ctx, engine->newString(QStringLiteral("set")), &pd);
}
- pd.value = Value::fromBoolean(desc->attrs.enumerable());
+ pd.value = Value::fromBoolean(desc->attrs.isEnumerable());
o->__defineOwnProperty__(ctx, engine->newString(QStringLiteral("enumerable")), &pd);
- pd.value = Value::fromBoolean(desc->attrs.configurable());
+ pd.value = Value::fromBoolean(desc->attrs.isConfigurable());
o->__defineOwnProperty__(ctx, engine->newString(QStringLiteral("configurable")), &pd);
return Value::fromObject(o);
namespace VM {
struct FunctionObject;
+struct PropertyDescriptor;
struct Property {
union {
FunctionObject *set;
};
};
+
+ // 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 {
+ attrs->clearWritable();
+ if ((quintptr)get == 0x1)
+ get = 0;
+ if ((quintptr)set == 0x1)
+ set = 0;
+ }
+ attrs->resolveEnumerable();
+ attrs->resolveConfigurable();
+ }
+
+ inline bool isSubset(const PropertyAttributes &attrs, PropertyDescriptor *other) const;
+ inline void merge(PropertyAttributes &attrs, const PropertyDescriptor &other);
};
struct PropertyDescriptor : public Property
pd.attrs.setType(PropertyAttributes::Accessor);
return pd;
}
+};
- PropertyAttributes toPropertyAttributes() const {
- return attrs;
- }
-
- // Section 8.10
- inline void fullyPopulated() {
- if (!attrs.hasType()) {
- attrs.setType(PropertyAttributes::Data);
- value = Value::undefinedValue();
- }
- if (attrs.type() == PropertyAttributes::Data) {
- attrs.resolveWritable();
- } else {
- attrs.clearWritable();
- if ((quintptr)get == 0x1)
- get = 0;
- if ((quintptr)set == 0x1)
- set = 0;
- }
- attrs.resolveEnumerable();
- attrs.resolveConfigurable();
- }
-
- inline bool isData() const { return attrs.isData(); }
- inline bool isAccessor() const { return attrs.isAccessor(); }
- inline bool isGeneric() const { return attrs.isGeneric(); }
-
- inline bool isWritable() const { return attrs.writable(); }
- inline bool isEnumerable() const { return attrs.enumerable(); }
- inline bool isConfigurable() const { return attrs.configurable(); }
-
- inline bool isEmpty() const {
- return attrs.isEmpty();
- }
- inline bool isSubset(PropertyDescriptor *other) const {
- if (attrs.type() != PropertyAttributes::Generic && attrs.type() != other->attrs.type())
- return false;
- if (attrs.hasEnumerable() && attrs.enumerable() != other->attrs.enumerable())
- return false;
- if (attrs.hasConfigurable() && attrs.configurable() != other->attrs.configurable())
- return false;
- if (attrs.hasWritable() && attrs.writable() != other->attrs.writable())
+inline bool Property::isSubset(const PropertyAttributes &attrs, PropertyDescriptor *other) const
+{
+ if (attrs.type() != PropertyAttributes::Generic && attrs.type() != other->attrs.type())
+ return false;
+ if (attrs.hasEnumerable() && attrs.isEnumerable() != other->attrs.isEnumerable())
+ return false;
+ if (attrs.hasConfigurable() && attrs.isConfigurable() != other->attrs.isConfigurable())
+ return false;
+ if (attrs.hasWritable() && attrs.isWritable() != other->attrs.isWritable())
+ return false;
+ if (attrs.type() == PropertyAttributes::Data && !value.sameValue(other->value))
+ return false;
+ if (attrs.type() == PropertyAttributes::Accessor) {
+ if (get != other->get)
return false;
- if (attrs.type() == PropertyAttributes::Data && !value.sameValue(other->value))
+ if (set != other->set)
return false;
- if (attrs.type() == PropertyAttributes::Accessor) {
- if (get != other->get)
- return false;
- if (set != other->set)
- return false;
- }
- return true;
}
- inline void operator+=(const PropertyDescriptor &other) {
- if (other.attrs.hasEnumerable())
- attrs.setEnumerable(other.attrs.enumerable());
- if (other.attrs.hasConfigurable())
- attrs.setConfigurable(other.attrs.configurable());
- if (other.attrs.hasWritable())
- attrs.setWritable(other.attrs.writable());
- if (other.attrs.type() == PropertyAttributes::Accessor) {
- attrs.setType(PropertyAttributes::Accessor);
- if (other.get)
- get = ((quintptr)other.get == 0x1) ? 0 : other.get;
- if (other.set)
- set = ((quintptr)other.set == 0x1) ? 0 : other.set;
- } else if (other.attrs.type() == PropertyAttributes::Data){
- attrs.setType(PropertyAttributes::Data);
- value = other.value;
- }
+ return true;
+}
+
+inline void Property::merge(PropertyAttributes &attrs, const PropertyDescriptor &other)
+{
+ 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) {
+ attrs.setType(PropertyAttributes::Accessor);
+ if (other.get)
+ get = ((quintptr)other.get == 0x1) ? 0 : other.get;
+ if (other.set)
+ set = ((quintptr)other.set == 0x1) ? 0 : other.set;
+ } else if (other.attrs.type() == PropertyAttributes::Data){
+ attrs.setType(PropertyAttributes::Data);
+ value = other.value;
}
-};
+}
+
} // namespace VM
} // namespace QQmlJS
uint idx = index.asArrayIndex();
if (idx < UINT_MAX) {
PropertyDescriptor *p = o->nonSparseArrayAt(idx);
- if (p && p->attrs.type() == PropertyAttributes::Data && p->isWritable()) {
+ if (p && p->attrs.type() == PropertyAttributes::Data && p->attrs.isWritable()) {
p->value = value;
return;
}