// Section 8.12.9 bool Object::__defineOwnProperty__(ExecutionEngine *engine, String *name, const Property *p, PropertyAttributes attrs) { uint idx = name->asArrayIndex(); if (idx != UINT_MAX) return __defineOwnProperty__(engine, idx, p, attrs); Scope scope(engine); name->makeIdentifier(); uint memberIndex; if (isArrayObject() && name->equals(engine->id_length())) { Q_ASSERT(Heap::ArrayObject::LengthPropertyIndex == internalClass()->find(engine->id_length())); ScopedProperty lp(scope); PropertyAttributes cattrs; getProperty(Heap::ArrayObject::LengthPropertyIndex, lp, &cattrs); if (attrs.isEmpty() || p->isSubset(attrs, lp, cattrs)) return true; if (!cattrs.isWritable() || attrs.type() == PropertyAttributes::Accessor || attrs.isConfigurable() || attrs.isEnumerable()) goto reject; bool succeeded = true; if (attrs.type() == PropertyAttributes::Data) { bool ok; uint l = p->value.asArrayLength(&ok); if (!ok) { ScopedValue v(scope, p->value); engine->throwRangeError(v); return false; } succeeded = setArrayLength(l); } if (attrs.hasWritable() && !attrs.isWritable()) { cattrs.setWritable(false); InternalClass::changeMember(this, engine->id_length(), cattrs); } if (!succeeded) goto reject; return true; } // Clause 1 memberIndex = internalClass()->find(name->identifier()); if (memberIndex == UINT_MAX) { // clause 3 if (!isExtensible()) goto reject; // clause 4 ScopedProperty pd(scope); pd->copy(p, attrs); pd->fullyPopulated(&attrs); insertMember(name, pd, attrs); return true; } return __defineOwnProperty__(engine, memberIndex, name, p, attrs); reject: if (engine->current->strictMode) engine->throwTypeError(); return false; }
void Object::advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *pd, PropertyAttributes *attrs) { Object *o = static_cast<Object *>(m); name->setM(0); *index = UINT_MAX; if (o->arrayData()) { if (!it->arrayIndex) it->arrayNode = o->sparseBegin(); // sparse arrays if (it->arrayNode) { while (it->arrayNode != o->sparseEnd()) { int k = it->arrayNode->key(); uint pidx = it->arrayNode->value; Heap::SparseArrayData *sa = o->d()->arrayData.cast<Heap::SparseArrayData>(); const Property *p = reinterpret_cast<const Property *>(sa->values.data() + pidx); it->arrayNode = it->arrayNode->nextNode(); PropertyAttributes a = sa->attrs ? sa->attrs[pidx] : Attr_Data; if (!(it->flags & ObjectIterator::EnumerableOnly) || a.isEnumerable()) { it->arrayIndex = k + 1; *index = k; *attrs = a; pd->copy(p, a); return; } } it->arrayNode = 0; it->arrayIndex = UINT_MAX; } // dense arrays while (it->arrayIndex < o->d()->arrayData->values.size) { Heap::SimpleArrayData *sa = o->d()->arrayData.cast<Heap::SimpleArrayData>(); const Value &val = sa->data(it->arrayIndex); PropertyAttributes a = o->arrayData()->attributes(it->arrayIndex); ++it->arrayIndex; if (!val.isEmpty() && (!(it->flags & ObjectIterator::EnumerableOnly) || a.isEnumerable())) { *index = it->arrayIndex - 1; *attrs = a; pd->value = val; return; } } } while (it->memberIndex < o->internalClass()->size) { Identifier *n = o->internalClass()->nameMap.at(it->memberIndex); if (!n) { // accessor properties have a dummy entry with n == 0 ++it->memberIndex; continue; } int idx = it->memberIndex; PropertyAttributes a = o->internalClass()->propertyData[it->memberIndex]; ++it->memberIndex; if (!(it->flags & ObjectIterator::EnumerableOnly) || a.isEnumerable()) { name->setM(o->engine()->identifierTable->stringFromIdentifier(n)); *attrs = a; pd->value = *o->propertyData(idx); if (a.isAccessor()) pd->set = *o->propertyData(idx + SetterOffset); return; } } *attrs = PropertyAttributes(); }
bool Object::__defineOwnProperty__(ExecutionEngine *engine, uint index, String *member, const Property *p, PropertyAttributes attrs) { // clause 5 if (attrs.isEmpty()) return true; Scope scope(engine); ScopedProperty current(scope); PropertyAttributes cattrs; if (member) { getProperty(index, current, &cattrs); cattrs = internalClass()->propertyData[index]; } else if (arrayData()) { arrayData()->getProperty(index, current, &cattrs); cattrs = arrayData()->attributes(index); } // clause 6 if (p->isSubset(attrs, current, cattrs)) return true; // clause 7 if (!cattrs.isConfigurable()) { if (attrs.isConfigurable()) goto reject; if (attrs.hasEnumerable() && attrs.isEnumerable() != cattrs.isEnumerable()) goto reject; } // clause 8 if (attrs.isGeneric() || current->value.isEmpty()) goto accept; // clause 9 if (cattrs.isData() != attrs.isData()) { // 9a if (!cattrs.isConfigurable()) goto reject; if (cattrs.isData()) { // 9b cattrs.setType(PropertyAttributes::Accessor); cattrs.clearWritable(); if (!member) { // need to convert the array and the slot initSparseArray(); Q_ASSERT(arrayData()); setArrayAttributes(index, cattrs); } current->setGetter(0); current->setSetter(0); } else { // 9c cattrs.setType(PropertyAttributes::Data); cattrs.setWritable(false); if (!member) { // need to convert the array and the slot setArrayAttributes(index, cattrs); } current->value = Primitive::undefinedValue(); } } 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 Q_ASSERT(cattrs.isAccessor() && attrs.isAccessor()); if (!cattrs.isConfigurable()) { if (!p->value.isEmpty() && current->value.rawValue() != p->value.rawValue()) goto reject; if (!p->set.isEmpty() && current->set.rawValue() != p->set.rawValue()) goto reject; } } accept: current->merge(cattrs, p, attrs); if (member) { InternalClass::changeMember(this, member, cattrs); setProperty(index, current); } else { setArrayAttributes(index, cattrs); arrayData()->setProperty(scope.engine, index, current); } return true; reject: if (engine->current->strictMode) engine->throwTypeError(); return false; }
bool Object::__defineOwnProperty__(ExecutionContext *ctx, uint index, const StringRef member, const Property &p, PropertyAttributes attrs) { // clause 5 if (attrs.isEmpty()) return true; Property *current; PropertyAttributes cattrs; if (!member.isNull()) { current = propertyAt(index); cattrs = internalClass->propertyData[index]; } else { current = arrayData->getProperty(index); cattrs = arrayData->attributes(index); } // clause 6 if (p.isSubset(attrs, *current, cattrs)) return true; // clause 7 if (!cattrs.isConfigurable()) { if (attrs.isConfigurable()) goto reject; if (attrs.hasEnumerable() && attrs.isEnumerable() != cattrs.isEnumerable()) goto reject; } // clause 8 if (attrs.isGeneric() || current->value.isEmpty()) goto accept; // clause 9 if (cattrs.isData() != attrs.isData()) { // 9a if (!cattrs.isConfigurable()) goto reject; if (cattrs.isData()) { // 9b cattrs.setType(PropertyAttributes::Accessor); cattrs.clearWritable(); if (member.isNull()) { // need to convert the array and the slot initSparseArray(); setArrayAttributes(index, cattrs); current = arrayData->getProperty(index); } current->setGetter(0); current->setSetter(0); } else { // 9c cattrs.setType(PropertyAttributes::Data); cattrs.setWritable(false); if (member.isNull()) { // need to convert the array and the slot setArrayAttributes(index, cattrs); current = arrayData->getProperty(index); } current->value = Primitive::undefinedValue(); } } 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 Q_ASSERT(cattrs.isAccessor() && attrs.isAccessor()); if (!cattrs.isConfigurable()) { if (!p.value.isEmpty() && current->value.val != p.value.val) goto reject; if (!p.set.isEmpty() && current->set.val != p.set.val) goto reject; } } accept: current->merge(cattrs, p, attrs); if (!member.isNull()) { InternalClass::changeMember(this, member.getPointer(), cattrs); } else { setArrayAttributes(index, cattrs); } if (cattrs.isAccessor()) hasAccessorProperty = 1; return true; reject: if (ctx->strictMode) ctx->throwTypeError(); return false; }
// Section 8.12.9 bool Object::__defineOwnProperty__(ExecutionContext *ctx, const StringRef name, const Property &p, PropertyAttributes attrs) { uint idx = name->asArrayIndex(); if (idx != UINT_MAX) return __defineOwnProperty__(ctx, idx, p, attrs); name->makeIdentifier(); Scope scope(ctx); Property *current; PropertyAttributes *cattrs; uint memberIndex; if (isArrayObject() && name->equals(ctx->engine->id_length)) { assert(ArrayObject::LengthPropertyIndex == internalClass->find(ctx->engine->id_length)); Property *lp = propertyAt(ArrayObject::LengthPropertyIndex); cattrs = internalClass->propertyData.constData() + ArrayObject::LengthPropertyIndex; if (attrs.isEmpty() || p.isSubset(attrs, *lp, *cattrs)) return true; if (!cattrs->isWritable() || attrs.type() == PropertyAttributes::Accessor || attrs.isConfigurable() || attrs.isEnumerable()) goto reject; bool succeeded = true; if (attrs.type() == PropertyAttributes::Data) { bool ok; uint l = p.value.asArrayLength(&ok); if (!ok) { ScopedValue v(scope, p.value); ctx->throwRangeError(v); return false; } succeeded = setArrayLength(l); } if (attrs.hasWritable() && !attrs.isWritable()) cattrs->setWritable(false); if (!succeeded) goto reject; if (attrs.isAccessor()) hasAccessorProperty = 1; return true; } // Clause 1 memberIndex = internalClass->find(name.getPointer()); current = (memberIndex < UINT_MAX) ? propertyAt(memberIndex) : 0; cattrs = internalClass->propertyData.constData() + memberIndex; if (!current) { // clause 3 if (!extensible) goto reject; // clause 4 Property pd; pd.copy(p, attrs); pd.fullyPopulated(&attrs); insertMember(name, pd, attrs); return true; } return __defineOwnProperty__(ctx, memberIndex, name, p, attrs); reject: if (ctx->strictMode) ctx->throwTypeError(); return false; }
void Object::advanceIterator(Managed *m, ObjectIterator *it, StringRef name, uint *index, Property *pd, PropertyAttributes *attrs) { Object *o = static_cast<Object *>(m); name = (String *)0; *index = UINT_MAX; if (o->arrayData) { if (!it->arrayIndex) it->arrayNode = o->sparseBegin(); // sparse arrays if (it->arrayNode) { while (it->arrayNode != o->sparseEnd()) { int k = it->arrayNode->key(); uint pidx = it->arrayNode->value; Property *p = reinterpret_cast<Property *>(o->arrayData->data + pidx); it->arrayNode = it->arrayNode->nextNode(); PropertyAttributes a = o->arrayData->attributes(k); if (!(it->flags & ObjectIterator::EnumerableOnly) || a.isEnumerable()) { it->arrayIndex = k + 1; *index = k; *attrs = a; pd->copy(*p, a); return; } } it->arrayNode = 0; it->arrayIndex = UINT_MAX; } // dense arrays while (it->arrayIndex < o->arrayData->length()) { Value *val = o->arrayData->data + it->arrayIndex; PropertyAttributes a = o->arrayData->attributes(it->arrayIndex); ++it->arrayIndex; if (!val->isEmpty() && (!(it->flags & ObjectIterator::EnumerableOnly) || a.isEnumerable())) { *index = it->arrayIndex - 1; *attrs = a; pd->value = *val; return; } } } while (it->memberIndex < o->internalClass->size) { String *n = o->internalClass->nameMap.at(it->memberIndex); if (!n) { // accessor properties have a dummy entry with n == 0 ++it->memberIndex; continue; } Property *p = o->propertyAt(it->memberIndex); PropertyAttributes a = o->internalClass->propertyData[it->memberIndex]; ++it->memberIndex; if (!(it->flags & ObjectIterator::EnumerableOnly) || a.isEnumerable()) { name = n; *attrs = a; pd->copy(*p, a); return; } } *attrs = PropertyAttributes(); }