Esempio n. 1
0
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;
}
Esempio n. 2
0
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;
}
Esempio n. 3
0
static void
_objc_unload_IMPs_in_class(Class cl, void *kernel_module){
	if (cl->methods == NULL){
		return;
	}
	
	objc_debug_log("Unloading IMPs in class %s\n", class_getName(cl));
	
	for (objc_method_list *list = cl->methods; list != NULL; list = list->next){
		objc_debug_log("\t [%p]\n", list);
		for (int i = 0; i < list->size; ++i){
			Method m = &list->list[i];
			if (module_contains_IMP(kernel_module, m->implementation)){
				objc_debug_log("\t\t [%02i] - %s\n", i, sel_getName(m->selector));
				IMP old_imp = m->implementation;
				m->implementation = objc_unloaded_module_method;
				
				/* Since the selector name and types can actually be also
				 * allocated in the module, we better update the strings
				 * as well.
				 */
				m->selector_name = "__objc_unloaded_method";
				m->selector_types = sizeof(void*) == 4 ? "v8@0:4" : "v16@0:8";
				
				/* Update the dtable! */
				SparseArray *arr = (SparseArray*)cl->dtable;
				if (arr != NULL && arr != uninstalled_dtable){
					struct objc_slot *slot = SparseArrayLookup(arr, m->selector);
					if (slot != NULL && slot->implementation == old_imp){
						slot->implementation = m->implementation;
						
						slot->types = m->selector_types;
						
						++slot->version;
					}
				}
			}
		}
	}
}
Esempio n. 4
0
	SparseArrayDestroy(&uninstalled_dtable);
	
	slot_pool_free();
}

static BOOL installMethodInDtable(Class class,
                                  Class owner,
                                  SparseArray *dtable,
                                  struct objc_method *method,
                                  BOOL replaceExisting)
{
	objc_debug_log("Installing method %s into dtable of class %s\n", sel_getName(method->selector), class_getName(class));
	
	objc_assert(uninstalled_dtable != dtable, "");
	SEL sel_id = method->selector;
	struct objc_slot *slot = SparseArrayLookup(dtable, sel_id);
	if (NULL != slot)
	{
		// If this method is the one already installed, pretend to install it again.
		if (slot->implementation == method->implementation) { return NO; }

		// If the existing slot is for this class, we can just replace the
		// implementation.  We don't need to bump the version; this operation
		// updates cached slots, it doesn't invalidate them.  
		if (slot->owner == owner)
		{
			// Don't replace methods if we're not meant to (if they're from
			// later in a method list, for example)
			if (!replaceExisting) { return NO; }
			slot->implementation = method->implementation;
			return YES;