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