// 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(); }
ReturnedValue ExecutionContext::getPropertyAndBase(const StringRef name, ObjectRef base) { Scope scope(this); ScopedValue v(scope); base = (Object *)0; name->makeIdentifier(); if (name->equals(engine->id_this)) return callData->thisObject.asReturnedValue(); bool hasWith = false; bool hasCatchScope = false; for (ExecutionContext *ctx = this; ctx; ctx = ctx->outer) { if (ctx->type == Type_WithContext) { Object *w = static_cast<WithContext *>(ctx)->withObject; hasWith = true; bool hasProperty = false; v = w->get(name, &hasProperty); if (hasProperty) { base = w; return v.asReturnedValue(); } continue; } else if (ctx->type == Type_CatchContext) { hasCatchScope = true; CatchContext *c = static_cast<CatchContext *>(ctx); if (c->exceptionVarName->isEqualTo(name)) return c->exceptionValue.asReturnedValue(); } else if (ctx->type >= Type_CallContext) { QV4::CallContext *c = static_cast<CallContext *>(ctx); FunctionObject *f = c->function; if (f->function && (f->needsActivation || hasWith || hasCatchScope)) { uint index = f->function->internalClass->find(name); if (index < UINT_MAX) { if (index < c->function->formalParameterCount) return c->callData->args[c->function->formalParameterCount - index - 1].asReturnedValue(); return c->locals[index - c->function->formalParameterCount].asReturnedValue(); } } if (c->activation) { bool hasProperty = false; v = c->activation->get(name, &hasProperty); if (hasProperty) { if (ctx->type == Type_QmlContext) base = c->activation; return v.asReturnedValue(); } } if (f->function && f->function->isNamedExpression() && name->equals(f->function->name)) return c->function->asReturnedValue(); } else if (ctx->type == Type_GlobalContext) { GlobalContext *g = static_cast<GlobalContext *>(ctx); bool hasProperty = false; v = g->global->get(name, &hasProperty); if (hasProperty) return v.asReturnedValue(); } } ScopedValue n(scope, name.asReturnedValue()); return throwReferenceError(n); }
// 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); } }