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