예제 #1
0
		Dictionary <IntPtr, MethodDescription> RegisterMethods (Type type) {
			// Caller must hold the obj_lock.
			Dictionary <IntPtr, MethodDescription> methods = new Dictionary <IntPtr, MethodDescription> (Runtime.IntPtrEqualityComparer);
			
			foreach (PropertyInfo pinfo in type.GetProperties (BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)) {
				ExportAttribute ea = (ExportAttribute) Attribute.GetCustomAttribute (pinfo, typeof (ExportAttribute));
				if (ea == null)
					continue;
				
				MethodInfo g = pinfo.GetGetMethod (true);
				if (g != null) {
					IntPtr selector = Selector.GetHandle (ea.ToGetter (pinfo).Selector);
#if DEBUG_POPULATE
					Console.WriteLine ("[GETTER] Registering {0}[0x{1:x}|{2}] on {3} -> ({4})", ea.Selector, (int) selector, Method.Signature (g), type, pinfo);
#endif
					methods [selector] = new MethodDescription (g, ea.ArgumentSemantic);
				}
				MethodInfo s = pinfo.GetSetMethod (true);
				if (s != null) {
					IntPtr selector = Selector.GetHandle (ea.ToSetter (pinfo).Selector);
#if DEBUG_POPULATE
					Console.WriteLine ("[SETTER] Registering {0}[0x{1:x}|{2}] on {3} -> ({4})", ea.Selector, (int) selector, Method.Signature (s), type, pinfo);
#endif
					methods [selector] = new MethodDescription (s, ea.ArgumentSemantic);
				}
			}
			
			var method_interface_map = SharedDynamic.PrepareInterfaceMethodMapping (type);
			foreach (MethodInfo minfo in type.GetMethods (BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)) {
				ExportAttribute ea = (ExportAttribute) Attribute.GetCustomAttribute (minfo.GetBaseDefinition (), typeof (ExportAttribute));
				
				if (ea == null)
					ea = GetMappedExportAttribute (method_interface_map, minfo);

				if (ea == null)
					continue;

				IntPtr selector = Selector.GetHandle (ea.Selector ?? minfo.Name);
				
				MethodDescription md;
				if (!methods.TryGetValue (selector, out md)) {
#if DEBUG_POPULATE
					Console.WriteLine ("[METHOD] Registering {0}[0x{1:x}|{2}] from {3} -> ({4} on {5})", ea.Selector, (int) selector, Method.Signature (minfo), type, minfo, minfo.DeclaringType);
#endif
					methods.Add (selector, new MethodDescription (minfo, ea.ArgumentSemantic));
					continue;
				}
				
				//
				// More than one method can exist for hidden methods. Choose one closest to
				// the caller type
				//
				if (minfo.DeclaringType.IsSubclassOf (md.method.DeclaringType)) {
#if DEBUG_POPULATE
					Console.WriteLine ("[METHOD] Re-registering {0}[0x{1:x}|{2}] from {3} -> ({4} on {5})", ea.Selector, (int) selector, Method.Signature (minfo), type, minfo, minfo.DeclaringType);
#endif
					methods [selector] = new MethodDescription (minfo, ea.ArgumentSemantic);
				}
			}
			
			bool default_ctor_found = false;
			foreach (ConstructorInfo cinfo in type.GetConstructors (BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)) {
				if (!default_ctor_found && !cinfo.IsStatic && cinfo.GetParameters ().Length == 0) {
					default_ctor_found = true;
					methods [Selector.GetHandle ("init")] = new MethodDescription (cinfo, ArgumentSemantic.Assign);
				}
				ExportAttribute ea = (ExportAttribute) Attribute.GetCustomAttribute (cinfo, typeof (ExportAttribute));
				if (ea == null)
					continue;
				if (ea.Selector == null)
					throw new Exception ("Constructor's must have a Export attribute with the selector specified");
				IntPtr selector = Selector.GetHandle (ea.Selector);
#if DEBUG_POPULATE
				Console.WriteLine ("[CTOR] Registering {0}[0x{1:x}|{2}] on {3} -> ({4})", ea.Selector, (int) selector, Method.Signature (cinfo), type, cinfo);
#endif
				methods [selector] = new MethodDescription (cinfo, ea.ArgumentSemantic);
			}
			
			method_map [type] = methods;
			
			return methods;
		}
