Skip to content

Commit 8f142d8

Browse files
committed
[marshal methods] Part 2 of ?
Implement a marshal method candidate classifier which is passed to JavaCallableWrapperGenerator in order to identify methods that can be registered "statically" and for which we can generate native code instead of using System.Reflection.Emit. The selected methods are marked with the `[UnmanagedCallersOnly]` attribute and their support code in the form of the connector method (which returns a delegate to the native callback) as well as its backing field which stores the delegate, are removed from the assemblies.
1 parent 6873dc7 commit 8f142d8

File tree

11 files changed

+881
-30
lines changed

11 files changed

+881
-30
lines changed

Java.Interop.diff

Lines changed: 283 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,283 @@
1+
diff --git a/src/Java.Interop.NamingCustomAttributes/Android.Runtime/RegisterAttribute.cs b/src/Java.Interop.NamingCustomAttributes/Android.Runtime/RegisterAttribute.cs
2+
index ec1ea955..7f8e1a1b 100644
3+
--- a/src/Java.Interop.NamingCustomAttributes/Android.Runtime/RegisterAttribute.cs
4+
+++ b/src/Java.Interop.NamingCustomAttributes/Android.Runtime/RegisterAttribute.cs
5+
@@ -1,5 +1,7 @@
6+
using System;
7+
8+
+using Mono.Cecil;
9+
+
10+
namespace Android.Runtime {
11+
12+
[AttributeUsage (AttributeTargets.Class | AttributeTargets.Constructor | AttributeTargets.Field | AttributeTargets.Interface | AttributeTargets.Method | AttributeTargets.Property)]
13+
@@ -23,7 +25,21 @@ namespace Android.Runtime {
14+
this.connector = connector;
15+
this.signature = signature;
16+
}
17+
+#if HAVE_CECIL
18+
+ public RegisterAttribute (string name, CustomAttribute originAttribute)
19+
+ : this (name)
20+
+ {
21+
+ OriginAttribute = originAttribute;
22+
+ }
23+
+
24+
+ public RegisterAttribute (string name, string signature, string connector, CustomAttribute originAttribute)
25+
+ : this (name, signature, connector)
26+
+ {
27+
+ OriginAttribute = originAttribute;
28+
+ }
29+
30+
+ public CustomAttribute OriginAttribute { get; }
31+
+#endif
32+
public string Connector {
33+
get { return connector; }
34+
set { connector = value; }
35+
diff --git a/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/JavaCallableWrapperGenerator.cs b/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/JavaCallableWrapperGenerator.cs
36+
index d30bce4a..afde1e48 100644
37+
--- a/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/JavaCallableWrapperGenerator.cs
38+
+++ b/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/JavaCallableWrapperGenerator.cs
39+
@@ -25,40 +25,9 @@ namespace Java.Interop.Tools.JavaCallableWrappers {
40+
JavaInterop1,
41+
}
42+
43+
- public class OverriddenMethodDescriptor
44+
+ public abstract class JavaCallableMethodClassifier
45+
{
46+
- static readonly char[] methodDescSplitChars = new char[] { ':' };
47+
-
48+
- public string JavaPackageName { get; }
49+
- public string NativeName { get; }
50+
- public string JniSignature { get; }
51+
- public string Connector { get; }
52+
- public string ManagedTypeName { get; }
53+
- public string OriginalDescString { get; }
54+
-
55+
- public OverriddenMethodDescriptor (string javaPackageName, string methodDescription, string fallbackManagedTypeName)
56+
- {
57+
- OriginalDescString = methodDescription;
58+
- JavaPackageName = javaPackageName;
59+
- string[] parts = methodDescription.Split (methodDescSplitChars, 4);
60+
-
61+
- if (parts.Length < 2) {
62+
- throw new InvalidOperationException ($"Unexpected format for method description. Expected at least 2 parts, got {parts.Length} from: '{methodDescription}'");
63+
- }
64+
-
65+
- NativeName = parts[0];
66+
- JniSignature = parts[1];
67+
- if (parts.Length > 2) {
68+
- Connector = parts[2];
69+
- if (parts.Length > 3) {
70+
- ManagedTypeName = TypeDefinitionRocks.CecilTypeNameToReflectionTypeName (parts[3]);
71+
- }
72+
- }
73+
-
74+
- if (String.IsNullOrEmpty (ManagedTypeName)) {
75+
- ManagedTypeName = fallbackManagedTypeName;
76+
- }
77+
- }
78+
+ public abstract bool ShouldBeDynamicallyRegistered (MethodDefinition registeredMethod, MethodDefinition implementedMethod, CustomAttribute registerAttribute);
79+
}
80+
81+
public class JavaCallableWrapperGenerator {
82+
@@ -95,21 +64,22 @@ namespace Java.Interop.Tools.JavaCallableWrappers {
83+
List<Signature> methods = new List<Signature> ();
84+
List<Signature> ctors = new List<Signature> ();
85+
List<JavaCallableWrapperGenerator> children;
86+
- List<OverriddenMethodDescriptor> overriddenMethodDescriptors;
87+
+
88+
readonly IMetadataResolver cache;
89+
+ readonly JavaCallableMethodClassifier methodClassifier;
90+
91+
[Obsolete ("Use the TypeDefinitionCache overload for better performance.")]
92+
public JavaCallableWrapperGenerator (TypeDefinition type, Action<string, object []> log)
93+
: this (type, null, log, resolver: null)
94+
{ }
95+
96+
- public JavaCallableWrapperGenerator (TypeDefinition type, Action<string, object[]> log, TypeDefinitionCache cache)
97+
- : this (type, log, (IMetadataResolver) cache)
98+
+ public JavaCallableWrapperGenerator (TypeDefinition type, Action<string, object[]> log, TypeDefinitionCache cache, JavaCallableMethodClassifier methodClassifier = null)
99+
+ : this (type, log, (IMetadataResolver) cache, methodClassifier)
100+
{
101+
}
102+
103+
- public JavaCallableWrapperGenerator (TypeDefinition type, Action<string, object[]> log, IMetadataResolver resolver)
104+
- : this (type, null, log, resolver)
105+
+ public JavaCallableWrapperGenerator (TypeDefinition type, Action<string, object[]> log, IMetadataResolver resolver, JavaCallableMethodClassifier methodClassifier = null)
106+
+ : this (type, null, log, resolver, methodClassifier)
107+
{
108+
if (type.HasNestedTypes) {
109+
children = new List<JavaCallableWrapperGenerator> ();
110+
@@ -117,7 +87,6 @@ namespace Java.Interop.Tools.JavaCallableWrappers {
111+
}
112+
}
113+
114+
- public IList<OverriddenMethodDescriptor> OverriddenMethodDescriptors => overriddenMethodDescriptors;
115+
public string ApplicationJavaClass { get; set; }
116+
public JavaPeerStyle CodeGenerationTarget { get; set; }
117+
118+
@@ -125,6 +94,9 @@ namespace Java.Interop.Tools.JavaCallableWrappers {
119+
120+
public bool HasExport { get; private set; }
121+
122+
+ // If there are no methods, we need to generate "empty" registration because of backward compatibility
123+
+ public bool HasDynamicallyRegisteredMethods => methods.Count == 0 || methods.Any ((Signature sig) => sig.IsDynamicallyRegistered);
124+
+
125+
/// <summary>
126+
/// The Java source code to be included in Instrumentation.onCreate
127+
///
128+
@@ -152,8 +124,9 @@ namespace Java.Interop.Tools.JavaCallableWrappers {
129+
HasExport |= children.Any (t => t.HasExport);
130+
}
131+
132+
- JavaCallableWrapperGenerator (TypeDefinition type, string outerType, Action<string, object[]> log, IMetadataResolver resolver)
133+
+ JavaCallableWrapperGenerator (TypeDefinition type, string outerType, Action<string, object[]> log, IMetadataResolver resolver, JavaCallableMethodClassifier methodClassifier = null)
134+
{
135+
+ this.methodClassifier = methodClassifier;
136+
this.type = type;
137+
this.log = log;
138+
this.cache = resolver ?? new TypeDefinitionCache ();
139+
@@ -366,12 +339,13 @@ namespace Java.Interop.Tools.JavaCallableWrappers {
140+
// attr.Resolve ();
141+
RegisterAttribute r = null;
142+
if (attr.ConstructorArguments.Count == 1)
143+
- r = new RegisterAttribute ((string) attr.ConstructorArguments [0].Value);
144+
+ r = new RegisterAttribute ((string) attr.ConstructorArguments [0].Value, attr);
145+
else if (attr.ConstructorArguments.Count == 3)
146+
r = new RegisterAttribute (
147+
(string) attr.ConstructorArguments [0].Value,
148+
(string) attr.ConstructorArguments [1].Value,
149+
- (string) attr.ConstructorArguments [2].Value);
150+
+ (string) attr.ConstructorArguments [2].Value,
151+
+ attr);
152+
if (r != null) {
153+
var v = attr.Properties.FirstOrDefault (p => p.Name == "DoNotGenerateAcw");
154+
r.DoNotGenerateAcw = v.Name == null ? false : (bool) v.Argument.Value;
155+
@@ -384,7 +358,7 @@ namespace Java.Interop.Tools.JavaCallableWrappers {
156+
// attr.Resolve ();
157+
RegisterAttribute r = null;
158+
if (attr.ConstructorArguments.Count == 1)
159+
- r = new RegisterAttribute ((string) attr.ConstructorArguments [0].Value);
160+
+ r = new RegisterAttribute ((string) attr.ConstructorArguments [0].Value, attr);
161+
if (r != null) {
162+
var v = attr.Properties.FirstOrDefault (p => p.Name == "GenerateJavaPeer");
163+
if (v.Name == null) {
164+
@@ -403,7 +377,8 @@ namespace Java.Interop.Tools.JavaCallableWrappers {
165+
if (attr.ConstructorArguments.Count == 2)
166+
r = new RegisterAttribute ((string) attr.ConstructorArguments [0].Value,
167+
(string) attr.ConstructorArguments [1].Value,
168+
- "");
169+
+ "",
170+
+ attr);
171+
return r;
172+
}
173+
174+
@@ -467,7 +442,8 @@ namespace Java.Interop.Tools.JavaCallableWrappers {
175+
if (attr.Name.Contains ("-impl") || (attr.Name.Length > 7 && attr.Name[attr.Name.Length - 8] == '-'))
176+
Diagnostic.Error (4217, LookupSource (implementedMethod), Localization.Resources.JavaCallableWrappers_XA4217, attr.Name);
177+
178+
- var msig = new Signature (implementedMethod, attr);
179+
+ bool shouldBeDynamicallyRegistered = methodClassifier?.ShouldBeDynamicallyRegistered (registeredMethod, implementedMethod, attr.OriginAttribute) ?? true;
180+
+ var msig = new Signature (implementedMethod, attr, shouldBeDynamicallyRegistered);
181+
if (!registeredMethod.IsConstructor && !methods.Any (m => m.Name == msig.Name && m.Params == msig.Params))
182+
methods.Add (msig);
183+
}
184+
@@ -542,21 +518,38 @@ namespace Java.Interop.Tools.JavaCallableWrappers {
185+
186+
GenerateHeader (writer);
187+
188+
- writer.WriteLine ("/** @hide */");
189+
- writer.WriteLine ("\tpublic static final String __md_methods;");
190+
- if (children != null) {
191+
- foreach (var i in Enumerable.Range (1, children.Count))
192+
- writer.WriteLine ("\tstatic final String __md_{0}_methods;", i);
193+
+ bool needCtor = false;
194+
+ if (HasDynamicallyRegisteredMethods) {
195+
+ needCtor = true;
196+
+ writer.WriteLine ("/** @hide */");
197+
+ writer.WriteLine ("\tpublic static final String __md_methods;");
198+
}
199+
- writer.WriteLine ("\tstatic {");
200+
- GenerateRegisterType (writer, this, "__md_methods");
201+
+
202+
if (children != null) {
203+
- for (int i = 0; i < children.Count; ++i) {
204+
- string methods = string.Format ("__md_{0}_methods", i + 1);
205+
- GenerateRegisterType (writer, children [i], methods);
206+
+ for (int i = 0; i < children.Count; i++) {
207+
+ if (!children[i].HasDynamicallyRegisteredMethods) {
208+
+ continue;
209+
+ }
210+
+ needCtor = true;
211+
+ writer.WriteLine ("\tstatic final String __md_{0}_methods;", i + 1);
212+
+ }
213+
+ }
214+
+
215+
+ if (needCtor) {
216+
+ writer.WriteLine ("\tstatic {");
217+
+
218+
+ if (HasDynamicallyRegisteredMethods) {
219+
+ GenerateRegisterType (writer, this, "__md_methods");
220+
+ }
221+
+
222+
+ if (children != null) {
223+
+ for (int i = 0; i < children.Count; ++i) {
224+
+ string methods = string.Format ("__md_{0}_methods", i + 1);
225+
+ GenerateRegisterType (writer, children [i], methods);
226+
+ }
227+
}
228+
+ writer.WriteLine ("\t}");
229+
}
230+
- writer.WriteLine ("\t}");
231+
232+
GenerateBody (writer);
233+
234+
@@ -710,16 +703,19 @@ namespace Java.Interop.Tools.JavaCallableWrappers {
235+
236+
void GenerateRegisterType (TextWriter sw, JavaCallableWrapperGenerator self, string field)
237+
{
238+
- if (overriddenMethodDescriptors == null) {
239+
- overriddenMethodDescriptors = new List<OverriddenMethodDescriptor> ();
240+
+ string managedTypeName = self.type.GetPartialAssemblyQualifiedName (cache);
241+
+ string javaTypeName = $"{package}.{name}";
242+
+
243+
+ if (!self.HasDynamicallyRegisteredMethods) {
244+
+ return;
245+
}
246+
247+
sw.WriteLine ("\t\t{0} = ", field);
248+
- string managedTypeName = self.type.GetPartialAssemblyQualifiedName (cache);
249+
- string javaTypeName = $"{package}.{name}";
250+
+
251+
foreach (Signature method in self.methods) {
252+
- sw.WriteLine ("\t\t\t\"{0}\\n\" +", method.Method);
253+
- overriddenMethodDescriptors.Add (new OverriddenMethodDescriptor (javaTypeName, method.Method, managedTypeName));
254+
+ if (method.IsDynamicallyRegistered) {
255+
+ sw.WriteLine ("\t\t\t\"{0}\\n\" +", method.Method);
256+
+ }
257+
}
258+
sw.WriteLine ("\t\t\t\"\";");
259+
if (CannotRegisterInStaticConstructor (self.type))
260+
@@ -772,12 +768,13 @@ namespace Java.Interop.Tools.JavaCallableWrappers {
261+
262+
class Signature {
263+
264+
- public Signature (MethodDefinition method, RegisterAttribute register) : this (method, register, null, null) {}
265+
+ public Signature (MethodDefinition method, RegisterAttribute register, bool shouldBeDynamicallyRegistered = true) : this (method, register, null, null, shouldBeDynamicallyRegistered) {}
266+
267+
- public Signature (MethodDefinition method, RegisterAttribute register, string managedParameters, string outerType)
268+
+ public Signature (MethodDefinition method, RegisterAttribute register, string managedParameters, string outerType, bool shouldBeDynamicallyRegistered = true)
269+
: this (register.Name, register.Signature, register.Connector, managedParameters, outerType, null)
270+
{
271+
Annotations = JavaCallableWrapperGenerator.GetAnnotationsString ("\t", method.CustomAttributes);
272+
+ IsDynamicallyRegistered = shouldBeDynamicallyRegistered;
273+
}
274+
275+
public Signature (MethodDefinition method, ExportAttribute export, IMetadataResolver cache)
276+
@@ -880,6 +877,7 @@ namespace Java.Interop.Tools.JavaCallableWrappers {
277+
public readonly string Method;
278+
public readonly bool IsExport;
279+
public readonly bool IsStatic;
280+
+ public readonly bool IsDynamicallyRegistered = true;
281+
public readonly string [] ThrownTypeNames;
282+
public readonly string Annotations;
283+
}

0 commit comments

Comments
 (0)