ObjFW  Check-in [d4cae4c963]

Overview
Comment:runtime: Add class_addMethod()

Also moves out some stuff to functions to be reusable by
class_addMethod().

Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: d4cae4c963b8c7a21891069cb6d552bc724b70e681949733c2d8d16c8578bda4
User & Date: js on 2016-07-03 11:24:15
Other Links: manifest | tags
Context
2016-07-03
12:01
runtime: Add objc_enumerationMutation() check-in: 5e267364ae user: js tags: trunk
11:24
runtime: Add class_addMethod() check-in: d4cae4c963 user: js tags: trunk
2016-07-02
23:35
OFHTTPClient: Properly escape path & query string check-in: c25601d462 user: js tags: trunk
Changes

Modified src/runtime/class.m from [8bf9db28f4] to [c8cb26401f].

663
664
665
666
667
668
669

















































670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714


















715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
	if (cls == Nil)
		return NULL;

	dummy.isa = cls;
	return objc_msg_lookup_stret((id)&dummy, sel);
}


















































const char*
class_getMethodTypeEncoding(Class cls, SEL sel)
{
	struct objc_method_list *ml;
	struct objc_category **cats;

	if (cls == Nil)
		return NULL;

	objc_global_mutex_lock();

	for (ml = cls->methodlist; ml != NULL; ml = ml->next) {
		for (unsigned int i = 0; i < ml->count; i++) {
			if (sel_isEqual((SEL)&ml->methods[i].sel, sel)) {
				const char *ret = ml->methods[i].sel.types;
				objc_global_mutex_unlock();
				return ret;
			}
		}
	}

	if ((cats = objc_categories_for_class(cls)) != NULL) {
		for (; *cats != NULL; cats++) {
			for (ml = (*cats)->instance_methods; ml != NULL;
			    ml = ml->next) {
				for (unsigned int i = 0; i < ml->count; i++) {
					if (ml->methods[i].sel.uid ==
					    sel->uid) {
						const char *ret =
						    ml->methods[i].sel.types;
						objc_global_mutex_unlock();
						return ret;
					}
				}
			}
		}
	}

	objc_global_mutex_unlock();

	if (cls->superclass != Nil)
		return class_getMethodTypeEncoding(cls->superclass, sel);

	return NULL;
}



















IMP
class_replaceMethod(Class cls, SEL sel, IMP newimp, const char *types)
{
	struct objc_method_list *ml;
	struct objc_category **cats;
	IMP oldimp;

	objc_global_mutex_lock();

	for (ml = cls->methodlist; ml != NULL; ml = ml->next) {
		for (unsigned int i = 0; i < ml->count; i++) {
			if (ml->methods[i].sel.uid == sel->uid) {
				oldimp = ml->methods[i].imp;

				ml->methods[i].imp = newimp;
				objc_update_dtable(cls);

				objc_global_mutex_unlock();

				return oldimp;
			}
		}
	}

	if ((cats = objc_categories_for_class(cls)) != NULL) {
		for (; *cats != NULL; cats++) {
			if (cls->info & OBJC_CLASS_INFO_METACLASS)
				ml = (*cats)->class_methods;
			else
				ml = (*cats)->instance_methods;

			for (; ml != NULL; ml = ml->next) {
				for (unsigned int i = 0; i < ml->count; i++) {
					if (ml->methods[i].sel.uid ==
					    sel->uid) {
						oldimp = ml->methods[i].imp;

						ml->methods[i].imp = newimp;
						objc_update_dtable(cls);

						objc_global_mutex_unlock();

						return oldimp;
					}
				}
			}
		}
	}

	/* FIXME: We need a way to free this at objc_exit() */
	if ((ml = malloc(sizeof(struct objc_method_list))) == NULL)
		OBJC_ERROR("Not enough memory to replace method!");

	ml->next = cls->methodlist;
	ml->count = 1;
	ml->methods[0].sel.uid = sel->uid;
	ml->methods[0].sel.types = types;
	ml->methods[0].imp = newimp;

	cls->methodlist = ml;

	objc_update_dtable(cls);

	objc_global_mutex_unlock();

	return NULL;
}

Class
object_getClass(id obj_)
{
	struct objc_object *obj;








>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>



|
<






<
<
<
<
<
<
<
<
<
|
<
<
<
<
<
<
<
|
<
|
|
<
<
<
<









>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>




|
<




|
<
<
|
<
|
|
<
<
<
<
<
<
<
<
<
<
<
<
|
<
<
<
<
<
<
|
|
<
<
|
<

<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


|







663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722

723
724
725
726
727
728









729







730

731
732




733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764

765
766
767
768
769


770

771
772












773






774
775


776

777





















778
779
780
781
782
783
784
785
786
787
	if (cls == Nil)
		return NULL;

	dummy.isa = cls;
	return objc_msg_lookup_stret((id)&dummy, sel);
}