예제 #2
0
		public void RegisterMethod (MethodInfo minfo, ExportAttribute ea, Type type, IntPtr handle, bool update_map) {
			IntPtr reg_handle = IntPtr.Zero;
			IntPtr tramp = IntPtr.Zero;
			IntPtr sel = Selector.GetHandle (ea.Selector ?? minfo.Name);
			string signature = Method.Signature (minfo);
			Type return_type = minfo.ReturnType;
			
			reg_handle = minfo.IsStatic ? Class.object_getClass (handle) : handle;
			
			if (return_type.IsValueType && !return_type.IsEnum && return_type.Assembly != typeof (object).Assembly && (Runtime.Arch == Arch.DEVICE || Marshal.SizeOf (return_type) > 8)) {
				if (Runtime.Arch == Arch.SIMULATOR) {
					if (TypeContainsDouble (return_type))
						tramp = minfo.IsStatic ? Method.X86_DoubleABI_StaticStretTrampoline : Method.X86_DoubleABI_StretTrampoline;
					else
						tramp = minfo.IsStatic ? Method.StaticStretTrampoline : Method.StretTrampoline;
				} else {
					tramp = minfo.IsStatic ? Method.StaticStretTrampoline : Method.StretTrampoline;
				}
			} else if (return_type.IsValueType && !return_type.IsEnum && return_type.Assembly != typeof (object).Assembly && Runtime.Arch == Arch.SIMULATOR && Marshal.SizeOf (return_type) > 4) {
				// for instance CGSize...
				tramp = minfo.IsStatic ? Method.StaticLongTrampoline : Method.LongTrampoline;
			} else {
				switch (signature [0]) {
				case 'Q':
				case 'q':
					tramp = minfo.IsStatic ? Method.StaticLongTrampoline : Method.LongTrampoline;
					break;
				case 'f':
					tramp = minfo.IsStatic ? Method.StaticSingleTrampoline : Method.SingleTrampoline;
					break;
				case 'd':
					tramp = minfo.IsStatic ? Method.StaticDoubleTrampoline : Method.DoubleTrampoline;
					break;
				default:
					tramp = minfo.IsStatic ? Method.StaticTrampoline : Method.Trampoline;
					break;
				}
			}
			
#if DEBUG_REGISTER
			Console.WriteLine ("[METHOD] Registering {0}[0x{1:x}|{2}] on {3} -> ({4}) tramp: 0x{5}", ea.Selector, (int) sel, Method.Signature (minfo), type, minfo, tramp.ToString ("x"));
#endif
			Class.class_addMethod (reg_handle, sel, tramp, Method.Signature (minfo));
			
			if (update_map) {
				Dictionary<IntPtr, MethodDescription> methods;
				lock (lock_obj) {
					if (!method_map.TryGetValue (type, out methods)) {
						methods = new Dictionary<IntPtr, MethodDescription> (Runtime.IntPtrEqualityComparer);
						method_map.Add (type, methods);
					}
					
					methods[sel] = new MethodDescription (minfo, ea.ArgumentSemantic);
				}
			}
		}
