bool Object::hasOwnProperty(const StringRef name) const { uint idx = name->asArrayIndex(); if (idx != UINT_MAX) return hasOwnProperty(idx); if (internalClass->find(name) < UINT_MAX) return true; if (!query(name).isEmpty()) return true; return false; }
PropertyAttributes Object::query(const Managed *m, StringRef name) { uint idx = name->asArrayIndex(); if (idx != UINT_MAX) return queryIndexed(m, idx); const Object *o = static_cast<const Object *>(m); idx = o->internalClass->find(name.getPointer()); if (idx < UINT_MAX) return o->internalClass->propertyData[idx]; return Attr_Invalid; }
bool Object::hasProperty(const StringRef name) const { uint idx = name->asArrayIndex(); if (idx != UINT_MAX) return hasProperty(idx); const Object *o = this; while (o) { if (o->hasOwnProperty(name)) return true; o = o->prototype(); } return false; }
// Section 8.12.7 bool Object::internalDeleteProperty(const StringRef name) { if (internalClass->engine->hasException) return false; uint idx = name->asArrayIndex(); if (idx != UINT_MAX) return deleteIndexedProperty(idx); name->makeIdentifier(); uint memberIdx = internalClass->find(name); if (memberIdx != UINT_MAX) { if (internalClass->propertyData[memberIdx].isConfigurable()) { InternalClass::removeMember(this, name->identifier); return true; } if (engine()->currentContext()->strictMode) engine()->currentContext()->throwTypeError(); return false; } return true; }
// Section 8.12.3 ReturnedValue Object::internalGet(const StringRef name, bool *hasProperty) { uint idx = name->asArrayIndex(); if (idx != UINT_MAX) return getIndexed(idx, hasProperty); name->makeIdentifier(); Object *o = this; while (o) { uint idx = o->internalClass->find(name.getPointer()); if (idx < UINT_MAX) { if (hasProperty) *hasProperty = true; return getValue(o->propertyAt(idx), o->internalClass->propertyData.at(idx)); } o = o->prototype(); } if (hasProperty) *hasProperty = false; return Encode::undefined(); }
// 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; }
// 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); } }