From 87622d0ebd8a623a79e014d3c5169d5af3a48731 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Wed, 27 May 2020 21:20:05 +0300 Subject: [PATCH 1/7] Improve Console for iOS and Android --- .../src/System/ConsolePal.Android.cs | 37 ++++++++++++++++- .../src/System/ConsolePal.iOS.cs | 40 ++++++++++++++++++- src/mono/netcore/sample/iOS/Makefile | 6 +-- src/mono/netcore/sample/iOS/Program.csproj | 2 +- 4 files changed, 77 insertions(+), 8 deletions(-) diff --git a/src/libraries/System.Console/src/System/ConsolePal.Android.cs b/src/libraries/System.Console/src/System/ConsolePal.Android.cs index 87958be3c4858..32cbf52a9426c 100644 --- a/src/libraries/System.Console/src/System/ConsolePal.Android.cs +++ b/src/libraries/System.Console/src/System/ConsolePal.Android.cs @@ -4,20 +4,53 @@ using System.IO; using System.Text; +using System.Diagnostics; using System.Runtime.InteropServices; namespace System { internal sealed unsafe class LogcatStream : ConsoleStream { + private StringBuilder _buffer = new StringBuilder(); + public LogcatStream() : base(FileAccess.Write) {} public override int Read(byte[] buffer, int offset, int count) => throw Error.GetReadNotSupported(); public override unsafe void Write(byte[] buffer, int offset, int count) { - string log = ConsolePal.OutputEncoding.GetString(buffer, offset, count); - Interop.Logcat.AndroidLogPrint(Interop.Logcat.LogLevel.Info, "DOTNET", log); + ValidateWrite(buffer, offset, count); + + Span bufferSpan = buffer.AsSpan(offset, count); + + Debug.Assert(ConsolePal.OutputEncoding == Encoding.Unicode); + Debug.Assert(bufferSpan.Length % 2 == 0); + + Span charSpan = MemoryMarshal.Cast(bufferSpan); + + lock (_buffer) + { + if (charSpan.Contains('\n')) + { + string logLine; + if (_buffer.Length > 0) + { + _buffer.Append(charSpan); + logLine = _buffer.ToString(); + _buffer.Clear(); + } + else + { + logLine = charSpan.ToString(); + } + Interop.Logcat.AndroidLogPrint(Interop.Logcat.LogLevel.Info, "DOTNET", logLine); + } + else + { + // accumulate results until "\n" is written + _buffer.Append(charSpan); + } + } } } diff --git a/src/libraries/System.Console/src/System/ConsolePal.iOS.cs b/src/libraries/System.Console/src/System/ConsolePal.iOS.cs index d8ff911ed75d0..4ec771a0934f4 100644 --- a/src/libraries/System.Console/src/System/ConsolePal.iOS.cs +++ b/src/libraries/System.Console/src/System/ConsolePal.iOS.cs @@ -4,11 +4,15 @@ using System.IO; using System.Text; +using System.Diagnostics; +using System.Runtime.InteropServices; namespace System { internal sealed class NSLogStream : ConsoleStream { + private StringBuilder _buffer = new StringBuilder(); + public NSLogStream() : base(FileAccess.Write) {} public override int Read(byte[] buffer, int offset, int count) => throw Error.GetReadNotSupported(); @@ -17,9 +21,41 @@ public override unsafe void Write(byte[] buffer, int offset, int count) { ValidateWrite(buffer, offset, count); - fixed (byte* ptr = buffer) + Span bufferSpan = buffer.AsSpan(offset, count); + + Debug.Assert(ConsolePal.OutputEncoding == Encoding.Unicode); + Debug.Assert(bufferSpan.Length % 2 == 0); + + Span charSpan = MemoryMarshal.Cast(bufferSpan); + + lock (_buffer) { - Interop.Sys.Log(ptr + offset, count); + if (charSpan.Contains('\n')) + { + string logLine; + if (_buffer.Length > 0) + { + _buffer.Append(charSpan); + logLine = _buffer.ToString(); + _buffer.Clear(); + fixed (char* ptr = logLine) + { + Interop.Sys.Log((byte*)ptr, logLine.Length * 2); + } + } + else + { + fixed (byte* ptr = buffer) + { + Interop.Sys.Log(ptr + offset, count); + } + } + } + else + { + // accumulate results until "\n" is written + _buffer.Append(charSpan); + } } } } diff --git a/src/mono/netcore/sample/iOS/Makefile b/src/mono/netcore/sample/iOS/Makefile index 36dec2bc18dab..e8fe9e1c0cf60 100644 --- a/src/mono/netcore/sample/iOS/Makefile +++ b/src/mono/netcore/sample/iOS/Makefile @@ -7,15 +7,15 @@ all: runtimepack run TOOLS_DIR=../../../../../tools-local/tasks/mobile.tasks appbuilder: - $(DOTNET) build -c Release $(TOOLS_DIR)/AotCompilerTask/MonoAOTCompiler.csproj - $(DOTNET) build -c Release $(TOOLS_DIR)/AppleAppBuilder/AppleAppBuilder.csproj + $(DOTNET) build -c $(MONO_ARCH) $(TOOLS_DIR)/AotCompilerTask/MonoAOTCompiler.csproj + $(DOTNET) build -c $(MONO_ARCH) $(TOOLS_DIR)/AppleAppBuilder/AppleAppBuilder.csproj runtimepack: ../../../../.././build.sh Mono+Libs -os iOS -arch $(MONO_ARCH) -c $(MONO_CONFIG) run: clean appbuilder $(DOTNET) publish -c $(MONO_CONFIG) /p:TargetArchitecture=$(MONO_ARCH) \ - /p:UseLLVM=$(USE_LLVM) /p:UseAotForSimulator=true + /p:UseLLVM=$(USE_LLVM) /p:UseAotForSimulator=false clean: rm -rf bin diff --git a/src/mono/netcore/sample/iOS/Program.csproj b/src/mono/netcore/sample/iOS/Program.csproj index f08d1806b4f4c..c0f02b26f7102 100644 --- a/src/mono/netcore/sample/iOS/Program.csproj +++ b/src/mono/netcore/sample/iOS/Program.csproj @@ -25,7 +25,7 @@ + AssemblyFile="$(ArtifactsBinDir)AppleAppBuilder\$(Platform)\$(NetCoreAppCurrent)\AppleAppBuilder.dll" /> From ad41075ab4c9c76c9eaae3d3a90a02cade1a3452 Mon Sep 17 00:00:00 2001 From: Egor Bogatov Date: Wed, 27 May 2020 22:41:51 +0300 Subject: [PATCH 2/7] Update src/libraries/System.Console/src/System/ConsolePal.Android.cs Co-authored-by: campersau --- src/libraries/System.Console/src/System/ConsolePal.Android.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Console/src/System/ConsolePal.Android.cs b/src/libraries/System.Console/src/System/ConsolePal.Android.cs index 32cbf52a9426c..1feca864e9b2c 100644 --- a/src/libraries/System.Console/src/System/ConsolePal.Android.cs +++ b/src/libraries/System.Console/src/System/ConsolePal.Android.cs @@ -11,7 +11,7 @@ namespace System { internal sealed unsafe class LogcatStream : ConsoleStream { - private StringBuilder _buffer = new StringBuilder(); + private readonly StringBuilder _buffer = new StringBuilder(); public LogcatStream() : base(FileAccess.Write) {} From eb867ae6e3158169f298adcd28644ba9db3f6fc1 Mon Sep 17 00:00:00 2001 From: Egor Bogatov Date: Wed, 27 May 2020 22:41:58 +0300 Subject: [PATCH 3/7] Update src/libraries/System.Console/src/System/ConsolePal.iOS.cs Co-authored-by: campersau --- src/libraries/System.Console/src/System/ConsolePal.iOS.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Console/src/System/ConsolePal.iOS.cs b/src/libraries/System.Console/src/System/ConsolePal.iOS.cs index 4ec771a0934f4..7ecf7574e132b 100644 --- a/src/libraries/System.Console/src/System/ConsolePal.iOS.cs +++ b/src/libraries/System.Console/src/System/ConsolePal.iOS.cs @@ -11,7 +11,7 @@ namespace System { internal sealed class NSLogStream : ConsoleStream { - private StringBuilder _buffer = new StringBuilder(); + private readonly StringBuilder _buffer = new StringBuilder(); public NSLogStream() : base(FileAccess.Write) {} @@ -206,4 +206,4 @@ internal sealed class ControlCHandlerRegistrar internal void Unregister() => throw new PlatformNotSupportedException(); } } -} \ No newline at end of file +} From f4f66136b1b20b2b897295db4775cfe9dbe1bf64 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Thu, 28 May 2020 00:11:57 +0300 Subject: [PATCH 4/7] Address feedback --- src/mono/netcore/sample/iOS/Makefile | 4 ++-- src/mono/netcore/sample/iOS/Program.csproj | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/mono/netcore/sample/iOS/Makefile b/src/mono/netcore/sample/iOS/Makefile index e8fe9e1c0cf60..0bc8bb63879b6 100644 --- a/src/mono/netcore/sample/iOS/Makefile +++ b/src/mono/netcore/sample/iOS/Makefile @@ -7,8 +7,8 @@ all: runtimepack run TOOLS_DIR=../../../../../tools-local/tasks/mobile.tasks appbuilder: - $(DOTNET) build -c $(MONO_ARCH) $(TOOLS_DIR)/AotCompilerTask/MonoAOTCompiler.csproj - $(DOTNET) build -c $(MONO_ARCH) $(TOOLS_DIR)/AppleAppBuilder/AppleAppBuilder.csproj + $(DOTNET) build -c Debug $(TOOLS_DIR)/AotCompilerTask/MonoAOTCompiler.csproj + $(DOTNET) build -c Debug $(TOOLS_DIR)/AppleAppBuilder/AppleAppBuilder.csproj runtimepack: ../../../../.././build.sh Mono+Libs -os iOS -arch $(MONO_ARCH) -c $(MONO_CONFIG) diff --git a/src/mono/netcore/sample/iOS/Program.csproj b/src/mono/netcore/sample/iOS/Program.csproj index c0f02b26f7102..f90a3d88cd8af 100644 --- a/src/mono/netcore/sample/iOS/Program.csproj +++ b/src/mono/netcore/sample/iOS/Program.csproj @@ -23,12 +23,12 @@ - + + AssemblyFile="$(ArtifactsBinDir)AppleAppBuilder\Debug\$(NetCoreAppCurrent)\AppleAppBuilder.dll" /> + AssemblyFile="$(ArtifactsBinDir)MonoAOTCompiler\Debug\$(NetCoreAppCurrent)\MonoAOTCompiler.dll" /> From 835cdc09a0e8c7dab421b7d38d5b37ab072421fc Mon Sep 17 00:00:00 2001 From: EgorBo Date: Thu, 28 May 2020 14:39:39 +0300 Subject: [PATCH 5/7] Address feedback --- src/mono/netcore/sample/iOS/Makefile | 2 +- src/mono/netcore/sample/iOS/Program.csproj | 8 ++------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/mono/netcore/sample/iOS/Makefile b/src/mono/netcore/sample/iOS/Makefile index 0bc8bb63879b6..e3d8b5271453c 100644 --- a/src/mono/netcore/sample/iOS/Makefile +++ b/src/mono/netcore/sample/iOS/Makefile @@ -15,7 +15,7 @@ runtimepack: run: clean appbuilder $(DOTNET) publish -c $(MONO_CONFIG) /p:TargetArchitecture=$(MONO_ARCH) \ - /p:UseLLVM=$(USE_LLVM) /p:UseAotForSimulator=false + /p:UseLLVM=$(USE_LLVM) /p:UseAotForSimulator=false /p:TargetOS=iOS clean: rm -rf bin diff --git a/src/mono/netcore/sample/iOS/Program.csproj b/src/mono/netcore/sample/iOS/Program.csproj index f90a3d88cd8af..7b7d84303ecd0 100644 --- a/src/mono/netcore/sample/iOS/Program.csproj +++ b/src/mono/netcore/sample/iOS/Program.csproj @@ -4,7 +4,6 @@ bin Portable $(NetCoreAppCurrent) - iOS $(ArtifactsBinDir)lib-runtime-packs\$(NetCoreAppCurrent)-iOS-$(Configuration)-$(TargetArchitecture)\runtimes\ios-$(TargetArchitecture) false ios-$(TargetArchitecture) @@ -24,11 +23,8 @@ - - - + + From 8eb4d0833c8c5b280708d0c0581cb4404dde243c Mon Sep 17 00:00:00 2001 From: EgorBo Date: Thu, 28 May 2020 15:28:30 +0300 Subject: [PATCH 6/7] Introduce AccumulateNewLines --- .../src/System/ConsolePal.Android.cs | 26 +++------------ .../src/System/ConsolePal.iOS.cs | 31 ++++-------------- .../src/System/IO/ConsoleStream.cs | 32 +++++++++++++++++++ 3 files changed, 43 insertions(+), 46 deletions(-) diff --git a/src/libraries/System.Console/src/System/ConsolePal.Android.cs b/src/libraries/System.Console/src/System/ConsolePal.Android.cs index 1feca864e9b2c..f1e5e6374c0d1 100644 --- a/src/libraries/System.Console/src/System/ConsolePal.Android.cs +++ b/src/libraries/System.Console/src/System/ConsolePal.Android.cs @@ -21,35 +21,19 @@ public override unsafe void Write(byte[] buffer, int offset, int count) { ValidateWrite(buffer, offset, count); - Span bufferSpan = buffer.AsSpan(offset, count); + ReadOnlySpan bufferSpan = new ReadOnlySpan(buffer, offset, count) Debug.Assert(ConsolePal.OutputEncoding == Encoding.Unicode); Debug.Assert(bufferSpan.Length % 2 == 0); - Span charSpan = MemoryMarshal.Cast(bufferSpan); + ReadOnlySpan charSpan = MemoryMarshal.Cast(bufferSpan); lock (_buffer) { - if (charSpan.Contains('\n')) + AccumulateNewLines(_buffer, charSpan, line => { - string logLine; - if (_buffer.Length > 0) - { - _buffer.Append(charSpan); - logLine = _buffer.ToString(); - _buffer.Clear(); - } - else - { - logLine = charSpan.ToString(); - } - Interop.Logcat.AndroidLogPrint(Interop.Logcat.LogLevel.Info, "DOTNET", logLine); - } - else - { - // accumulate results until "\n" is written - _buffer.Append(charSpan); - } + Interop.Logcat.AndroidLogPrint(Interop.Logcat.LogLevel.Info, "DOTNET", line); + }); } } } diff --git a/src/libraries/System.Console/src/System/ConsolePal.iOS.cs b/src/libraries/System.Console/src/System/ConsolePal.iOS.cs index 7ecf7574e132b..5ce2d98fe85c7 100644 --- a/src/libraries/System.Console/src/System/ConsolePal.iOS.cs +++ b/src/libraries/System.Console/src/System/ConsolePal.iOS.cs @@ -21,41 +21,22 @@ public override unsafe void Write(byte[] buffer, int offset, int count) { ValidateWrite(buffer, offset, count); - Span bufferSpan = buffer.AsSpan(offset, count); + ReadOnlySpan bufferSpan = new ReadOnlySpan(buffer, offset, count) Debug.Assert(ConsolePal.OutputEncoding == Encoding.Unicode); Debug.Assert(bufferSpan.Length % 2 == 0); - Span charSpan = MemoryMarshal.Cast(bufferSpan); + ReadOnlySpan charSpan = MemoryMarshal.Cast(bufferSpan); lock (_buffer) { - if (charSpan.Contains('\n')) + AccumulateNewLines(_buffer, charSpan, line => { - string logLine; - if (_buffer.Length > 0) + fixed (char* ptr = line) { - _buffer.Append(charSpan); - logLine = _buffer.ToString(); - _buffer.Clear(); - fixed (char* ptr = logLine) - { - Interop.Sys.Log((byte*)ptr, logLine.Length * 2); - } + Interop.Sys.Log((byte*)ptr, line.Length * 2); } - else - { - fixed (byte* ptr = buffer) - { - Interop.Sys.Log(ptr + offset, count); - } - } - } - else - { - // accumulate results until "\n" is written - _buffer.Append(charSpan); - } + }); } } } diff --git a/src/libraries/System.Console/src/System/IO/ConsoleStream.cs b/src/libraries/System.Console/src/System/IO/ConsoleStream.cs index d2eda09de1c90..ec4591be12e96 100644 --- a/src/libraries/System.Console/src/System/IO/ConsoleStream.cs +++ b/src/libraries/System.Console/src/System/IO/ConsoleStream.cs @@ -93,5 +93,37 @@ protected void ValidateWrite(byte[] buffer, int offset, int count) if (!_canWrite) throw Error.GetWriteNotSupported(); } + + private static void AccumulateNewLines(StringBuilder accumulator, ReadOnlySpan buffer, Action printer) + { + int lineStartIndex = 0; + for (int i = 0; i < buffer.Length; i++) + { + if (buffer[i] == '\n') + { + ReadOnlySpan sliceWithNl = buffer.Slice(lineStartIndex, i - lineStartIndex); + if (accumulator.Length > 0) + { + // we found a new line, append content from accumulator if it's not empty + accumulator.Append(sliceWithNl); + printer(accumulator.ToString()); + accumulator.Clear(); + } + else + { + // accumulator is empty - print the line as it is + printer(sliceWithNl.ToString()); + } + lineStartIndex = i + 1; + } + } + + if (buffer.Length > 0 && buffer[^1] != '\n') + { + // add a line without '\n' to accumulator + ReadOnlySpan appendix = buffer.Slice(lineStartIndex, buffer.Length - lineStartIndex); + accumulator.Append(appendix); + } + } } } From bd8b9f64c174776e515c4e06ebf694f7aa8a5c73 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Thu, 28 May 2020 15:46:37 +0300 Subject: [PATCH 7/7] Fix compilation errors --- src/libraries/System.Console/src/System/ConsolePal.Android.cs | 2 +- src/libraries/System.Console/src/System/ConsolePal.iOS.cs | 2 +- src/libraries/System.Console/src/System/IO/ConsoleStream.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Console/src/System/ConsolePal.Android.cs b/src/libraries/System.Console/src/System/ConsolePal.Android.cs index f1e5e6374c0d1..7f5dd1395ac76 100644 --- a/src/libraries/System.Console/src/System/ConsolePal.Android.cs +++ b/src/libraries/System.Console/src/System/ConsolePal.Android.cs @@ -21,7 +21,7 @@ public override unsafe void Write(byte[] buffer, int offset, int count) { ValidateWrite(buffer, offset, count); - ReadOnlySpan bufferSpan = new ReadOnlySpan(buffer, offset, count) + ReadOnlySpan bufferSpan = new ReadOnlySpan(buffer, offset, count); Debug.Assert(ConsolePal.OutputEncoding == Encoding.Unicode); Debug.Assert(bufferSpan.Length % 2 == 0); diff --git a/src/libraries/System.Console/src/System/ConsolePal.iOS.cs b/src/libraries/System.Console/src/System/ConsolePal.iOS.cs index 5ce2d98fe85c7..f68c7a2f2c2aa 100644 --- a/src/libraries/System.Console/src/System/ConsolePal.iOS.cs +++ b/src/libraries/System.Console/src/System/ConsolePal.iOS.cs @@ -21,7 +21,7 @@ public override unsafe void Write(byte[] buffer, int offset, int count) { ValidateWrite(buffer, offset, count); - ReadOnlySpan bufferSpan = new ReadOnlySpan(buffer, offset, count) + ReadOnlySpan bufferSpan = new ReadOnlySpan(buffer, offset, count); Debug.Assert(ConsolePal.OutputEncoding == Encoding.Unicode); Debug.Assert(bufferSpan.Length % 2 == 0); diff --git a/src/libraries/System.Console/src/System/IO/ConsoleStream.cs b/src/libraries/System.Console/src/System/IO/ConsoleStream.cs index ec4591be12e96..f5432f23de665 100644 --- a/src/libraries/System.Console/src/System/IO/ConsoleStream.cs +++ b/src/libraries/System.Console/src/System/IO/ConsoleStream.cs @@ -94,7 +94,7 @@ protected void ValidateWrite(byte[] buffer, int offset, int count) if (!_canWrite) throw Error.GetWriteNotSupported(); } - private static void AccumulateNewLines(StringBuilder accumulator, ReadOnlySpan buffer, Action printer) + protected static void AccumulateNewLines(StringBuilder accumulator, ReadOnlySpan buffer, Action printer) { int lineStartIndex = 0; for (int i = 0; i < buffer.Length; i++)