~ubuntu-branches/ubuntu/trusty/monodevelop/trusty-proposed

« back to all changes in this revision

Viewing changes to external/monomac/src/ObjCRuntime/Class.cs

  • Committer: Package Import Robot
  • Author(s): Jo Shields
  • Date: 2013-05-12 09:46:03 UTC
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20130512094603-mad323bzcxvmcam0
Tags: upstream-4.0.5+dfsg
ImportĀ upstreamĀ versionĀ 4.0.5+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
25
25
// Class.cs
26
26
//
27
27
// Copyright 2009 Novell, Inc
 
28
// Copyright 2013 Xamarin Inc
28
29
//
29
30
using System;
30
31
using System.Reflection;
35
36
 
36
37
namespace MonoMac.ObjCRuntime {
37
38
         public class Class : INativeObject {
38
 
#if OBJECT_REF_TRACKING
39
 
                static NativeMethodBuilder release_builder = new NativeMethodBuilder (typeof (NSObject).GetMethod ("NativeRelease", BindingFlags.NonPublic | BindingFlags.Instance));
40
 
                static NativeMethodBuilder retain_builder = new NativeMethodBuilder (typeof (NSObject).GetMethod ("NativeRetain", BindingFlags.NonPublic | BindingFlags.Instance));
41
 
#endif
 
39
                public static bool ThrowOnInitFailure = true;
 
40
 
42
41
                static Dictionary <IntPtr, Type> type_map = new Dictionary <IntPtr, Type> ();
43
 
                static List <Type> custom_types = new List <Type> ();
 
42
                static Dictionary <Type, Type> custom_types = new Dictionary <Type, Type> ();
44
43
                static List <Delegate> method_wrappers = new List <Delegate> ();
 
44
                static object lock_obj = new object ();
45
45
 
46
46
                internal IntPtr handle;
47
47
 
49
49
                        this.handle = objc_getClass (name);
50
50
 
51
51
                        if (this.handle == IntPtr.Zero)
52
 
                                throw new ArgumentException ("name is an unknown class", name);
 
52
                                throw new ArgumentException (String.Format ("name {0} is an unknown class", name), "name");
53
53
                }
54
54
 
55
55
                public Class (Type type) {
78
78
                                return Marshal.PtrToStringAuto (ptr);
79
79
                        }
80
80
                }
 
81
                
 
82
                internal static string GetName (IntPtr @class)
 
83
                {
 
84
                        return Marshal.PtrToStringAuto (class_getName (@class));
 
85
                }
81
86
 
82
87
                public static IntPtr GetHandle (string name) {
83
88
                        return objc_getClass (name);
84
89
                }
 
90
                
 
91
                public static IntPtr GetHandle (Type type) {
 
92
                        RegisterAttribute attr = (RegisterAttribute) Attribute.GetCustomAttribute (type, typeof (RegisterAttribute), false);
 
93
                        string name = attr == null ? type.FullName : attr.Name ?? type.FullName;
 
94
                        bool is_wrapper = attr == null ? false : attr.IsWrapper;
 
95
                        var handle = objc_getClass (name);
 
96
                        
 
97
                        if (handle == IntPtr.Zero)
 
98
                                handle = Class.Register (type, name, is_wrapper);
 
99
                        
 
100
                        return handle;
 
101
                }
85
102
 
86
103
                public static bool IsCustomType (Type type) {
87
 
                        return custom_types.Contains (type);
88
 
                }
89
 
 
90
 
                internal static Type Lookup (IntPtr klass) {
 
104
                        lock (lock_obj)
 
105
                                return custom_types.ContainsKey (type);
 
106
                }
 
107
 
 
108
                internal static Type Lookup (IntPtr klass)
 
109
                {
 
110
                        return Lookup (klass, true);
 
111
                }
 
