diff --git a/tools/jnimarshalmethod-gen/App.cs b/tools/jnimarshalmethod-gen/App.cs index 68b707e70..bc6a6332a 100644 --- a/tools/jnimarshalmethod-gen/App.cs +++ b/tools/jnimarshalmethod-gen/App.cs @@ -172,6 +172,8 @@ void ProcessAssemblies (List assemblies) ad = AssemblyDefinition.ReadAssembly (assembly, readWriteParametersNoSymbols); resolver.AddToCache (ad); } + + Extensions.MethodMap.Clear (); } foreach (var assembly in assemblies) { @@ -221,6 +223,42 @@ static TypeBuilder GetTypeBuilder (ModuleBuilder mb, Type type) return tb; } + class MethodsComparer : IComparer + { + readonly Type type; + readonly TypeDefinition td; + + public MethodsComparer (Type type, TypeDefinition td) + { + this.type = type; + this.td = td; + } + + public int Compare (MethodInfo a, MethodInfo b) + { + if (a.DeclaringType != type) + return 1; + + var atd = td.GetMethodDefinition (a); + if (atd == null) + return 1; + + if (b.DeclaringType != type) + return -1; + + var btd = td.GetMethodDefinition (b); + if (btd == null) + return -1; + + if (atd.HasOverrides ^ btd.HasOverrides) + return btd.HasOverrides ? -1 : 1; + + return string.Compare (a.Name, b.Name); + } + } + + static HashSet addedMethods = new HashSet (); + void CreateMarshalMethodAssembly (string path) { var assembly = Assembly.LoadFile (Path.GetFullPath (path)); @@ -299,7 +337,13 @@ void CreateMarshalMethodAssembly (string path) var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static; - foreach (var method in type.GetMethods (flags)) { + + var methods = type.GetMethods (flags); + Array.Sort (methods, new MethodsComparer (type, td)); + + addedMethods.Clear (); + + foreach (var method in methods) { // TODO: Constructors var export = method.GetCustomAttribute (); string signature = null; @@ -328,6 +372,9 @@ void CreateMarshalMethodAssembly (string path) if (dt == null) dt = GetTypeBuilder (dm, type); + if (addedMethods.Contains (methodName)) + continue; + if (Verbose) { Console.Write ("Adding marshal method for "); ColorWriteLine ($"{method}", ConsoleColor.Green ); @@ -349,6 +396,8 @@ void CreateMarshalMethodAssembly (string path) signature = builder.GetJniMethodSignature (method); registrationElements.Add (CreateRegistration (name, signature, lambda, targetType, methodName)); + + addedMethods.Add (methodName); } if (dt != null) AddRegisterNativeMembers (dt, targetType, registrationElements); @@ -463,11 +512,11 @@ static TypeDefinition FindType (Type type) } } - static class Extensions + internal static class Extensions { public static string GetCecilName (this Type type) { - return type.FullName.Replace ('+', '/'); + return type.FullName?.Replace ('+', '/'); } static bool CompareTypes (Type reflectionType, TypeReference cecilType) @@ -503,11 +552,19 @@ static bool MethodsAreEqual (MethodInfo methodInfo, MethodDefinition methodDefin return true; } + internal static Dictionary MethodMap = new Dictionary (); + public static MethodDefinition GetMethodDefinition (this TypeDefinition td, MethodInfo method) { + if (MethodMap.TryGetValue (method, out var md)) + return md; + foreach (var m in td.Methods) - if (MethodsAreEqual (method, m)) + if (MethodsAreEqual (method, m)) { + MethodMap [method] = m; + return m; + } return null; }