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; }
// 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; }