112
 
 
113
                internal static Type Lookup (IntPtr klass, bool throw_on_error) {
91
114
                        // FAST PATH
92
 
                        Type type;
93
 
                        if (type_map.TryGetValue (klass, out type))
94
 
                                return type;
95
 
 
96
 
                        // TODO:  When we type walk we currently populate the type map
97
 
                        // from the walk point with the target, we should gather some 
98
 
                        // stats here, and see how many times there is a intermediate class
99
 
                        // and see if we should populate them in the map as well
100
 
                        IntPtr orig_klass = klass;
101
 
 
102
 
                        do {
103
 
                                IntPtr kls = class_getSuperclass (klass);
104
 
 
105
 
                                if (type_map.TryGetValue (kls, out type)) {
106
 
                                        type_map [orig_klass] = type;
 
115
                        lock (lock_obj) {
 
116
                                Type type;
 
117
                                if (type_map.TryGetValue (klass, out type))
107
118
                                        return type;
108
 
                                }
109
 
 
110
 
                                klass = kls;
111
 
                        } while (true);
 
119
 
 
120
                                // TODO:  When we type walk we currently populate the type map
 
121
                                // from the walk point with the target, we should gather some 
 
122
                                // stats here, and see how many times there is a intermediate class
 
123
                                // and see if we should populate them in the map as well
 
124
                                IntPtr orig_klass = klass;
 
125
 
 
126
                                do {
 
127
                                        IntPtr kls = class_getSuperclass (klass);
 
128
 
 
129
                                        if (type_map.TryGetValue (kls, out type)) {
 
130
                                                type_map [orig_klass] = type;
 
131
                                                return type;
 
132
                                        }
 
133
 
 
134
                                        if (kls == IntPtr.Zero) {
 
135
                                                if (!throw_on_error)
 
136
                                                        return null;
 
137
 
 
138
                                                var message = "Could not find a valid superclass for type " + new Class (orig_klass).Name 
 
139
                                                        + ". Did you forget to register the bindings at " + typeof(Class).FullName
 
140
                                                        + ".Register() or call NSApplication.Init()?";
 
141
                                                throw new ArgumentException (message);
 
142
                                        }
 
143
 
 
144
                                        klass = kls;
 
145
                                } while (true);
 
146
                        }
112
147
                }
113
148
 
114
149
                internal static IntPtr Register (Type type) { 
115
150
                        RegisterAttribute attr = (RegisterAttribute) Attribute.GetCustomAttribute (type, typeof (RegisterAttribute), false);
116
151
                        string name = attr == null ? type.FullName : attr.Name ?? type.FullName;
117
 
                        return Class.Register (type, name);
 
152
                        bool is_wrapper = attr == null ? false : attr.IsWrapper;
 
153
                        return Register (type, name, is_wrapper);
118
154
                }
119
155
 
