DPQueue is now a two-lock concurrent queue.
[hom.git] / Source / DPObjCRuntime.h
blobc69b38dfdb639ed11b3010048d00f853b65dbead
1 //
2 // DPObjCRuntime.h
3 // HigherOrderMessaging
4 //
5 // Created by Ofri Wolfus on 03/11/06.
6 // Copyright 2006-2007 Ofri Wolfus. All rights reserved.
7 //
8 // Redistribution and use in source and binary forms, with or without modification,
9 // are permitted provided that the following conditions are met:
10 //
11 // 1. Redistributions of source code must retain the above copyright
12 // notice, this list of conditions and the following disclaimer.
13 // 2. Redistributions in binary form must reproduce the above copyright
14 // notice, this list of conditions and the following disclaimer in the
15 // documentation and/or other materials provided with the distribution.
16 // 3. Neither the name of Ofri Wolfus nor the names of his contributors
17 // may be used to endorse or promote products derived from this software
18 // without specific prior written permission.
20 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 // IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #ifndef _DP_OBJCRUNTIME_H
32 #define _DP_OBJCRUNTIME_H
35 // Compatibility with C*
37 #if !defined(__OBJC2__)
38 #define __OBJC2__ 0
39 #endif
42 // Platform specific defs for externs
46 // For MACH
49 #if defined(__MACH__)
51 #ifdef __cplusplus
52 #define DP_EXTERN extern "C"
53 #define DP_PRIVATE_EXTERN __private_extern__
54 #else
55 #define DP_EXTERN extern
56 #define DP_PRIVATE_EXTERN __private_extern__
57 #endif
60 // For Windows
63 #elif defined(WIN32)
65 #ifndef _CKBUILDING_DP_DLL
66 #define _CKWINDOWS_DLL_GOOP __declspec(dllimport)
67 #else
68 #define _CKWINDOWS_DLL_GOOP __declspec(dllexport)
69 #endif
71 #ifdef __cplusplus
72 #define DP_EXTERN extern "C" _CKWINDOWS_DLL_GOOP
73 #define DP_PRIVATE_EXTERN extern
74 #else
75 #define DP_EXTERN _CKWINDOWS_DLL_GOOP extern
76 #define DP_PRIVATE_EXTERN extern
77 #endif
80 // For Solaris
83 #elif defined(SOLARIS)
85 #ifdef __cplusplus
86 #define DP_EXTERN extern "C"
87 #define DP_PRIVATE_EXTERN extern "C"
88 #else
89 #define DP_EXTERN extern
90 #define DP_PRIVATE_EXTERN extern
91 #endif
93 #endif
96 // Static Inline
98 #if !defined(DP_STATIC_INLINE)
99 #if defined (__GNUC__) && (__GNUC__ == 4)
100 #define DP_STATIC_INLINE static __inline__ __attribute__((always_inline))
101 #else
102 #define DP_STATIC_INLINE static __inline__
103 #endif
104 #endif
107 // Extern Inline
109 #if !defined(DP_EXTERN_INLINE)
110 #define DP_EXTERN_INLINE extern __inline__
111 #endif
113 //===============================================
115 #pragma mark Runtime Versions Compatibility Layer
118 * This section contains a compatibility layer between Objective-C 1
119 * (MacOS X 10.4) and Objective-C 2.0 (MacOS X 10.5).
120 * Mostly, this layer implements the new (v2.0) API for the old
121 * (v1) runtime, as thew new API is much cleaner and simpler to
122 * work with.
123 * In addition, a new type dp_marg_list is defined, that matches
124 * the runtime's marg_list type. As both types are interchangeable,
125 * you can freely use dp_marg_list instead of marg_list (which is
126 * the recommended way).
127 * WARNING: This API wasn't tested under ObjC 2.0 and might not
128 * even compile. Use at your own risk!
131 #ifndef _DP_OBJC_COMPATIBILITY_H
132 #define _DP_OBJC_COMPATIBILITY_H
135 /**************************************
136 * Objective-C v1 *
137 **************************************/
138 //#pragma mark Objective-C I
139 /* Stuff that exist in the Objective-C 2 runtime, but not in v1 */
140 #if !__OBJC2__
142 #import <objc/objc-class.h>
143 #import <objc/objc-runtime.h>
144 #import <objc/Protocol.h> // for objc_method_description
147 // Methods manipulation
149 #define method_getName(m) (m->method_name)
150 #define method_getImplementation(m) (m->method_imp)
151 #define method_getTypeEncoding(m) (m->method_types)
152 #define method_setImplementation(m, imp) ({IMP __r = m->method_imp; m->method_imp = imp; __r;})
154 DP_EXTERN char *method_copyReturnType(Method m);
155 DP_EXTERN char *method_copyArgumentType(Method m, unsigned int index);
156 DP_EXTERN void method_getReturnType(Method m, char *dst, size_t dst_len);
157 DP_EXTERN void method_getArgumentType(Method m, unsigned int index,
158 char *dst, size_t dst_len);
160 // struct objc_method_description *method_getDescription(Method m)
161 #define method_getDescription(m) \
162 ({ \
163 struct objc_method_description __desc; \
164 __desc.name = method_getName(m); \
165 __desc.types = method_getTypeEncoding(m); \
166 &__desc; \
170 // Class manipulation
172 #define class_getName(cls) (((Class)cls)->name)
173 #define class_getSuperclass(cls) (((Class)cls)->super_class)
174 #define class_getInstanceSize(cls) ( (size_t)(((Class)cls)->instance_size) )
175 DP_EXTERN Method * class_copyMethodList(Class cls, unsigned int *outCount);
176 DP_EXTERN BOOL class_addMethod(Class cls, SEL name, IMP imp,
177 const char *types);
180 // Selectors
182 /* Shouldn't this work with the new runtime as well? */
183 #define sel_isEqual(s1, s2) (s1 == s2)
186 // Classes and objects inspection
189 #define class_isMetaClass(cls) ((((Class)cls)->info & CLS_META) != 0)
190 #define object_getClass(obj) (obj->isa)
192 DP_EXTERN BOOL class_respondsToSelector(Class cls, SEL sel);
195 #define _CLS_IS_CLASS(cls) ((((Class)cls)->info & CLS_CLASS) != 0)
196 #define _CLS_IS_META(cls) ((((Class)cls)->info & CLS_META) != 0)
197 #define _CLS_GET_META(cls) (_CLS_IS_META(cls) ? cls : cls->isa)
201 // Missing types
203 #define _C_CONST 'r'
206 /**************************************
207 * Objective-C v2 *
208 **************************************/
209 //#pragma mark Objective-C II
210 /* Compatibility with the older Objective-C runtime */
211 #else // ObjC 2
213 #include <objc/runtime.h>
214 #include <objc/message.h>
215 #include <machine/types.h> // For uintptr_t
216 #include <malloc/malloc.h> // For malloc_size
218 #endif // !__OBJC2__
221 //#pragma mark -
223 // These are defined in the GNU runtime but not in Apple's runtime,
224 // although the characters are the same.
225 #ifndef _C_IN
226 #define _C_IN 'n'
227 #endif
229 #ifndef _C_INOUT
230 #define _C_INOUT 'N'
231 #endif
233 #ifndef _C_OUT
234 #define _C_OUT 'o'
235 #endif
237 #ifndef _C_BYCOPY
238 #define _C_BYCOPY 'O'
239 #endif
241 #ifndef _C_BYREF
242 #define _C_BYREF 'R'
243 #endif
245 #ifndef _C_ONEWAY
246 #define _C_ONEWAY 'V'
247 #endif
251 // Working with marg_list
254 /* PPC and PPC64 */
255 #if defined(__ppc__) || defined(__ppc64__)
257 #if __OBJC2__
258 typedef ppc_marg_list dp_ppc_marg_list;
259 typedef ppc64_marg_list dp_ppc64_marg_list;
260 #else
261 typedef struct {
262 double fpParams[13]; // F1..F13
263 uintptr_t linkage[6]; // ignored by objc_msgSendv; do not modify
264 uintptr_t regParams[8]; // R3..R10; objc_msgSendv ignores R3 and R4
265 uintptr_t stackParams[0]; // variable-size
266 } *dp_ppc_marg_list, *dp_ppc64_marg_list;
267 #endif
269 #define dp_marg_size (13 * sizeof(double) + (6 + 8) * sizeof(uintptr_t))
270 #define dp_marg_var_space (8 * sizeof(uintptr_t) /* regParams */)
272 /* i386 */
273 #elif defined(__i386__)
275 #if __OBJC2__
276 typedef x86_marg_list dp_x86_marg_list;
277 typedef i386_marg_list dp_i386_marg_list;
278 #else
279 typedef struct {
280 uintptr_t params[0]; // variable-size
281 } *dp_x86_marg_list, *dp_i386_marg_list;
282 #endif
284 // i386 passes arguments on stack
285 #define dp_marg_size 0
286 #define dp_marg_var_space 0
288 /* x86-64 */
289 #elif defined(__x86_64__)
291 #if __OBJC2__
292 typedef x86_64_marg_list dp_x86_64_marg_list;
294 #define dp_marg_size ( (sizeof(double) + sizeof(char) * 16) * 8 /* fpParams */\
295 + sizeof(uintptr_t) * 10 /* r10 + rax + linkage + regParams */)
296 #define dp_marg_var_space (6 * sizeof(uintptr_t) /* regParams */)
298 #else // __ObjC2__
299 # error x86-64 is not supported in ObjC 1
300 #endif
302 #else // PPC, PPC64, i386, x86-64
303 # error unknown architecture
304 #endif // PPC, PPC64, i386, x86-64
307 * This is the fixed size of the marg_list.
308 * This size plus the size returned from method_getSizeOfArguments()
309 * is the total size of the arguments list.
310 * Use dp_marg_alloc() for marg_list allocation.
312 #define dp_marg_prearg_size (dp_marg_size - dp_marg_var_space)
316 * If you need to work with marg_list, use dp_marg_list which works on all architectures
317 * and both on ObjC 1 and 2.
318 * An abstraction layer for modifying the contents of the arguments list is not yet
319 * supported, so you'll have to be very careful and read the function calling ABI
320 * of your target architectures.
322 #if defined(__ppc__) || defined(__ppc64__)
323 typedef dp_ppc_marg_list dp_marg_list;
324 #elif defined(__i386__)
325 typedef dp_i386_marg_list dp_marg_list;
326 #elif defined(__x86_64__)
327 typedef dp_x86_64_marg_list dp_marg_list;
328 #else
329 # error unknown architecture
330 #endif
332 #endif // _DP_OBJC_COMPATIBILITY_H
334 #pragma mark -
335 #pragma mark A simplified API for some parts of the runtime
338 // Size and alignment of types
340 #if __OBJC2__
341 #define sizeOfType(t...) ({ NSUInteger __s; NSGetSizeAndAlignment(t, &__s, NULL); __s; })
342 #define alignOfType(t...) ({ NSUInteger __s; NSGetSizeAndAlignment(t, NULL, &__s); __s; })
343 #else
344 #define sizeOfType(t...) ({ unsigned int __s; NSGetSizeAndAlignment(t, &__s, NULL); __s; })
345 #define alignOfType(t...) ({ unsigned int __s; NSGetSizeAndAlignment(t, NULL, &__s); __s; })
346 #endif
350 // Type descriptions
352 DP_EXTERN unsigned dp_getNumberOfArguments(const char *typedesc);
353 DP_EXTERN unsigned dp_getArgumentInfo(const char *typedesc, int argIndex, const char** type, int* offset);
354 DP_EXTERN unsigned dp_getSizeOfArguments(const char *typedesc);
355 DP_EXTERN void dp_getReturnType(const char *typedesc, char *dst, size_t dst_len);
359 // Classes and objects inspection
361 #define class_isClass(cls) class_isMetaClass(cls->isa)
362 DP_EXTERN BOOL class_isSubclassOfClass(Class cls, Class superCls);
364 #define object_isInstance(obj) class_isClass(obj->isa)
365 #define object_getClass(obj) (obj->isa)
366 #define object_isKindOfClass(obj, superCls) class_isSubclassOfClass(object_getClass(obj), superCls)
368 // Handles both objects and classes
369 DP_EXTERN_INLINE BOOL object_respondsToSelector(id object, SEL sel);
371 DP_EXTERN_INLINE Method dp_getMethod(id obj, SEL sel);
373 // Returns a NULL terminated array of classes (it's up to you to release it)
374 DP_EXTERN_INLINE Class *dp_copyClassList(void);
378 // Selectors
380 DP_EXTERN_INLINE unsigned int sel_getNumberOfArguments(SEL sel); // Always takes the self and _cmd arguments in count
384 // Allocation/copying of marg_list
387 #define dp_marg_malloc(argsSize) malloc(dp_marg_prearg_size + (7 + argsSize & ~7) /* <- huh? */)
389 #define dp_marg_alloc(method) dp_marg_malloc(method_getSizeOfArguments(method))
390 #define dp_marg_copy(margs, method) \
391 ({ marg_list __marg = dp_marg_alloc(method); memcpy(__marg, margs, malloc_size(__marg)); })
394 // Accessing integral types
396 #define dp_margGetObjectRef(margs, offset, type) \
397 ((type *)((char *)margs + dp_marg_prearg_size + offset))
399 #define dp_margGetObject(margs, offset, type) \
400 (*dp_margGetObjectRef(margs, offset, type))
402 #define dp_margSetObject(margs, offset, type, value) \
403 ( dp_margGetObject(margs, offset, type) = (value) )
407 // Messaging
410 DP_EXTERN id dp_msgSendv(id target, SEL sel, marg_list args);
413 #endif //_DP_OBJCRUNTIME_H