Skip to content

Commit 3e4a3c4

Browse files
authored
[Java.Interop.Tools.JavaCallableWrappers] JavaCallableMethodClassifier (#998)
Context: dotnet/android#7123 Context: fb94d59 Instead of having `JavaCallableWrapperGenerator` care about and collect marshal methods override information, introduce a new `JavaCallableMethodClassifier` type, and use that as the integration point: public abstract partial class JavaCallableMethodClassifier { public abstract bool ShouldBeDynamicallyRegistered TypeDefinition topType, MethodDefinition registeredMethod, MethodDefinition implementedMethod, CustomAttribute registerAttribute ); } An instance of `JavaCallableMethodClassifier` can now be provided to the `JavaCallableWrapperGenerator` constructor. If provided, then `ShouldBeDynamicallyRegistered()` will be used to control which methods are added to `__md_methods` and `Runtime.register()`. If a type `JavaCallableWrapperGenerator` is processing doesn't have any dynamically registered methods, then the code to register them is no longer generated.
1 parent c942ab6 commit 3e4a3c4

File tree

2 files changed

+83
-61
lines changed

2 files changed

+83
-61
lines changed

src/Java.Interop.NamingCustomAttributes/Android.Runtime/RegisterAttribute.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
using System;
22

3+
using Mono.Cecil;
4+
35
namespace Android.Runtime {
46

57
[AttributeUsage (AttributeTargets.Class | AttributeTargets.Constructor | AttributeTargets.Field | AttributeTargets.Interface | AttributeTargets.Method | AttributeTargets.Property)]
@@ -23,6 +25,21 @@ public RegisterAttribute (string name, string signature, string connector)
2325
this.connector = connector;
2426
this.signature = signature;
2527
}
28+
#if HAVE_CECIL
29+
public RegisterAttribute (string name, CustomAttribute originAttribute)
30+
: this (name)
31+
{
32+
OriginAttribute = originAttribute;
33+
}
34+
35+
public RegisterAttribute (string name, string signature, string connector, CustomAttribute originAttribute)
36+
: this (name, signature, connector)
37+
{
38+
OriginAttribute = originAttribute;
39+
}
40+
41+
public CustomAttribute OriginAttribute { get; }
42+
#endif // HAVE_CECIL
2643

2744
public string Connector {
2845
get { return connector; }

src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/JavaCallableWrapperGenerator.cs

Lines changed: 66 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -25,40 +25,9 @@ public enum JavaPeerStyle {
2525
JavaInterop1,
2626
}
2727

28-
public class OverriddenMethodDescriptor
28+
public abstract class JavaCallableMethodClassifier
2929
{
30-
static readonly char[] methodDescSplitChars = new char[] { ':' };
31-
32-
public string JavaPackageName { get; }
33-
public string NativeName { get; }
34-
public string JniSignature { get; }
35-
public string Connector { get; }
36-
public string ManagedTypeName { get; }
37-
public string OriginalDescString { get; }
38-
39-
public OverriddenMethodDescriptor (string javaPackageName, string methodDescription, string fallbackManagedTypeName)
40-
{
41-
OriginalDescString = methodDescription;
42-
JavaPackageName = javaPackageName;
43-
string[] parts = methodDescription.Split (methodDescSplitChars, 4);
44-
45-
if (parts.Length < 2) {
46-
throw new InvalidOperationException ($"Unexpected format for method description. Expected at least 2 parts, got {parts.Length} from: '{methodDescription}'");
47-
}
48-
49-
NativeName = parts[0];
50-
JniSignature = parts[1];
51-
if (parts.Length > 2) {
52-
Connector = parts[2];
53-
if (parts.Length > 3) {
54-
ManagedTypeName = TypeDefinitionRocks.CecilTypeNameToReflectionTypeName (parts[3]);
55-
}
56-
}
57-
58-
if (String.IsNullOrEmpty (ManagedTypeName)) {
59-
ManagedTypeName = fallbackManagedTypeName;
60-
}
61-
}
30+
public abstract bool ShouldBeDynamicallyRegistered (TypeDefinition topType, MethodDefinition registeredMethod, MethodDefinition implementedMethod, CustomAttribute registerAttribute);
6231
}
6332

6433
public class JavaCallableWrapperGenerator {
@@ -95,36 +64,47 @@ public string GetJavaAccess ()
9564
List<Signature> methods = new List<Signature> ();
9665
List<Signature> ctors = new List<Signature> ();
9766
List<JavaCallableWrapperGenerator> children;
98-
List<OverriddenMethodDescriptor> overriddenMethodDescriptors;
67+
9968
readonly IMetadataResolver cache;
69+
readonly JavaCallableMethodClassifier methodClassifier;
10070

10171
[Obsolete ("Use the TypeDefinitionCache overload for better performance.")]
10272
public JavaCallableWrapperGenerator (TypeDefinition type, Action<string, object []> log)
103-
: this (type, null, log, resolver: null)
73+
: this (type, log, resolver: null, methodClassifier: null)
10474
{ }
10575

10676
public JavaCallableWrapperGenerator (TypeDefinition type, Action<string, object[]> log, TypeDefinitionCache cache)
107-
: this (type, log, (IMetadataResolver) cache)
77+
: this (type, log, (IMetadataResolver) cache, methodClassifier: null)
78+
{ }
79+
80+
public JavaCallableWrapperGenerator (TypeDefinition type, Action<string, object[]> log, TypeDefinitionCache cache, JavaCallableMethodClassifier methodClassifier)
81+
: this (type, log, (IMetadataResolver) cache, methodClassifier)
10882
{
10983
}
11084

11185
public JavaCallableWrapperGenerator (TypeDefinition type, Action<string, object[]> log, IMetadataResolver resolver)
112-
: this (type, null, log, resolver)
86+
: this (type, log, resolver, methodClassifier: null)
87+
{ }
88+
89+
public JavaCallableWrapperGenerator (TypeDefinition type, Action<string, object[]> log, IMetadataResolver resolver, JavaCallableMethodClassifier methodClassifier)
90+
: this (type, null, log, resolver, methodClassifier)
11391
{
11492
if (type.HasNestedTypes) {
11593
children = new List<JavaCallableWrapperGenerator> ();
11694
AddNestedTypes (type);
11795
}
11896
}
11997

120-
public IList<OverriddenMethodDescriptor> OverriddenMethodDescriptors => overriddenMethodDescriptors;
12198
public string ApplicationJavaClass { get; set; }
12299
public JavaPeerStyle CodeGenerationTarget { get; set; }
123100

124101
public bool GenerateOnCreateOverrides { get; set; }
125102

126103
public bool HasExport { get; private set; }
127104

105+
// If there are no methods, we need to generate "empty" registration because of backward compatibility
106+
public bool HasDynamicallyRegisteredMethods => methods.Count == 0 || methods.Any ((Signature sig) => sig.IsDynamicallyRegistered);
107+
128108
/// <summary>
129109
/// The Java source code to be included in Instrumentation.onCreate
130110
///
@@ -152,8 +132,9 @@ void AddNestedTypes (TypeDefinition type)
152132
HasExport |= children.Any (t => t.HasExport);
153133
}
154134

155-
JavaCallableWrapperGenerator (TypeDefinition type, string outerType, Action<string, object[]> log, IMetadataResolver resolver)
135+
JavaCallableWrapperGenerator (TypeDefinition type, string outerType, Action<string, object[]> log, IMetadataResolver resolver, JavaCallableMethodClassifier methodClassifier = null)
156136
{
137+
this.methodClassifier = methodClassifier;
157138
this.type = type;
158139
this.log = log;
159140
this.cache = resolver ?? new TypeDefinitionCache ();
@@ -366,12 +347,13 @@ internal static RegisterAttribute ToRegisterAttribute (CustomAttribute attr)
366347
// attr.Resolve ();
367348
RegisterAttribute r = null;
368349
if (attr.ConstructorArguments.Count == 1)
369-
r = new RegisterAttribute ((string) attr.ConstructorArguments [0].Value);
350+
r = new RegisterAttribute ((string) attr.ConstructorArguments [0].Value, attr);
370351
else if (attr.ConstructorArguments.Count == 3)
371352
r = new RegisterAttribute (
372353
(string) attr.ConstructorArguments [0].Value,
373354
(string) attr.ConstructorArguments [1].Value,
374-
(string) attr.ConstructorArguments [2].Value);
355+
(string) attr.ConstructorArguments [2].Value,
356+
attr);
375357
if (r != null) {
376358
var v = attr.Properties.FirstOrDefault (p => p.Name == "DoNotGenerateAcw");
377359
r.DoNotGenerateAcw = v.Name == null ? false : (bool) v.Argument.Value;
@@ -384,7 +366,7 @@ internal static RegisterAttribute RegisterFromJniTypeSignatureAttribute (CustomA
384366
// attr.Resolve ();
385367
RegisterAttribute r = null;
386368
if (attr.ConstructorArguments.Count == 1)
387-
r = new RegisterAttribute ((string) attr.ConstructorArguments [0].Value);
369+
r = new RegisterAttribute ((string) attr.ConstructorArguments [0].Value, attr);
388370
if (r != null) {
389371
var v = attr.Properties.FirstOrDefault (p => p.Name == "GenerateJavaPeer");
390372
if (v.Name == null) {
@@ -403,7 +385,8 @@ internal static RegisterAttribute RegisterFromJniMethodSignatureAttribute (Custo
403385
if (attr.ConstructorArguments.Count == 2)
404386
r = new RegisterAttribute ((string) attr.ConstructorArguments [0].Value,
405387
(string) attr.ConstructorArguments [1].Value,
406-
"");
388+
"",
389+
attr);
407390
return r;
408391
}
409392

@@ -467,7 +450,8 @@ void AddMethod (MethodDefinition registeredMethod, MethodDefinition implementedM
467450
if (attr.Name.Contains ("-impl") || (attr.Name.Length > 7 && attr.Name[attr.Name.Length - 8] == '-'))
468451
Diagnostic.Error (4217, LookupSource (implementedMethod), Localization.Resources.JavaCallableWrappers_XA4217, attr.Name);
469452

470-
var msig = new Signature (implementedMethod, attr);
453+
bool shouldBeDynamicallyRegistered = methodClassifier?.ShouldBeDynamicallyRegistered (type, registeredMethod, implementedMethod, attr.OriginAttribute) ?? true;
454+
var msig = new Signature (implementedMethod, attr, shouldBeDynamicallyRegistered);
471455
if (!registeredMethod.IsConstructor && !methods.Any (m => m.Name == msig.Name && m.Params == msig.Params))
472456
methods.Add (msig);
473457
}
@@ -542,21 +526,38 @@ public void Generate (TextWriter writer)
542526

543527
GenerateHeader (writer);
544528

545-
writer.WriteLine ("/** @hide */");
546-
writer.WriteLine ("\tpublic static final String __md_methods;");
547-
if (children != null) {
548-
foreach (var i in Enumerable.Range (1, children.Count))
549-
writer.WriteLine ("\tstatic final String __md_{0}_methods;", i);
529+
bool needCtor = false;
530+
if (HasDynamicallyRegisteredMethods) {
531+
needCtor = true;
532+
writer.WriteLine ("/** @hide */");
533+
writer.WriteLine ("\tpublic static final String __md_methods;");
550534
}
551-
writer.WriteLine ("\tstatic {");
552-
GenerateRegisterType (writer, this, "__md_methods");
535+
553536
if (children != null) {
554-
for (int i = 0; i < children.Count; ++i) {
555-
string methods = string.Format ("__md_{0}_methods", i + 1);
556-
GenerateRegisterType (writer, children [i], methods);
537+
for (int i = 0; i < children.Count; i++) {
538+
if (!children[i].HasDynamicallyRegisteredMethods) {
539+
continue;
540+
}
541+
needCtor = true;
542+
writer.WriteLine ("\tstatic final String __md_{0}_methods;", i + 1);
557543
}
558544
}
559-
writer.WriteLine ("\t}");
545+
546+
if (needCtor) {
547+
writer.WriteLine ("\tstatic {");
548+
549+
if (HasDynamicallyRegisteredMethods) {
550+
GenerateRegisterType (writer, this, "__md_methods");
551+
}
552+
553+
if (children != null) {
554+
for (int i = 0; i < children.Count; ++i) {
555+
string methods = string.Format ("__md_{0}_methods", i + 1);
556+
GenerateRegisterType (writer, children [i], methods);
557+
}
558+
}
559+
writer.WriteLine ("\t}");
560+
}
560561

561562
GenerateBody (writer);
562563

@@ -710,16 +711,18 @@ void GenerateBody (TextWriter sw)
710711

711712
void GenerateRegisterType (TextWriter sw, JavaCallableWrapperGenerator self, string field)
712713
{
713-
if (overriddenMethodDescriptors == null) {
714-
overriddenMethodDescriptors = new List<OverriddenMethodDescriptor> ();
714+
if (!self.HasDynamicallyRegisteredMethods) {
715+
return;
715716
}
716717

717718
sw.WriteLine ("\t\t{0} = ", field);
718719
string managedTypeName = self.type.GetPartialAssemblyQualifiedName (cache);
719720
string javaTypeName = $"{package}.{name}";
721+
720722
foreach (Signature method in self.methods) {
721-
sw.WriteLine ("\t\t\t\"{0}\\n\" +", method.Method);
722-
overriddenMethodDescriptors.Add (new OverriddenMethodDescriptor (javaTypeName, method.Method, managedTypeName));
723+
if (method.IsDynamicallyRegistered) {
724+
sw.WriteLine ("\t\t\t\"{0}\\n\" +", method.Method);
725+
}
723726
}
724727
sw.WriteLine ("\t\t\t\"\";");
725728
if (CannotRegisterInStaticConstructor (self.type))
@@ -772,12 +775,13 @@ bool CannotRegisterInStaticConstructor (TypeDefinition type)
772775

773776
class Signature {
774777

775-
public Signature (MethodDefinition method, RegisterAttribute register) : this (method, register, null, null) {}
778+
public Signature (MethodDefinition method, RegisterAttribute register, bool shouldBeDynamicallyRegistered = true) : this (method, register, null, null, shouldBeDynamicallyRegistered) {}
776779

777-
public Signature (MethodDefinition method, RegisterAttribute register, string managedParameters, string outerType)
780+
public Signature (MethodDefinition method, RegisterAttribute register, string managedParameters, string outerType, bool shouldBeDynamicallyRegistered = true)
778781
: this (register.Name, register.Signature, register.Connector, managedParameters, outerType, null)
779782
{
780783
Annotations = JavaCallableWrapperGenerator.GetAnnotationsString ("\t", method.CustomAttributes);
784+
IsDynamicallyRegistered = shouldBeDynamicallyRegistered;
781785
}
782786

783787
public Signature (MethodDefinition method, ExportAttribute export, IMetadataResolver cache)
@@ -880,6 +884,7 @@ public string ThrowsDeclaration {
880884
public readonly string Method;
881885
public readonly bool IsExport;
882886
public readonly bool IsStatic;
887+
public readonly bool IsDynamicallyRegistered = true;
883888
public readonly string [] ThrownTypeNames;
884889
public readonly string Annotations;
885890
}

0 commit comments

Comments
 (0)