1/*
2 * super-call.m -- Finding the right dispatch function for a method-call
3 *
4 * This file defines a registry that is used to find the right function to
5 * call when a method is called. There are 3 variants:
6 * - Call the method from python
7 * - Call the superclass implementation from python
8 * - Call the python implementation of a method from Objective-C
9 *
10 * The first will almost always be 'execute_and_pythonify_method', the other
11 * two classes contain lots of functions because the normal runtime doesn't
12 * allow for dynamicly creating these types of calls (see also: register.m)
13 */
14#include "pyobjc.h"
15
16Py_ssize_t PyObjC_MappingCount = 0;
17
18struct registry
19{
20	PyObjC_CallFunc 	call_to_objc;
21	PyObjCFFI_ClosureFunc	call_to_python;
22};
23
24/* Dict mapping from signature-string to a 'struct registry' */
25static PyObject* signature_registry = NULL;
26
27/* List of 3-tuples: (Class, "selector", 'struct registry' */
28static PyObject* special_registry  = NULL;
29
30/*
31 * Initialize the data structures
32 */
33static int
34init_registry(void)
35{
36	if (signature_registry == NULL) {
37		signature_registry = PyDict_New();
38		if (signature_registry == NULL) return -1;
39	}
40
41	if (special_registry == NULL) {
42		special_registry = PyList_New(0);
43		if (special_registry == NULL) return -1;
44	}
45
46	return 0;
47}
48
49#if PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION < 7
50
51static void memblock_capsule_cleanup(void* ptr)
52{
53	PyMem_Free(ptr);
54}
55#else
56static void memblock_capsule_cleanup(PyObject* ptr)
57{
58	PyMem_Free(PyCapsule_GetPointer(ptr, "objc.__memblock__"));
59}
60#endif
61
62
63/*
64 * Add a custom mapping for a method in a class
65 */
66int
67PyObjC_RegisterMethodMapping(Class class, SEL sel,
68	PyObjC_CallFunc call_to_objc,
69	PyObjCFFI_ClosureFunc call_to_python)
70{
71	struct registry* v;
72	const char* selname = sel_getName(sel);
73	PyObject* pyclass;
74	PyObject* entry;
75
76	if (signature_registry == NULL) {
77		if (init_registry() < 0) return -1;
78	}
79
80	if (!call_to_python) {
81		PyErr_SetString(PyObjCExc_Error,
82			"PyObjC_RegisterMethodMapping: all functions required");
83		return -1;
84	}
85
86	if (!call_to_objc) {
87		call_to_objc = PyObjCFFI_Caller;
88	}
89
90	if (class == nil) {
91		pyclass = Py_None; Py_INCREF(Py_None);
92	} else {
93		pyclass = PyObjCClass_New(class);
94		if (pyclass == NULL) return -1;
95	}
96
97	v = PyMem_Malloc(sizeof(*v));
98	if (v == NULL) {
99		PyErr_NoMemory();
100		return -1;
101	}
102	v->call_to_objc  = call_to_objc;
103	v->call_to_python = call_to_python;
104
105	entry = PyTuple_New(3);
106	if (entry == NULL) return -1;
107
108	PyTuple_SET_ITEM(entry, 0, pyclass);
109	PyTuple_SET_ITEM(entry, 1, PyBytes_InternFromString((char*)selname));
110	PyTuple_SET_ITEM(entry, 2, PyCapsule_New(v, "objc.__memblock__", memblock_capsule_cleanup));
111
112	if (PyErr_Occurred()) {
113		Py_DECREF(entry);
114		return -1;
115	}
116
117	if (PyList_Append(special_registry, entry) < 0) {
118		Py_DECREF(entry);
119		return -1;
120	}
121
122	PyObjC_MappingCount += 1;
123
124	return 0;
125}
126
127int PyObjC_RegisterSignatureMapping(
128	char* signature,
129	PyObjC_CallFunc call_to_objc,
130	PyObjCFFI_ClosureFunc call_to_python)
131{
132	struct registry* v;
133	PyObject*  entry;
134	char signature_buf[1024];
135	int r;
136
137	if (special_registry == NULL) {
138		if (init_registry() < 0) return -1;
139	}
140
141	r = PyObjCRT_SimplifySignature(
142			signature,
143			signature_buf,
144			sizeof(signature_buf));
145	if (r == -1) {
146		PyErr_SetString(PyObjCExc_Error, "cannot simplify signature");
147		return -1;
148	}
149
150	if (!call_to_objc || !call_to_python) {
151		PyErr_SetString(PyObjCExc_Error,
152		   "PyObjC_RegisterSignatureMapping: all functions required");
153		return -1;
154	}
155
156	v = PyMem_Malloc(sizeof(*v));
157	if (v == NULL) {
158		PyErr_NoMemory();
159		return -1;
160	}
161	v->call_to_objc  = call_to_objc;
162	v->call_to_python = call_to_python;
163
164	entry = PyCapsule_New(v, "objc.__memblock__", memblock_capsule_cleanup);
165	if (entry == NULL) {
166		PyMem_Free(v);
167		return -1;
168	}
169
170	PyObject* key = PyBytes_FromString(signature_buf);
171	if (key == NULL) {
172		return -1;
173	}
174
175	if (PyDict_SetItem(signature_registry, key, entry) < 0){
176		Py_DECREF(key);
177		Py_DECREF(entry);
178		return -1;
179	}
180	Py_DECREF(key);
181	Py_DECREF(entry);
182	PyObjC_MappingCount += 1;
183
184	return 0;
185}
186
187
188static struct registry*
189search_special(Class class, SEL sel)
190{
191	PyObject* result = NULL;
192	PyObject* special_class = NULL;
193	Py_ssize_t special_len;
194	Py_ssize_t i;
195
196	if (special_registry == NULL) goto error;
197
198	if (class) {
199		special_class = PyObjCClass_New(class);
200		if (special_class == NULL) goto error;
201
202	}
203
204	special_len = PyList_Size(special_registry);
205
206	for (i = 0; i < special_len; i++) {
207		PyObject* entry = PyList_GetItem(special_registry, i);
208		PyObject* pyclass = PyTuple_GET_ITEM(entry, 0);
209		PyObject* pysel = PyTuple_GET_ITEM(entry, 1);
210
211		if (pyclass == NULL || pysel == NULL) continue;
212
213		if (
214			(PyUnicode_Check(pysel) && PyObjC_is_ascii_string(pysel, sel_getName(sel)))
215#if PY_MAJOR_VERSION == 2
216		     || (PyString_Check(pysel) && strcmp(PyString_AsString(pysel), sel_getName(sel)) == 0)
217#else
218		     || (PyBytes_Check(pysel) && strcmp(PyBytes_AsString(pysel), sel_getName(sel)) == 0)
219#endif
220		     ) {
221
222			if (!special_class) {
223				special_class = pyclass;
224				Py_INCREF(special_class);
225				result = PyTuple_GET_ITEM(entry, 2);
226
227			} else if (pyclass == Py_None) {
228				Py_DECREF(special_class);
229				special_class = pyclass;
230				Py_INCREF(special_class);
231				result = PyTuple_GET_ITEM(entry, 2);
232
233			} else if (PyType_IsSubtype(
234					(PyTypeObject*)special_class,
235					(PyTypeObject*)pyclass
236				    )) {
237				Py_DECREF(special_class);
238				special_class = pyclass;
239				Py_INCREF(special_class);
240				result = PyTuple_GET_ITEM(entry, 2);
241			}
242		}
243	}
244	Py_XDECREF(special_class);
245	if (!result) goto error;
246
247	return PyCapsule_GetPointer(result, "objc.__memblock__");
248
249error:
250	PyErr_Format(PyObjCExc_Error,
251		"PyObjC: don't know how to call method '%s'",
252			sel_getName(sel));
253	return NULL;
254}
255
256
257PyObjC_CallFunc
258PyObjC_FindCallFunc(Class class, SEL sel)
259{
260/*
261 * TODO: Should add special case code for NSUndoManager: If this
262 * is a selector that is forwarded to the 'target' we should get
263 * the caller for the target instead of for this object!
264 */
265	struct registry* special;
266
267	if (special_registry == NULL) return PyObjCFFI_Caller;
268
269	special = search_special(class, sel);
270	if (special) {
271		return special->call_to_objc;
272	} else {
273		PyErr_Clear();
274	}
275
276	return PyObjCFFI_Caller;
277}
278
279static struct registry*
280find_signature(const char* signature)
281{
282	PyObject* o;
283	struct registry* r;
284	char signature_buf[1024];
285	int res;
286
287	res = PyObjCRT_SimplifySignature(
288			signature,
289			signature_buf,
290			sizeof(signature_buf));
291	if (res == -1) {
292		PyErr_SetString(PyObjCExc_Error, "cannot simplify signature");
293		return NULL;
294	}
295
296	if (signature_registry == NULL) goto error;
297
298	PyObject* key = PyBytes_FromString(signature_buf);
299	if (key == NULL) {
300		return NULL;
301	}
302	o = PyDict_GetItem(signature_registry, key);
303	Py_DECREF(key);
304	if (o == NULL) goto error;
305
306	r = PyCapsule_GetPointer(o, "objc.__memblock__");
307	return r;
308
309error:
310	PyErr_Format(PyObjCExc_Error,
311		"PyObjC: don't know how to call a method with "
312		"signature '%s'", signature);
313	return NULL;
314}
315
316extern IMP
317PyObjC_MakeIMP(Class class, Class super_class, PyObject* sel, PyObject* imp)
318{
319	struct registry* generic;
320	struct registry* special;
321	SEL aSelector = PyObjCSelector_GetSelector(sel);
322	PyObjCFFI_ClosureFunc func = NULL;
323	IMP retval;
324	PyObjCMethodSignature* methinfo;
325
326	if (super_class != nil) {
327		special = search_special(super_class, aSelector);
328		if (special) {
329			func = special->call_to_python;
330		} else {
331			PyErr_Clear();
332		}
333	}
334
335	if (func == NULL) {
336		generic = find_signature(PyObjCSelector_Signature(sel));
337		if (generic != NULL) {
338			func = generic->call_to_python;
339		}
340	}
341
342	if (func == PyObjCUnsupportedMethod_IMP) {
343		PyErr_Format(PyExc_TypeError,
344			"Implementing %s in Python is not supported",
345			sel_getName(aSelector));
346		return NULL;
347	}
348
349	if (func != NULL) {
350		methinfo = PyObjCMethodSignature_ForSelector(
351				class, (PyObjCSelector_GetFlags(sel) & PyObjCSelector_kCLASS_METHOD) != 0,
352				PyObjCSelector_GetSelector(sel),
353				PyObjCSelector_Signature(sel),
354				PyObjCNativeSelector_Check(sel));
355		if (methinfo == NULL) {
356			return NULL;
357		}
358		retval = PyObjCFFI_MakeClosure(methinfo, func, imp);
359		if (retval != NULL) {
360			Py_INCREF(imp);
361		}
362		Py_DECREF(methinfo);
363		return retval;
364	} else {
365		PyErr_Clear();
366		methinfo = PyObjCMethodSignature_ForSelector(
367				class, (PyObjCSelector_GetFlags(sel) & PyObjCSelector_kCLASS_METHOD) != 0,
368				PyObjCSelector_GetSelector(sel),
369				PyObjCSelector_Signature(sel),
370				PyObjCNativeSelector_Check(sel));
371		if (methinfo == NULL) {
372			return NULL;
373		}
374		retval = PyObjCFFI_MakeIMPForSignature(
375				methinfo, PyObjCSelector_GetSelector(sel), imp);
376		Py_DECREF(methinfo);
377		return retval;
378	}
379}
380
381void
382PyObjCUnsupportedMethod_IMP(
383	ffi_cif* cif __attribute__((__unused__)),
384	void* resp __attribute__((__unused__)),
385	void** args,
386	void* userdata __attribute__((__unused__)))
387{
388	[NSException raise:NSInvalidArgumentException
389		format:@"Implementing %s from Python is not supported for %@",
390			sel_getName(*(SEL*)args[1]),
391			*(id*)args[0]];
392}
393
394PyObject*
395PyObjCUnsupportedMethod_Caller(
396	PyObject* meth,
397	PyObject* self,
398	PyObject* args __attribute__((__unused__)))
399{
400#if PY_MAJOR_VERSION == 2
401	PyObject* repr;
402
403	repr = PyObject_Repr(self);
404	if (repr == NULL || !PyString_Check(repr)) {
405		Py_XDECREF(repr);
406		PyErr_Format(PyExc_TypeError,
407			"Cannot call '%s' on instances of '%s' from Python",
408			sel_getName(PyObjCSelector_GetSelector(meth)),
409			Py_TYPE(self)->tp_name);
410		return NULL;
411	}
412
413	PyErr_Format(PyExc_TypeError,
414		"Cannot call '%s' on '%s' from Python",
415		sel_getName(PyObjCSelector_GetSelector(meth)),
416		PyString_AS_STRING(repr));
417	Py_DECREF(repr);
418	return NULL;
419#else
420	PyErr_Format(PyExc_TypeError,
421		"Cannot call '%s' on '%R' from Python",
422		sel_getName(PyObjCSelector_GetSelector(meth)),
423		self);
424	return NULL;
425#endif
426
427}
428