예제 #3
0
		unsafe IntPtr Register (Type type, string name, bool is_wrapper) {
			IntPtr parent = IntPtr.Zero;
			IntPtr handle = IntPtr.Zero;
			
			lock (lock_obj) {
				handle = Class.objc_getClass (name);
				
				if (handle != IntPtr.Zero) {
					if (!type_map.ContainsKey (handle)) {
						type_map [handle] = type;
					}
					return handle;
				}
				
				/*FIXME pick a more suitable exception type */
				/*FIXME try to guess the name of the missing library - quite trivial for monotouch.dll*/
				if (is_wrapper) {
					if (Runtime.Arch == Arch.DEVICE) {
						// types decorated with [Model] attribute are not registered (see registrar.cs and regression from #769)
						// a missing [Model] attribute will cause this error on devices (e.g. bug #4864)
						if (!Attribute.IsDefined (type, typeof (ModelAttribute), false))
							throw new Exception (string.Format ("Wrapper type '{0}' is missing its native ObjectiveC class '{1}'.", type.FullName, name));
					} else {
						/*On simulator this is a common issue since we eagerly register all types. This is an issue with unlinked
						monotouch.dll since we don't link all frameworks most of the time.
						*/
						return IntPtr.Zero;
					}
				}
				
				Dictionary <IntPtr, MethodDescription> methods = new Dictionary <IntPtr, MethodDescription> (Runtime.IntPtrEqualityComparer);
				
				Type parent_type = type.BaseType;
				string parent_name = null;
				while (Attribute.IsDefined (parent_type, typeof (ModelAttribute), false))
					parent_type = parent_type.BaseType;
				RegisterAttribute parent_attr = (RegisterAttribute) Attribute.GetCustomAttribute (parent_type, typeof (RegisterAttribute), false);
				parent_name = parent_attr == null ? parent_type.FullName : parent_attr.Name ?? parent_type.FullName;
				parent = Class.objc_getClass (parent_name);
				if (parent == IntPtr.Zero && parent_type.Assembly != NSObject.MonoTouchAssembly) {
					bool parent_is_wrapper = parent_attr == null ? false : parent_attr.IsWrapper;
					// Its possible as we scan that we might be derived from a type that isn't reigstered yet.
					Register (parent_type, parent_name, parent_is_wrapper);
					parent = Class.objc_getClass (parent_name);
				}
				if (parent == IntPtr.Zero) {
					// This spams mtouch, we need a way to differentiate from mtouch's (ab)use
					// Console.WriteLine ("CRITICAL WARNING: Falling back to NSObject for type {0} reported as {1}", type, parent_type);
					parent = Class.objc_getClass ("NSObject");
				}
				handle = Class.objc_allocateClassPair (parent, name, IntPtr.Zero);
				
				Class.class_addIvar (handle, "__monoObjectGCHandle", (IntPtr) Marshal.SizeOf (typeof (Int32)), (byte) 4, "i");
				
				foreach (PropertyInfo prop in type.GetProperties (BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static)) {
					ConnectAttribute cattr = (ConnectAttribute) Attribute.GetCustomAttribute (prop, typeof (ConnectAttribute));
					if (cattr != null) {
						string ivar_name = cattr.Name ?? prop.Name;
						Class.class_addIvar (handle, ivar_name, (IntPtr) Marshal.SizeOf (typeof (IntPtr)), (byte) Math.Log (Marshal.SizeOf (typeof (IntPtr)), 2), "@");
					}
					
					var exportAtt = (ExportAttribute) Attribute.GetCustomAttribute (prop, typeof (ExportAttribute));
					if (exportAtt != null) {
						var m = prop.GetGetMethod (true);
						if (m != null) {
							var ea = exportAtt.ToGetter (prop);
							RegisterMethod (m, ea, type, handle, false);
							var sel = Selector.GetHandle (ea.Selector);
							methods [sel] = new MethodDescription (m, ea.ArgumentSemantic);
						}
						m = prop.GetSetMethod (true);
						if (m != null) {
							var ea = exportAtt.ToSetter (prop);
							RegisterMethod (m, ea, type, handle, false);
							var sel = Selector.GetHandle (ea.Selector);
							methods [sel] = new MethodDescription (m, ea.ArgumentSemantic);
						}
						
						// http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtPropertyIntrospection.html
						int count = 0;
						var props = new Class.objc_attribute_prop [3];
						props [count++] = new Class.objc_attribute_prop { name = "T", value = TypeConverter.ToNative (prop.PropertyType) };
						switch (exportAtt.ArgumentSemantic) {
						case ArgumentSemantic.Copy:
							props [count++] = new Class.objc_attribute_prop { name = "C", value = "" };
							break;
						case ArgumentSemantic.Retain:
							props [count++] = new Class.objc_attribute_prop { name = "&", value = "" };
							break;
						}
						props [count++] = new Class.objc_attribute_prop { name = "V", value = exportAtt.Selector };
						
						Class.class_addProperty (handle, exportAtt.Selector, props, count);
						
#if DEBUG_REGISTER
						Console.WriteLine ("[PROPERTY] Registering {0} of type {2} ({3}) on {1}", exportAtt.Selector, type, prop.PropertyType, TypeConverter.ToNative (prop.PropertyType));
#endif
					}
				}
				
				Class.class_addMethod (handle, Selector.GetHandle (Selector.Release), Method.ReleaseTrampoline, "v@:");
				Class.class_addMethod (handle, Selector.GetHandle (Selector.Retain), Method.RetainTrampoline, "@@:");
				Class.class_addMethod (handle, Selector.GetHandle ("xamarinGetGCHandle"), Method.GetGCHandleTrampoline, "i@:");
				Class.class_addMethod (handle, Selector.GetHandle ("xamarinSetGCHandle:"), Method.SetGCHandleTrampoline, "v@:i");
				
				var method_interface_map = SharedDynamic.PrepareInterfaceMethodMapping (type);
				foreach (MethodInfo minfo in type.GetMethods (BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)) {
					ExportAttribute ea = (ExportAttribute) Attribute.GetCustomAttribute (minfo.GetBaseDefinition (), typeof (ExportAttribute));
					
					if (ea == null)
						ea = GetMappedExportAttribute (method_interface_map, minfo);

					if (ea == null)
						continue;
					
					if (minfo.IsGenericMethod || minfo.IsGenericMethodDefinition) {
						Console.WriteLine ("The registrar found an exported generic method: '{0}.{1}'. Exporting generic methods is not supported.", minfo.DeclaringType.FullName, minfo.Name);
						continue;
					}
					
					bool is_conforms_to_protocol;
					bool is_model = false;
					
					is_conforms_to_protocol = minfo.DeclaringType.Assembly == NSObject.MonoTouchAssembly && minfo.DeclaringType.Name == "NSObject" && minfo.Name == "ConformsToProtocol";
					
					if (!is_conforms_to_protocol)
						is_model = minfo.IsVirtual && ((minfo.DeclaringType != type && minfo.DeclaringType.Assembly == NSObject.MonoTouchAssembly) || (Attribute.IsDefined (minfo.DeclaringType, typeof (ModelAttribute), false)));
					
					if (is_model)
						continue;
					
					RegisterMethod (minfo, ea, type, handle, false);
					
					var sel = Selector.GetHandle (ea.Selector ?? minfo.Name);
					
					methods [sel] = new MethodDescription (minfo, ea.ArgumentSemantic);
				}
				
				bool default_ctor_found = false;
				foreach (ConstructorInfo cinfo in type.GetConstructors (BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)) {
					if (!default_ctor_found && !cinfo.IsStatic && cinfo.GetParameters ().Length == 0) {
#if DEBUG_REGISTER
						Console.WriteLine ("[CTOR] Registering {0}[0x{1:x}|{2}] on {3} -> ({4})", "init", (int) Selector.Init, Method.Signature (cinfo), type, cinfo);
#endif
						default_ctor_found = true;
						Class.class_addMethod (handle, Selector.GetHandle ("init"), Method.ConstructorTrampoline, Method.Signature (cinfo));
						methods [Selector.GetHandle ("init")] = new MethodDescription (cinfo, ArgumentSemantic.Assign);
					}

					ExportAttribute ea = (ExportAttribute) Attribute.GetCustomAttribute (cinfo, typeof (ExportAttribute));
					if (ea == null)
						continue;
					
					IntPtr sel = Selector.GetHandle (ea.Selector);
					
					Class.class_addMethod (handle, sel, Method.ConstructorTrampoline, Method.Signature (cinfo));
#if DEBUG_REGISTER
					Console.WriteLine ("[CTOR] Registering {0}[0x{1:x}|{2}] on {3} -> ({4})", ea.Selector, (int) sel, Method.Signature (cinfo), type, cinfo);
#endif
					methods [sel] = new MethodDescription (cinfo, ea.ArgumentSemantic);
				}
				
				Class.objc_registerClassPair (handle);
				
				type_map [handle] = type;
				method_map [type] = methods;
				AddCustomType (type);

				return handle;
			}
		}