bool install_slot(struct objc_object *obj, int offset, IMP method, char * types, uint32_t sel) { //Type must match selector type char * seltypes = types_for_selector(sel); if(safestrcmp(seltypes, types) != 0) { return false; } objc_lock_object(obj); if(SLOTS(obj) == NULL) { SLOTS(obj) = SparseArrayNew(); } struct objc_slot * oldSlot = SparseArrayLookup(SLOTS(obj), sel); if(oldSlot) { if(safestrcmp(types, oldSlot->types) != 0) { objc_unlock_object(obj); return false; } oldSlot->offset = offset; oldSlot->method = method; } else { //We are adding a new slot, not modifying an old one, so we need to //invalidate a load of caches. id object = obj; oldSlot = slot_lookup(&object, sel, nil); struct objc_slot * newslot = calloc(1, sizeof(struct objc_slot)); //TODO: Factor this out into a slot constructor newslot->offset = offset; newslot->method = method; if(types == NULL) { newslot->types = NULL; } else { newslot->types = strdup(types); } if(oldSlot != NULL) { oldSlot->version++; } SparseArrayInsert(SLOTS(obj), sel, newslot); } objc_unlock_object(obj); return true; }
static inline struct objc_slot * real_slot_lookup(struct objc_object ** obj, uint32_t sel, id sender) { id object = *obj; struct objc_slot * ret = NULL; do { if(LOOKUP(object)) { return (*LOOKUP(object))(obj, object, sel, sender); } if(SLOTS(object)) { ret = SparseArrayLookup(SLOTS(object), sel); } object = object->isa; } while(object != NULL && ret == NULL); return ret; }
static ATOMID get_value(WORD wType, OBJECTID idObj, ATOMID idName, BOOL *bMlt, SLOTID *idSlot) { LPSLOT lpSlot; ATOMID idValue; WORD wLen; *idSlot = NULLID; while (!*idSlot) { LPOBJECT lpObj = (LPOBJECT) KppGetItem(wType, idObj); OBJECTID idClass = CLASSOF(lpObj); if (!(FLAGS(lpObj) & REMOTE)) *idSlot = KppGetElemPair(SLOTS(lpObj), idName); KppReleaseItem(wType, idObj); if (!*idSlot) { wType = CLASS; idObj = idClass; if (!idObj) return NULLID; } } lpSlot = (LPSLOT) KppGetItem(SLOT, *idSlot); *bMlt = ISOPTMULTI(lpSlot); idValue = VALUE(lpSlot); KppReleaseItem(SLOT, *idSlot); if (*bMlt) KppCheckList(idValue, &wLen); if (!idValue || *bMlt && !wLen) idValue = lpIDs->idNull; return idValue; }
WORD PEXPORT Kpp_Set_SlotValue(WORD wType, OBJECTID idObj, ATOMID idSlotName, ITEMID idValue, WORD wIdType) { LPOBJECT lpObj = (LPOBJECT) KppGetItem(wType, idObj); LPSLOT lpSlot = NULL; ATOMID idObjName; SLOTID idSlot = NULLID, idSlot2; LISTID idList; OBJECTID idClass; WORD wCode, wInherited = FALSE; if (!lpObj) return ERROR; idObjName = NAME(lpObj); idClass = CLASSOF(lpObj); idList = SLOTS(lpObj); if (idList) idSlot = KppGetElemPair(idList, idSlotName); if (!idSlot) { wInherited = TRUE; idSlot = Kpp_Get_Slot(CLASS, idClass, idSlotName); } if (KppIsRemoteObject(wType, idObj) && IsRemoteSlot(idSlot, &lpSlot, TRUE)) { if (!InvokeRemoteSlotOP(idObj, idSlotName, (BOOL *) &wIdType, idSlot, lpSlot, &idValue, REMOTE_SET_VALUE)) return NULLID; if (!idSlot || wIdType == EXPLIST) return idValue; } if (!idSlot) { KppReleaseItem(wType, idObj); return ERROR; } lpSlot = (LPSLOT) KppGetItem(SLOT, idSlot); if (!lpSlot) { KppReleaseItem(wType, idObj); return ERROR; } /* Check if compatible value & slot (single or multi) */ if (idValue && idValue != lpIDs->idNull) { wCode = ISOPTMULTI(lpSlot); if (wCode && wIdType != EXPLIST || !wCode && wIdType != EXPATOM) { KppReleaseItem(SLOT, idSlot); KppReleaseItem(wType, idObj); return ERROR; } } if (!idValue) /* ResetValue */ { WORD wDelete; KppReleaseItem(wType, idObj); if (wInherited == TRUE) { KppReleaseItem(SLOT, idSlot); return lpIDs->idNull; } if (!_ResetSlotValue(LOBYTE(wType), lpSlot, idObj, idObjName, wIdType, &wDelete)) { KppReleaseItem(SLOT, idSlot); return ERROR; } if (wDelete) { KppDeleteElemPair(idList, idSlotName); KppDeleteItem(SLOT, idSlot); } KppReleaseItem(SLOT, idSlot); return lpIDs->idNull; } if (wInherited == TRUE) /* make a copy before setting the value */ { KppReleaseItem(SLOT, idSlot); idSlot2 = Kpp__Inherit_Slot(idSlot, (LPLPSTR) &lpSlot); if (!idSlot2) { KppReleaseItem(wType, idObj); return ERROR; } idSlot = idSlot2; if (!idList) idList = SLOTS(lpObj) = KppMakeList(0); KppAppendElemPair(idList, idSlotName, idSlot); } KppReleaseItem(wType, idObj); wCode = __SetSlotValue(wType, idObj, idSlot, lpSlot, idValue, idObjName, wIdType); KppReleaseItem(SLOT, idSlot); return wCode; }
ITEMID PEXPORT Kpp_Get_SlotListValue(WORD wType, OBJECTID idObj, ATOMID idSlotName) { LPOBJECT lpObj; ITEMID idSlot; LPSLOT lpSlot = NULL; ITEMID idValue = NULLID, idList, idMethod; ATOMID idINMethodName, idWAMethodName; LPMETHOD lpMethod; CLASSID idClass; WORD wNumVars; WORD i = FALSE; BOOL bMonitor; idSlot = Kpp_Get_LocalSlot(wType, idObj, idSlotName); if (KppIsRemoteObject(wType, idObj) && IsRemoteSlot(idSlot, &lpSlot, FALSE)) { BOOL bMulti; ITEMID idValue; if (!InvokeRemoteSlotOP(idObj, idSlotName, &bMulti, idSlot, lpSlot, &idValue, REMOTE_GET_VALUE)) return NULLID; if (!bMulti) return NULLID; return idValue; } if (!idSlot) { lpObj = (LPOBJECT) KppGetItem(wType, idObj); if (!lpObj) return ERROR; idClass = CLASSOF(lpObj); if (!idClass || (!(idSlot = Kpp_Copy_Slot(CLASS, idClass, idSlotName))) || (!(lpSlot = (LPSLOT) KppGetItem(SLOT, idSlot)))) { KppReleaseItem(wType, idObj); if (idSlot) KppDeleteItem(SLOT, idSlot); return NULLID; } if (!ISOPTMULTI(lpSlot)) { KppReleaseItem(wType, idObj); KppReleaseItem(SLOT, idSlot); KppDeleteItem(SLOT, idSlot); return NULLID; } idValue = VALUE(lpSlot); if (!(idList = SLOTS(lpObj))) idList = SLOTS(lpObj) = KppMakeList(0); KppReleaseItem(wType, idObj); KppAppendElemPair(idList, idSlotName, idSlot); } else { if (!(lpSlot = (LPSLOT) KppGetItem(SLOT, idSlot))) return NULLID; if (!ISOPTMULTI(lpSlot)) { KppReleaseItem(SLOT, idSlot); return NULLID; } idValue = VALUE(lpSlot); } idINMethodName = OPTNEEDED(lpSlot); idWAMethodName = OPTWACCESS(lpSlot); KppReleaseItem(SLOT, idSlot); bMonitor = KppGetFileMonitor(); /* Do the IF_NEEDED demon */ if (!idValue || !KppListLen(idValue)) { long lReturnSet; if (idINMethodName && idINMethodName != lpIDs->idNull && bMonitor) { if (!(idMethod = Kpp_Get_Method(wType, idObj, idINMethodName))) return RegisterKappaMessage(IDE_NOTEXIST, lpIDs->idIfNeeded, idINMethodName, NULLID); if (!(lpMethod = (LPMETHOD) KppGetItem(METHOD, idMethod))) return ERROR; idList = KppMakeList(0); wNumVars = NUMVARS(lpMethod); if (wNumVars == 4) KppAppendElem(idList, idSlotName); if (wNumVars > 4) { KppDeleteList(idList); KppReleaseItem(METHOD, idMethod); return RegisterKappaMessage(IDE_BADNUMARG, lpIDs->idIfNeeded, NULLID, NULLID); } UnwindProtect(cleanup); i = Kpp_Eval_Method(wType, idObj, idINMethodName, idList, FALSE); cleanup: KppReleaseItem(METHOD, idMethod); KppDeleteList(idList); EndProtect(); if (!i) return NULLID; lReturnSet = KppGetKappaReturnSet(); if (!(FAST_RETURNFLAGS & EXPLIST)) return RegisterKappaMessage(IDE_IFBADRETURN, KppGetItemName(wType, idObj), idSlotName, NULLID); if (FAST_RETURNVALUE != lpIDs->idNull) idValue = FAST_RETURNVALUE; } /* no IF_NEEDED method is defined and the list is empty */ else if (!idValue) idValue = lpIDs->idNull; } if (idWAMethodName && idWAMethodName != lpIDs->idNull && bMonitor) { long lReturnSet; if (!(idMethod = Kpp_Get_Method(wType, idObj, idWAMethodName))) return RegisterKappaMessage(IDE_NOTEXIST, lpIDs->idWhenAccess, idWAMethodName, NULLID); if (!(lpMethod = (LPMETHOD) KppGetItem(METHOD, idMethod))) return ERROR; idList = KppMakeList(0); wNumVars = NUMVARS(lpMethod); if (wNumVars >= 4) KppAppendElem(idList, idSlotName); if (wNumVars == 5) KppAppendElem(idList, idValue); if (wNumVars > 5) { KppReleaseItem(METHOD, idMethod); KppDeleteList(idList); return RegisterKappaMessage(IDE_BADNUMARG, lpIDs->idWhenAccess, NULLID, NULLID); } UnwindProtect(cleanup2); i = Kpp_Eval_Method(wType, idObj, idWAMethodName, idList, FALSE); cleanup2: KppReleaseItem(METHOD, idMethod); KppDeleteList(idList); EndProtect(); if (!i) return NULLID; lReturnSet = KppGetKappaReturnSet(); if (!(FAST_RETURNFLAGS & EXPLIST)) return RegisterKappaMessage(IDE_WABADRETURN, KppGetItemName(wType, idObj), idSlotName, NULLID); if (FAST_RETURNVALUE && FAST_RETURNVALUE != lpIDs->idNull) idValue = FAST_RETURNVALUE; } return idValue; }
struct objc_slot * objc_object_next_slot(id obj, SEL * selector) { return SparseArrayNext(SLOTS(obj), selector); }