120
 
                internal unsafe static IntPtr Register (Type type, string name) {
 
156
                static IntPtr Register (Type type, string name, bool is_wrapper) {
121
157
                        IntPtr parent = IntPtr.Zero;
122
158
                        IntPtr handle = IntPtr.Zero;
123
159
 
124
160
                        handle = objc_getClass (name);
125
161
 
126
 
                        if (handle != IntPtr.Zero) {
127
 
                                if (!type_map.ContainsKey (handle)) {
128
 
                                        type_map [handle] = type;
 
162
                        lock (lock_obj) {
 
163
                                if (handle != IntPtr.Zero) {
 
164
                                        if (!type_map.ContainsKey (handle)) {
 
165
                                                type_map [handle] = type;
 
166
                                        }
 
167
                                        return handle;
129
168
                                }
130
 
                                return handle;
131
 
                        }
132
 
 
133
 
                        if (objc_getProtocol (name) != IntPtr.Zero)
134
 
                                throw new ArgumentException ("Attempting to register a class named: " + name + " which is a valid protocol");
135
 
 
136
 
                        Type parent_type = type.BaseType;
137
 
                        string parent_name = null;
138
 
                        while (Attribute.IsDefined (parent_type, typeof (ModelAttribute), false))
139
 
                                parent_type = parent_type.BaseType;
140
 
                        RegisterAttribute parent_attr = (RegisterAttribute) Attribute.GetCustomAttribute (parent_type, typeof (RegisterAttribute), false);
141
 
                        parent_name = parent_attr == null ? parent_type.FullName : parent_attr.Name ?? parent_type.FullName;
142
 
                        parent = objc_getClass (parent_name);
143
 
                        if (parent == IntPtr.Zero && parent_type.Assembly != NSObject.MonoMacAssembly) {
144
 
                                // Its possible as we scan that we might be derived from a type that isn't reigstered yet.
145
 
                                Class.Register (parent_type, parent_name);
 
169
 
 
170
                                if (objc_getProtocol (name) != IntPtr.Zero)
 
171
                                        throw new ArgumentException ("Attempting to register a class named: " + name + " which is a valid protocol");
 
172
                                
 
173
                                if (is_wrapper)
 
174
                                        return IntPtr.Zero;
 
175
 
 
176
                                Type parent_type = type.BaseType;
 
177
                                string parent_name = null;
 
178
                                while (Attribute.IsDefined (parent_type, typeof (ModelAttribute), false))
 
179
                                        parent_type = parent_type.BaseType;
 
180
                                RegisterAttribute parent_attr = (RegisterAttribute)Attribute.GetCustomAttribute (parent_type, typeof(RegisterAttribute), false);
 
181
                                parent_name = parent_attr == null ? parent_type.FullName : parent_attr.Name ?? parent_type.FullName;
146
182
                                parent = objc_getClass (parent_name);
147
 
                        }
148
 
                        if (parent == IntPtr.Zero) {
149
 
                                // This spams mtouch, we need a way to differentiate from mtouch's (ab)use
150
 
                                // Console.WriteLine ("CRITICAL WARNING: Falling back to NSObject for type {0} reported as {1}", type, parent_type);
151
 
                                parent = objc_getClass ("NSObject");
152
 
                        }
153
 
                        handle = objc_allocateClassPair (parent, name, IntPtr.Zero);
154
 
 
155
 
                        foreach (PropertyInfo prop in type.GetProperties (BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) {
156
 
                                ConnectAttribute cattr = (ConnectAttribute) Attribute.GetCustomAttribute (prop, typeof (ConnectAttribute));
157
 
                                if (cattr != null) {
158
 
                                        string ivar_name = cattr.Name ?? prop.Name;
159
 
                                        class_addIvar (handle, ivar_name, (IntPtr) Marshal.SizeOf (typeof (IntPtr)), (ushort) Math.Log (Marshal.SizeOf (typeof (IntPtr)), 2), "@");
160
 
                                }
161
 
 
162
 
                                RegisterProperty (prop, type, handle);
163
 
                        }
 
183
                                if (parent == IntPtr.Zero && parent_type.Assembly != NSObject.MonoMacAssembly) {
 
184
                                        bool parent_is_wrapper = parent_attr == null ? false : parent_attr.IsWrapper;
 
185
                                        // Its possible as we scan that we might be derived from a type that isn't reigstered yet.
 
186
                                        Register (parent_type, parent_name, parent_is_wrapper);
 
187
                                        parent = objc_getClass (parent_name);
 
188
                                }
 
189
                                if (parent == IntPtr.Zero) {
 
190
                                        // This spams mtouch, we need a way to differentiate from mtouch's (ab)use
 
191
                                        // Console.WriteLine ("CRITICAL WARNING: Falling back to NSObject for type {0} reported as {1}", type, parent_type);
 
192
                                        parent = objc_getClass ("NSObject");
 
193
                                }
 
194
                                handle = objc_allocateClassPair (parent, name, IntPtr.Zero);
 
195
 
 
196
                                foreach (PropertyInfo prop in type.GetProperties (BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) {
 
197
                                        ConnectAttribute cattr = (ConnectAttribute)Attribute.GetCustomAttribute (prop, typeof(ConnectAttribute));
 
198
                                        if (cattr != null) {
 
199
                                                string ivar_name = cattr.Name ?? prop.Name;
 
200
                                                class_addIvar (handle, ivar_name, (IntPtr)Marshal.SizeOf (typeof(IntPtr)), (ushort)Math.Log (Marshal.SizeOf (typeof(IntPtr)), 2), "@");
 
201
                                        }
 
202
 
 
203
                                        RegisterProperty (prop, type, handle);
 
204
                                }
164
205
        
165
 
#if OBJECT_REF_TRACKING
166
 
                        class_addMethod (handle, release_builder.Selector, release_builder.Delegate, release_builder.Signature);
167
 
                        class_addMethod (handle, retain_builder.Selector, retain_builder.Delegate, retain_builder.Signature);
168
 
#endif
169
 
 
170
 
                        foreach (MethodInfo minfo in type.GetMethods (BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static))
171
 
                                RegisterMethod (minfo, type, handle);
172
 
 
173
 
                        ConstructorInfo default_ctor = type.GetConstructor (Type.EmptyTypes);
174
 
                        if (default_ctor != null) {
175
 
                                NativeConstructorBuilder builder = new NativeConstructorBuilder (default_ctor);
176
 
 
177
 
                                class_addMethod (handle, builder.Selector, builder.Delegate, builder.Signature);
178
 
                                method_wrappers.Add (builder.Delegate);
179
 
#if DEBUG
180
 
                                Console.WriteLine ("[CTOR] Registering {0}[0x{1:x}|{2}] on {3} -> ({4})", "init", (int) builder.Selector, builder.Signature, type, default_ctor);
181
 
#endif
182
 
                        }
183
 
 
184
 
                        foreach (ConstructorInfo cinfo in type.GetConstructors (BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)) {
185
 
                                ExportAttribute ea = (ExportAttribute) Attribute.GetCustomAttribute (cinfo, typeof (ExportAttribute));
186
 
                                if (ea == null)
187
 
                                        continue;
188
 
                                NativeConstructorBuilder builder = new NativeConstructorBuilder (cinfo);
189
 
 
190
 
                                class_addMethod (handle, builder.Selector, builder.Delegate, builder.Signature);
191
 
                                method_wrappers.Add (builder.Delegate);
192
 
#if DEBUG
193
 
                                Console.WriteLine ("[CTOR] Registering {0}[0x{1:x}|{2}] on {3} -> ({4})", ea.Selector, (int) builder.Selector, builder.Signature, type, cinfo);
194
 
#endif
195
 
                        }
196
 
 
197
 
                        objc_registerClassPair (handle);
198
 
 
199
 
                        type_map [handle] = type;
200
 
                        custom_types.Add (type);
201
 
 
202
 
                        return handle;
 
206
                                NSObject.OverrideRetainAndRelease (handle);
 
207
 
 
208
                                foreach (MethodInfo minfo in type.GetMethods (BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static))
 
209
                                        RegisterMethod (minfo, type, handle);
 
210
 
 
211
                                ConstructorInfo default_ctor = type.GetConstructor (Type.EmptyTypes);
 
212
                                if (default_ctor != null) {
 
213
                                        NativeConstructorBuilder builder = new NativeConstructorBuilder (default_ctor);
 
214
 
 
215
                                        class_addMethod (handle, builder.Selector, builder.Delegate, builder.Signature);
 
216
                                        method_wrappers.Add (builder.Delegate);
 
217
#if DEBUG
 
218
                                        Console.WriteLine ("[CTOR] Registering {0}[0x{1:x}|{2}] on {3} -> ({4})", "init", (int) builder.Selector, builder.Signature, type, default_ctor);
 
219
#endif
 
220
                                }
 
221
 
 
222
                                foreach (ConstructorInfo cinfo in type.GetConstructors (BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)) {
 
223
                                        ExportAttribute ea = (ExportAttribute)Attribute.GetCustomAttribute (cinfo, typeof(ExportAttribute));
 
224
                                        if (ea == null)
 
225
                                                continue;
 
226
                                        NativeConstructorBuilder builder = new NativeConstructorBuilder (cinfo);
 
227
 
 
228
                                        class_addMethod (handle, builder.Selector, builder.Delegate, builder.Signature);
 
229
                                        method_wrappers.Add (builder.Delegate);
 
230
#if DEBUG
 
231
                                        Console.WriteLine ("[CTOR] Registering {0}[0x{1:x}|{2}] on {3} -> ({4})", ea.Selector, (int) builder.Selector, builder.Signature, type, cinfo);
 
232
#endif
 
233
                                }
 
234
 
 
235
                                objc_registerClassPair (handle);
 
236
 
 
237
                                type_map [handle] = type;
 
238
                                custom_types.Add (type, type);
 
239
 
 
240
                                return handle;
 
241
                        }
203
242
                }
204
243
 
205
244
                // FIXME: This doesn't properly handle virtual properties yet
208
247
                        if (ea == null)
209
248
                                return;
210
249
                        
 
250
                        if (prop.PropertyType.IsGenericType || prop.PropertyType.IsGenericTypeDefinition)
 
251
                                throw new ArgumentException (string.Format ("Cannot export the property '{0}.{1}': it is generic.", prop.DeclaringType.FullName, prop.Name));
 
252
 
211
253
                        var m = prop.GetGetMethod (true);
212
254
                        if (m != null)
213
255
                                RegisterMethod (m, ea.ToGetter (prop), type, handle);
214
256
                        m = prop.GetSetMethod (true);
215
257
                        if (m != null)
216
258
                                RegisterMethod (m, ea.ToSetter (prop), type, handle);
 
259
                                
 
260
                        // http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtPropertyIntrospection.html
 
261
                        int count = 0;
 
262
                        var props = new objc_attribute_prop [3];
 
263
                        props [count++] = new objc_attribute_prop { name = "T", value = TypeConverter.ToNative (prop.PropertyType) };
 
264
                        switch (ea.ArgumentSemantic) {
 
265
                        case ArgumentSemantic.Copy:
 
266
                                props [count++] = new objc_attribute_prop { name = "C", value = "" };
 
267
                                break;
 
268
                        case ArgumentSemantic.Retain:
 
269
                                props [count++] = new objc_attribute_prop { name = "&", value = "" };
 
270
                                break;
 
271
                        }
 
272
                        props [count++] = new objc_attribute_prop { name = "V", value = ea.Selector };
 
273
                        
 
274
                        class_addProperty (handle, ea.Selector, props, count);
 
275
                        
217
276
                }
218
277
 
219
278
                private unsafe static void RegisterMethod (MethodInfo minfo, Type type, IntPtr handle) {
271
330
                        foreach (var field in t.GetFields (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) {
272
331
                                if (field.FieldType == typeof (double) || field.FieldType == typeof (float))
273
332
                                        return true;
 
333
                                if (field.FieldType == t)
 
334
                                        continue;
274
335
                                if (TypeContainsFloatingPoint (field.FieldType))
275
336
                                        return true;
276
337
                        }
277
338
 
278
339
                        return false;
279
340
                }
280
 
                
 
341
 
 
342
                [MonoNativeFunctionWrapper]
281
343
                delegate int getFrameLengthDelegate (IntPtr @this, IntPtr sel);
282
344
                static getFrameLengthDelegate getFrameLength = Selector.GetFrameLength;
283
345
                static IntPtr getFrameLengthPtr = Marshal.GetFunctionPointerForDelegate (getFrameLength);
388
450
                        NativeMethodBuilder builder = new NativeMethodBuilder (minfo, type, ea);
389
451
 
390
452
                        class_addMethod (minfo.IsStatic ? ((objc_class *) handle)->isa : handle, builder.Selector, GetFunctionPointer (minfo, builder.Delegate), builder.Signature);
391
 
                        method_wrappers.Add (builder.Delegate);
 
453
                        lock (lock_obj)
 
454
                                method_wrappers.Add (builder.Delegate);
392
455
#if DEBUG
393
456
                        Console.WriteLine ("[METHOD] Registering {0}[0x{1:x}|{2}] on {3} -> ({4})", ea.Selector, (int) builder.Selector, builder.Signature, type, minfo);
394
457
#endif
410
473
                [DllImport ("/usr/lib/libobjc.dylib")]
411
474
                extern static bool class_addIvar (IntPtr cls, string name, IntPtr size, ushort alignment, string types);
412
475
                [DllImport ("/usr/lib/libobjc.dylib")]
413
 
                extern static bool class_addMethod (IntPtr cls, IntPtr name, Delegate imp, string types);
 
476
                internal extern static bool class_addMethod (IntPtr cls, IntPtr name, Delegate imp, string types);
414
477
                [DllImport ("/usr/lib/libobjc.dylib")]
415
 
                extern static bool class_addMethod (IntPtr cls, IntPtr name, IntPtr imp, string types);
 
478
                internal extern static bool class_addMethod (IntPtr cls, IntPtr name, IntPtr imp, string types);
416
479
                [DllImport ("/usr/lib/libobjc.dylib")]
417
480
                extern static IntPtr class_getName (IntPtr cls);
418
481
                [DllImport ("/usr/lib/libobjc.dylib")]
419
 
                extern static IntPtr class_getSuperclass (IntPtr cls);
420
 
 
 
482
                internal extern static IntPtr class_getSuperclass (IntPtr cls);
 
483
                [DllImport ("/usr/lib/libobjc.dylib")]
 
484
                internal extern static IntPtr class_getMethodImplementation (IntPtr cls, IntPtr sel);
 
485
                [DllImport ("/usr/lib/libobjc.dylib")]
 
486
                internal extern static IntPtr class_getInstanceVariable (IntPtr cls, string name);
 
487
 
 
488
                [MonoNativeFunctionWrapper]
 
489
                delegate IntPtr addPropertyDelegate (IntPtr cls, string name, objc_attribute_prop [] attributes, int count);
 
490
                static addPropertyDelegate addProperty;
 
491
                static bool addPropertyInitialized;
 
492
 
 
493
                static IntPtr class_addProperty (IntPtr cls, string name, objc_attribute_prop [] attributes, int count)
 
494
                {
 
495
                        if (!addPropertyInitialized) {
 
496
                                var handle = Dlfcn.dlopen (Constants.ObjectiveCLibrary, 0);
 
497
                                try {
 
498
                                        var fptr = Dlfcn.dlsym (handle, "class_addProperty");
 
499
                                        if (fptr != IntPtr.Zero)
 
500
                                                addProperty = (addPropertyDelegate) Marshal.GetDelegateForFunctionPointer (fptr, typeof (addPropertyDelegate));
 
501
                                } finally {
 
502
                                        Dlfcn.dlclose (handle);
 
503
                                }
 
504
                                addPropertyInitialized = true;
 
505
                        }
 
506
                        if (addProperty == null)
 
507
                                return IntPtr.Zero;
 
508
                        return addProperty (cls, name, attributes, count);
 
509
                }
 
510
 
 
511
                [StructLayout (LayoutKind.Sequential, CharSet=CharSet.Ansi)]
 
512
                private struct objc_attribute_prop {
 
513
                        [MarshalAs (UnmanagedType.LPStr)] internal string name;
 
514
                        [MarshalAs (UnmanagedType.LPStr)] internal string value;
 
515
                }
 
516
                
421
517
                internal struct objc_class {
422
518
                        internal IntPtr isa;
423
519
                }