]> git.saurik.com Git - wxWidgets.git/blob - include/wx/cocoa/objc/objc_uniquifying.h
cleanup
[wxWidgets.git] / include / wx / cocoa / objc / objc_uniquifying.h
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: wx/cocoa/objc/objc_uniquifying.h
3 // Purpose: Allows wxWidgets code to get a direct pointer to a compiled
4 // Objective-C class and provides a method to fix up the
5 // name to include a unique identifier (currently the address
6 // of the objc_class structure).
7 // Author: David Elliott <dfe@cox.net>
8 // Modified by:
9 // Created: 2007/05/15
10 // RCS-ID: $Id$
11 // Copyright: (c) 2007 Software 2000 Ltd.
12 // Licence: wxWindows licence
13 /////////////////////////////////////////////////////////////////////////////
14
15 #ifndef __WX_COCOA_OBJC_CLASS_H__
16 #define __WX_COCOA_OBJC_CLASS_H__
17
18 /* A note about this header:
19 Nothing in here is guaranteed to exist in future versions of wxCocoa. There
20 are other ways of adding Objective-C classes at runtime and a future wxCocoa
21 might use these instead of this ugly hack. You may use this header file in
22 your own wxCocoa code if you need your own Objective-C classes to be
23 unqiuified.
24
25 You cannot turn this on for 64-bit mode. It will not compile due to opaque
26 Objective-C data structures and it is not needed because it is a workaround
27 for a bug that does not exist in the 64-bit runtime.
28
29 You should not use this when wxCocoa is built as a dynamic library. This has
30 only been tested for the case when wxCocoa is built as a static library and
31 statically linked to user code to form a loadable bundle (e.g. a Cocoa plugin).
32 It forces each plugin (when multiple wxCocoa-using plugins are used) to use
33 its own internal Objective-C classes which is desirable when wxCocoa is
34 statically linked to the rest of the code.
35
36 Do not use uniquifying on your principal class. That one should be named
37 differently for different bundles.
38 */
39
40 #if wxUSE_OBJC_UNIQUIFYING
41
42 // objc_getClass and stuff
43 #include <objc/objc-runtime.h>
44
45 ////////////// Objective-C uniquifying implementation //////////////
46
47 template <typename ObjcType>
48 class wxObjcClassInitializer;
49
50 template <typename ObjcType>
51 class UniquifiedName;
52
53 template <typename ObjcType>
54 class wxObjcCompilerInformation
55 {
56 friend class wxObjcClassInitializer<ObjcType>;
57 friend class UniquifiedName<ObjcType>;
58 private:
59 // GetCompiledClass must be partially specialized for an ObjcType
60 // If you're not using it, implement an inline returning NULL
61 inline static struct objc_class * GetCompiledClass();
62
63 // sm_theClassName must be partially specialized for each type
64 static const char sm_theClassName[];
65
66 // GetSuperclass must be specialized. Typically one of two ways:
67 // 1. objc_getClass("SomeRealClassName")
68 // 2. wxGetObjcClass_SomeWxClassName();
69 inline static struct objc_class *GetSuperclass();
70 };
71
72
73 template <typename ObjcType>
74 struct UniquifiedName
75 {
76 // We're going for OriginalClassName@ClassStructureAddress
77 // Therefore our size is the sizeof the original class name constant string (which includes the terminating NULL)
78 // plus the sizeof a pointer to struct objc_class times two (two hex digits for each byte) plus 3 for "@0x"
79 typedef char Type[sizeof(wxObjcCompilerInformation<ObjcType>::sm_theClassName) + (sizeof(struct objc_class*)<<1) + 3];
80 static void Init(Type m_theString, const objc_class *aClass)
81 {
82 snprintf(const_cast<char*>(m_theString), sizeof(Type), "%s@%p", wxObjcCompilerInformation<ObjcType>::sm_theClassName, aClass);
83 }
84 };
85
86 template <typename ObjcType>
87 class wxObjcClassInitializer
88 {
89 public:
90 static struct objc_class* Get()
91 {
92 static wxObjcClassInitializer<ObjcType> s_theInstance;
93 s_theInstance.noop(); // Make the compiler think we need this instance
94 return wxObjcCompilerInformation<ObjcType>::GetCompiledClass();
95 }
96 private:
97 void noop()
98 {}
99 // This "constructor" operates solely on static data
100 // It exists so that we can take advantage of a function-static
101 // "instance" of this class to do the static data initialization.
102 wxObjcClassInitializer()
103 {
104 // Objective-C class initialization occurs before C++ static initialization because the
105 // libobjc.dylib gets notified directly by dyld on Tiger.
106 // Therefore, even though we change the name, the class is still registered with the
107 // original name. We unfortunately can't change that.
108
109 // The first time the class is loaded, Objective-C will already have fixed up the super_class
110 // and isa->isa and isa->super_class variables so much of this won't do anything. But
111 // the next time the class is loaded, Objective-C will ignore it and thus we need to
112 // initialize the data structures appropriately.
113
114 // Ideally we'd have some sort of lock here, but we depend on the fact that we get called
115 // just before the first time someone wants to send a class message so it should be
116 // reasonably safe to do this without any locks.
117
118 struct objc_class &theClassData = *wxObjcCompilerInformation<ObjcType>::GetCompiledClass();
119 // Initialize the uniquified class name
120 UniquifiedName<ObjcType>::Init(sm_theUniquifiedClassName, &theClassData);
121
122 //////// Class Initialization ////////
123 // Use objc_getClass to fix up the superclass pointer
124 theClassData.super_class = wxObjcCompilerInformation<ObjcType>::GetSuperclass();
125 // Fix up the compiler generated class struct to use the new name
126 theClassData.name = sm_theUniquifiedClassName;
127
128 //////// Meta-Class Initialization ////////
129 // theClassData.isa is the metaclass pointer
130 // Globals on Darwin use PC-relative access (slow) so it's quicker to use theClassData.isa
131
132 // In any object hierarchy a metaclass's metaclass is always the root class's metaclass
133 // Therefore, our superclass's metaclass's metaclass should already be the root class's metaclass
134 theClassData.isa->isa = theClassData.super_class->isa->isa;
135 // A metaclass's superclass is always the superclass's metaclass.
136 theClassData.isa->super_class = theClassData.super_class->isa;
137 // Fix up the compiler generated metaclass struct to use the new name
138 theClassData.isa->name = sm_theUniquifiedClassName;
139
140 // We need to set the initialized flag because after we change the name, Objective-C can't
141 // look us up by name because we're only registered with the original name.
142 theClassData.isa->info |= CLS_INITIALIZED;
143 }
144 wxObjcClassInitializer(const wxObjcClassInitializer&); // NO COPY
145 wxObjcClassInitializer& operator =(const wxObjcClassInitializer&); // NO ASSIGN
146 static typename UniquifiedName<ObjcType>::Type sm_theUniquifiedClassName;
147 };
148
149 template<typename ObjcType>
150 typename UniquifiedName<ObjcType>::Type wxObjcClassInitializer<ObjcType>::sm_theUniquifiedClassName;
151
152 // WX_DECLARE_GET_OBJC_CLASS
153 // Declares a function to get a direct pointer to an objective-C class.
154 // The class is guaranteed to be usable.
155 // When wxCocoa is built into a Mach-O bundle this function allows the wxCocoa
156 // code to get a reference to the Objective-C class structure located in the
157 // same bundle. This allows a static wxCocoa library to be built into
158 // two different Mach-O bundles without having one bundle's Objective-C
159 // classes trample on the other's.
160 // Right now we toss the ObjcSuperClass parameter, but we might use it later.
161 #define WX_DECLARE_GET_OBJC_CLASS(ObjcClass,ObjcSuperClass) \
162 struct objc_class* wx_GetObjcClass_ ## ObjcClass();
163
164 // WX_IMPLEMENT_OBJC_GET_COMPILED_CLASS(ObjcClass)
165 // Provides an architecture-dependent way to get the direct pointer to the
166 // objc_class structure in the __OBJC segment.
167 // This takes advantage of the fact that the Objective-C compiler uses guessable
168 // local assembler labels for the class structures.
169 // Those class structures are only available on the Objective-C file containing the
170 // @implementation block.
171
172 #if 1
173 // Generic implementation - Tested on i386 and PPC. Should work in all cases.
174 // This is a hack that depends on GCC asm symbol names.
175 // The static variable winds up being initialized with a direct reference to the appropriate
176 // L_OBJC_CLASS and no global symbol reference is generated because nothing uses the global symbol
177 // except for the static initializer which does it directly.
178 // The generated assembler for s_objc_class_ptr is basically like this:
179 // _s_objc_class_ptr_ObjcClass:
180 // .long L_OBJC_CLASS_ObjcClass
181 // Once that static symbol is defined, the function implementation is easy for GCC to generate.
182 // Do note that return &s_objc_class_data_ObjcClass won't work. The code is wrong in the case.
183 #define WX_IMPLEMENT_OBJC_GET_COMPILED_CLASS(ObjcClass) \
184 extern "C" objc_class s_objc_class_data_ ## ObjcClass asm("L_OBJC_CLASS_" #ObjcClass); \
185 static objc_class * s_objc_class_ptr_ ## ObjcClass = &s_objc_class_data_ ## ObjcClass; \
186 template<> \
187 inline objc_class * wxObjcCompilerInformation<ObjcClass>::GetCompiledClass() \
188 { \
189 return s_objc_class_ptr_## ObjcClass; \
190 }
191
192 #elif defined(__i386__)
193 // Not used because the generic implementation seems to work fine.
194 // But this is here since it was written beforehand and it also works.
195
196 // This is based on the code GCC generates for accessing file-static data on i386.
197 // The i386 PC-relative addressing happens in this manner
198 // 1. The program counter is placed into ecx using the code that GCC should have
199 // already generated.
200 // 2. A label is placed directly after the call to get the program counter.
201 // 3. The Load Effective Address instruction is used to add the offset of the
202 // local assembler label we're interested in minus the local assembler label
203 // from step 2 to the program counter register in ecx and place the result
204 // into the result register (typically eax if not inlined).
205 #define WX_IMPLEMENT_OBJC_GET_COMPILED_CLASS(ObjcClass) \
206 template<> \
207 inline objc_class * wxObjcCompilerInformation<ObjcClass>::GetCompiledClass() \
208 { \
209 register struct objc_class *retval; \
210 asm \
211 ( "call ___i686.get_pc_thunk.cx\n" \
212 "\"LPC_FOR_GET_CLASS_" #ObjcClass "\":\n\t" \
213 "leal L_OBJC_CLASS_" #ObjcClass "-\"LPC_FOR_GET_CLASS_" #ObjcClass "\"(%%ecx), %0" \
214 : "=r"(retval) \
215 : \
216 : "ecx" \
217 ); \
218 return retval; \
219 }
220
221 #elif defined(__ppc__)
222 // Not used because the generic implementation seems to work fine.
223 // But this is here since it was written beforehand and it also works.
224
225 // This is based on the code GCC generates for accessing file-static data on PPC.
226 // The PowerPC PC-relative addressing happens in this manner
227 // 1. The link register is saved (mflr) to a temporary (we re-use the output register for this)
228 // 2. An unconditional branch instruction (bcl) "branches" to the following address (labeled)
229 // 3. The link register (filled in by bcl) is saved to r10 (a temporary)
230 // 4. The previous link register is restored (mtlr) (from the output register we were using as a temporary)
231 // 5. The address of the LPC label as executed is added to the high 16 bits of the offset between that label and the static data we want
232 // and stored in a temporary register (r2)
233 // 6. That temporary register plus the low 16 bits of the offset are stored into the result register.
234 #define WX_IMPLEMENT_OBJC_GET_COMPILED_CLASS(ObjcClass) \
235 template<> \
236 inline objc_class * wxObjcCompilerInformation<ObjcClass>::GetCompiledClass() \
237 { \
238 register struct objc_class *retval; \
239 asm \
240 ( "mflr %0" \
241 "\n\tbcl 20, 31, \"LPC_FOR_GET_CLASS_" #ObjcClass "\"" \
242 "\n\"LPC_FOR_GET_CLASS_" #ObjcClass "\":" \
243 "\n\tmflr r10" \
244 "\n\tmtlr %0" \
245 "\n\taddis r2,r10,ha16(L_OBJC_CLASS_" #ObjcClass "-\"LPC_FOR_GET_CLASS_" #ObjcClass "\")" \
246 "\n\tla %0,lo16(L_OBJC_CLASS_" #ObjcClass "-\"LPC_FOR_GET_CLASS_" #ObjcClass "\")(r2)" \
247 : "=r" (retval) \
248 : \
249 : "r10","r2" \
250 ); \
251 return retval; \
252 }
253
254 // TODO: __x86_64__, __ppc64__
255 #else // Can't wrie inline asm to bust into __OBJC segment
256 // This won't be used since the generic implementation takes precedence.
257
258 #warning "Don't know how to implement wxObjcCompilerInformation<ObjcClass>::GetCompiledClass on this platform"
259
260 #endif // platforms
261
262 // The WX_IMPLEMENT_OBJC_GET_SUPERCLASS macro implements the template specialization
263 // to get the superclass. This only works if it's a real superclass. If you are
264 // deriving from a class that's already being uniquified then you'd need to
265 // implement the specialization to call the appropriate get method instead.
266 #define WX_IMPLEMENT_OBJC_GET_SUPERCLASS(ObjcClass,ObjcSuperClass) \
267 template <> \
268 inline objc_class* wxObjcCompilerInformation<ObjcClass>::GetSuperclass() \
269 { \
270 return objc_getClass(#ObjcSuperClass); \
271 }
272
273 // The WX_IMPLEMENT_OBJC_CLASS_NAME macro implements the template specialization
274 // of the sm_theClassName constant. As soon as this specialization is in place
275 // sizeof(sm_theClassName) will return the number of bytes at compile time.
276 #define WX_IMPLEMENT_OBJC_CLASS_NAME(ObjcClass) \
277 template <> \
278 const char wxObjcCompilerInformation<ObjcClass>::sm_theClassName[] = #ObjcClass;
279
280 // The WX_IMPLEMENT_GET_OBJC_CLASS macro combines all of these together and adds
281 // a global wx_GetObjcClass_ObjcClass() function.
282 #define WX_IMPLEMENT_GET_OBJC_CLASS(ObjcClass,ObjcSuperClass) \
283 WX_IMPLEMENT_OBJC_GET_COMPILED_CLASS(ObjcClass) \
284 WX_IMPLEMENT_OBJC_GET_SUPERCLASS(ObjcClass,ObjcSuperClass) \
285 WX_IMPLEMENT_OBJC_CLASS_NAME(ObjcClass) \
286 objc_class* wx_GetObjcClass_ ## ObjcClass() \
287 { \
288 return wxObjcClassInitializer<ObjcClass>::Get(); \
289 }
290
291 // The WX_GET_OBJC_CLASS macro is intended to wrap the class name when the class
292 // is used as a message receiver (e.g. for calling class methods). When
293 // class name uniquifying is used, this calls the global function implemented
294 // in the Objective-C file containing the class @implementation.
295 #define WX_GET_OBJC_CLASS(ObjcClass) wx_GetObjcClass_ ## ObjcClass()
296
297 #else // wxUSE_OBJC_UNIQUIFYING
298
299 // Define WX_DECLARE_GET_OBJC_CLASS as nothing
300 #define WX_DECLARE_GET_OBJC_CLASS(ObjcClass,ObjcSuperClass)
301 // Define WX_IMPLEMENT_GET_OBJC_CLASS as nothing
302 #define WX_IMPLEMENT_GET_OBJC_CLASS(ObjcClass,ObjcSuperClass)
303
304 // Define WX_GET_OBJC_CLASS macro to output the class name and let the compiler do the normal thing
305 // The WX_GET_OBJC_CLASS macro is intended to wrap the class name when the class
306 // is used as a message receiver (e.g. for calling class methods). When
307 // class name uniquifying is not used, this is simply defined to be the class
308 // name which will allow the compiler to do the normal thing.
309 #define WX_GET_OBJC_CLASS(ObjcClass) ObjcClass
310
311 #endif // wxUSE_OBJC_UNIQUIFYING
312
313 #endif //ndef __WX_COCOA_OBJC_CLASS_H__