static struct objc_method*
get_method(Class cls, SEL sel)
{
	struct objc_method_list *ml;
	struct objc_category **cats;

	for (ml = cls->methodlist; ml != NULL; ml = ml->next)
		for (unsigned int i = 0; i < ml->count; i++)
			if (sel_isEqual((SEL)&ml->methods[i].sel, sel))
				return &ml->methods[i];

	if ((cats = objc_categories_for_class(cls)) != NULL) {
		for (; *cats != NULL; cats++) {
			if (cls->info & OBJC_CLASS_INFO_METACLASS)
				ml = (*cats)->class_methods;
			else
				ml = (*cats)->instance_methods;

			for (; ml != NULL; ml = ml->next)
				for (unsigned int i = 0; i < ml->count; i++)
					if (sel_isEqual(
					    (SEL)&ml->methods[i].sel, sel))
						return &ml->methods[i];
		}
	}

	return NULL;
}

static void
add_method(Class cls, SEL sel, IMP imp, const char *types)
{
	struct objc_method_list *ml;

	/* FIXME: We need a way to free this at objc_exit() */
	if ((ml = malloc(sizeof(struct objc_method_list))) == NULL)
		OBJC_ERROR("Not enough memory to replace method!");

	ml->next = cls->methodlist;
	ml->count = 1;
	ml->methods[0].sel.uid = sel->uid;
	ml->methods[0].sel.types = types;
	ml->methods[0].imp = imp;

	cls->methodlist = ml;

	objc_update_dtable(cls);
}

const char*
class_getMethodTypeEncoding(Class cls, SEL sel)
{
	struct objc_method *method;


	if (cls == Nil)
		return NULL;

	objc_global_mutex_lock();










	if ((method = get_method(cls, sel)) != NULL) {







		const char *ret = method->sel.types;

		objc_global_mutex_unlock();
		return ret;




	}

	objc_global_mutex_unlock();

	if (cls->superclass != Nil)
		return class_getMethodTypeEncoding(cls->superclass, sel);

	return NULL;
}

bool
class_addMethod(Class cls, SEL sel, IMP imp, const char *types)
{
	bool ret;

	objc_global_mutex_lock();

	if (get_method(cls, sel) == NULL) {
		add_method(cls, sel, imp, types);
		ret = true;
	} else
		ret = false;

	objc_global_mutex_unlock();

	return ret;
}

IMP
class_replaceMethod(Class cls, SEL sel, IMP newimp, const char *types)
{
	struct objc_method *method;

	IMP oldimp;

	objc_global_mutex_lock();

	if ((method = get_method(cls, sel)) != NULL) {


		oldimp = method->imp;

		method->imp = newimp;
		objc_update_dtable(cls);












	} else {






		oldimp = NULL;
		add_method(cls, sel, newimp, types);


	}























	objc_global_mutex_unlock();

	return oldimp;
}

Class
object_getClass(id obj_)
{
	struct objc_object *obj;

Modified src/runtime/runtime.h from [ddc272f296] to [ee48ca9342].

213
214
215
216
217
218
219

220
221
222
223
224
225
226
extern Class class_getSuperclass(Class);
extern unsigned long class_getInstanceSize(Class);
extern bool class_respondsToSelector(Class, SEL);
extern bool class_conformsToProtocol(Class, Protocol*);
extern IMP class_getMethodImplementation(Class, SEL);
extern IMP class_getMethodImplementation_stret(Class, SEL);
extern const char* class_getMethodTypeEncoding(Class, SEL);

extern IMP class_replaceMethod(Class, SEL, IMP, const char*);
extern Class object_getClass(id);
extern Class object_setClass(id, Class);
extern const char* object_getClassName(id);
extern const char* protocol_getName(Protocol*);
extern bool protocol_isEqual(Protocol*, Protocol*);
extern bool protocol_conformsToProtocol(Protocol*, Protocol*);







>







213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
extern Class class_getSuperclass(Class);
extern unsigned long class_getInstanceSize(Class);
extern bool class_respondsToSelector(Class, SEL);
extern bool class_conformsToProtocol(Class, Protocol*);
extern IMP class_getMethodImplementation(Class, SEL);
extern IMP class_getMethodImplementation_stret(Class, SEL);
extern const char* class_getMethodTypeEncoding(Class, SEL);
extern bool class_addMethod(Class, SEL, IMP, const char*);
extern IMP class_replaceMethod(Class, SEL, IMP, const char*);
extern Class object_getClass(id);
extern Class object_setClass(id, Class);
extern const char* object_getClassName(id);
extern const char* protocol_getName(Protocol*);
extern bool protocol_isEqual(Protocol*, Protocol*);
extern bool protocol_conformsToProtocol(Protocol*, Protocol*);