1/*
2 * alloc_hack.m -- Implementation of alloc_hack.h
3 */
4#include "pyobjc.h"
5
6static PyObject*
7call_NSObject_alloc(PyObject* method,
8	PyObject* self, PyObject* arguments)
9{
10	id result = nil;
11	struct objc_super spr;
12	IMP anIMP;
13	Class aClass;
14	SEL volatile aSel;
15
16	if (unlikely(PyArg_ParseTuple(arguments, "") < 0)) {
17		return NULL;
18	}
19
20	if (unlikely(!PyObjCClass_Check(self))) {
21		PyErr_Format(PyExc_TypeError, "Expecting Objective-C class, got instance of '%s'", Py_TYPE(self)->tp_name);
22		return NULL;
23	}
24
25	if (unlikely(PyObjCIMP_Check(method))) {
26		anIMP = PyObjCIMP_GetIMP(method);
27		aClass = PyObjCClass_GetClass(self);
28		aSel = PyObjCIMP_GetSelector(method);
29
30		PyObjC_DURING
31			result = anIMP(aClass, aSel);
32
33		PyObjC_HANDLER
34			PyObjCErr_FromObjC(localException);
35			result = nil;
36
37		PyObjC_ENDHANDLER;
38
39	} else {
40		objc_superSetReceiver(spr, (id)PyObjCClass_GetClass(self));
41		objc_superSetClass(spr, object_getClass(PyObjCSelector_GetClass(method)));
42		aSel = PyObjCSelector_GetSelector(method);
43
44		PyObjC_DURING
45			result = objc_msgSendSuper(&spr, aSel);
46
47		PyObjC_HANDLER
48			PyObjCErr_FromObjC(localException);
49			result = nil;
50
51		PyObjC_ENDHANDLER;
52	}
53
54	if (unlikely(result == nil && PyErr_Occurred())) {
55		return NULL;
56	}
57
58	return PyObjCObject_New(result, PyObjCObject_kUNINITIALIZED, NO);
59}
60
61static void
62imp_NSObject_alloc(
63	ffi_cif* cif __attribute__((__unused__)),
64	void* resp,
65	void** args __attribute__((__unused__)),
66	void* callable)
67{
68	int err;
69	PyObject* arglist = NULL;
70	PyObject* v = NULL;
71	PyObject* result = NULL;
72
73	PyObjC_BEGIN_WITH_GIL
74
75		arglist = PyTuple_New(1);
76		if (unlikely(arglist == NULL)) {
77			PyObjC_GIL_FORWARD_EXC();
78		}
79
80		v = PyObjC_IdToPython(*(id*)args[0]);
81		if (unlikely(v == NULL)) {
82			Py_DECREF(arglist);
83			PyObjC_GIL_FORWARD_EXC();
84		}
85		v = PyObjC_AdjustSelf(v);
86		if (unlikely(v == NULL)) {
87			Py_DECREF(arglist);
88			PyObjC_GIL_FORWARD_EXC();
89		}
90
91		PyTuple_SET_ITEM(arglist, 0, v);
92		v = NULL;
93
94		result = PyObject_Call((PyObject*)callable, arglist, NULL);
95		if (unlikely(result == NULL)) {
96			Py_DECREF(arglist);
97			PyObjC_GIL_FORWARD_EXC();
98		}
99
100		Py_DECREF(arglist);
101
102		err = depythonify_c_value(@encode(id), result, resp);
103		Py_DECREF(result);
104		if (unlikely(err == -1)) {
105			PyObjC_GIL_FORWARD_EXC();
106		}
107
108	PyObjC_END_WITH_GIL
109}
110
111static PyObject*
112call_NSObject_dealloc(PyObject* method,
113	PyObject* self, PyObject* arguments)
114{
115	struct objc_super spr;
116	IMP anIMP;
117	Class aClass;
118	SEL volatile aSel;
119
120	if (unlikely(PyArg_ParseTuple(arguments, "") < 0)) {
121		return NULL;
122	}
123
124	if (unlikely(!PyObjCObject_Check(self))) {
125		PyErr_Format(PyExc_TypeError,
126			"[dealloc] Expecting Objective-C instance, got instance of '%s'",
127			Py_TYPE(self)->tp_name);
128		return NULL;
129	}
130
131	if (unlikely(PyObjCIMP_Check(method))) {
132		anIMP = PyObjCIMP_GetIMP(method);
133		aClass = PyObjCClass_GetClass(self);
134		aSel = PyObjCIMP_GetSelector(method);
135
136		PyObjC_DURING
137			(void)anIMP(aClass, aSel);
138
139		PyObjC_HANDLER
140			PyObjCErr_FromObjC(localException);
141
142		PyObjC_ENDHANDLER;
143
144	} else {
145		objc_superSetReceiver(spr, PyObjCObject_GetObject(self));
146		objc_superSetClass(spr, PyObjCSelector_GetClass(method));
147		aSel = PyObjCSelector_GetSelector(method);
148
149		PyObjC_DURING
150			(void)objc_msgSendSuper(&spr, aSel);
151
152		PyObjC_HANDLER
153			PyObjCErr_FromObjC(localException);
154
155		PyObjC_ENDHANDLER;
156	}
157
158	PyObjCObject_ClearObject(self);
159
160	if (unlikely(PyErr_Occurred())) {
161		return NULL;
162	}
163
164
165	Py_INCREF(Py_None);
166	return Py_None;
167}
168
169static void
170imp_NSObject_dealloc(
171	ffi_cif* cif __attribute__((__unused__)),
172	void* resp __attribute__((__unused__)),
173	void** args __attribute__((__unused__)),
174	void* callable)
175{
176	PyObject* arglist = NULL;
177	PyObject* v = NULL;
178	PyObject* result = NULL;
179
180	PyObjC_BEGIN_WITH_GIL
181
182		arglist = PyTuple_New(1);
183		if (unlikely(arglist == NULL)) {
184			PyObjC_GIL_FORWARD_EXC();
185		}
186
187		v = PyObjC_IdToPython(*(id*)args[0]);
188		if (unlikely(v == NULL)) {
189			Py_DECREF(arglist);
190			PyObjC_GIL_FORWARD_EXC();
191		}
192
193		PyTuple_SET_ITEM(arglist, 0, v);
194		v = NULL;
195
196		result = PyObject_Call((PyObject*)callable, arglist, NULL);
197		if (unlikely(result == NULL)) {
198			Py_DECREF(arglist);
199			PyObjC_GIL_FORWARD_EXC();
200		}
201
202		Py_DECREF(arglist);
203
204		if (unlikely(result != Py_None)) {
205			PyErr_Format(PyExc_TypeError,
206				"dealloc should return None, returned instance"
207				" of %s", Py_TYPE(result)->tp_name);
208			PyObjC_GIL_FORWARD_EXC();
209		}
210
211		Py_DECREF(result);
212
213	PyObjC_END_WITH_GIL
214}
215
216static PyObject*
217call_NSObject_release(PyObject* method,
218	PyObject* self, PyObject* arguments)
219{
220	struct objc_super spr;
221	IMP anIMP;
222	Class aClass;
223	SEL volatile aSel;
224
225	if (unlikely(PyArg_ParseTuple(arguments, "") < 0)) {
226		return NULL;
227	}
228
229	if (unlikely(!PyObjCObject_Check(self))) {
230		PyErr_Format(PyExc_TypeError,
231			"[release] Expecting Objective-C instance, got instance of '%s'",
232			Py_TYPE(self)->tp_name);
233		return NULL;
234	}
235
236	if (unlikely(PyObjCIMP_Check(method))) {
237		anIMP = PyObjCIMP_GetIMP(method);
238		aClass = PyObjCClass_GetClass(self);
239		aSel = PyObjCIMP_GetSelector(method);
240
241		PyObjC_DURING
242			(void)anIMP(aClass, aSel);
243
244		PyObjC_HANDLER
245			PyObjCErr_FromObjC(localException);
246
247		PyObjC_ENDHANDLER;
248
249	} else {
250		objc_superSetReceiver(spr, PyObjCObject_GetObject(self));
251		objc_superSetClass(spr, PyObjCSelector_GetClass(method));
252		aSel = PyObjCSelector_GetSelector(method);
253
254		PyObjC_DURING
255			(void)objc_msgSendSuper(&spr, aSel);
256
257		PyObjC_HANDLER
258			PyObjCErr_FromObjC(localException);
259
260		PyObjC_ENDHANDLER;
261	}
262
263	if (unlikely(PyErr_Occurred())) {
264		return NULL;
265	}
266
267
268	Py_INCREF(Py_None);
269	return Py_None;
270}
271
272static PyObject*
273call_NSObject_retain(PyObject* method,
274	PyObject* self, PyObject* arguments)
275{
276	struct objc_super spr;
277	IMP anIMP;
278	Class aClass;
279	SEL volatile aSel;
280	volatile id retval = nil;
281
282	if (unlikely(PyArg_ParseTuple(arguments, "") < 0)) {
283		return NULL;
284	}
285
286	if (!PyObjCObject_Check(self)) {
287		PyErr_Format(PyExc_TypeError,
288			"[retain] Expecting Objective-C instance, got instance of '%s'",
289			Py_TYPE(self)->tp_name);
290		return NULL;
291	}
292
293	if (PyObjCIMP_Check(method)) {
294		anIMP = PyObjCIMP_GetIMP(method);
295		aClass = PyObjCClass_GetClass(self);
296		aSel = PyObjCIMP_GetSelector(method);
297
298		PyObjC_DURING
299			retval = anIMP(aClass, aSel);
300
301		PyObjC_HANDLER
302			PyObjCErr_FromObjC(localException);
303
304		PyObjC_ENDHANDLER;
305
306	} else {
307		objc_superSetReceiver(spr, PyObjCObject_GetObject(self));
308		objc_superSetClass(spr, PyObjCSelector_GetClass(method));
309		aSel = PyObjCSelector_GetSelector(method);
310
311		PyObjC_DURING
312			retval = objc_msgSendSuper(&spr, aSel);
313
314		PyObjC_HANDLER
315			PyObjCErr_FromObjC(localException);
316
317		PyObjC_ENDHANDLER;
318	}
319
320	if (PyErr_Occurred()) {
321		return NULL;
322	}
323
324	return PyObjC_IdToPython(retval);
325}
326
327static void
328imp_NSObject_release(
329	ffi_cif* cif __attribute__((__unused__)),
330	void* resp __attribute__((__unused__)),
331	void** args __attribute__((__unused__)),
332	void* callable)
333{
334	PyObject* arglist = NULL;
335	PyObject* result = NULL;
336	PyObject* pyself;
337	int cookie;
338
339	PyObjC_BEGIN_WITH_GIL
340
341		arglist = PyTuple_New(1);
342		if (arglist == NULL) {
343			PyObjC_GIL_FORWARD_EXC();
344		}
345
346		pyself = PyObjCObject_NewTransient(*(id*)args[0], &cookie);
347		if (pyself == NULL) {
348			Py_DECREF(arglist);
349			PyObjC_GIL_FORWARD_EXC();
350		}
351
352		PyTuple_SET_ITEM(arglist, 0, pyself);
353		Py_INCREF(pyself);
354
355		result = PyObject_Call((PyObject*)callable, arglist, NULL);
356		if (result == NULL) {
357			Py_DECREF(arglist);
358			PyObjCObject_ReleaseTransient(pyself, cookie);
359			PyObjC_GIL_FORWARD_EXC();
360		}
361
362		Py_DECREF(arglist);
363		PyObjCObject_ReleaseTransient(pyself, cookie);
364
365		if (result != Py_None) {
366			PyErr_Format(PyExc_TypeError,
367				"release should return None, returned instance"
368				" of %s", Py_TYPE(result)->tp_name);
369			PyObjC_GIL_FORWARD_EXC();
370		}
371
372		Py_DECREF(result);
373
374	PyObjC_END_WITH_GIL
375}
376
377static void
378imp_NSObject_retain(
379	ffi_cif* cif __attribute__((__unused__)),
380	void* resp __attribute__((__unused__)),
381	void** args __attribute__((__unused__)),
382	void* callable)
383{
384	PyObject* arglist = NULL;
385	PyObject* result = NULL;
386	PyObject* pyself;
387	int cookie;
388	int err;
389
390	PyObjC_BEGIN_WITH_GIL
391
392		arglist = PyTuple_New(1);
393		if (arglist == NULL) {
394			PyObjC_GIL_FORWARD_EXC();
395		}
396
397		pyself = PyObjCObject_NewTransient(*(id*)args[0], &cookie);
398		if (pyself == NULL) {
399			Py_DECREF(arglist);
400			PyObjC_GIL_FORWARD_EXC();
401		}
402
403		PyTuple_SET_ITEM(arglist, 0, pyself);
404		Py_INCREF(pyself);
405
406		result = PyObject_Call((PyObject*)callable, arglist, NULL);
407		if (result == NULL) {
408			Py_DECREF(arglist);
409			PyObjCObject_ReleaseTransient(pyself, cookie);
410			PyObjC_GIL_FORWARD_EXC();
411		}
412
413		Py_DECREF(arglist);
414
415		err = depythonify_c_value(@encode(id), result, resp);
416		Py_DECREF(result);
417		PyObjCObject_ReleaseTransient(pyself, cookie);
418		if (err == -1) {
419			PyObjC_GIL_FORWARD_EXC();
420		}
421
422	PyObjC_END_WITH_GIL
423}
424
425
426int
427PyObjC_InstallAllocHack(void)
428{
429	int r;
430
431	r = PyObjC_RegisterMethodMapping(
432		objc_lookUpClass("NSObject"),
433		@selector(alloc),
434		call_NSObject_alloc,
435		imp_NSObject_alloc);
436	if (r != 0) return r;
437
438	r = PyObjC_RegisterMethodMapping(
439		objc_lookUpClass("NSObject"),
440		@selector(dealloc),
441		call_NSObject_dealloc,
442		imp_NSObject_dealloc);
443	if (r != 0) return r;
444
445	r = PyObjC_RegisterMethodMapping(
446		objc_lookUpClass("NSObject"),
447		@selector(retain),
448		call_NSObject_retain,
449		imp_NSObject_retain);
450	if (r != 0) return r;
451
452	r = PyObjC_RegisterMethodMapping(
453		objc_lookUpClass("NSObject"),
454		@selector(release),
455		call_NSObject_release,
456		imp_NSObject_release);
457	if (r != 0) return r;
458
459	return r;
460}
461