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
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_list *ml;
	struct objc_method *method;
	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 ((method = get_method(cls, sel)) != NULL) {
	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 =
		const char *ret = method->sel.types;
						    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)
bool
class_addMethod(Class cls, SEL sel, IMP imp, const char *types)
{
	struct objc_method_list *ml;
	struct objc_category **cats;
	IMP oldimp;
	bool ret;

	objc_global_mutex_lock();

	for (ml = cls->methodlist; ml != NULL; ml = ml->next) {
	if (get_method(cls, sel) == NULL) {
		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;
		add_method(cls, sel, imp, types);
		ret = true;
	} else
		ret = false;
				objc_update_dtable(cls);

				objc_global_mutex_unlock();

				return oldimp;
	return ret;
			}
		}
	}

	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;

IMP
						ml->methods[i].imp = newimp;
class_replaceMethod(Class cls, SEL sel, IMP newimp, const char *types)
						objc_update_dtable(cls);

{
						objc_global_mutex_unlock();

						return oldimp;
					}
	struct objc_method *method;
	IMP oldimp;

				}
			}
		}
	}

	objc_global_mutex_lock();
	/* 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;
	if ((method = get_method(cls, sel)) != NULL) {
	ml->count = 1;
	ml->methods[0].sel.uid = sel->uid;
		oldimp = method->imp;
	ml->methods[0].sel.types = types;
	ml->methods[0].imp = newimp;

	cls->methodlist = ml;

		method->imp = newimp;
		objc_update_dtable(cls);
	} else {
		oldimp = NULL;
		add_method(cls, sel, newimp, types);
	}
	objc_update_dtable(cls);

	objc_global_mutex_unlock();

	return NULL;
	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
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*);