Skip to content

Commit f89b4ed

Browse files
committed
[XABT] Separate marshal method storage from MarshalMethodClassifier to MarshalMethodCollection.
1 parent ee56aaa commit f89b4ed

12 files changed

+609
-293
lines changed

src/Xamarin.Android.Build.Tasks/Linker/MonoDroid.Tuner/FindJavaObjectsStep.cs

+4-2
Original file line numberDiff line numberDiff line change
@@ -119,8 +119,10 @@ List<CallableWrapperType> ConvertToCallableWrappers (List<TypeDefinition> types)
119119
DefaultMonoRuntimeInitialization = "mono.MonoPackageManager.LoadApplication (context);",
120120
};
121121

122-
if (UseMarshalMethods)
123-
reader_options.MethodClassifier = new MarshalMethodsClassifier (Context, Context.Resolver, Log);
122+
if (UseMarshalMethods) {
123+
var classifier = new MarshalMethodsClassifier (Context, Context.Resolver, Log);
124+
reader_options.MethodClassifier = new MarshalMethodsCollection (classifier);
125+
}
124126

125127
foreach (var type in types) {
126128
var wrapper = CecilImporter.CreateType (type, Context, reader_options);

src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs

+9-6
Original file line numberDiff line numberDiff line change
@@ -212,25 +212,28 @@ internal static Dictionary<string, ITaskItem> MaybeGetArchAssemblies (Dictionary
212212
XAAssemblyResolver resolver = MakeResolver (useMarshalMethods, arch, assemblies);
213213
var tdCache = new TypeDefinitionCache ();
214214
(List<TypeDefinition> allJavaTypes, List<TypeDefinition> javaTypesForJCW) = ScanForJavaTypes (resolver, tdCache, assemblies, userAssemblies, useMarshalMethods);
215-
var jcwContext = new JCWGeneratorContext (arch, resolver, assemblies.Values, javaTypesForJCW, tdCache, useMarshalMethods);
215+
var jcwContext = new JCWGeneratorContext (arch, resolver, assemblies.Values, javaTypesForJCW, tdCache);
216216
var jcwGenerator = new JCWGenerator (Log, jcwContext) {
217217
CodeGenerationTarget = codeGenerationTarget,
218218
};
219-
bool success;
219+
bool success = true;
220220

221221
if (generateJavaCode && RunCheckedBuild) {
222-
success = jcwGenerator.GenerateAndClassify (AndroidSdkPlatform, outputPath: Path.Combine (OutputDirectory, "src"), ApplicationJavaClass);
222+
success = jcwGenerator.Generate (AndroidSdkPlatform, outputPath: Path.Combine (OutputDirectory, "src"), ApplicationJavaClass);
223223

224224
generatedJavaFiles = jcwGenerator.GeneratedJavaFiles;
225-
} else {
226-
success = jcwGenerator.Classify (AndroidSdkPlatform);
227225
}
228226

229227
if (!success) {
230228
return (false, null);
231229
}
232230

233-
return (true, new NativeCodeGenState (arch, tdCache, resolver, allJavaTypes, javaTypesForJCW, jcwGenerator.Classifier));
231+
MarshalMethodsCollection? marshalMethodsCollection = null;
232+
233+
if (useMarshalMethods)
234+
marshalMethodsCollection = MarshalMethodsCollection.FromAssemblies (arch, assemblies.Values.ToList (), resolver, Log);
235+
236+
return (true, new NativeCodeGenState (arch, tdCache, resolver, allJavaTypes, javaTypesForJCW, marshalMethodsCollection));
234237
}
235238

236239
(List<TypeDefinition> allJavaTypes, List<TypeDefinition> javaTypesForJCW) ScanForJavaTypes (XAAssemblyResolver res, TypeDefinitionCache cache, Dictionary<string, ITaskItem> assemblies, Dictionary<string, ITaskItem> userAssemblies, bool useMarshalMethods)

src/Xamarin.Android.Build.Tasks/Tasks/GenerateMainAndroidManifest.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ void GenerateAdditionalProviderSources (NativeCodeGenState codeGenState, IList<s
177177
regCallsWriter.WriteLine ("// Application and Instrumentation ACWs must be registered first.");
178178
foreach (TypeDefinition type in codeGenState.JavaTypesForJCW) {
179179
if (JavaNativeTypeManager.IsApplication (type, codeGenState.TypeCache) || JavaNativeTypeManager.IsInstrumentation (type, codeGenState.TypeCache)) {
180-
if (codeGenState.Classifier != null && !codeGenState.Classifier.FoundDynamicallyRegisteredMethods (type)) {
180+
if (codeGenState.Classifier != null && !codeGenState.Classifier.TypeHasDynamicallyRegisteredMethods (type)) {
181181
continue;
182182
}
183183

src/Xamarin.Android.Build.Tasks/Tasks/RewriteMarshalMethods.cs

+7-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#nullable enable
22
using System.Collections.Concurrent;
3+
using System.Linq;
34
using Microsoft.Android.Build.Tasks;
45
using Microsoft.Build.Framework;
56
using Xamarin.Android.Tools;
@@ -51,13 +52,15 @@ public override bool RunTask ()
5152
}
5253

5354
Log.LogDebugMessage ($"[{state.TargetArch}] Number of generated marshal methods: {state.Classifier.MarshalMethods.Count}");
54-
if (state.Classifier.RejectedMethodCount > 0) {
55-
Log.LogWarning ($"[{state.TargetArch}] Number of methods in the project that will be registered dynamically: {state.Classifier.RejectedMethodCount}");
55+
if (state.Classifier.DynamicallyRegisteredMarshalMethods.Count > 0) {
56+
Log.LogWarning ($"[{state.TargetArch}] Number of methods in the project that will be registered dynamically: {state.Classifier.DynamicallyRegisteredMarshalMethods.Count}");
5657
}
5758

58-
if (state.Classifier.WrappedMethodCount > 0) {
59+
var wrappedCount = state.Classifier.MarshalMethods.Sum (m => m.Value.Count (m2 => m2.NeedsBlittableWorkaround));
60+
61+
if (wrappedCount > 0) {
5962
// TODO: change to LogWarning once the generator can output code which requires no non-blittable wrappers
60-
Log.LogDebugMessage ($"[{state.TargetArch}] Number of methods in the project that need marshal method wrappers: {state.Classifier.WrappedMethodCount}");
63+
Log.LogDebugMessage ($"[{state.TargetArch}] Number of methods in the project that need marshal method wrappers: {wrappedCount}");
6164
}
6265
}
6366

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Text.RegularExpressions;
6+
using Android.Runtime;
7+
using Java.Interop.Tools.Cecil;
8+
using Mono.Cecil;
9+
using Mono.Cecil.Cil;
10+
11+
namespace Xamarin.Android.Tasks;
12+
13+
static class CecilExtensions
14+
{
15+
public static MethodDefinition? GetBaseRegisteredMethod (MethodDefinition method, IMetadataResolver cache)
16+
{
17+
MethodDefinition bmethod;
18+
while ((bmethod = method.GetBaseDefinition (cache)) != method) {
19+
method = bmethod;
20+
21+
if (HasMethodRegistrationAttributes (method)) {
22+
return method;
23+
}
24+
}
25+
return null;
26+
}
27+
28+
static readonly string [] MethodRegistrationAttributes = new []{
29+
typeof (RegisterAttribute).FullName,
30+
"Java.Interop.JniConstructorSignatureAttribute",
31+
"Java.Interop.JniMethodSignatureAttribute",
32+
};
33+
34+
// Keep in sync w/ HasMethodRegistrationAttributes()
35+
public static IEnumerable<RegisterAttribute> GetMethodRegistrationAttributes (Mono.Cecil.ICustomAttributeProvider p)
36+
{
37+
foreach (var a in CecilExtensions.GetAttributes<RegisterAttribute> (p, a => CecilExtensions.ToRegisterAttribute (a))) {
38+
yield return a;
39+
}
40+
foreach (var c in p.GetCustomAttributes ("Java.Interop.JniConstructorSignatureAttribute")) {
41+
var r = RegisterFromJniConstructorSignatureAttribute (c);
42+
if (r == null) {
43+
continue;
44+
}
45+
yield return r;
46+
}
47+
foreach (var c in p.GetCustomAttributes ("Java.Interop.JniMethodSignatureAttribute")) {
48+
var r = RegisterFromJniMethodSignatureAttribute (c);
49+
if (r == null) {
50+
continue;
51+
}
52+
yield return r;
53+
}
54+
}
55+
56+
internal static RegisterAttribute? RegisterFromJniMethodSignatureAttribute (CustomAttribute attr)
57+
{
58+
// attr.Resolve ();
59+
RegisterAttribute? r = null;
60+
if (attr.ConstructorArguments.Count == 2)
61+
r = new RegisterAttribute ((string) attr.ConstructorArguments [0].Value,
62+
(string) attr.ConstructorArguments [1].Value,
63+
"",
64+
attr);
65+
return r;
66+
}
67+
68+
internal static RegisterAttribute? RegisterFromJniConstructorSignatureAttribute (CustomAttribute attr)
69+
{
70+
// attr.Resolve ();
71+
RegisterAttribute? r = null;
72+
if (attr.ConstructorArguments.Count == 1)
73+
r = new RegisterAttribute (
74+
name: ".ctor",
75+
signature: (string) attr.ConstructorArguments [0].Value,
76+
connector: "",
77+
originAttribute: attr);
78+
return r;
79+
}
80+
81+
// Keep in sync w/ GetMethodRegistrationAttributes()
82+
public static bool HasMethodRegistrationAttributes (Mono.Cecil.ICustomAttributeProvider p)
83+
{
84+
foreach (CustomAttribute custom_attribute in p.CustomAttributes) {
85+
var customAttrType = custom_attribute.Constructor.DeclaringType.FullName;
86+
foreach (var t in MethodRegistrationAttributes) {
87+
if (customAttrType == t)
88+
return true;
89+
}
90+
}
91+
return false;
92+
}
93+
94+
public static IEnumerable<TAttribute> GetAttributes<TAttribute> (Mono.Cecil.ICustomAttributeProvider p, Func<CustomAttribute, TAttribute?> selector)
95+
where TAttribute : class
96+
{
97+
return GetAttributes (p, typeof (TAttribute).FullName!, selector);
98+
}
99+
100+
public static IEnumerable<TAttribute> GetAttributes<TAttribute> (Mono.Cecil.ICustomAttributeProvider p, string attributeName, Func<CustomAttribute, TAttribute?> selector)
101+
where TAttribute : class
102+
{
103+
return p.GetCustomAttributes (attributeName)
104+
.Select (selector)
105+
.Where (v => v != null)
106+
.Select (v => v!);
107+
}
108+
109+
internal static IEnumerable<RegisterAttribute> GetTypeRegistrationAttributes (Mono.Cecil.ICustomAttributeProvider p)
110+
{
111+
foreach (var a in CecilExtensions.GetAttributes<RegisterAttribute> (p, a => CecilExtensions.ToRegisterAttribute (a))) {
112+
yield return a;
113+
}
114+
foreach (var c in p.GetCustomAttributes ("Java.Interop.JniTypeSignatureAttribute")) {
115+
var r = RegisterFromJniTypeSignatureAttribute (c);
116+
if (r == null) {
117+
continue;
118+
}
119+
yield return r;
120+
}
121+
}
122+
123+
internal static RegisterAttribute? RegisterFromJniTypeSignatureAttribute (CustomAttribute attr)
124+
{
125+
// attr.Resolve ();
126+
RegisterAttribute? r = null;
127+
if (attr.ConstructorArguments.Count == 1)
128+
r = new RegisterAttribute ((string) attr.ConstructorArguments [0].Value, attr);
129+
if (r != null) {
130+
var v = attr.Properties.FirstOrDefault (p => p.Name == "GenerateJavaPeer");
131+
if (v.Name == null) {
132+
r.DoNotGenerateAcw = false;
133+
} else if (v.Name == "GenerateJavaPeer") {
134+
r.DoNotGenerateAcw = !(bool) v.Argument.Value;
135+
}
136+
var isKeyProp = attr.Properties.FirstOrDefault (p => p.Name == "IsKeyword");
137+
var isKeyword = isKeyProp.Name != null && ((bool) isKeyProp.Argument.Value) == true;
138+
var arrRankProp = attr.Properties.FirstOrDefault (p => p.Name == "ArrayRank");
139+
if (arrRankProp.Name != null && arrRankProp.Argument.Value is int rank) {
140+
r.Name = new string ('[', rank) + (isKeyword ? r.Name : "L" + r.Name + ";");
141+
}
142+
}
143+
return r;
144+
}
145+
146+
internal static RegisterAttribute? ToRegisterAttribute (CustomAttribute attr)
147+
{
148+
// attr.Resolve ();
149+
RegisterAttribute? r = null;
150+
if (attr.ConstructorArguments.Count == 1)
151+
r = new RegisterAttribute ((string) attr.ConstructorArguments [0].Value, attr);
152+
else if (attr.ConstructorArguments.Count == 3)
153+
r = new RegisterAttribute (
154+
(string) attr.ConstructorArguments [0].Value,
155+
(string) attr.ConstructorArguments [1].Value,
156+
(string) attr.ConstructorArguments [2].Value,
157+
attr);
158+
if (r != null) {
159+
var v = attr.Properties.FirstOrDefault (p => p.Name == "DoNotGenerateAcw");
160+
r.DoNotGenerateAcw = v.Name == null ? false : (bool) v.Argument.Value;
161+
}
162+
return r;
163+
}
164+
165+
public static SequencePoint? LookupSource (TypeDefinition type)
166+
{
167+
SequencePoint? candidate = null;
168+
foreach (var method in type.Methods) {
169+
if (!method.HasBody)
170+
continue;
171+
172+
foreach (var ins in method.Body.Instructions) {
173+
var seq = method.DebugInformation.GetSequencePoint (ins);
174+
if (seq == null)
175+
continue;
176+
177+
if (Regex.IsMatch (seq.Document.Url, ".+\\.(g|designer)\\..+"))
178+
break;
179+
if (candidate == null || seq.StartLine < candidate.StartLine)
180+
candidate = seq;
181+
break;
182+
}
183+
}
184+
185+
return candidate;
186+
}
187+
188+
}

0 commit comments

Comments
 (0)