Пример #1
0
ReturnedValue ObjectIterator::nextPropertyNameAsString()
{
    if (!object->as<Object>())
        return Encode::null();

    PropertyAttributes attrs;
    uint index;
    Scope scope(engine);
    ScopedProperty p(scope);
    ScopedString name(scope);
    next(name.getRef(), &index, p, &attrs);
    if (attrs.isEmpty())
        return Encode::null();

    if (!!name)
        return name->asReturnedValue();
    Q_ASSERT(index < UINT_MAX);
    return Encode(engine->newString(QString::number(index)));
}
InternalClass *InternalClass::sealed()
{
    if (m_sealed)
        return m_sealed;

    m_sealed = engine->emptyClass;
    m_sealed = m_sealed->changeVTable(vtable);
    m_sealed = m_sealed->changePrototype(prototype);
    for (uint i = 0; i < size; ++i) {
        PropertyAttributes attrs = propertyData.at(i);
        if (attrs.isEmpty())
            continue;
        attrs.setConfigurable(false);
        m_sealed = m_sealed->addMember(nameMap.at(i), attrs);
    }

    m_sealed->m_sealed = m_sealed;
    return m_sealed;
}
Пример #3
0
void Object::insertMember(String *s, const Property *p, PropertyAttributes attributes)
{
    uint idx;
    InternalClass::addMember(this, s, attributes, &idx);

    if (attributes.isAccessor()) {
        setProperty(idx + GetterOffset, p->value);
        setProperty(idx + SetterOffset, p->set);
    } else {
        setProperty(idx, p->value);
    }
}
Пример #4
0
ReturnedValue ObjectIterator::nextPropertyName(Value *value)
{
    if (!object->asObject())
        return Encode::null();

    PropertyAttributes attrs;
    uint index;
    Scope scope(engine);
    ScopedProperty p(scope);
    ScopedString name(scope);
    next(name.getRef(), &index, p, &attrs);
    if (attrs.isEmpty())
        return Encode::null();

    *value = object->objectValue()->getValue(p, attrs);

    if (!!name)
        return name->asReturnedValue();
    assert(index < UINT_MAX);
    return Encode(index);
}
ReturnedValue ObjectIterator::nextPropertyName(ValueRef value)
{
    if (!object)
        return Encode::null();

    PropertyAttributes attrs;
    Property p;
    uint index;
    Scope scope(object->engine());
    ScopedString name(scope);
    next(name, &index, &p, &attrs);
    if (attrs.isEmpty())
        return Encode::null();

    value = object->getValue(&p, attrs);

    if (!!name)
        return name->asReturnedValue();
    assert(index < UINT_MAX);
    return Encode(index);
}
Пример #6
0
ReturnedValue ObjectIterator::nextPropertyNameAsString()
{
    if (!object->asObject())
        return Encode::null();

    PropertyAttributes attrs;
    Property p;
    uint index;
    Scope scope(object->engine());
    ScopedString name(scope);
    String *n;
    next(n, &index, &p, &attrs);
    name = n;
    if (attrs.isEmpty())
        return Encode::null();

    if (!!name)
        return name->asReturnedValue();
    assert(index < UINT_MAX);
    return Encode(object->engine()->newString(QString::number(index)));
}
Пример #7
0
ReturnedValue Object::getLookup(const Managed *m, Lookup *l)
{
    const Object *o = static_cast<const Object *>(m);
    PropertyAttributes attrs;
    ReturnedValue v = l->lookup(o, &attrs);
    if (v != Primitive::emptyValue().asReturnedValue()) {
        l->proto = l->classList[0]->prototype;
        if (attrs.isData()) {
            Q_ASSERT(l->classList[0] == o->internalClass());
            if (l->level == 0) {
                uint nInline = o->d()->vtable()->nInlineProperties;
                if (l->index < nInline)
                    l->getter = Lookup::getter0Inline;
                else {
                    l->index -= nInline;
                    l->getter = Lookup::getter0MemberData;
                }
                }
            else if (l->level == 1)
                l->getter = Lookup::getter1;
            else if (l->level == 2)
                l->getter = Lookup::getter2;
            else
                l->getter = Lookup::getterFallback;
            return v;
        } else {
            if (l->level == 0)
                l->getter = Lookup::getterAccessor0;
            else if (l->level == 1)
                l->getter = Lookup::getterAccessor1;
            else if (l->level == 2)
                l->getter = Lookup::getterAccessor2;
            else
                l->getter = Lookup::getterFallback;
            return v;
        }
    }
    return Encode::undefined();
}
ReturnedValue Object::getValue(const ValueRef thisObject, const Property *p, PropertyAttributes attrs)
{
    if (!attrs.isAccessor())
        return p->value.asReturnedValue();
    FunctionObject *getter = p->getter();
    if (!getter)
        return Encode::undefined();

    Scope scope(getter->engine());
    ScopedCallData callData(scope, 0);
    callData->thisObject = *thisObject;
    return getter->call(callData);
}
Пример #9
0
ReturnedValue Object::getValue(const Value &thisObject, const Value &v, PropertyAttributes attrs)
{
    if (!attrs.isAccessor())
        return v.asReturnedValue();
    const QV4::FunctionObject *f = v.as<FunctionObject>();
    if (!f)
        return Encode::undefined();

    Scope scope(f->engine());
    ScopedCallData callData(scope);
    callData->thisObject = thisObject;
    f->call(scope, callData);
    return scope.result.asReturnedValue();
}
void InternalClass::addMember(Object *object, String *string, PropertyAttributes data, uint *index)
{
    data.resolve();
    object->internalClass->engine->identifierTable->identifier(string);
    if (object->internalClass->propertyTable.lookup(string->identifier) < object->internalClass->size) {
        changeMember(object, string, data, index);
        return;
    }

    uint idx;
    InternalClass *newClass = object->internalClass->addMemberImpl(string, data, &idx);
    if (index)
        *index = idx;

    object->internalClass = newClass;
}
void Object::insertMember(const StringRef s, const Property &p, PropertyAttributes attributes)
{
    uint idx;
    InternalClass::addMember(this, s.getPointer(), attributes, &idx);


    ensureMemberIndex(internalClass->size);

    if (attributes.isAccessor()) {
        hasAccessorProperty = 1;
        Property *pp = propertyAt(idx);
        pp->value = p.value;
        pp->set = p.set;
    } else {
        memberData[idx] = p.value;
    }
}
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();
}
Пример #13
0
bool Object::internalPutIndexed(uint index, const Value &value)
{
    ExecutionEngine *engine = this->engine();
    if (engine->hasException)
        return false;

    PropertyAttributes attrs;

    ArrayData::Index arrayIndex = arrayData() ? arrayData()->getValueOrSetter(index, &attrs) : ArrayData::Index{ 0, 0 };

    if (arrayIndex.isNull() && isStringObject()) {
        if (index < static_cast<StringObject *>(this)->length())
            // not writable
            goto reject;
    }

    // clause 1
    if (!arrayIndex.isNull()) {
        if (attrs.isAccessor()) {
            if (arrayIndex->as<FunctionObject>())
                goto cont;
            goto reject;
        } else if (!attrs.isWritable())
            goto reject;

        arrayIndex.set(engine, value);
        return true;
    } else if (!prototype()) {
        if (!isExtensible())
            goto reject;
    } else {
        // clause 4
        Scope scope(engine);
        arrayIndex = ScopedObject(scope, prototype())->getValueOrSetter(index, &attrs);
        if (!arrayIndex.isNull()) {
            if (attrs.isAccessor()) {
                if (!arrayIndex->as<FunctionObject>())
                    goto reject;
            } else if (!isExtensible() || !attrs.isWritable()) {
                goto reject;
            }
        } else if (!isExtensible()) {
            goto reject;
        }
    }

    cont:

    // Clause 5
    if (!arrayIndex.isNull() && attrs.isAccessor()) {
        Q_ASSERT(arrayIndex->as<FunctionObject>());

        Scope scope(engine);
        ScopedFunctionObject setter(scope, *arrayIndex);
        ScopedCallData callData(scope, 1);
        callData->args[0] = value;
        callData->thisObject = this;
        setter->call(scope, callData);
        return !internalClass()->engine->hasException;
    }

    arraySet(index, value);
    return true;

  reject:
    // ### this should be removed once everything is ported to use Object::setIndexed()
    if (engine->current->strictMode)
        engine->throwTypeError();
    return false;
}
Пример #14
0
// 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;
}
Пример #15
0
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();
}
Пример #16
0
// Section 8.12.5
bool Object::internalPut(String *name, const Value &value)
{
    ExecutionEngine *engine = this->engine();
    if (engine->hasException)
        return false;

    uint idx = name->asArrayIndex();
    if (idx != UINT_MAX)
        return putIndexed(idx, value);

    name->makeIdentifier();
    Identifier *id = name->identifier();

    MemberData::Index memberIndex{0, 0};
    uint member = internalClass()->find(id);
    PropertyAttributes attrs;
    if (member < UINT_MAX) {
        attrs = internalClass()->propertyData[member];
        memberIndex = d()->writablePropertyData(attrs.isAccessor() ? member + SetterOffset : member);
    }

    // clause 1
    if (!memberIndex.isNull()) {
        if (attrs.isAccessor()) {
            if (memberIndex->as<FunctionObject>())
                goto cont;
            goto reject;
        } else if (!attrs.isWritable())
            goto reject;
        else if (isArrayObject() && name->equals(engine->id_length())) {
            bool ok;
            uint l = value.asArrayLength(&ok);
            if (!ok) {
                engine->throwRangeError(value);
                return false;
            }
            ok = setArrayLength(l);
            if (!ok)
                goto reject;
        } else {
            memberIndex.set(engine, value);
        }
        return true;
    } else if (!prototype()) {
        if (!isExtensible())
            goto reject;
    } else {
        // clause 4
        Scope scope(engine);
        memberIndex = ScopedObject(scope, prototype())->getValueOrSetter(name, &attrs);
        if (!memberIndex.isNull()) {
            if (attrs.isAccessor()) {
                if (!memberIndex->as<FunctionObject>())
                    goto reject;
            } else if (!isExtensible() || !attrs.isWritable()) {
                goto reject;
            }
        } else if (!isExtensible()) {
            goto reject;
        }
    }

    cont:

    // Clause 5
    if (!memberIndex.isNull() && attrs.isAccessor()) {
        Q_ASSERT(memberIndex->as<FunctionObject>());

        Scope scope(engine);
        ScopedFunctionObject setter(scope, *memberIndex);
        ScopedCallData callData(scope, 1);
        callData->args[0] = value;
        callData->thisObject = this;
        setter->call(scope, callData);
        return !internalClass()->engine->hasException;
    }

    insertMember(name, value);
    return true;

  reject:
    // ### this should be removed once everything is ported to use Object::set()
    if (engine->current->strictMode) {
        QString message = QLatin1String("Cannot assign to read-only property \"") +
                name->toQString() + QLatin1Char('\"');
        engine->throwTypeError(message);
    }
    return false;
}
// Section 8.12.5
void Object::internalPut(const StringRef name, const ValueRef value)
{
    if (internalClass->engine->hasException)
        return;

    uint idx = name->asArrayIndex();
    if (idx != UINT_MAX)
        return putIndexed(idx, value);

    name->makeIdentifier();

    uint member = internalClass->find(name.getPointer());
    Property *pd = 0;
    PropertyAttributes attrs;
    if (member < UINT_MAX) {
        pd = propertyAt(member);
        attrs = internalClass->propertyData[member];
    }

    // clause 1
    if (pd) {
        if (attrs.isAccessor()) {
            if (pd->setter())
                goto cont;
            goto reject;
        } else if (!attrs.isWritable())
            goto reject;
        else if (isArrayObject() && name->equals(engine()->id_length)) {
            bool ok;
            uint l = value->asArrayLength(&ok);
            if (!ok) {
                engine()->currentContext()->throwRangeError(value);
                return;
            }
            ok = setArrayLength(l);
            if (!ok)
                goto reject;
        } else {
            pd->value = *value;
        }
        return;
    } else if (!prototype()) {
        if (!extensible)
            goto reject;
    } else {
        // clause 4
        if ((pd = prototype()->__getPropertyDescriptor__(name, &attrs))) {
            if (attrs.isAccessor()) {
                if (!pd->setter())
                    goto reject;
            } else if (!extensible || !attrs.isWritable()) {
                goto reject;
            }
        } else if (!extensible) {
            goto reject;
        }
    }

    cont:

    // Clause 5
    if (pd && attrs.isAccessor()) {
        assert(pd->setter() != 0);

        Scope scope(engine());
        ScopedCallData callData(scope, 1);
        callData->args[0] = *value;
        callData->thisObject = this;
        pd->setter()->call(callData);
        return;
    }

    insertMember(name, value);
    return;

  reject:
    if (engine()->currentContext()->strictMode) {
        QString message = QStringLiteral("Cannot assign to read-only property \"");
        message += name->toQString();
        message += QLatin1Char('\"');
        engine()->currentContext()->throwTypeError(message);
    }
}
void Object::internalPutIndexed(uint index, const ValueRef value)
{
    if (internalClass->engine->hasException)
        return;

    PropertyAttributes attrs;

    Property *pd = arrayData->getProperty(index);
    if (pd)
        attrs = arrayData->attributes(index);

    if (!pd && isStringObject()) {
        pd = static_cast<StringObject *>(this)->getIndex(index);
        if (pd)
            // not writable
            goto reject;
    }

    // clause 1
    if (pd) {
        if (attrs.isAccessor()) {
            if (pd->setter())
                goto cont;
            goto reject;
        } else if (!attrs.isWritable())
            goto reject;
        else
            pd->value = *value;
        return;
    } else if (!prototype()) {
        if (!extensible)
            goto reject;
    } else {
        // clause 4
        if ((pd = prototype()->__getPropertyDescriptor__(index, &attrs))) {
            if (attrs.isAccessor()) {
                if (!pd->setter())
                    goto reject;
            } else if (!extensible || !attrs.isWritable()) {
                goto reject;
            }
        } else if (!extensible) {
            goto reject;
        }
    }

    cont:

    // Clause 5
    if (pd && attrs.isAccessor()) {
        assert(pd->setter() != 0);

        Scope scope(engine());
        ScopedCallData callData(scope, 1);
        callData->args[0] = *value;
        callData->thisObject = this;
        pd->setter()->call(callData);
        return;
    }

    arraySet(index, value);
    return;

  reject:
    if (engine()->currentContext()->strictMode)
        engine()->currentContext()->throwTypeError();
}
Пример #19
0
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;
}
// 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;
}
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;
}