From d3426fc44206e6fdd2a68857935957a2cf2aedbc Mon Sep 17 00:00:00 2001 From: spaceflint <> Date: Sun, 15 Nov 2020 11:12:37 +0200 Subject: [PATCH] Some changes for BNA --- Baselib/mscorlib.filter | 4 + Baselib/src/System/BitConverter.cs | 149 ++++++++++++++++++++++++ Baselib/src/System/Buffer.cs | 8 ++ Baselib/src/System/DateTime.cs | 19 ++- Baselib/src/System/Double.cs | 23 ++++ Baselib/src/System/IO/Directory.cs | 32 +++++ Baselib/src/System/IO/DirectoryInfo.cs | 12 ++ Baselib/src/System/IO/File.cs | 22 ++++ Baselib/src/System/IO/FileStream.cs | 34 +++++- Baselib/src/System/IO/FileSystemInfo.cs | 101 ++++++++++++++++ Baselib/src/System/IO/Path.cs | 8 +- Baselib/src/System/Single.cs | 23 ++++ Baselib/src/System/Text/Encoding.cs | 7 ++ CilToJava/src/CilType.cs | 6 +- CilToJava/src/CodeArray.cs | 38 +++++- CilToJava/src/CodeBuilder.cs | 2 +- CilToJava/src/CodeMisc.cs | 13 ++- README.md | 2 + 18 files changed, 487 insertions(+), 16 deletions(-) create mode 100644 Baselib/src/System/BitConverter.cs create mode 100644 Baselib/src/System/IO/Directory.cs create mode 100644 Baselib/src/System/IO/DirectoryInfo.cs create mode 100644 Baselib/src/System/IO/File.cs create mode 100644 Baselib/src/System/IO/FileSystemInfo.cs diff --git a/Baselib/mscorlib.filter b/Baselib/mscorlib.filter index a34b3c9..1bbc9f0 100644 --- a/Baselib/mscorlib.filter +++ b/Baselib/mscorlib.filter @@ -142,14 +142,18 @@ System.Runtime.Serialization.StreamingContext System.Runtime.Serialization.SerializationException System.IO.BinaryReader +System.IO.BinaryWriter System.IO.DirectoryNotFoundException System.IO.EndOfStreamException System.IO.FileAccess +System.IO.FileAttributes System.IO.FileMode System.IO.FileNotFoundException +System.IO.FileShare System.IO.MemoryStream System.IO.TextReader System.IO.TextWriter +System.IO.SeekOrigin System.IO.StringReader System.IO.Stream System.IO.StreamReader diff --git a/Baselib/src/System/BitConverter.cs b/Baselib/src/System/BitConverter.cs new file mode 100644 index 0000000..bcbefe8 --- /dev/null +++ b/Baselib/src/System/BitConverter.cs @@ -0,0 +1,149 @@ + +namespace system +{ + + public static class BitConverter + { + + [java.attr.RetainType] private static readonly bool _IsLittleEndian = + java.nio.ByteOrder.nativeOrder() == java.nio.ByteOrder.LITTLE_ENDIAN; + public static readonly bool IsLittleEndian = _IsLittleEndian; + + public static int SingleToInt32Bits(float value) => java.lang.Float.floatToRawIntBits(value); + public static float Int32BitsToSingle(int value) => java.lang.Float.intBitsToFloat(value); + + public static long DoubleToInt64Bits(double value) => java.lang.Double.doubleToRawLongBits(value); + public static double Int64BitsToDouble(long value) => java.lang.Double.longBitsToDouble(value); + + public static byte[] GetBytes(bool value) => new byte[] { value ? (byte) 1 : (byte) 0 }; + public static byte[] GetBytes(short value) + => (byte[]) (object) java.util.Arrays.copyOf( + GetByteBuffer(2).putShort(0, value).array(), 2); + public static byte[] GetBytes(ushort value) => GetBytes((short) value); + public static byte[] GetBytes(char value) => GetBytes((short) value); + public static byte[] GetBytes(int value) + => (byte[]) (object) java.util.Arrays.copyOf( + GetByteBuffer(4).putInt(0, value).array(), 4); + public static byte[] GetBytes(uint value) => GetBytes((int) value); + public static byte[] GetBytes(long value) + => (byte[]) (object) java.util.Arrays.copyOf( + GetByteBuffer(8).putLong(0, value).array(), 8); + public static byte[] GetBytes(ulong value) => GetBytes((long) value); + public static byte[] GetBytes(float value) + => (byte[]) (object) java.util.Arrays.copyOf( + GetByteBuffer(4).putFloat(0, value).array(), 4); + public static byte[] GetBytes(double value) + => (byte[]) (object) java.util.Arrays.copyOf( + GetByteBuffer(8).putDouble(0, value).array(), 8); + + public static short ToInt16(byte[] value, int startIndex) + { + ThrowHelper.ThrowIfNull(value); + if ((uint) startIndex >= value.Length || startIndex > value.Length - 2) + ThrowHelper.ThrowArgumentOutOfRangeException(); + byte b0 = value[startIndex]; + byte b1 = value[++startIndex]; + if (! _IsLittleEndian) + (b0, b1) = (b1, b0); + return (short) (b0 | (b1 << 8)); + } + public static ushort ToUInt16(byte[] value, int startIndex) + => (ushort) ToInt16(value, startIndex); + public static char ToChar(byte[] value, int startIndex) + => (char) ToInt16(value, startIndex); + + public static int ToInt32(byte[] value, int startIndex) + { + ThrowHelper.ThrowIfNull(value); + if ((uint) startIndex >= value.Length || startIndex > value.Length - 4) + ThrowHelper.ThrowArgumentOutOfRangeException(); + byte b0 = value[startIndex]; + byte b1 = value[++startIndex]; + byte b2 = value[++startIndex]; + byte b3 = value[++startIndex]; + if (! _IsLittleEndian) + (b0, b1, b2, b3) = (b3, b2, b1, b0); + return (b0 | (b1 << 8) | (b2 << 16) | (b3 << 24)); + } + public static uint ToUInt32(byte[] value, int startIndex) + => (uint) ToInt32(value, startIndex); + public static float ToSingle(byte[] value, int startIndex) + => java.lang.Float.intBitsToFloat(ToInt32(value, startIndex)); + + public static long ToInt64(byte[] value, int startIndex) + { + ThrowHelper.ThrowIfNull(value); + if ((uint) startIndex >= value.Length || startIndex > value.Length - 8) + ThrowHelper.ThrowArgumentOutOfRangeException(); + byte b0 = value[startIndex]; + byte b1 = value[++startIndex]; + byte b2 = value[++startIndex]; + byte b3 = value[++startIndex]; + byte b4 = value[++startIndex]; + byte b5 = value[++startIndex]; + byte b6 = value[++startIndex]; + byte b7 = value[++startIndex]; + if (! _IsLittleEndian) + (b0, b1, b2, b3, b4, b5, b6, b7) = (b7, b6, b5, b4, b3, b2, b1, b0); + int i1 = (b0 | (b1 << 8) | (b2 << 16) | (b3 << 24)); + int i2 = (b4 | (b5 << 8) | (b6 << 16) | (b7 << 24)); + return (uint) i1 | ((long) i2 << 32); + } + public static ulong ToUInt64(byte[] value, int startIndex) + => (ulong) ToInt64(value, startIndex); + public static double ToDouble(byte[] value, int startIndex) + => java.lang.Double.longBitsToDouble(ToInt64(value, startIndex)); + + public static bool ToBoolean(byte[] value, int startIndex) + { + ThrowHelper.ThrowIfNull(value); + if (startIndex < 0 || startIndex > value.Length - 1) + ThrowHelper.ThrowArgumentOutOfRangeException(); + return (value[startIndex] != 0); + } + + public static string ToString(byte[] value, int startIndex, int length) + { + ThrowHelper.ThrowIfNull(value); + int valueLength = value.Length; + if ( startIndex < 0 || length < 0 + || (startIndex >= valueLength && startIndex > 0) + || (startIndex > valueLength - length)) + { + ThrowHelper.ThrowArgumentOutOfRangeException(); + } + if (length == 0) + return ""; + + var output = new char[valueLength * 2]; + int outputIndex = 0; + while (valueLength --> 0) + { + byte v = value[startIndex++]; + output[outputIndex++] = HexChars[v >> 4]; + output[outputIndex++] = HexChars[v & 0x0F]; + } + return new string(output); + } + + private static java.nio.ByteBuffer GetByteBuffer(int len) + { + var buffer = (java.nio.ByteBuffer) TlsByteBuffer.get(); + if (buffer == null || buffer.limit() < len) + { + buffer = java.nio.ByteBuffer.allocate(len) + .order(java.nio.ByteOrder.nativeOrder()); + TlsByteBuffer.set(buffer); + } + return buffer; + } + + [java.attr.RetainType] static java.lang.ThreadLocal TlsByteBuffer = + new java.lang.ThreadLocal(); + + [java.attr.RetainType] private static readonly char[] HexChars = + "0123456789ABCDEF".ToCharArray(); + + } + +} diff --git a/Baselib/src/System/Buffer.cs b/Baselib/src/System/Buffer.cs index 593098e..88eccb0 100644 --- a/Baselib/src/System/Buffer.cs +++ b/Baselib/src/System/Buffer.cs @@ -8,6 +8,13 @@ namespace system public static void InternalBlockCopy(Array src, int srcOffsetBytes, Array dst, int dstOffsetBytes, int byteCount) { + if (src.SyncRoot is sbyte[] srcBytes && dst.SyncRoot is sbyte[] dstBytes) + { + java.lang.System.arraycopy(srcBytes, srcOffsetBytes, + dstBytes, dstOffsetBytes, byteCount); + return; + } + if (src.SyncRoot is char[] srcChars && dst.SyncRoot is char[] dstChars) { int srcIndex = srcOffsetBytes >> 1; @@ -21,6 +28,7 @@ namespace system return; } } + throw new System.PlatformNotSupportedException( "InternalBlockCopy/" + src.GetType() + "/" + dst.GetType()); } diff --git a/Baselib/src/System/DateTime.cs b/Baselib/src/System/DateTime.cs index e5552f0..b0107b0 100644 --- a/Baselib/src/System/DateTime.cs +++ b/Baselib/src/System/DateTime.cs @@ -82,7 +82,7 @@ namespace system // ToString // - public override string ToString() => JavaCalendar.ToString(); + public override string ToString() => ToString(null, null); public string ToString(IFormatProvider provider) => ToString(null, provider); @@ -207,6 +207,23 @@ namespace system public static bool operator >= (DateTime d1, DateTime d2) => d1.Ticks >= d2.Ticks; + // + // SpecifyKind, ToUniversalTime, ToLocalTime + // + + public static DateTime SpecifyKind(DateTime value, DateTimeKind kind) + { + var javaCalendar = java.util.Calendar.getInstance(); + if (kind == DateTimeKind.Utc) + javaCalendar.setTimeZone(TimeZoneUTC); + javaCalendar.setTimeInMillis(value.JavaCalendar.getTimeInMillis()); + return new DateTime(javaCalendar, kind); + } + + public DateTime ToUniversalTime() => SpecifyKind(this, DateTimeKind.Utc); + + public DateTime ToLocalTime() => SpecifyKind(this, DateTimeKind.Local); + // // ISerializable // diff --git a/Baselib/src/System/Double.cs b/Baselib/src/System/Double.cs index 7f6d30d..c07a573 100644 --- a/Baselib/src/System/Double.cs +++ b/Baselib/src/System/Double.cs @@ -157,6 +157,29 @@ namespace system + // + // CodeNumber.Indirection methods + // + + public int Get_U8() => throw new System.NotSupportedException(); + public int Get_I8() => throw new System.NotSupportedException(); + public void Set_I8(int v) => throw new System.NotSupportedException(); + + public int Get_U16() => throw new System.NotSupportedException(); + public int Get_I16() => throw new System.NotSupportedException(); + public void Set_I16(int v) => throw new System.NotSupportedException(); + + public int Get_I32() => throw new System.NotSupportedException(); + public void Set_I32(int v) => throw new System.NotSupportedException(); + + public long Get_I64() => java.lang.Double.doubleToRawLongBits(v); + public void Set_I64(long v) => Set(java.lang.Double.longBitsToDouble(v)); + + public double Get_F64() => throw new System.NotSupportedException(); + public void Set_F64(double v) => throw new System.NotSupportedException(); + + + // // IConvertible // diff --git a/Baselib/src/System/IO/Directory.cs b/Baselib/src/System/IO/Directory.cs new file mode 100644 index 0000000..335e613 --- /dev/null +++ b/Baselib/src/System/IO/Directory.cs @@ -0,0 +1,32 @@ + +namespace system.io +{ + + public static class Directory + { + + public static bool Exists(string path) + { + bool exists = false; + if (path != null && path.Length != 0) + { + var file = new java.io.File(path); + exists = file.exists() && file.isDirectory(); + } + return exists; + } + + public static DirectoryInfo CreateDirectory(string path) + { + ThrowHelper.ThrowIfNull(path); + path = path.Trim(); + if (path.Length == 0) + throw new System.ArgumentException(); + var file = new java.io.File(path); + file.mkdirs(); + return new DirectoryInfo(file); + } + + } + +} diff --git a/Baselib/src/System/IO/DirectoryInfo.cs b/Baselib/src/System/IO/DirectoryInfo.cs new file mode 100644 index 0000000..5f30f03 --- /dev/null +++ b/Baselib/src/System/IO/DirectoryInfo.cs @@ -0,0 +1,12 @@ + +namespace system.io +{ + + public sealed class DirectoryInfo : FileSystemInfo + { + + public DirectoryInfo(java.io.File javaFile) : base(javaFile) { } + + } + +} diff --git a/Baselib/src/System/IO/File.cs b/Baselib/src/System/IO/File.cs new file mode 100644 index 0000000..83d7622 --- /dev/null +++ b/Baselib/src/System/IO/File.cs @@ -0,0 +1,22 @@ + +using FileMode = System.IO.FileMode; +using FileAccess = System.IO.FileAccess; +using FileShare = System.IO.FileShare; + +namespace system.io +{ + + public static class File + { + + public static FileStream Open(string path, FileMode mode) + => new FileStream(path, mode); + + public static FileStream Open(string path, FileMode mode, FileAccess access) + => new FileStream(path, mode, access); + + public static FileStream Open(string path, FileMode mode, FileAccess access, FileShare share) + => new FileStream(path, mode, access); + } + +} diff --git a/Baselib/src/System/IO/FileStream.cs b/Baselib/src/System/IO/FileStream.cs index 7401726..89f3778 100644 --- a/Baselib/src/System/IO/FileStream.cs +++ b/Baselib/src/System/IO/FileStream.cs @@ -27,6 +27,9 @@ namespace system.io : this(path, mode, (mode == System.IO.FileMode.Append ? System.IO.FileAccess.Write : System.IO.FileAccess.ReadWrite)) { } + public FileStream(string path, System.IO.FileMode mode, System.IO.FileAccess access, System.IO.FileShare share) + : this(path, mode, access) { } + public FileStream(string path, System.IO.FileMode mode, System.IO.FileAccess access) { ThrowHelper.ThrowIfNull(path); @@ -131,8 +134,7 @@ namespace system.io public override bool CanWrite => (Flags & CAN_WRITE) != 0; public override bool CanSeek => (Flags & CAN_SEEK) != 0; - public override long Length - => throw new System.PlatformNotSupportedException(); + public override long Length => JavaChannel.size(); public override long Position { @@ -184,10 +186,23 @@ namespace system.io } public override void SetLength(long value) - => throw new System.PlatformNotSupportedException(); + { + if (value < 0) + throw new System.ArgumentOutOfRangeException(); + JavaChannel.truncate(value); + } public override long Seek(long offset, System.IO.SeekOrigin origin) - => throw new System.PlatformNotSupportedException(); + { + if (origin == System.IO.SeekOrigin.Current) + offset += JavaChannel.position(); + else if (origin == System.IO.SeekOrigin.End) + offset = JavaChannel.size() - offset; + else if (origin != System.IO.SeekOrigin.Begin) + throw new System.ArgumentException(); + JavaChannel.position(offset); + return JavaChannel.position(); + } // // static constructor @@ -199,6 +214,17 @@ namespace system.io (java.lang.Class) typeof(java.io.FileNotFoundException), (exc) => new System.IO.FileNotFoundException(exc.getMessage()) ); + + system.Util.DefineException( + (java.lang.Class) typeof(java.nio.channels.NonWritableChannelException), + (exc) => new System.NotSupportedException(exc.getMessage()) + ); + + system.Util.DefineException( + (java.lang.Class) typeof(java.nio.channels.ClosedChannelException), + (exc) => new System.ObjectDisposedException(exc.getMessage()) + ); + } } diff --git a/Baselib/src/System/IO/FileSystemInfo.cs b/Baselib/src/System/IO/FileSystemInfo.cs new file mode 100644 index 0000000..04f9cb1 --- /dev/null +++ b/Baselib/src/System/IO/FileSystemInfo.cs @@ -0,0 +1,101 @@ + +using FileAttributes = System.IO.FileAttributes; + +namespace system.io +{ + + public abstract class FileSystemInfo + { + [java.attr.RetainType] protected java.io.File JavaFile; + + protected FileSystemInfo(java.io.File javaFile) + { + JavaFile = javaFile; + } + + public virtual string FullName => JavaFile.getAbsolutePath(); + + public virtual string Name => JavaFile.getName(); + + public string Extension + { + get + { + var name = Name; + int dot = Name.LastIndexOf('.'); + if (dot != -1) + { + int slash = Name.LastIndexOf('/'); + if (dot > slash) + { + return ((java.lang.String) (object) name).substring(dot); + } + } + return ""; + } + } + + public FileAttributes Attributes + { + get + { + FileAttributes attr = (FileAttributes) 0; + if (JavaFile.isDirectory()) + attr |= FileAttributes.Directory; + if (JavaFile.isHidden()) + attr |= FileAttributes.Hidden; + if (! JavaFile.canWrite()) + attr |= FileAttributes.ReadOnly; + if (attr == (FileAttributes) 0) + attr = FileAttributes.Normal; + return attr; + } + set => throw new System.PlatformNotSupportedException(); + } + + public virtual void Delete() => JavaFile.delete(); + + public virtual bool Exists => JavaFile.exists(); + + public DateTime CreationTimeUtc + { + get => throw new System.PlatformNotSupportedException(); + set => throw new System.PlatformNotSupportedException(); + } + + public DateTime LastAccessTimeUtc + { + get => throw new System.PlatformNotSupportedException(); + set => throw new System.PlatformNotSupportedException(); + } + + public DateTime LastWriteTimeUtc + { + // 10,000 DateTime ticks in a millisecond + get => new DateTime(JavaFile.lastModified() * 10000); + set => JavaFile.setLastModified(value.Ticks / 10000); + } + + public DateTime CreationTime + { + get => CreationTimeUtc.ToLocalTime(); + set => CreationTimeUtc = value.ToUniversalTime(); + } + + public DateTime LastAccessTime + { + get => LastAccessTimeUtc.ToLocalTime(); + set => LastAccessTimeUtc = value.ToUniversalTime(); + } + + public DateTime LastWriteTime + { + get => LastWriteTimeUtc.ToLocalTime(); + set => LastWriteTimeUtc = value.ToUniversalTime(); + } + + public void Refresh() { } + + } + +} diff --git a/Baselib/src/System/IO/Path.cs b/Baselib/src/System/IO/Path.cs index 0c4d4d5..2bc39a1 100644 --- a/Baselib/src/System/IO/Path.cs +++ b/Baselib/src/System/IO/Path.cs @@ -13,7 +13,7 @@ namespace system.io public static bool IsPathRooted(string path) => false; - public static string Combine (string path1, string path2) + public static string Combine(string path1, string path2) { path1 = CheckPath(path1); path2 = CheckPath(path2); @@ -26,6 +26,12 @@ namespace system.io return (ch != '/') ? (path1 + "/" + path2) : (path1 + path2); } + public static string Combine(string path1, string path2, string path3) + => Combine(Combine(path1, path2), path3); + } + + public static class PathInternal + { } } diff --git a/Baselib/src/System/Single.cs b/Baselib/src/System/Single.cs index 32f8224..09e53a2 100644 --- a/Baselib/src/System/Single.cs +++ b/Baselib/src/System/Single.cs @@ -122,6 +122,29 @@ namespace system + // + // CodeNumber.Indirection methods + // + + public int Get_U8() => throw new System.NotSupportedException(); + public int Get_I8() => throw new System.NotSupportedException(); + public void Set_I8(int v) => throw new System.NotSupportedException(); + + public int Get_U16() => throw new System.NotSupportedException(); + public int Get_I16() => throw new System.NotSupportedException(); + public void Set_I16(int v) => throw new System.NotSupportedException(); + + public int Get_I32() => java.lang.Float.floatToRawIntBits(v); + public void Set_I32(int v) => Set(java.lang.Float.intBitsToFloat(v)); + + public long Get_I64() => throw new System.NotSupportedException(); + public void Set_I64(long v) => throw new System.NotSupportedException(); + + public double Get_F64() => throw new System.NotSupportedException(); + public void Set_F64(double v) => throw new System.NotSupportedException(); + + + // // IConvertible // diff --git a/Baselib/src/System/Text/Encoding.cs b/Baselib/src/System/Text/Encoding.cs index 38e6837..359a4cb 100644 --- a/Baselib/src/System/Text/Encoding.cs +++ b/Baselib/src/System/Text/Encoding.cs @@ -255,6 +255,13 @@ namespace system.text return bytes; } + public virtual int GetBytes(string s, int charIndex, int charCount, + byte[] bytes, int byteIndex) + { + ThrowHelper.ThrowIfNull(s); + return GetBytes(s.ToCharArray(), charIndex, charCount, bytes, byteIndex); + } + public virtual string GetString(byte[] bytes) { ThrowHelper.ThrowIfNull(bytes); diff --git a/CilToJava/src/CilType.cs b/CilToJava/src/CilType.cs index 9acd8b1..695289a 100644 --- a/CilToJava/src/CilType.cs +++ b/CilToJava/src/CilType.cs @@ -561,10 +561,10 @@ namespace SpaceFlint.CilToJava // if we detect such a conflict at a branch target, we assume this // is the cause, and set the stack elements to a common denominator // or to the lowest common denominator, java.lang.Object - if ( IsReference && other.IsReference && other is CilType other2 - && (! this.IsValueClass) && (! other2.IsValueClass)) + if (IsReference && other.IsReference && other is CilType other2) { - return FindCommonSuperType(this, other2) ?? CilType.From(JavaType.ObjectType); + return FindCommonSuperType(this, other2) + ?? CilType.From(JavaType.ObjectType); } return null; diff --git a/CilToJava/src/CodeArray.cs b/CilToJava/src/CodeArray.cs index 9c60a16..99d2c19 100644 --- a/CilToJava/src/CodeArray.cs +++ b/CilToJava/src/CodeArray.cs @@ -330,7 +330,7 @@ namespace SpaceFlint.CilToJava - public void Store(Code op) + public void Store(Code op, Mono.Cecil.Cil.Instruction inst) { TypeCode elemType; @@ -338,7 +338,7 @@ namespace SpaceFlint.CilToJava { case Code.Stelem_Ref: case Code.Stelem_Any: - Store(null); + Store(null, null); return; case Code.Stelem_I1: elemType = TypeCode.Byte; break; @@ -351,12 +351,12 @@ namespace SpaceFlint.CilToJava default: throw new InvalidProgramException(); } - Store(CilType.From(new JavaType(elemType, 0, null))); + Store(CilType.From(new JavaType(elemType, 0, null)), inst); } - void Store(CilType elemType) + void Store(CilType elemType, Mono.Cecil.Cil.Instruction inst) { stackMap.PopStack(CilMain.Where); // value stackMap.PopStack(CilMain.Where); // index @@ -406,6 +406,8 @@ namespace SpaceFlint.CilToJava elemType = arrayType.AdjustRank(-arrayType.ArrayRank); } + CheckImmediate(arrayType.PrimitiveType, inst); + if (arrayType.IsValueClass || elemType.IsValueClass) { CilMethod.ValueMethod(CilMethod.ValueClone, code); @@ -413,6 +415,32 @@ namespace SpaceFlint.CilToJava code.NewInstruction(elemType.StoreArrayOpcode, null, null); } + + + void CheckImmediate(TypeCode arrayPrimitiveType, Mono.Cecil.Cil.Instruction inst) + { + // Android AOT aborts the compilation with a crash if storing + // an immediate value that does not fit in the target array. + if ( inst != null && inst.Previous != null + && inst.Previous.OpCode.Code == Code.Ldc_I4) + { + var imm = (int) inst.Previous.Operand; + if ( arrayType.PrimitiveType == TypeCode.Boolean + || arrayType.PrimitiveType == TypeCode.SByte + || arrayType.PrimitiveType == TypeCode.Byte) + { + if (imm < -128 || imm >= 128) + code.NewInstruction(0x91 /* i2b */, null, null); + } + else if ( arrayType.PrimitiveType == TypeCode.Char + || arrayType.PrimitiveType == TypeCode.Int16 + || arrayType.PrimitiveType == TypeCode.UInt16) + { + if (imm < -32768 || imm >= 32768) + code.NewInstruction(0x93 /* i2s */, null, null); + } + } + } } @@ -505,7 +533,7 @@ namespace SpaceFlint.CilToJava stackMap.PushStack(valueType); } - Store(elemType); + Store(elemType, null); } else if (method.Name == "Address") diff --git a/CilToJava/src/CodeBuilder.cs b/CilToJava/src/CodeBuilder.cs index 9fe3850..4f26b7d 100644 --- a/CilToJava/src/CodeBuilder.cs +++ b/CilToJava/src/CodeBuilder.cs @@ -418,7 +418,7 @@ namespace SpaceFlint.CilToJava case Code.Stelem_I: case Code.Stelem_R4:case Code.Stelem_R8:case Code.Stelem_Any: case Code.Stelem_Ref: - arrays.Store(cilOp); + arrays.Store(cilOp, cilInst); break; case Code.Ldftn: case Code.Ldvirtftn: diff --git a/CilToJava/src/CodeMisc.cs b/CilToJava/src/CodeMisc.cs index 81f1f3d..508c547 100644 --- a/CilToJava/src/CodeMisc.cs +++ b/CilToJava/src/CodeMisc.cs @@ -121,7 +121,18 @@ namespace SpaceFlint.CilToJava else if (dstType.IsReference) { CodeArrays.CheckCast(dstType, true, code); - if (dstType.IsGenericParameter) + + if ( srcType.ArrayRank != 0 + && srcType.ArrayRank == dstType.ArrayRank + && srcType.PrimitiveType != 0 + && dstType.PrimitiveType != 0 + && srcType.AdjustRank(-srcType.ArrayRank).NewArrayType + == dstType.AdjustRank(-dstType.ArrayRank).NewArrayType) + { + // casting to same java array type, e.g. byte[] to sbyte[] + op = 0x00; // nop + } + else if (dstType.IsGenericParameter) op = 0x00; // nop else op = 0xC0; // checkcast diff --git a/README.md b/README.md index a4dcdd3..2dad064 100644 --- a/README.md +++ b/README.md @@ -58,6 +58,8 @@ There are some additional demos: - Note that the Android demos require the `ANDROID_HOME` environment directory, and the project is hard-coded to use Android platform version 28, and build-tools 30.0.2 - Note also that the Android demos build an APK file, but do not install it. +See the [BNA](https://github.com/spaceflint7/bna) repository for another demo for Android. + ## Usage For more information about using Bluebonnet, please see the [USAGE.md](USAGE.md) file. That document also records any known differences and deficiencies, compared to a proper .NET implementation. \ No newline at end of file