Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Xamarin.Android.Build.Tasks] implement a MemoryStreamPool #4251

Merged
merged 2 commits into from
Feb 19, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 0 additions & 100 deletions src/Xamarin.Android.Build.Tasks/Generator/Generator.cs

This file was deleted.

2 changes: 1 addition & 1 deletion src/Xamarin.Android.Build.Tasks/Tasks/Aot.cs
Original file line number Diff line number Diff line change
Expand Up @@ -435,7 +435,7 @@ bool RunAotCompiler (string assembliesPath, string aotCompiler, string aotOption
var stdout_completed = new ManualResetEvent (false);
var stderr_completed = new ManualResetEvent (false);

using (var sw = new StreamWriter (responseFile, append: false, encoding: new UTF8Encoding (encoderShouldEmitUTF8Identifier: false))) {
using (var sw = new StreamWriter (responseFile, append: false, encoding: MonoAndroidHelper.UTF8withoutBOM)) {
sw.WriteLine (aotOptions + " " + QuoteFileName (assembly));
}

Expand Down
2 changes: 1 addition & 1 deletion src/Xamarin.Android.Build.Tasks/Tasks/ClassParse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public class ClassParse : AndroidTask
public override bool RunTask ()
{
using (var output = new StreamWriter (OutputFile, append: false,
encoding: new UTF8Encoding (encoderShouldEmitUTF8Identifier: false))) {
encoding: MonoAndroidHelper.UTF8withoutBOM)) {
Bytecode.Log.OnLog = LogEventHandler;
var classPath = new Bytecode.ClassPath () {
ApiSource = "class-parse",
Expand Down
2 changes: 1 addition & 1 deletion src/Xamarin.Android.Build.Tasks/Tasks/CompileToDalvik.cs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ protected override string GenerateCommandLineCommands ()
cmd.AppendSwitchIfNotNull ("--output ", Path.GetDirectoryName (ClassesOutputDirectory));

using (var sw = new StreamWriter (path: inputListFile, append: false,
encoding: new UTF8Encoding (encoderShouldEmitUTF8Identifier: false))) {
encoding: MonoAndroidHelper.UTF8withoutBOM)) {
// .jar files
if (AlternativeJarFiles != null && AlternativeJarFiles.Any ()) {
Log.LogDebugMessage (" processing AlternativeJarFiles...");
Expand Down
112 changes: 91 additions & 21 deletions src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Xml.Linq;
using System.Reflection;
using System.Text;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
Expand Down Expand Up @@ -171,7 +171,7 @@ void Run (DirectoryAssemblyResolver res)

// Step 2 - Generate type maps
// Type mappings need to use all the assemblies, always.
WriteTypeMappings (res, allJavaTypes);
WriteTypeMappings (allJavaTypes);

var javaTypes = new List<TypeDefinition> ();
foreach (TypeDefinition td in allJavaTypes) {
Expand All @@ -183,15 +183,7 @@ void Run (DirectoryAssemblyResolver res)
}

// Step 3 - Generate Java stub code
var success = Generator.CreateJavaSources (
Log,
javaTypes,
Path.Combine (OutputDirectory, "src"),
ApplicationJavaClass,
AndroidSdkPlatform,
UseSharedRuntime,
int.Parse (AndroidSdkPlatform) <= 10,
hasExportReference);
var success = CreateJavaSources (javaTypes);
if (!success)
return;

Expand All @@ -202,9 +194,7 @@ void Run (DirectoryAssemblyResolver res)
var managedConflicts = new Dictionary<string, List<string>> (0, StringComparer.Ordinal);
var javaConflicts = new Dictionary<string, List<string>> (0, StringComparer.Ordinal);

// Allocate a MemoryStream with a reasonable guess at its capacity
using (var stream = new MemoryStream (javaTypes.Count * 32))
using (var acw_map = new StreamWriter (stream)) {
using (var acw_map = MemoryStreamPool.Shared.CreateStreamWriter (Encoding.Default)) {
foreach (TypeDefinition type in javaTypes) {
string managedKey = type.FullName.Replace ('/', '.');
string javaKey = JavaNativeTypeManager.ToJniName (type).Replace ('/', '.');
Expand Down Expand Up @@ -246,7 +236,7 @@ void Run (DirectoryAssemblyResolver res)
}

acw_map.Flush ();
MonoAndroidHelper.CopyIfStreamChanged (stream, AcwMapFile);
MonoAndroidHelper.CopyIfStreamChanged (acw_map.BaseStream, AcwMapFile);
}

foreach (var kvp in managedConflicts) {
Expand Down Expand Up @@ -281,11 +271,9 @@ void Run (DirectoryAssemblyResolver res)

var additionalProviders = manifest.Merge (Log, allJavaTypes, ApplicationJavaClass, EmbedAssemblies, BundledWearApplicationName, MergedManifestDocuments);

using (var stream = new MemoryStream ()) {
manifest.Save (Log, stream);

// Only write the new manifest if it actually changed
MonoAndroidHelper.CopyIfStreamChanged (stream, MergedAndroidManifestOutput);
// Only write the new manifest if it actually changed
if (manifest.SaveIfChanged (Log, MergedAndroidManifestOutput)) {
Log.LogDebugMessage ($"Saving: {MergedAndroidManifestOutput}");
}

// Create additional runtime provider java sources.
Expand Down Expand Up @@ -316,6 +304,88 @@ void Run (DirectoryAssemblyResolver res)
template => template.Replace ("// REGISTER_APPLICATION_AND_INSTRUMENTATION_CLASSES_HERE", regCallsWriter.ToString ()));
}

bool CreateJavaSources (IEnumerable<TypeDefinition> javaTypes)
{
string outputPath = Path.Combine (OutputDirectory, "src");
string monoInit = GetMonoInitSource (AndroidSdkPlatform, UseSharedRuntime);
bool hasExportReference = ResolvedAssemblies.Any (assembly => Path.GetFileName (assembly.ItemSpec) == "Mono.Android.Export.dll");
bool generateOnCreateOverrides = int.Parse (AndroidSdkPlatform) <= 10;

bool ok = true;
foreach (var t in javaTypes) {
using (var writer = MemoryStreamPool.Shared.CreateStreamWriter ()) {
try {
var jti = new JavaCallableWrapperGenerator (t, Log.LogWarning) {
GenerateOnCreateOverrides = generateOnCreateOverrides,
ApplicationJavaClass = ApplicationJavaClass,
MonoRuntimeInitialization = monoInit,
};

jti.Generate (writer);
writer.Flush ();

var path = jti.GetDestinationPath (outputPath);
MonoAndroidHelper.CopyIfStreamChanged (writer.BaseStream, path);
if (jti.HasExport && !hasExportReference)
Diagnostic.Error (4210, Properties.Resources.XA4210);
} catch (XamarinAndroidException xae) {
ok = false;
Log.LogError (
subcategory: "",
errorCode: "XA" + xae.Code,
helpKeyword: string.Empty,
file: xae.SourceFile,
lineNumber: xae.SourceLine,
columnNumber: 0,
endLineNumber: 0,
endColumnNumber: 0,
message: xae.MessageWithoutCode,
messageArgs: new object [0]
);
} catch (DirectoryNotFoundException ex) {
ok = false;
if (OS.IsWindows) {
Diagnostic.Error (5301, Properties.Resources.XA5301, t.FullName, ex);
} else {
Diagnostic.Error (4209, Properties.Resources.XA4209, t.FullName, ex);
}
} catch (Exception ex) {
ok = false;
Diagnostic.Error (4209, Properties.Resources.XA4209, t.FullName, ex);
}
}
}
return ok;
}

static string GetMonoInitSource (string androidSdkPlatform, bool useSharedRuntime)
{
// Lookup the mono init section from MonoRuntimeProvider:
// Mono Runtime Initialization {{{
// }}}
var builder = new StringBuilder ();
var runtime = useSharedRuntime ? "Shared" : "Bundled";
var api = "";
if (int.TryParse (androidSdkPlatform, out int apiLevel) && apiLevel < 21) {
api = ".20";
}
var assembly = Assembly.GetExecutingAssembly ();
using (var s = assembly.GetManifestResourceStream ($"MonoRuntimeProvider.{runtime}{api}.java"))
using (var reader = new StreamReader (s)) {
bool copy = false;
string line;
while ((line = reader.ReadLine ()) != null) {
if (string.CompareOrdinal ("\t\t// Mono Runtime Initialization {{{", line) == 0)
copy = true;
if (copy)
builder.AppendLine (line);
if (string.CompareOrdinal ("\t\t// }}}", line) == 0)
break;
}
}
return builder.ToString ();
}

string GetResource (string resource)
{
using (var stream = GetType ().Assembly.GetManifestResourceStream (resource))
Expand All @@ -330,7 +400,7 @@ void SaveResource (string resource, string filename, string destDir, Func<string
MonoAndroidHelper.CopyIfStringChanged (template, Path.Combine (destDir, filename));
}

void WriteTypeMappings (DirectoryAssemblyResolver resolver, List<TypeDefinition> types)
void WriteTypeMappings (List<TypeDefinition> types)
{
var tmg = new TypeMapGenerator ((string message) => Log.LogDebugMessage (message), SupportedAbis);
if (!tmg.Generate (types, TypemapOutputDirectory, GenerateNativeAssembly))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,7 @@ void GenerateJava (Package package)
}

var lines = LoadValues (package);
using (var memory = new MemoryStream ())
using (var writer = new StreamWriter (memory, Encoding)) {
using (var writer = MemoryStreamPool.Shared.CreateStreamWriter ()) {
// This code is based on the Android gradle plugin
// https://android.googlesource.com/platform/tools/base/+/908b391a9c006af569dfaff08b37f8fdd6c4da89/build-system/builder/src/main/java/com/android/builder/internal/SymbolWriter.java

Expand Down Expand Up @@ -173,7 +172,7 @@ void GenerateJava (Package package)

writer.Flush ();
var r_java = Path.Combine (output_directory, package.Name.Replace ('.', Path.DirectorySeparatorChar), "R.java");
if (MonoAndroidHelper.CopyIfStreamChanged (memory, r_java)) {
if (MonoAndroidHelper.CopyIfStreamChanged (writer.BaseStream, r_java)) {
LogDebugMessage ($"Writing: {r_java}");
} else {
LogDebugMessage ($"Up to date: {r_java}");
Expand Down Expand Up @@ -227,8 +226,6 @@ bool SetValue (string key, string[] line, string r_txt)
}
return false;
}

static readonly Encoding Encoding = new UTF8Encoding (encoderShouldEmitUTF8Identifier: false);
static readonly char [] Delimiter = new [] { ' ' };

class Index
Expand Down
Loading