TiValue TiObject::lookupSetter(TiExcState*, const Identifier& propertyName) { TiObject* object = this; while (true) { if (TiValue value = object->getDirect(propertyName)) { if (!value.isGetterSetter()) return jsUndefined(); TiObject* functionObject = asGetterSetter(value)->setter(); if (!functionObject) return jsUndefined(); return functionObject; } if (!object->prototype() || !object->prototype().isObject()) return jsUndefined(); object = asObject(object->prototype()); } }
// ECMA 8.6.2.2 void TiObject::put(TiExcState* exec, const Identifier& propertyName, TiValue value, PutPropertySlot& slot) { ASSERT(value); ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this)); if (propertyName == exec->propertyNames().underscoreProto) { // Setting __proto__ to a non-object, non-null value is silently ignored to match Mozilla. if (!value.isObject() && !value.isNull()) return; TiValue nextPrototypeValue = value; while (nextPrototypeValue && nextPrototypeValue.isObject()) { TiObject* nextPrototype = asObject(nextPrototypeValue)->unwrappedObject(); if (nextPrototype == this) { throwError(exec, GeneralError, "cyclic __proto__ value"); return; } nextPrototypeValue = nextPrototype->prototype(); } setPrototype(value); return; } // Check if there are any setters or getters in the prototype chain TiValue prototype; for (TiObject* obj = this; !obj->structure()->hasGetterSetterProperties(); obj = asObject(prototype)) { prototype = obj->prototype(); if (prototype.isNull()) { putDirectInternal(exec->globalData(), propertyName, value, 0, true, slot); return; } } unsigned attributes; TiCell* specificValue; if ((m_structure->get(propertyName, attributes, specificValue) != WTI::notFound) && attributes & ReadOnly) return; for (TiObject* obj = this; ; obj = asObject(prototype)) { if (TiValue gs = obj->getDirect(propertyName)) { if (gs.isGetterSetter()) { TiObject* setterFunc = asGetterSetter(gs)->setter(); if (!setterFunc) { throwSetterError(exec); return; } CallData callData; CallType callType = setterFunc->getCallData(callData); MarkedArgumentBuffer args; args.append(value); call(exec, setterFunc, callType, callData, this, args); return; } // If there's an existing property on the object or one of its // prototypes it should be replaced, so break here. break; } prototype = obj->prototype(); if (prototype.isNull()) break; } putDirectInternal(exec->globalData(), propertyName, value, 0, true, slot); return; }