diff --git a/IKVM.deps.targets b/IKVM.deps.targets index f2ef26dcb7..14041a31ea 100644 --- a/IKVM.deps.targets +++ b/IKVM.deps.targets @@ -1,7 +1,7 @@ - + diff --git a/src/IKVM.Java.Extensions/java/util/CollectionExtensions.cs b/src/IKVM.Java.Extensions/java/util/CollectionExtensions.cs index c7f73f3cfb..c78e0d2d5c 100644 --- a/src/IKVM.Java.Extensions/java/util/CollectionExtensions.cs +++ b/src/IKVM.Java.Extensions/java/util/CollectionExtensions.cs @@ -1,5 +1,4 @@ -using System.Collections; -using System.Collections.Generic; +using System.Collections.Generic; namespace java.util { diff --git a/src/IKVM.Java.Tests/java/lang/ByteTests.java b/src/IKVM.Java.Tests/java/lang/ByteTests.java new file mode 100644 index 0000000000..776e432588 --- /dev/null +++ b/src/IKVM.Java.Tests/java/lang/ByteTests.java @@ -0,0 +1,33 @@ +package ikvm.tests.java.java.lang; + +import java.lang.*; + +@cli.Microsoft.VisualStudio.TestTools.UnitTesting.TestClassAttribute.Annotation() +public class ByteTests { + + @cli.Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute.Annotation() + public void canCastMinMax() throws Throwable { + if (!String.valueOf(Byte.MAX_VALUE).equals("127")) + throw new Exception(); + if (!String.valueOf(Byte.MIN_VALUE).equals("-128")) + throw new Exception(); + if (!String.valueOf((short)Byte.MAX_VALUE).equals("127")) + throw new Exception(); + if (!String.valueOf((short)Byte.MIN_VALUE).equals("-128")) + throw new Exception(); + if (!String.valueOf((int)Byte.MAX_VALUE).equals("127")) + throw new Exception(); + if (!String.valueOf((int)Byte.MIN_VALUE).equals("-128")) + throw new Exception(); + if (!String.valueOf((long)Byte.MAX_VALUE).equals("127")) + throw new Exception(); + if (!String.valueOf((long)Byte.MIN_VALUE).equals("-128")) + throw new Exception(); + + if (!Integer.valueOf(Byte.MAX_VALUE).equals(Integer.valueOf(127))) + throw new Exception(); + if (!Integer.valueOf(Byte.MIN_VALUE).equals(Integer.valueOf(-128))) + throw new Exception(); + } + +} diff --git a/src/IKVM.Runtime/Attributes/AnnotationDefaultAttribute.cs b/src/IKVM.Runtime/Attributes/AnnotationDefaultAttribute.cs index 633652b30e..a4f758099b 100644 --- a/src/IKVM.Runtime/Attributes/AnnotationDefaultAttribute.cs +++ b/src/IKVM.Runtime/Attributes/AnnotationDefaultAttribute.cs @@ -37,7 +37,32 @@ public sealed class AnnotationDefaultAttribute : Attribute public const byte TAG_ANNOTATION = (byte)'@'; public const byte TAG_ARRAY = (byte)'['; public const byte TAG_ERROR = (byte)'?'; - private object defaultValue; + + internal static object Escape(object obj) + { + return EscapeOrUnescape(obj, true); + } + + internal static object Unescape(object obj) + { + return EscapeOrUnescape(obj, false); + } + + static object EscapeOrUnescape(object obj, bool escape) + { + var str = obj as string; + if (str != null) + return escape ? UnicodeUtil.EscapeInvalidSurrogates(str) : UnicodeUtil.UnescapeInvalidSurrogates(str); + + var arr = obj as object[]; + if (arr != null) + for (int i = 0; i < arr.Length; i++) + arr[i] = EscapeOrUnescape(arr[i], escape); + + return obj; + } + + object defaultValue; // element_value encoding: // primitives: @@ -59,41 +84,7 @@ public AnnotationDefaultAttribute(object defaultValue) this.defaultValue = Unescape(defaultValue); } - public object Value - { - get - { - return defaultValue; - } - } - - internal static object Escape(object obj) - { - return EscapeOrUnescape(obj, true); - } - - internal static object Unescape(object obj) - { - return EscapeOrUnescape(obj, false); - } - - private static object EscapeOrUnescape(object obj, bool escape) - { - string str = obj as string; - if (str != null) - { - return escape ? UnicodeUtil.EscapeInvalidSurrogates(str) : UnicodeUtil.UnescapeInvalidSurrogates(str); - } - object[] arr = obj as object[]; - if (arr != null) - { - for (int i = 0; i < arr.Length; i++) - { - arr[i] = EscapeOrUnescape(arr[i], escape); - } - } - return obj; - } + public object Value => defaultValue; } diff --git a/src/IKVM.Runtime/Attributes/ImplementsAttribute.cs b/src/IKVM.Runtime/Attributes/ImplementsAttribute.cs index 4bd1bb3fec..9182f1c89f 100644 --- a/src/IKVM.Runtime/Attributes/ImplementsAttribute.cs +++ b/src/IKVM.Runtime/Attributes/ImplementsAttribute.cs @@ -32,9 +32,12 @@ namespace IKVM.Attributes public sealed class ImplementsAttribute : Attribute { - private string[] interfaces; + string[] interfaces; - // NOTE this is not CLS compliant, so maybe we should have a couple of overloads + /// + /// Initializes a new instance. + /// + /// public ImplementsAttribute(string[] interfaces) { this.interfaces = UnicodeUtil.UnescapeInvalidSurrogates(interfaces); diff --git a/src/IKVM.Runtime/Java/Externs/sun/net/www/protocol/ikvmres/Handler.cs b/src/IKVM.Runtime/Java/Externs/sun/net/www/protocol/ikvmres/Handler.cs index 3c83e02c0d..41301ab729 100644 --- a/src/IKVM.Runtime/Java/Externs/sun/net/www/protocol/ikvmres/Handler.cs +++ b/src/IKVM.Runtime/Java/Externs/sun/net/www/protocol/ikvmres/Handler.cs @@ -43,7 +43,7 @@ public static byte[] GenerateStub(global::java.lang.Class c) throw new NotImplementedException(); #else using var mem = new MemoryStream(); - JVM.Context.StubGenerator.WriteClass(mem, RuntimeJavaType.FromClass(c), true, true, true, true, false); + JVM.Context.StubGenerator.Write(mem, RuntimeJavaType.FromClass(c), true, true, true, true, false); return mem.ToArray(); #endif } diff --git a/src/IKVM.Runtime/RuntimeContext.cs b/src/IKVM.Runtime/RuntimeContext.cs index e2ef4cdc49..fd1dea7a1c 100644 --- a/src/IKVM.Runtime/RuntimeContext.cs +++ b/src/IKVM.Runtime/RuntimeContext.cs @@ -10,7 +10,7 @@ #endif #if IMPORTER == false -using IKVM.StubGen; +using IKVM.Runtime.StubGen; #endif namespace IKVM.Runtime diff --git a/src/IKVM.Runtime/StubGen/AnnotationDefaultClassFileAttribute.cs b/src/IKVM.Runtime/StubGen/AnnotationDefaultClassFileAttribute.cs deleted file mode 100644 index 46996f0fb1..0000000000 --- a/src/IKVM.Runtime/StubGen/AnnotationDefaultClassFileAttribute.cs +++ /dev/null @@ -1,53 +0,0 @@ -/* - Copyright (C) 2002-2013 Jeroen Frijters - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jeroen Frijters - jeroen@frijters.net - -*/ - -namespace IKVM.StubGen -{ - - sealed class AnnotationDefaultClassFileAttribute : ClassFileAttribute - { - - private ClassFileWriter classFile; - private byte[] buf; - - internal AnnotationDefaultClassFileAttribute(ClassFileWriter classFile, byte[] buf) - : base(classFile.AddUtf8("AnnotationDefault")) - { - this.classFile = classFile; - this.buf = buf; - } - - public override void Write(BigEndianStream bes) - { - base.Write(bes); - bes.WriteUInt32((uint)(buf.Length)); - foreach (byte b in buf) - { - bes.WriteByte(b); - } - } - - } - -} diff --git a/src/IKVM.Runtime/StubGen/BigEndianStream.cs b/src/IKVM.Runtime/StubGen/BigEndianStream.cs deleted file mode 100644 index 3c667aeae4..0000000000 --- a/src/IKVM.Runtime/StubGen/BigEndianStream.cs +++ /dev/null @@ -1,116 +0,0 @@ -/* - Copyright (C) 2002-2013 Jeroen Frijters - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jeroen Frijters - jeroen@frijters.net - -*/ -using System; -using System.IO; - -namespace IKVM.StubGen -{ - - sealed class BigEndianStream - { - - private Stream stream; - - public BigEndianStream(Stream stream) - { - this.stream = stream; - } - - public void WriteUInt16(ushort s) - { - stream.WriteByte((byte)(s >> 8)); - stream.WriteByte((byte)s); - } - - public void WriteUInt32(uint u) - { - stream.WriteByte((byte)(u >> 24)); - stream.WriteByte((byte)(u >> 16)); - stream.WriteByte((byte)(u >> 8)); - stream.WriteByte((byte)u); - } - - public void WriteInt64(long l) - { - WriteUInt32((uint)(l >> 32)); - WriteUInt32((uint)l); - } - - public void WriteFloat(float f) - { - WriteUInt32(BitConverter.ToUInt32(BitConverter.GetBytes(f), 0)); - } - - public void WriteDouble(double d) - { - WriteInt64(BitConverter.ToInt64(BitConverter.GetBytes(d), 0)); - } - - public void WriteByte(byte b) - { - stream.WriteByte(b); - } - - public void WriteBytes(byte[] data) - { - stream.Write(data, 0, data.Length); - } - - public void WriteUtf8(string str) - { - byte[] buf = new byte[str.Length * 3 + 1]; - int j = 0; - for (int i = 0, e = str.Length; i < e; i++) - { - char ch = str[i]; - if ((ch != 0) && (ch <= 0x7f)) - { - buf[j++] = (byte)ch; - } - else if (ch <= 0x7FF) - { - /* 11 bits or less. */ - byte high_five = (byte)(ch >> 6); - byte low_six = (byte)(ch & 0x3F); - buf[j++] = (byte)(high_five | 0xC0); /* 110xxxxx */ - buf[j++] = (byte)(low_six | 0x80); /* 10xxxxxx */ - } - else - { - /* possibly full 16 bits. */ - byte high_four = (byte)(ch >> 12); - byte mid_six = (byte)((ch >> 6) & 0x3F); - byte low_six = (byte)(ch & 0x3f); - buf[j++] = (byte)(high_four | 0xE0); /* 1110xxxx */ - buf[j++] = (byte)(mid_six | 0x80); /* 10xxxxxx */ - buf[j++] = (byte)(low_six | 0x80); /* 10xxxxxx*/ - } - } - WriteUInt16((ushort)j); - stream.Write(buf, 0, j); - } - - } - -} diff --git a/src/IKVM.Runtime/StubGen/ClassFileAttribute.cs b/src/IKVM.Runtime/StubGen/ClassFileAttribute.cs deleted file mode 100644 index ab5e1e2b50..0000000000 --- a/src/IKVM.Runtime/StubGen/ClassFileAttribute.cs +++ /dev/null @@ -1,45 +0,0 @@ -/* - Copyright (C) 2002-2013 Jeroen Frijters - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jeroen Frijters - jeroen@frijters.net - -*/ - -namespace IKVM.StubGen -{ - - abstract class ClassFileAttribute - { - - private ushort name_index; - - public ClassFileAttribute(ushort name_index) - { - this.name_index = name_index; - } - - public virtual void Write(BigEndianStream bes) - { - bes.WriteUInt16(name_index); - } - - } - -} diff --git a/src/IKVM.Runtime/StubGen/ClassFileWriter.cs b/src/IKVM.Runtime/StubGen/ClassFileWriter.cs deleted file mode 100644 index 0802204ee1..0000000000 --- a/src/IKVM.Runtime/StubGen/ClassFileWriter.cs +++ /dev/null @@ -1,246 +0,0 @@ -/* - Copyright (C) 2002-2013 Jeroen Frijters - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jeroen Frijters - jeroen@frijters.net - -*/ -using System; -using System.Collections.Generic; -using System.IO; - -using IKVM.Attributes; - -namespace IKVM.StubGen -{ - - sealed class ClassFileWriter : IAttributeOwner - { - - List cplist = new List(); - Dictionary cphashtable = new Dictionary(); - List fields = new List(); - List methods = new List(); - List attribs = new List(); - List interfaces = new List(); - Modifiers access_flags; - ushort this_class; - ushort super_class; - ushort minorVersion; - ushort majorVersion; - - public ClassFileWriter(Modifiers mods, string name, string super, ushort minorVersion, ushort majorVersion) - { - cplist.Add(null); - access_flags = mods; - this_class = AddClass(name); - if (super != null) - { - super_class = AddClass(super); - } - this.minorVersion = minorVersion; - this.majorVersion = majorVersion; - } - - private ushort Add(ConstantPoolItem cpi) - { - ushort index; - if (!cphashtable.TryGetValue(cpi, out index)) - { - index = (ushort)cplist.Count; - cplist.Add(cpi); - if (cpi is ConstantPoolItemDouble || cpi is ConstantPoolItemLong) - { - cplist.Add(null); - } - cphashtable.Add(cpi, index); - } - return index; - } - - public ushort AddUtf8(string str) - { - return Add(new ConstantPoolItemUtf8(str)); - } - - public ushort AddClass(string classname) - { - return Add(new ConstantPoolItemClass(AddUtf8(classname))); - } - - public ushort AddMethodRef(string classname, string methodname, string signature) - { - return Add(new ConstantPoolItemMethodref(AddClass(classname), AddNameAndType(methodname, signature))); - } - - public ushort AddNameAndType(string name, string type) - { - return Add(new ConstantPoolItemNameAndType(AddUtf8(name), AddUtf8(type))); - } - - public ushort AddInt(int i) - { - return Add(new ConstantPoolItemInt(i)); - } - - public ushort AddLong(long l) - { - return Add(new ConstantPoolItemLong(l)); - } - - public ushort AddFloat(float f) - { - return Add(new ConstantPoolItemFloat(f)); - } - - public ushort AddDouble(double d) - { - return Add(new ConstantPoolItemDouble(d)); - } - - public ushort AddString(string s) - { - return Add(new ConstantPoolItemString(AddUtf8(s))); - } - - public void AddInterface(string name) - { - interfaces.Add(AddClass(name)); - } - - public FieldOrMethod AddMethod(Modifiers access, string name, string signature) - { - FieldOrMethod method = new FieldOrMethod(access, AddUtf8(name), AddUtf8(signature)); - methods.Add(method); - return method; - } - - public FieldOrMethod AddField(Modifiers access, string name, string signature, object constantValue) - { - FieldOrMethod field = new FieldOrMethod(access, AddUtf8(name), AddUtf8(signature)); - if (constantValue != null) - { - ushort constantValueIndex; - if (constantValue is byte) - { - constantValueIndex = AddInt((sbyte)(byte)constantValue); - } - else if (constantValue is bool) - { - constantValueIndex = AddInt((bool)constantValue ? 1 : 0); - } - else if (constantValue is short) - { - constantValueIndex = AddInt((short)constantValue); - } - else if (constantValue is char) - { - constantValueIndex = AddInt((char)constantValue); - } - else if (constantValue is int) - { - constantValueIndex = AddInt((int)constantValue); - } - else if (constantValue is long) - { - constantValueIndex = AddLong((long)constantValue); - } - else if (constantValue is float) - { - constantValueIndex = AddFloat((float)constantValue); - } - else if (constantValue is double) - { - constantValueIndex = AddDouble((double)constantValue); - } - else if (constantValue is string) - { - constantValueIndex = AddString((string)constantValue); - } - else - { - throw new InvalidOperationException(constantValue.GetType().FullName); - } - field.AddAttribute(new ConstantValueAttribute(AddUtf8("ConstantValue"), constantValueIndex)); - } - fields.Add(field); - return field; - } - - public ClassFileAttribute MakeStringAttribute(string name, string value) - { - return new StringAttribute(AddUtf8(name), AddUtf8(value)); - } - - public void AddStringAttribute(string name, string value) - { - attribs.Add(MakeStringAttribute(name, value)); - } - - public void AddAttribute(ClassFileAttribute attrib) - { - attribs.Add(attrib); - } - - public void Write(Stream stream) - { - BigEndianStream bes = new BigEndianStream(stream); - bes.WriteUInt32(0xCAFEBABE); - bes.WriteUInt16(minorVersion); - bes.WriteUInt16(majorVersion); - bes.WriteUInt16((ushort)cplist.Count); - foreach (ConstantPoolItem cpi in cplist) - { - if (cpi != null) - { - cpi.Write(bes); - } - } - bes.WriteUInt16((ushort)access_flags); - bes.WriteUInt16(this_class); - bes.WriteUInt16(super_class); - // interfaces count - bes.WriteUInt16((ushort)interfaces.Count); - for (int i = 0; i < interfaces.Count; i++) - { - bes.WriteUInt16(interfaces[i]); - } - // fields count - bes.WriteUInt16((ushort)fields.Count); - for (int i = 0; i < fields.Count; i++) - { - fields[i].Write(bes); - } - // methods count - bes.WriteUInt16((ushort)methods.Count); - for (int i = 0; i < methods.Count; i++) - { - methods[i].Write(bes); - } - // attributes count - bes.WriteUInt16((ushort)attribs.Count); - for (int i = 0; i < attribs.Count; i++) - { - attribs[i].Write(bes); - } - } - - } - -} diff --git a/src/IKVM.Runtime/StubGen/CodeAttribute.cs b/src/IKVM.Runtime/StubGen/CodeAttribute.cs deleted file mode 100644 index a73de1dd3d..0000000000 --- a/src/IKVM.Runtime/StubGen/CodeAttribute.cs +++ /dev/null @@ -1,77 +0,0 @@ -/* - Copyright (C) 2002-2013 Jeroen Frijters - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jeroen Frijters - jeroen@frijters.net - -*/ - -namespace IKVM.StubGen -{ - - sealed class CodeAttribute : ClassFileAttribute - { - - private ClassFileWriter classFile; - private ushort max_stack; - private ushort max_locals; - private byte[] code; - - public CodeAttribute(ClassFileWriter classFile) - : base(classFile.AddUtf8("Code")) - { - this.classFile = classFile; - } - - public ushort MaxStack - { - get { return max_stack; } - set { max_stack = value; } - } - - public ushort MaxLocals - { - get { return max_locals; } - set { max_locals = value; } - } - - public byte[] ByteCode - { - get { return code; } - set { code = value; } - } - - public override void Write(BigEndianStream bes) - { - base.Write(bes); - bes.WriteUInt32((uint)(2 + 2 + 4 + code.Length + 2 + 2)); - bes.WriteUInt16(max_stack); - bes.WriteUInt16(max_locals); - bes.WriteUInt32((uint)code.Length); - for (int i = 0; i < code.Length; i++) - { - bes.WriteByte(code[i]); - } - bes.WriteUInt16(0); // no exceptions - bes.WriteUInt16(0); // no attributes - } - - } - -} diff --git a/src/IKVM.Runtime/StubGen/Constant.cs b/src/IKVM.Runtime/StubGen/Constant.cs deleted file mode 100644 index d45bbb6ec2..0000000000 --- a/src/IKVM.Runtime/StubGen/Constant.cs +++ /dev/null @@ -1,45 +0,0 @@ -/* - Copyright (C) 2002-2013 Jeroen Frijters - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jeroen Frijters - jeroen@frijters.net - -*/ - -namespace IKVM.StubGen -{ - - enum Constant - { - - Utf8 = 1, - Integer = 3, - Float = 4, - Long = 5, - Double = 6, - Class = 7, - String = 8, - Fieldref = 9, - Methodref = 10, - InterfaceMethodref = 11, - NameAndType = 12 - - } - -} diff --git a/src/IKVM.Runtime/StubGen/ConstantPoolItem.cs b/src/IKVM.Runtime/StubGen/ConstantPoolItem.cs deleted file mode 100644 index 9a17aea004..0000000000 --- a/src/IKVM.Runtime/StubGen/ConstantPoolItem.cs +++ /dev/null @@ -1,34 +0,0 @@ -/* - Copyright (C) 2002-2013 Jeroen Frijters - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jeroen Frijters - jeroen@frijters.net - -*/ - -namespace IKVM.StubGen -{ - - abstract class ConstantPoolItem - { - - public abstract void Write(BigEndianStream bes); - } - -} diff --git a/src/IKVM.Runtime/StubGen/ConstantPoolItemClass.cs b/src/IKVM.Runtime/StubGen/ConstantPoolItemClass.cs deleted file mode 100644 index 6e9ccb6d25..0000000000 --- a/src/IKVM.Runtime/StubGen/ConstantPoolItemClass.cs +++ /dev/null @@ -1,60 +0,0 @@ -/* - Copyright (C) 2002-2013 Jeroen Frijters - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jeroen Frijters - jeroen@frijters.net - -*/ - -namespace IKVM.StubGen -{ - - sealed class ConstantPoolItemClass : ConstantPoolItem - { - - private ushort name_index; - - public ConstantPoolItemClass(ushort name_index) - { - this.name_index = name_index; - } - - public override int GetHashCode() - { - return name_index; - } - - public override bool Equals(object o) - { - if (o != null && o.GetType() == typeof(ConstantPoolItemClass)) - { - return ((ConstantPoolItemClass)o).name_index == name_index; - } - return false; - } - - public override void Write(BigEndianStream bes) - { - bes.WriteByte((byte)Constant.Class); - bes.WriteUInt16(name_index); - } - - } - -} diff --git a/src/IKVM.Runtime/StubGen/ConstantPoolItemDouble.cs b/src/IKVM.Runtime/StubGen/ConstantPoolItemDouble.cs deleted file mode 100644 index 2024f0f95a..0000000000 --- a/src/IKVM.Runtime/StubGen/ConstantPoolItemDouble.cs +++ /dev/null @@ -1,62 +0,0 @@ -/* - Copyright (C) 2002-2013 Jeroen Frijters - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jeroen Frijters - jeroen@frijters.net - -*/ -using System; - -namespace IKVM.StubGen -{ - - sealed class ConstantPoolItemDouble : ConstantPoolItem - { - - private double v; - - public ConstantPoolItemDouble(double v) - { - this.v = v; - } - - public override int GetHashCode() - { - long l = BitConverter.DoubleToInt64Bits(v); - return ((int)l) ^ ((int)(l >> 32)); - } - - public override bool Equals(object o) - { - if (o != null && o.GetType() == typeof(ConstantPoolItemDouble)) - { - return ((ConstantPoolItemDouble)o).v == v; - } - return false; - } - - public override void Write(BigEndianStream bes) - { - bes.WriteByte((byte)Constant.Double); - bes.WriteDouble(v); - } - - } - -} diff --git a/src/IKVM.Runtime/StubGen/ConstantPoolItemFloat.cs b/src/IKVM.Runtime/StubGen/ConstantPoolItemFloat.cs deleted file mode 100644 index a9e65f7495..0000000000 --- a/src/IKVM.Runtime/StubGen/ConstantPoolItemFloat.cs +++ /dev/null @@ -1,61 +0,0 @@ -/* - Copyright (C) 2002-2013 Jeroen Frijters - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jeroen Frijters - jeroen@frijters.net - -*/ -using System; - -namespace IKVM.StubGen -{ - - sealed class ConstantPoolItemFloat : ConstantPoolItem - { - - private float v; - - public ConstantPoolItemFloat(float v) - { - this.v = v; - } - - public override int GetHashCode() - { - return BitConverter.ToInt32(BitConverter.GetBytes(v), 0); - } - - public override bool Equals(object o) - { - if (o != null && o.GetType() == typeof(ConstantPoolItemFloat)) - { - return ((ConstantPoolItemFloat)o).v == v; - } - return false; - } - - public override void Write(BigEndianStream bes) - { - bes.WriteByte((byte)Constant.Float); - bes.WriteFloat(v); - } - - } - -} diff --git a/src/IKVM.Runtime/StubGen/ConstantPoolItemInt.cs b/src/IKVM.Runtime/StubGen/ConstantPoolItemInt.cs deleted file mode 100644 index 6671a04d76..0000000000 --- a/src/IKVM.Runtime/StubGen/ConstantPoolItemInt.cs +++ /dev/null @@ -1,60 +0,0 @@ -/* - Copyright (C) 2002-2013 Jeroen Frijters - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jeroen Frijters - jeroen@frijters.net - -*/ - -namespace IKVM.StubGen -{ - - sealed class ConstantPoolItemInt : ConstantPoolItem - { - - private int v; - - public ConstantPoolItemInt(int v) - { - this.v = v; - } - - public override int GetHashCode() - { - return v; - } - - public override bool Equals(object o) - { - if (o != null && o.GetType() == typeof(ConstantPoolItemInt)) - { - return ((ConstantPoolItemInt)o).v == v; - } - return false; - } - - public override void Write(BigEndianStream bes) - { - bes.WriteByte((byte)Constant.Integer); - bes.WriteUInt32((uint)v); - } - - } - -} diff --git a/src/IKVM.Runtime/StubGen/ConstantPoolItemLong.cs b/src/IKVM.Runtime/StubGen/ConstantPoolItemLong.cs deleted file mode 100644 index 4ea35e09f8..0000000000 --- a/src/IKVM.Runtime/StubGen/ConstantPoolItemLong.cs +++ /dev/null @@ -1,60 +0,0 @@ -/* - Copyright (C) 2002-2013 Jeroen Frijters - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jeroen Frijters - jeroen@frijters.net - -*/ - -namespace IKVM.StubGen -{ - - sealed class ConstantPoolItemLong : ConstantPoolItem - { - - private long v; - - public ConstantPoolItemLong(long v) - { - this.v = v; - } - - public override int GetHashCode() - { - return (int)v; - } - - public override bool Equals(object o) - { - if (o != null && o.GetType() == typeof(ConstantPoolItemLong)) - { - return ((ConstantPoolItemLong)o).v == v; - } - return false; - } - - public override void Write(BigEndianStream bes) - { - bes.WriteByte((byte)Constant.Long); - bes.WriteInt64(v); - } - - } - -} diff --git a/src/IKVM.Runtime/StubGen/ConstantPoolItemMethodref.cs b/src/IKVM.Runtime/StubGen/ConstantPoolItemMethodref.cs deleted file mode 100644 index a348e5225e..0000000000 --- a/src/IKVM.Runtime/StubGen/ConstantPoolItemMethodref.cs +++ /dev/null @@ -1,64 +0,0 @@ -/* - Copyright (C) 2002-2013 Jeroen Frijters - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jeroen Frijters - jeroen@frijters.net - -*/ - -namespace IKVM.StubGen -{ - - sealed class ConstantPoolItemMethodref : ConstantPoolItem - { - - private ushort class_index; - private ushort name_and_type_index; - - public ConstantPoolItemMethodref(ushort class_index, ushort name_and_type_index) - { - this.class_index = class_index; - this.name_and_type_index = name_and_type_index; - } - - public override int GetHashCode() - { - return class_index | (name_and_type_index << 16); - } - - public override bool Equals(object o) - { - if (o != null && o.GetType() == typeof(ConstantPoolItemMethodref)) - { - ConstantPoolItemMethodref m = (ConstantPoolItemMethodref)o; - return m.class_index == class_index && m.name_and_type_index == name_and_type_index; - } - return false; - } - - public override void Write(BigEndianStream bes) - { - bes.WriteByte((byte)Constant.Methodref); - bes.WriteUInt16(class_index); - bes.WriteUInt16(name_and_type_index); - } - - } - -} diff --git a/src/IKVM.Runtime/StubGen/ConstantPoolItemNameAndType.cs b/src/IKVM.Runtime/StubGen/ConstantPoolItemNameAndType.cs deleted file mode 100644 index c946e069d0..0000000000 --- a/src/IKVM.Runtime/StubGen/ConstantPoolItemNameAndType.cs +++ /dev/null @@ -1,64 +0,0 @@ -/* - Copyright (C) 2002-2013 Jeroen Frijters - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jeroen Frijters - jeroen@frijters.net - -*/ - -namespace IKVM.StubGen -{ - - sealed class ConstantPoolItemNameAndType : ConstantPoolItem - { - - private ushort name_index; - private ushort descriptor_index; - - public ConstantPoolItemNameAndType(ushort name_index, ushort descriptor_index) - { - this.name_index = name_index; - this.descriptor_index = descriptor_index; - } - - public override int GetHashCode() - { - return name_index | (descriptor_index << 16); - } - - public override bool Equals(object o) - { - if (o != null && o.GetType() == typeof(ConstantPoolItemNameAndType)) - { - ConstantPoolItemNameAndType n = (ConstantPoolItemNameAndType)o; - return n.name_index == name_index && n.descriptor_index == descriptor_index; - } - return false; - } - - public override void Write(BigEndianStream bes) - { - bes.WriteByte((byte)Constant.NameAndType); - bes.WriteUInt16(name_index); - bes.WriteUInt16(descriptor_index); - } - - } - -} diff --git a/src/IKVM.Runtime/StubGen/ConstantPoolItemString.cs b/src/IKVM.Runtime/StubGen/ConstantPoolItemString.cs deleted file mode 100644 index 08a1a0e495..0000000000 --- a/src/IKVM.Runtime/StubGen/ConstantPoolItemString.cs +++ /dev/null @@ -1,60 +0,0 @@ -/* - Copyright (C) 2002-2013 Jeroen Frijters - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jeroen Frijters - jeroen@frijters.net - -*/ - -namespace IKVM.StubGen -{ - - sealed class ConstantPoolItemString : ConstantPoolItem - { - - private ushort string_index; - - public ConstantPoolItemString(ushort string_index) - { - this.string_index = string_index; - } - - public override int GetHashCode() - { - return string_index; - } - - public override bool Equals(object o) - { - if (o != null && o.GetType() == typeof(ConstantPoolItemString)) - { - return ((ConstantPoolItemString)o).string_index == string_index; - } - return false; - } - - public override void Write(BigEndianStream bes) - { - bes.WriteByte((byte)Constant.String); - bes.WriteUInt16(string_index); - } - - } - -} diff --git a/src/IKVM.Runtime/StubGen/ConstantPoolItemUtf8.cs b/src/IKVM.Runtime/StubGen/ConstantPoolItemUtf8.cs deleted file mode 100644 index bc1fe7cb40..0000000000 --- a/src/IKVM.Runtime/StubGen/ConstantPoolItemUtf8.cs +++ /dev/null @@ -1,60 +0,0 @@ -/* - Copyright (C) 2002-2013 Jeroen Frijters - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jeroen Frijters - jeroen@frijters.net - -*/ - -namespace IKVM.StubGen -{ - - sealed class ConstantPoolItemUtf8 : ConstantPoolItem - { - - private string str; - - public ConstantPoolItemUtf8(string str) - { - this.str = str; - } - - public override int GetHashCode() - { - return str.GetHashCode(); - } - - public override bool Equals(object o) - { - if (o != null && o.GetType() == typeof(ConstantPoolItemUtf8)) - { - return ((ConstantPoolItemUtf8)o).str == str; - } - return false; - } - - public override void Write(BigEndianStream bes) - { - bes.WriteByte((byte)Constant.Utf8); - bes.WriteUtf8(str); - } - - } - -} diff --git a/src/IKVM.Runtime/StubGen/ConstantValueAttribute.cs b/src/IKVM.Runtime/StubGen/ConstantValueAttribute.cs deleted file mode 100644 index d35d884282..0000000000 --- a/src/IKVM.Runtime/StubGen/ConstantValueAttribute.cs +++ /dev/null @@ -1,48 +0,0 @@ -/* - Copyright (C) 2002-2013 Jeroen Frijters - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jeroen Frijters - jeroen@frijters.net - -*/ - -namespace IKVM.StubGen -{ - - sealed class ConstantValueAttribute : ClassFileAttribute - { - - private ushort constant_index; - - public ConstantValueAttribute(ushort name_index, ushort constant_index) - : base(name_index) - { - this.constant_index = constant_index; - } - - public override void Write(BigEndianStream bes) - { - base.Write(bes); - bes.WriteUInt32(2); - bes.WriteUInt16(constant_index); - } - - } - -} diff --git a/src/IKVM.Runtime/StubGen/DeprecatedAttribute.cs b/src/IKVM.Runtime/StubGen/DeprecatedAttribute.cs deleted file mode 100644 index 15ca9fd5c3..0000000000 --- a/src/IKVM.Runtime/StubGen/DeprecatedAttribute.cs +++ /dev/null @@ -1,44 +0,0 @@ -/* - Copyright (C) 2002-2013 Jeroen Frijters - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jeroen Frijters - jeroen@frijters.net - -*/ - -namespace IKVM.StubGen -{ - - sealed class DeprecatedAttribute : ClassFileAttribute - { - - internal DeprecatedAttribute(ClassFileWriter classFile) - : base(classFile.AddUtf8("Deprecated")) - { - } - - public override void Write(BigEndianStream bes) - { - base.Write(bes); - bes.WriteUInt32(0); - } - - } - -} diff --git a/src/IKVM.Runtime/StubGen/ExceptionsAttribute.cs b/src/IKVM.Runtime/StubGen/ExceptionsAttribute.cs deleted file mode 100644 index 49caff7318..0000000000 --- a/src/IKVM.Runtime/StubGen/ExceptionsAttribute.cs +++ /dev/null @@ -1,59 +0,0 @@ -/* - Copyright (C) 2002-2013 Jeroen Frijters - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jeroen Frijters - jeroen@frijters.net - -*/ -using System.Collections.Generic; - -namespace IKVM.StubGen -{ - - sealed class ExceptionsAttribute : ClassFileAttribute - { - - private ClassFileWriter classFile; - private List classes = new List(); - - internal ExceptionsAttribute(ClassFileWriter classFile) - : base(classFile.AddUtf8("Exceptions")) - { - this.classFile = classFile; - } - - internal void Add(string exceptionClass) - { - classes.Add(classFile.AddClass(exceptionClass)); - } - - public override void Write(BigEndianStream bes) - { - base.Write(bes); - bes.WriteUInt32((uint)(2 + 2 * classes.Count)); - bes.WriteUInt16((ushort)classes.Count); - foreach (ushort idx in classes) - { - bes.WriteUInt16(idx); - } - } - - } - -} diff --git a/src/IKVM.Runtime/StubGen/FieldOrMethod.cs b/src/IKVM.Runtime/StubGen/FieldOrMethod.cs deleted file mode 100644 index 14699a6f60..0000000000 --- a/src/IKVM.Runtime/StubGen/FieldOrMethod.cs +++ /dev/null @@ -1,65 +0,0 @@ -/* - Copyright (C) 2002-2013 Jeroen Frijters - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jeroen Frijters - jeroen@frijters.net - -*/ -using System.Collections.Generic; - -using IKVM.Attributes; - -namespace IKVM.StubGen -{ - - sealed class FieldOrMethod : IAttributeOwner - { - - private Modifiers access_flags; - private ushort name_index; - private ushort descriptor_index; - private List attribs = new List(); - - public FieldOrMethod(Modifiers access_flags, ushort name_index, ushort descriptor_index) - { - this.access_flags = access_flags; - this.name_index = name_index; - this.descriptor_index = descriptor_index; - } - - public void AddAttribute(ClassFileAttribute attrib) - { - attribs.Add(attrib); - } - - public void Write(BigEndianStream bes) - { - bes.WriteUInt16((ushort)access_flags); - bes.WriteUInt16(name_index); - bes.WriteUInt16(descriptor_index); - bes.WriteUInt16((ushort)attribs.Count); - for (int i = 0; i < attribs.Count; i++) - { - attribs[i].Write(bes); - } - } - - } - -} diff --git a/src/IKVM.Runtime/StubGen/IAttributeOwner.cs b/src/IKVM.Runtime/StubGen/IAttributeOwner.cs deleted file mode 100644 index d1a00616c2..0000000000 --- a/src/IKVM.Runtime/StubGen/IAttributeOwner.cs +++ /dev/null @@ -1,35 +0,0 @@ -/* - Copyright (C) 2002-2013 Jeroen Frijters - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jeroen Frijters - jeroen@frijters.net - -*/ - -namespace IKVM.StubGen -{ - - interface IAttributeOwner - { - - void AddAttribute(ClassFileAttribute attrib); - - } - -} diff --git a/src/IKVM.Runtime/StubGen/InnerClassesAttribute.cs b/src/IKVM.Runtime/StubGen/InnerClassesAttribute.cs deleted file mode 100644 index ac05c5c2da..0000000000 --- a/src/IKVM.Runtime/StubGen/InnerClassesAttribute.cs +++ /dev/null @@ -1,78 +0,0 @@ -/* - Copyright (C) 2002-2013 Jeroen Frijters - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jeroen Frijters - jeroen@frijters.net - -*/ -using System.Collections.Generic; - -namespace IKVM.StubGen -{ - - sealed class InnerClassesAttribute : ClassFileAttribute - { - - private ClassFileWriter classFile; - private List classes = new List(); - - public InnerClassesAttribute(ClassFileWriter classFile) - : base(classFile.AddUtf8("InnerClasses")) - { - this.classFile = classFile; - } - - public override void Write(BigEndianStream bes) - { - base.Write(bes); - bes.WriteUInt32((uint)(2 + 8 * classes.Count)); - bes.WriteUInt16((ushort)classes.Count); - foreach (Item i in classes) - { - bes.WriteUInt16(i.inner_class_info_index); - bes.WriteUInt16(i.outer_class_info_index); - bes.WriteUInt16(i.inner_name_index); - bes.WriteUInt16(i.inner_class_access_flags); - } - } - - private class Item - { - internal ushort inner_class_info_index; - internal ushort outer_class_info_index; - internal ushort inner_name_index; - internal ushort inner_class_access_flags; - } - - public void Add(string inner, string outer, string name, ushort access) - { - Item i = new Item(); - i.inner_class_info_index = classFile.AddClass(inner); - i.outer_class_info_index = classFile.AddClass(outer); - if (name != null) - { - i.inner_name_index = classFile.AddUtf8(name); - } - i.inner_class_access_flags = access; - classes.Add(i); - } - - } - -} diff --git a/src/IKVM.Runtime/StubGen/MethodParametersAttribute.cs b/src/IKVM.Runtime/StubGen/MethodParametersAttribute.cs deleted file mode 100644 index 5b79728c01..0000000000 --- a/src/IKVM.Runtime/StubGen/MethodParametersAttribute.cs +++ /dev/null @@ -1,63 +0,0 @@ -/* - Copyright (C) 2002-2013 Jeroen Frijters - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jeroen Frijters - jeroen@frijters.net - -*/ - -namespace IKVM.StubGen -{ - - sealed class MethodParametersAttribute : ClassFileAttribute - { - - private readonly ClassFileWriter classFile; - private readonly ushort[] names; - private readonly ushort[] flags; - - internal MethodParametersAttribute(ClassFileWriter classFile, ushort[] names, ushort[] flags) - : base(classFile.AddUtf8("MethodParameters")) - { - this.classFile = classFile; - this.names = names; - this.flags = flags; - } - - public override void Write(BigEndianStream bes) - { - base.Write(bes); - if (flags == null || names == null || flags.Length != names.Length) - { - // write a malformed MethodParameters attribute - bes.WriteUInt32(0); - return; - } - bes.WriteUInt32((uint)(1 + names.Length * 4)); - bes.WriteByte((byte)names.Length); - for (int i = 0; i < names.Length; i++) - { - bes.WriteUInt16(names[i]); - bes.WriteUInt16(flags[i]); - } - } - - } - -} diff --git a/src/IKVM.Runtime/StubGen/RuntimeVisibleAnnotationsAttribute.cs b/src/IKVM.Runtime/StubGen/RuntimeVisibleAnnotationsAttribute.cs deleted file mode 100644 index c4eea5710d..0000000000 --- a/src/IKVM.Runtime/StubGen/RuntimeVisibleAnnotationsAttribute.cs +++ /dev/null @@ -1,184 +0,0 @@ -/* - Copyright (C) 2002-2013 Jeroen Frijters - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jeroen Frijters - jeroen@frijters.net - -*/ -using System.IO; - -using IKVM.Attributes; - -namespace IKVM.StubGen -{ - - sealed class RuntimeVisibleAnnotationsAttribute : ClassFileAttribute - { - - private ClassFileWriter classFile; - private MemoryStream mem; - private BigEndianStream bes; - private ushort count; - - internal RuntimeVisibleAnnotationsAttribute(ClassFileWriter classFile) - : base(classFile.AddUtf8("RuntimeVisibleAnnotations")) - { - this.classFile = classFile; - mem = new MemoryStream(); - bes = new BigEndianStream(mem); - } - - internal void Add(object[] annot) - { - count++; - bes.WriteUInt16(classFile.AddUtf8((string)annot[1])); - bes.WriteUInt16((ushort)((annot.Length - 2) / 2)); - for (int i = 2; i < annot.Length; i += 2) - { - bes.WriteUInt16(classFile.AddUtf8((string)annot[i])); - WriteElementValue(bes, annot[i + 1]); - } - } - - private static string DecodeTypeName(string typeName) - { -#if !FIRST_PASS && !EXPORTER - int index = typeName.IndexOf(','); - if (index > 0) - { - // HACK if we have an assembly qualified type name we have to resolve it to a Java class name - // (at the very least we should use the right class loader here) - try - { - typeName = "L" + java.lang.Class.forName(typeName.Substring(1, typeName.Length - 2).Replace('/', '.')).getName().Replace('.', '/') + ";"; - } - catch { } - } -#endif - return typeName; - } - - private void WriteElementValue(BigEndianStream bes, object val) - { - if (val is object[]) - { - object[] arr = (object[])val; - if (AnnotationDefaultAttribute.TAG_ENUM.Equals(arr[0])) - { - bes.WriteByte(AnnotationDefaultAttribute.TAG_ENUM); - bes.WriteUInt16(classFile.AddUtf8(DecodeTypeName((string)arr[1]))); - bes.WriteUInt16(classFile.AddUtf8((string)arr[2])); - } - else if (AnnotationDefaultAttribute.TAG_ARRAY.Equals(arr[0])) - { - bes.WriteByte(AnnotationDefaultAttribute.TAG_ARRAY); - bes.WriteUInt16((ushort)(arr.Length - 1)); - for (int i = 1; i < arr.Length; i++) - { - WriteElementValue(bes, arr[i]); - } - } - else if (AnnotationDefaultAttribute.TAG_CLASS.Equals(arr[0])) - { - bes.WriteByte(AnnotationDefaultAttribute.TAG_CLASS); - bes.WriteUInt16(classFile.AddUtf8(DecodeTypeName((string)arr[1]))); - } - else if (AnnotationDefaultAttribute.TAG_ANNOTATION.Equals(arr[0])) - { - bes.WriteByte(AnnotationDefaultAttribute.TAG_ANNOTATION); - bes.WriteUInt16(classFile.AddUtf8(DecodeTypeName((string)arr[1]))); - bes.WriteUInt16((ushort)((arr.Length - 2) / 2)); - for (int i = 2; i < arr.Length; i += 2) - { - bes.WriteUInt16(classFile.AddUtf8((string)arr[i])); - WriteElementValue(bes, arr[i + 1]); - } - } - } - else if (val is bool) - { - bes.WriteByte((byte)'Z'); - bes.WriteUInt16(classFile.AddInt((bool)val ? 1 : 0)); - } - else if (val is byte) - { - bes.WriteByte((byte)'B'); - bes.WriteUInt16(classFile.AddInt((byte)val)); - } - else if (val is char) - { - bes.WriteByte((byte)'C'); - bes.WriteUInt16(classFile.AddInt((char)val)); - } - else if (val is short) - { - bes.WriteByte((byte)'S'); - bes.WriteUInt16(classFile.AddInt((short)val)); - } - else if (val is int) - { - bes.WriteByte((byte)'I'); - bes.WriteUInt16(classFile.AddInt((int)val)); - } - else if (val is long) - { - bes.WriteByte((byte)'J'); - bes.WriteUInt16(classFile.AddLong((long)val)); - } - else if (val is float) - { - bes.WriteByte((byte)'F'); - bes.WriteUInt16(classFile.AddFloat((float)val)); - } - else if (val is double) - { - bes.WriteByte((byte)'D'); - bes.WriteUInt16(classFile.AddDouble((double)val)); - } - else if (val is string) - { - bes.WriteByte((byte)'s'); - bes.WriteUInt16(classFile.AddUtf8((string)val)); - } - } - - public override void Write(BigEndianStream bes) - { - base.Write(bes); - bes.WriteUInt32(Length); - WriteImpl(bes); - } - - internal void WriteImpl(BigEndianStream bes) - { - bes.WriteUInt16(count); - foreach (byte b in mem.ToArray()) - { - bes.WriteByte(b); - } - } - - internal uint Length - { - get { return (uint)mem.Length + 2; } - } - - } - -} diff --git a/src/IKVM.Runtime/StubGen/RuntimeVisibleParameterAnnotationsAttribute.cs b/src/IKVM.Runtime/StubGen/RuntimeVisibleParameterAnnotationsAttribute.cs deleted file mode 100644 index aee6935a78..0000000000 --- a/src/IKVM.Runtime/StubGen/RuntimeVisibleParameterAnnotationsAttribute.cs +++ /dev/null @@ -1,62 +0,0 @@ -/* - Copyright (C) 2002-2013 Jeroen Frijters - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jeroen Frijters - jeroen@frijters.net - -*/ -using System.Collections.Generic; - -namespace IKVM.StubGen -{ - - sealed class RuntimeVisibleParameterAnnotationsAttribute : ClassFileAttribute - { - - private readonly List parameters = new List(); - - internal RuntimeVisibleParameterAnnotationsAttribute(ClassFileWriter classFile) - : base(classFile.AddUtf8("RuntimeVisibleParameterAnnotations")) - { - } - - internal void Add(RuntimeVisibleAnnotationsAttribute parameter) - { - parameters.Add(parameter); - } - - public override void Write(BigEndianStream bes) - { - base.Write(bes); - uint length = 1; - foreach (RuntimeVisibleAnnotationsAttribute attr in parameters) - { - length += attr.Length; - } - bes.WriteUInt32(length); - bes.WriteByte((byte)parameters.Count); - foreach (RuntimeVisibleAnnotationsAttribute attr in parameters) - { - attr.WriteImpl(bes); - } - } - - } - -} diff --git a/src/IKVM.Runtime/StubGen/RuntimeVisibleTypeAnnotationsAttribute.cs b/src/IKVM.Runtime/StubGen/RuntimeVisibleTypeAnnotationsAttribute.cs deleted file mode 100644 index 8256941d79..0000000000 --- a/src/IKVM.Runtime/StubGen/RuntimeVisibleTypeAnnotationsAttribute.cs +++ /dev/null @@ -1,48 +0,0 @@ -/* - Copyright (C) 2002-2013 Jeroen Frijters - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jeroen Frijters - jeroen@frijters.net - -*/ - -namespace IKVM.StubGen -{ - - sealed class RuntimeVisibleTypeAnnotationsAttribute : ClassFileAttribute - { - - private readonly byte[] data; - - internal RuntimeVisibleTypeAnnotationsAttribute(ClassFileWriter classFile, byte[] data) - : base(classFile.AddUtf8("RuntimeVisibleTypeAnnotations")) - { - this.data = data; - } - - public override void Write(BigEndianStream bes) - { - base.Write(bes); - bes.WriteUInt32((uint)data.Length); - bes.WriteBytes(data); - } - - } - -} diff --git a/src/IKVM.Runtime/StubGen/SHA1HashWriter.cs b/src/IKVM.Runtime/StubGen/SHA1HashWriter.cs new file mode 100644 index 0000000000..c80b77b790 --- /dev/null +++ b/src/IKVM.Runtime/StubGen/SHA1HashWriter.cs @@ -0,0 +1,158 @@ +using System; +using System.Buffers; +using System.Buffers.Binary; +using System.Security.Cryptography; + +namespace IKVM.Runtime.StubGen +{ + + /// + /// Provides methods to write basic building blocks to an incremental hash. + /// + /// + /// The Framework version of this code writes to a temporary heap array. + /// + readonly struct SHA1HashWriter : IDisposable + { + + readonly IncrementalHash hash = IncrementalHash.CreateHash(HashAlgorithmName.SHA1); +#if NETFRAMEWORK + readonly byte[] temp = ArrayPool.Shared.Rent(1024); +#endif + + /// + /// Initializes a new instance. + /// + public SHA1HashWriter() + { + + } + + public void WriteUInt16(ushort s) + { +#if NETFRAMEWORK + BinaryPrimitives.WriteUInt16BigEndian(temp, s); + hash.AppendData(temp, 0, 2); +#else + var buf = (Span)stackalloc byte[2]; + BinaryPrimitives.WriteUInt16BigEndian(buf, s); + hash.AppendData(buf); +#endif + } + + public void WriteUInt32(uint u) + { +#if NETFRAMEWORK + BinaryPrimitives.WriteUInt32BigEndian(temp, u); + hash.AppendData(temp, 0, 4); +#else + var span = (Span)stackalloc byte[4]; + BinaryPrimitives.WriteUInt32BigEndian(span, u); + hash.AppendData(span); +#endif + } + + public void WriteInt64(long l) + { +#if NETFRAMEWORK + BinaryPrimitives.WriteInt64BigEndian(temp, l); + hash.AppendData(temp, 0, 8); +#else + var span = (Span)stackalloc byte[8]; + BinaryPrimitives.WriteInt64BigEndian(span, l); + hash.AppendData(span); +#endif + } + + public void WriteFloat(float f) + { + WriteUInt32(BitConverter.ToUInt32(BitConverter.GetBytes(f), 0)); + } + + public void WriteDouble(double d) + { + WriteInt64(BitConverter.ToInt64(BitConverter.GetBytes(d), 0)); + } + + public void WriteByte(byte b) + { +#if NETFRAMEWORK + temp[0] = b; + hash.AppendData(temp, 0, 1); +#else + var span = (Span)stackalloc byte[1]; + span[0] = b; + hash.AppendData(span); +#endif + } + + public void WriteBytes(byte[] data) + { + hash.AppendData(data); + } + + public void WriteUtf8(string str) + { + var buf = ArrayPool.Shared.Rent(str.Length * 3 + 1); + + try + { + int j = 0; + for (int i = 0, e = str.Length; i < e; i++) + { + char ch = str[i]; + if ((ch != 0) && (ch <= 0x7f)) + { + buf[j++] = (byte)ch; + } + else if (ch <= 0x7FF) + { + /* 11 bits or less. */ + var high_five = (byte)(ch >> 6); + var low_six = (byte)(ch & 0x3F); + buf[j++] = (byte)(high_five | 0xC0); /* 110xxxxx */ + buf[j++] = (byte)(low_six | 0x80); /* 10xxxxxx */ + } + else + { + /* possibly full 16 bits. */ + var high_four = (byte)(ch >> 12); + var mid_six = (byte)((ch >> 6) & 0x3F); + var low_six = (byte)(ch & 0x3f); + buf[j++] = (byte)(high_four | 0xE0); /* 1110xxxx */ + buf[j++] = (byte)(mid_six | 0x80); /* 10xxxxxx */ + buf[j++] = (byte)(low_six | 0x80); /* 10xxxxxx*/ + } + } + + WriteUInt16((ushort)j); + hash.AppendData(buf, 0, j); + } + finally + { + ArrayPool.Shared.Return(buf); + } + } + + /// + /// Finalizes the SHA1. + /// + /// + public byte[] Finalize() + { + return hash.GetHashAndReset(); + } + + /// + /// Disposes of the instance. + /// + public void Dispose() + { +#if NETFRAMEWORK + ArrayPool.Shared.Return(temp); +#endif + } + + } + +} diff --git a/src/IKVM.Runtime/StubGen/SerialVersionUID.cs b/src/IKVM.Runtime/StubGen/SerialVersionUID.cs index 8395faadc0..cfa9d343a6 100644 --- a/src/IKVM.Runtime/StubGen/SerialVersionUID.cs +++ b/src/IKVM.Runtime/StubGen/SerialVersionUID.cs @@ -1,140 +1,120 @@ -/* - Copyright (C) 2010 Jeroen Frijters - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jeroen Frijters - jeroen@frijters.net - -*/ -using System.IO; using System.Linq; -using System.Security.Cryptography; using IKVM.Attributes; -using IKVM.Runtime; -namespace IKVM.StubGen +namespace IKVM.Runtime.StubGen { + /// + /// Generates a SerialVerisonUID value by hashing data related to the type. + /// static class SerialVersionUID { - - readonly static SHA1 sha1 = SHA1.Create(); - - internal static long Compute(RuntimeJavaType tw) + /// + /// Computes the SerialVerisonUID for the given Java type. + /// + /// + /// + internal static long Compute(RuntimeJavaType javaType) { - var mem = new MemoryStream(); - var bes = new BigEndianStream(mem); - WriteClassName(bes, tw); - WriteModifiers(bes, tw); - WriteInterfaces(bes, tw); - WriteFields(bes, tw); - WriteStaticInitializer(bes, tw); - WriteConstructors(bes, tw); - WriteMethods(bes, tw); - mem.Position = 0; - var buf = sha1.ComputeHash(mem); - var hash = 0; + // dump class structure into hash writer + var writer = new SHA1HashWriter(); + WriteClassName(writer, javaType); + WriteModifiers(writer, javaType); + WriteInterfaces(writer, javaType); + WriteFields(writer, javaType); + WriteStaticInitializer(writer, javaType); + WriteConstructors(writer, javaType); + WriteMethods(writer, javaType); + + // finalize and convert to long + var hash = writer.Finalize(); + var uuid = 0; for (var i = 7; i >= 0; i--) { - hash <<= 8; - hash |= buf[i]; + uuid <<= 8; + uuid |= hash[i]; } - return hash; + return uuid; } - static void WriteClassName(BigEndianStream bes, RuntimeJavaType tw) + static void WriteClassName(SHA1HashWriter writer, RuntimeJavaType javaType) { - bes.WriteUtf8(tw.Name); + writer.WriteUtf8(javaType.Name); } - static void WriteModifiers(BigEndianStream bes, RuntimeJavaType tw) + static void WriteModifiers(SHA1HashWriter writer, RuntimeJavaType javaType) { - var mods = tw.ReflectiveModifiers & (Modifiers.Public | Modifiers.Final | Modifiers.Interface | Modifiers.Abstract); + var mods = javaType.ReflectiveModifiers & (Modifiers.Public | Modifiers.Final | Modifiers.Interface | Modifiers.Abstract); if ((mods & Modifiers.Interface) != 0) { mods &= ~Modifiers.Abstract; - if (HasJavaMethods(tw)) + if (HasJavaMethods(javaType)) mods |= Modifiers.Abstract; } - bes.WriteUInt32((uint)mods); + writer.WriteUInt32((uint)mods); } - static bool HasJavaMethods(RuntimeJavaType tw) + static bool HasJavaMethods(RuntimeJavaType javaType) { - return tw.GetMethods().Any(i => !i.IsHideFromReflection && !i.IsClassInitializer); + return javaType.GetMethods().Any(i => !i.IsHideFromReflection && !i.IsClassInitializer); } - static void WriteInterfaces(BigEndianStream bes, RuntimeJavaType tw) + static void WriteInterfaces(SHA1HashWriter writer, RuntimeJavaType javaType) { - foreach (var i in tw.Interfaces.OrderBy(i => i.Name)) - bes.WriteUtf8(i.Name); + foreach (var i in javaType.Interfaces.OrderBy(i => i.Name)) + writer.WriteUtf8(i.Name); } - static void WriteFields(BigEndianStream bes, RuntimeJavaType tw) + static void WriteFields(SHA1HashWriter writer, RuntimeJavaType javaType) { - foreach (var fw in tw.GetFields().Where(i => !i.IsHideFromReflection).OrderBy(i => i.Name)) + foreach (var fw in javaType.GetFields().Where(i => !i.IsHideFromReflection).OrderBy(i => i.Name)) { var mods = fw.Modifiers & (Modifiers.Public | Modifiers.Private | Modifiers.Protected | Modifiers.Static | Modifiers.Final | Modifiers.Volatile | Modifiers.Transient); if (((mods & Modifiers.Private) == 0) || ((mods & (Modifiers.Static | Modifiers.Transient)) == 0)) { - bes.WriteUtf8(fw.Name); - bes.WriteUInt32((uint)mods); - bes.WriteUtf8(fw.Signature.Replace('.', '/')); + writer.WriteUtf8(fw.Name); + writer.WriteUInt32((uint)mods); + writer.WriteUtf8(fw.Signature.Replace('.', '/')); } } } - static void WriteStaticInitializer(BigEndianStream bes, RuntimeJavaType tw) + static void WriteStaticInitializer(SHA1HashWriter writer, RuntimeJavaType javaType) { - var type = tw.TypeAsTBD; + var type = javaType.TypeAsTBD; if (!type.IsArray && type.TypeInitializer != null) { - if (!tw.Context.AttributeHelper.IsHideFromJava(type.TypeInitializer)) + if (!javaType.Context.AttributeHelper.IsHideFromJava(type.TypeInitializer)) { - bes.WriteUtf8(""); - bes.WriteUInt32((uint)Modifiers.Static); - bes.WriteUtf8("()V"); + writer.WriteUtf8(""); + writer.WriteUInt32((uint)Modifiers.Static); + writer.WriteUtf8("()V"); } } } - static void WriteConstructors(BigEndianStream bes, RuntimeJavaType tw) + static void WriteConstructors(SHA1HashWriter writer, RuntimeJavaType javaType) { - var ctors = tw.GetMethods() + var ctors = javaType.GetMethods() .Where(i => i.IsConstructor && !i.IsHideFromReflection && !i.IsPrivate) .OrderBy(i => i.Signature); foreach (var ctor in ctors) { var mods = ctor.Modifiers & (Modifiers.Public | Modifiers.Private | Modifiers.Protected | Modifiers.Static | Modifiers.Final | Modifiers.Synchronized | Modifiers.Native | Modifiers.Abstract | Modifiers.Strictfp); - bes.WriteUtf8(ctor.Name); - bes.WriteUInt32((uint)mods); - bes.WriteUtf8(ctor.Signature); + writer.WriteUtf8(ctor.Name); + writer.WriteUInt32((uint)mods); + writer.WriteUtf8(ctor.Signature); } } - static void WriteMethods(BigEndianStream bes, RuntimeJavaType tw) + static void WriteMethods(SHA1HashWriter writer, RuntimeJavaType javaType) { - var methods = tw.GetMethods() + var methods = javaType.GetMethods() .Where(i => !i.IsConstructor && !i.IsHideFromReflection && !i.IsPrivate) .OrderBy(i => i.Name) .ThenBy(i => i.Signature); @@ -142,9 +122,9 @@ static void WriteMethods(BigEndianStream bes, RuntimeJavaType tw) foreach (var method in methods) { var mods = method.Modifiers & (Modifiers.Public | Modifiers.Private | Modifiers.Protected | Modifiers.Static | Modifiers.Final | Modifiers.Synchronized | Modifiers.Native | Modifiers.Abstract | Modifiers.Strictfp); - bes.WriteUtf8(method.Name); - bes.WriteUInt32((uint)mods); - bes.WriteUtf8(method.Signature); + writer.WriteUtf8(method.Name); + writer.WriteUInt32((uint)mods); + writer.WriteUtf8(method.Signature); } } diff --git a/src/IKVM.Runtime/StubGen/StringAttribute.cs b/src/IKVM.Runtime/StubGen/StringAttribute.cs deleted file mode 100644 index 79f8377d99..0000000000 --- a/src/IKVM.Runtime/StubGen/StringAttribute.cs +++ /dev/null @@ -1,48 +0,0 @@ -/* - Copyright (C) 2002-2013 Jeroen Frijters - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jeroen Frijters - jeroen@frijters.net - -*/ - -namespace IKVM.StubGen -{ - - sealed class StringAttribute : ClassFileAttribute - { - - private ushort string_index; - - public StringAttribute(ushort name_index, ushort string_index) - : base(name_index) - { - this.string_index = string_index; - } - - public override void Write(BigEndianStream bes) - { - base.Write(bes); - bes.WriteUInt32(2); - bes.WriteUInt16(string_index); - } - - } - -} diff --git a/src/IKVM.Runtime/StubGen/StubGenerator.cs b/src/IKVM.Runtime/StubGen/StubGenerator.cs index ac462b5458..01bd58815d 100644 --- a/src/IKVM.Runtime/StubGen/StubGenerator.cs +++ b/src/IKVM.Runtime/StubGen/StubGenerator.cs @@ -1,32 +1,13 @@ -/* - Copyright (C) 2002-2013 Jeroen Frijters - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jeroen Frijters - jeroen@frijters.net - -*/ using System; using System.IO; using System.Collections.Generic; +using IKVM.ByteCode.Encoding; using IKVM.Attributes; -using IKVM.Runtime; +using IKVM.ByteCode; +using IKVM.ByteCode.Decoding; +using IKVM.ByteCode.Buffers; + #if EXPORTER using IKVM.Reflection; @@ -36,7 +17,7 @@ Jeroen Frijters using System.Reflection; #endif -namespace IKVM.StubGen +namespace IKVM.Runtime.StubGen { class StubGenerator @@ -53,527 +34,1137 @@ public StubGenerator(RuntimeContext context) this.context = context ?? throw new ArgumentNullException(nameof(context)); } - internal void WriteClass(Stream stream, RuntimeJavaType tw, bool includeNonPublicTypes, bool includeNonPublicInterfaces, bool includeNonPublicMembers, bool includeParameterNames, bool includeSerialVersionUID) + /// + /// Generates a class file stub for the specified . + /// + /// + /// + /// + /// + /// + /// + /// + internal void Write(Stream stream, RuntimeJavaType type, bool includeNonPublicTypes, bool includeNonPublicInterfaces, bool includeNonPublicMembers, bool includeParameterNames, bool includeSerialVersionUID) { - string name = tw.Name.Replace('.', '/'); - string super = null; + var name = type.Name.Replace('.', '/'); - if (tw.IsInterface) + string super = null; + if (type.IsInterface) super = "java/lang/Object"; - else if (tw.BaseTypeWrapper != null) - super = tw.BaseTypeWrapper.Name.Replace('.', '/'); + else if (type.BaseTypeWrapper != null) + super = type.BaseTypeWrapper.Name.Replace('.', '/'); - var writer = new ClassFileWriter(tw.Modifiers, name, super, 0, includeParameterNames ? (ushort)52 : (ushort)49); - foreach (var iface in tw.Interfaces) + var builder = new ClassFileBuilder(new ClassFormatVersion(includeParameterNames ? (ushort)52 : (ushort)49, 0), (AccessFlag)type.Modifiers, name, super); + + AddInterfaces(builder, type, includeNonPublicInterfaces); + AddMethods(builder, type, includeNonPublicMembers, includeParameterNames); + AddFields(builder, type, includeNonPublicMembers, includeSerialVersionUID); + AddInnerClassesAttribute(builder, type, name, includeNonPublicTypes); + AddSignatureAttribute(builder, type); + AddAssemblyAttribute(builder, type); + AddDeprecatedAttribute(builder, type); + AddRuntimeVisibleAnnotationsAttribute(builder, type); + AddRuntimeVisibleTypeAnnotationsAttribute(builder, type); + + // serialize final class file + var blob = new BlobBuilder(); + builder.Serialize(blob); + blob.WriteContentTo(stream); + } + + /// + /// Adds the Interfaces available to the type. + /// + /// + /// + /// + void AddInterfaces(ClassFileBuilder builder, RuntimeJavaType type, bool includeNonPublicInterfaces) + { + foreach (var iface in type.Interfaces) if (iface.IsPublic || includeNonPublicInterfaces) - writer.AddInterface(iface.Name.Replace('.', '/')); + builder.AddInterface(iface.Name.Replace('.', '/')); + } - InnerClassesAttribute innerClassesAttribute = null; - if (tw.DeclaringTypeWrapper != null) + /// + /// Adds the methods for a type. + /// + /// + /// + /// + /// + void AddMethods(ClassFileBuilder builder, RuntimeJavaType type, bool includeNonPublicMembers, bool includeParameterNames) + { + foreach (var method in type.GetMethods()) { - var outer = tw.DeclaringTypeWrapper; - string innername = name; + var accessFlags = (AccessFlag)method.Modifiers; + var attributes = new AttributeTableBuilder(builder.Constants); + + if (method.IsHideFromReflection == false && (method.IsPublic || method.IsProtected || includeNonPublicMembers)) + { + // HACK javac has a bug in com.sun.tools.javac.code.Types.isSignaturePolymorphic() where it assumes that + // MethodHandle doesn't have any native methods with an empty argument list + // (or at least it throws a NPE when it examines the signature of a method without any parameters when it + // accesses argtypes.tail.tail) + if (method.Name == "" || (type == context.JavaBase.TypeOfJavaLangInvokeMethodHandle && (method.Modifiers & Modifiers.Native) == 0)) + { + // generate the method code which throws a UnsatisfiedLinkError. + var codeBlob = new BlobBuilder(); + new CodeBuilder(codeBlob) + .New(builder.Constants.GetOrAddClass("java/lang/UnsatisfiedLinkError")) + .Dup() + .LoadConstant(builder.Constants.GetOrAddString("IKVM stubs can only be used on IKVM")) + .InvokeSpecial(builder.Constants.GetOrAddMethodref("java/lang/UnsatisfiedLinkError", "", "(Ljava/lang/String;)V")) + .Athrow(); + + attributes.Code(3, (ushort)(method.GetParameters().Length * 2 + 1), codeBlob, e => { }, new AttributeTableBuilder(builder.Constants)); + } + else + { + if ((accessFlags & AccessFlag.Abstract) == 0) + accessFlags |= AccessFlag.Native; + + if (method.IsOptionalAttributeAnnotationValue) + attributes.AnnotationDefault(e => EncodeAnnotationDefault(builder, ref e, method.ReturnType)); + } + + var methodBase = method.GetMethod(); + if (methodBase != null) + { + AddExceptionsAttribute(builder, type, method, attributes, methodBase); + AddDeprecatedAttribute(builder, type, method, attributes, methodBase); + AddAnnotationDefaultAttribute(builder, type, method, attributes, methodBase); + AddMethodParameters(builder, type, method, attributes, includeParameterNames); + } + + AddSignatureAttribute(builder, type, method, attributes); + AddRuntimeVisibleAnnotationsAttribute(builder, type, method, attributes); + AddRuntimeVisibleTypeAnnotationsAttribute(builder, type, method, attributes); + AddRuntimeVisibleParameterAnnotationsAttribute(builder, type, method, attributes); + + builder.AddMethod(accessFlags, method.Name, method.Signature.Replace('.', '/'), attributes); + } + } + } + + /// + /// Adds the fields for a type. + /// + /// + /// + /// + /// + void AddFields(ClassFileBuilder builder, RuntimeJavaType type, bool includeNonPublicMembers, bool includeSerialVersionUID) + { + var hasSerialVersionUID = false; + + foreach (var field in type.GetFields()) + { + if (field.IsHideFromReflection == false) + { + var attributes = new AttributeTableBuilder(builder.Constants); + + var isSerialVersionUID = includeSerialVersionUID && field.IsSerialVersionUID; + hasSerialVersionUID |= isSerialVersionUID; + + if (field.IsPublic || field.IsProtected || isSerialVersionUID || includeNonPublicMembers) + { + AddConstantValueAttribute(builder, type, field, attributes); + AddSignatureAttribute(builder, type, field, attributes); + AddDeprecatedAttribute(builder, type, field, attributes); + AddRuntimeVisibleAnnotationsAttribute(builder, type, field, attributes); + AddRuntimeVisibleTypeAnnotationsAttribute(builder, type, field, attributes); + builder.AddField((AccessFlag)field.Modifiers, field.Name, field.Signature.Replace('.', '/'), attributes); + } + } + } + + // class is serializable but doesn't have an explicit serialVersionUID, so we add the field to record + // the serialVersionUID as we see it (mainly to make the Japi reports more realistic) + if (includeSerialVersionUID && hasSerialVersionUID == false && IsSerializable(type)) + { + var fieldAttributes = new AttributeTableBuilder(builder.Constants); + fieldAttributes.ConstantValue(SerialVersionUID.Compute(type)); + builder.AddField(AccessFlag.Private | AccessFlag.Static | AccessFlag.Final, "serialVersionUID", "J", fieldAttributes); + } + } + + /// + /// Adds the RuntimeVisibleTypeAnnotations attribute for a type. + /// + /// + /// + void AddRuntimeVisibleTypeAnnotationsAttribute(ClassFileBuilder builder, RuntimeJavaType type) + { + var blob = new BlobBuilder(); + var encoder = new TypeAnnotationTableEncoder(blob); + if (ImportTypeAnnotations(builder, ref encoder, type, type.GetRawTypeAnnotations())) + builder.Attributes.Attribute(AttributeName.RuntimeVisibleTypeAnnotations, blob); + } + + /// + /// Adds the RuntimeVisibleAnnotations attribute for a type. + /// + /// + /// + void AddRuntimeVisibleAnnotationsAttribute(ClassFileBuilder builder, RuntimeJavaType type) + { + var blob = new BlobBuilder(); + var encoder = new AnnotationTableEncoder(blob); + if (EncodeAnnotations(builder, ref encoder, type.TypeAsBaseType) || + EncodeAnnotationsForType(builder, ref encoder, type)) + builder.Attributes.Attribute(AttributeName.RuntimeVisibleAnnotations, blob); + } + + /// + /// Adds the Deprecated attribute. + /// + /// + /// + void AddDeprecatedAttribute(ClassFileBuilder builder, RuntimeJavaType type) + { + if (type.TypeAsBaseType.IsDefined(context.Resolver.ResolveCoreType(typeof(ObsoleteAttribute).FullName), false)) + builder.Attributes.Deprecated(); + } + + /// + /// Adds the InnerClasses attribute. + /// + /// + /// + /// + /// + void AddInnerClassesAttribute(ClassFileBuilder builder, RuntimeJavaType javaType, string name, bool includeNonPublicTypes) + { + var any = false; + var blob = new BlobBuilder(); + var encoder = new InnerClassTableEncoder(blob); + + if (javaType.DeclaringTypeWrapper != null) + { + var innerName = name; int idx = name.LastIndexOf('$'); if (idx >= 0) - innername = innername.Substring(idx + 1); + innerName = innerName.Substring(idx + 1); + + encoder.InnerClass( + builder.Constants.GetOrAddClass(name), + builder.Constants.GetOrAddClass(javaType.DeclaringTypeWrapper.Name.Replace('.', '/')), + builder.Constants.GetOrAddUtf8(innerName), + (AccessFlag)javaType.ReflectiveModifiers); - innerClassesAttribute = new InnerClassesAttribute(writer); - innerClassesAttribute.Add(name, outer.Name.Replace('.', '/'), innername, (ushort)tw.ReflectiveModifiers); + any = true; } - foreach (var inner in tw.InnerClasses) + foreach (var innerType in javaType.InnerClasses) { - if (inner.IsPublic || includeNonPublicTypes) + if (innerType.IsPublic || includeNonPublicTypes) { - innerClassesAttribute ??= new InnerClassesAttribute(writer); - var namePart = inner.Name; + var namePart = innerType.Name; namePart = namePart.Substring(namePart.LastIndexOf('$') + 1); - innerClassesAttribute.Add(inner.Name.Replace('.', '/'), name, namePart, (ushort)inner.ReflectiveModifiers); + + encoder.InnerClass( + builder.Constants.GetOrAddClass(innerType.Name.Replace('.', '/')), + builder.Constants.GetOrAddClass(name), + builder.Constants.GetOrAddUtf8(namePart), + (AccessFlag)innerType.ReflectiveModifiers); + + any = true; } } - if (innerClassesAttribute != null) - writer.AddAttribute(innerClassesAttribute); + if (any) + builder.Attributes.Attribute(AttributeName.InnerClasses, blob); + } + + /// + /// Adds the Signature attribute for a type. + /// + /// + /// + void AddSignatureAttribute(ClassFileBuilder builder, RuntimeJavaType javaType) + { + var signature = javaType.GetGenericSignature(); + if (signature != null) + builder.Attributes.Signature(signature); + } - var genericTypeSignature = tw.GetGenericSignature(); - if (genericTypeSignature != null) - writer.AddStringAttribute("Signature", genericTypeSignature); + /// + /// Adds the IKVM.NET.Assembly attribute for a type. + /// + /// + /// + void AddAssemblyAttribute(ClassFileBuilder builder, RuntimeJavaType javaType) + { - AddAnnotations(writer, writer, tw.TypeAsBaseType); - AddTypeAnnotations(writer, writer, tw, tw.GetRawTypeAnnotations()); - writer.AddStringAttribute("IKVM.NET.Assembly", GetAssemblyName(tw)); - if (tw.TypeAsBaseType.IsDefined(context.Resolver.ResolveCoreType(typeof(ObsoleteAttribute).FullName), false)) - writer.AddAttribute(new DeprecatedAttribute(writer)); + // consists of a U2 constant pointing to the full name of the assembly + var assemblyAttributeBlob = new BlobBuilder(); + new ClassFormatWriter(assemblyAttributeBlob.ReserveBytes(ClassFormatWriter.U2).GetBytes()).WriteU2(builder.Constants.GetOrAddUtf8(GetAssemblyName(javaType)).Slot); + builder.Attributes.Encoder.Attribute(builder.Constants.GetOrAddUtf8("IKVM.NET.Assembly"), assemblyAttributeBlob); + } - foreach (var mw in tw.GetMethods()) + /// + /// Adds the Exceptions attribute for the method. + /// + /// + /// + /// + /// + /// + void AddExceptionsAttribute(ClassFileBuilder builder, RuntimeJavaType type, RuntimeJavaMethod method, AttributeTableBuilder attributes, MethodBase methodBase) + { + var throws = context.AttributeHelper.GetThrows(methodBase); + if (throws == null) { - if (!mw.IsHideFromReflection && (mw.IsPublic || mw.IsProtected || includeNonPublicMembers)) + var throwsArray = method.GetDeclaredExceptions(); + if (throwsArray != null && throwsArray.Length > 0) { - FieldOrMethod m; - - // HACK javac has a bug in com.sun.tools.javac.code.Types.isSignaturePolymorphic() where it assumes that - // MethodHandle doesn't have any native methods with an empty argument list - // (or at least it throws a NPE when it examines the signature of a method without any parameters when it - // accesses argtypes.tail.tail) - if (mw.Name == "" || (tw == context.JavaBase.TypeOfJavaLangInvokeMethodHandle && (mw.Modifiers & Modifiers.Native) == 0)) + attributes.Exceptions(e => { - m = writer.AddMethod(mw.Modifiers, mw.Name, mw.Signature.Replace('.', '/')); - var code = new CodeAttribute(writer); - code.MaxLocals = (ushort)(mw.GetParameters().Length * 2 + 1); - code.MaxStack = 3; - var index1 = writer.AddClass("java/lang/UnsatisfiedLinkError"); - var index2 = writer.AddString("ikvmstub generated stubs can only be used on IKVM.NET"); - var index3 = writer.AddMethodRef("java/lang/UnsatisfiedLinkError", "", "(Ljava/lang/String;)V"); - code.ByteCode = new byte[] { - 187, (byte)(index1 >> 8), (byte)index1, // new java/lang/UnsatisfiedLinkError - 89, // dup - 19, (byte)(index2 >> 8), (byte)index2, // ldc_w "..." - 183, (byte)(index3 >> 8), (byte)index3, // invokespecial java/lang/UnsatisfiedLinkError/init()V - 191 // athrow - }; - m.AddAttribute(code); - } - else + foreach (string ex in throwsArray) + e.Class(builder.Constants.GetOrAddClass(ex.Replace('.', '/'))); + }); + } + } + else + { + if (throws.classes != null || throws.types != null) + { + attributes.Exceptions(e => { - var mods = mw.Modifiers; - if ((mods & Modifiers.Abstract) == 0) - mods |= Modifiers.Native; + if (throws.classes != null) + foreach (string ex in throws.classes) + e.Class(builder.Constants.GetOrAddClass(ex.Replace('.', '/'))); + + if (throws.types != null) + foreach (Type ex in throws.types) + e.Class(builder.Constants.GetOrAddClass(context.ClassLoaderFactory.GetJavaTypeFromType(ex).Name.Replace('.', '/'))); + }); + } + } + } - m = writer.AddMethod(mods, mw.Name, mw.Signature.Replace('.', '/')); - if (mw.IsOptionalAttributeAnnotationValue) - m.AddAttribute(new AnnotationDefaultClassFileAttribute(writer, GetAnnotationDefault(writer, mw.ReturnType))); - } - var mb = mw.GetMethod(); - if (mb != null) + /// + /// Adds the MethodParameters attribute for a method. + /// + /// + /// + /// + /// + /// + void AddMethodParameters(ClassFileBuilder builder, RuntimeJavaType type, RuntimeJavaMethod method, AttributeTableBuilder attributes, bool includeParameterNames) + { + if (includeParameterNames) + { + var mp = type.GetMethodParameters(method); + if (mp == MethodParametersEntry.Malformed) + { + attributes.MethodParameters(e => { }); + } + else if (mp != null) + { + attributes.MethodParameters(e => { - var throws = context.AttributeHelper.GetThrows(mb); - if (throws == null) - { - var throwsArray = mw.GetDeclaredExceptions(); - if (throwsArray != null && throwsArray.Length > 0) - { - var attrib = new ExceptionsAttribute(writer); - foreach (string ex in throwsArray) - attrib.Add(ex.Replace('.', '/')); + foreach (var i in mp) + e.MethodParameter(builder.Constants.GetOrAddUtf8(i.name), i.accessFlags); + }); + } + } + } - m.AddAttribute(attrib); - } - } - else - { - var attrib = new ExceptionsAttribute(writer); - - if (throws.classes != null) - foreach (string ex in throws.classes) - attrib.Add(ex.Replace('.', '/')); - - if (throws.types != null) - foreach (Type ex in throws.types) - attrib.Add(context.ClassLoaderFactory.GetJavaTypeFromType(ex).Name.Replace('.', '/')); - - m.AddAttribute(attrib); - } - - if (mb.IsDefined(context.Resolver.ResolveCoreType(typeof(ObsoleteAttribute).FullName), false) - // HACK the instancehelper methods are marked as Obsolete (to direct people toward the ikvm.extensions methods instead) - // but in the Java world most of them are not deprecated (and to keep the Japi results clean we need to reflect this) - && (!mb.Name.StartsWith("instancehelper_") - || mb.DeclaringType.FullName != "java.lang.String" - // the Java deprecated methods actually have two Obsolete attributes - || GetObsoleteCount(mb) == 2)) - { - m.AddAttribute(new DeprecatedAttribute(writer)); - } + /// + /// Adds the AnnotationDefault attribute for a method. + /// + /// + /// + /// + /// + /// + void AddAnnotationDefaultAttribute(ClassFileBuilder builder, RuntimeJavaType type, RuntimeJavaMethod method, AttributeTableBuilder attributes, MethodBase methodBase) + { + var attr = GetAnnotationDefault(methodBase); + if (attr != null) + attributes.AnnotationDefault(e => EncodeAnnotationDefault(builder, ref e, attr.ConstructorArguments[0])); + } - var attr = GetAnnotationDefault(mb); - if (attr != null) - m.AddAttribute(new AnnotationDefaultClassFileAttribute(writer, GetAnnotationDefault(writer, attr.ConstructorArguments[0]))); + /// + /// Adds the Signature attribute for a method. + /// + /// + /// + /// + /// + void AddSignatureAttribute(ClassFileBuilder builder, RuntimeJavaType type, RuntimeJavaMethod method, AttributeTableBuilder methodAttributes) + { + var signature = type.GetGenericMethodSignature(method); + if (signature != null) + methodAttributes.Signature(signature); + } - if (includeParameterNames) - { - var mp = tw.GetMethodParameters(mw); - if (mp == MethodParametersEntry.Malformed) - { - m.AddAttribute(new MethodParametersAttribute(writer, null, null)); - } - else if (mp != null) - { - var names = new ushort[mp.Length]; - var flags = new ushort[mp.Length]; - for (int i = 0; i < names.Length; i++) - { - if (mp[i].name != null) - names[i] = writer.AddUtf8(mp[i].name); + /// + /// Adds the Deprecated attribute for a method. + /// + /// + /// + /// + /// + /// + void AddDeprecatedAttribute(ClassFileBuilder builder, RuntimeJavaType type, RuntimeJavaMethod method, AttributeTableBuilder attributes, MethodBase methodBase) + { + // HACK the instancehelper methods are marked as Obsolete (to direct people toward the ikvm.extensions methods instead) + // but in the Java world most of them are not deprecated (and to keep the Japi results clean we need to reflect this) + // the Java deprecated methods actually have two Obsolete attributes + if (methodBase.IsDefined(context.Resolver.ResolveCoreType(typeof(ObsoleteAttribute).FullName), false) && (!methodBase.Name.StartsWith("instancehelper_") || methodBase.DeclaringType.FullName != "java.lang.String" || GetObsoleteCount(methodBase) == 2)) + attributes.Deprecated(); + } - flags[i] = (ushort)mp[i].accessFlags; - } + /// + /// Adds the RuntimeVisibleParameterAnnotations attribute for a method. + /// + /// + /// + /// + /// + void AddRuntimeVisibleParameterAnnotationsAttribute(ClassFileBuilder builder, RuntimeJavaType type, RuntimeJavaMethod method, AttributeTableBuilder attributes) + { + var blob = new BlobBuilder(); + var encoder = new ParameterAnnotationTableEncoder(blob); + if (EncodeParameterAnnotations(builder, ref encoder, method.GetMethod())) + attributes.Attribute(AttributeName.RuntimeVisibleParameterAnnotations, blob); + } - m.AddAttribute(new MethodParametersAttribute(writer, names, flags)); - } - } + /// + /// Adds the RuntimeVisibleTypeAnnotations attribute for a method. + /// + /// + /// + /// + /// + void AddRuntimeVisibleTypeAnnotationsAttribute(ClassFileBuilder builder, RuntimeJavaType type, RuntimeJavaMethod method, AttributeTableBuilder attributes) + { + var blob = new BlobBuilder(); + var encoder = new TypeAnnotationTableEncoder(blob); + if (ImportTypeAnnotations(builder, ref encoder, type, type.GetMethodRawTypeAnnotations(method))) + attributes.Attribute(AttributeName.RuntimeVisibleTypeAnnotations, blob); + } + + /// + /// Adds the RuntimeVisibleAnnotations attribute for a method. + /// + /// + /// + /// + /// + void AddRuntimeVisibleAnnotationsAttribute(ClassFileBuilder builder, RuntimeJavaType type, RuntimeJavaMethod method, AttributeTableBuilder attributes) + { + var blob = new BlobBuilder(); + var encoder = new AnnotationTableEncoder(blob); + if (EncodeAnnotations(builder, ref encoder, method.GetMethod())) + attributes.Attribute(AttributeName.RuntimeVisibleAnnotations, blob); + } + + /// + /// Adds the ConstantValue attribute for a field. + /// + /// + /// + /// + /// + /// + void AddConstantValueAttribute(ClassFileBuilder builder, RuntimeJavaType type, RuntimeJavaField field, AttributeTableBuilder attributes) + { + if (field.GetField() != null && field.GetField().IsLiteral && (field.FieldTypeWrapper.IsPrimitive || field.FieldTypeWrapper == context.JavaBase.TypeOfJavaLangString)) + { + var constant = field.GetField().GetRawConstantValue(); + if (field.GetField().FieldType.IsEnum) + constant = EnumHelper.GetPrimitiveValue(context, EnumHelper.GetUnderlyingType(field.GetField().FieldType), constant); + + if (constant != null) + { + switch (constant) + { + case int i: + attributes.ConstantValue(i); + break; + case short s: + attributes.ConstantValue(s); + break; + case char c: + attributes.ConstantValue(c); + break; + case byte b: + attributes.ConstantValue((int)(sbyte)b); + break; + case bool z: + attributes.ConstantValue(z); + break; + case float f: + attributes.ConstantValue(f); + break; + case long j: + attributes.ConstantValue(j); + break; + case double d: + attributes.ConstantValue(d); + break; + case string l: + attributes.ConstantValue(l); + break; + default: + throw new Exception(); } - var sig = tw.GetGenericMethodSignature(mw); - if (sig != null) - m.AddAttribute(writer.MakeStringAttribute("Signature", sig)); + } + } + } + + /// + /// Adds the Signature attribute for a field. + /// + /// + /// + /// + /// + void AddSignatureAttribute(ClassFileBuilder builder, RuntimeJavaType type, RuntimeJavaField field, AttributeTableBuilder attributes) + { + var signature = type.GetGenericFieldSignature(field); + if (signature != null) + attributes.Signature(signature); + } + + /// + /// Adds the Deprecated attribute for a field. + /// + /// + /// + /// + /// + void AddDeprecatedAttribute(ClassFileBuilder builder, RuntimeJavaType type, RuntimeJavaField field, AttributeTableBuilder attributes) + { + // .NET ObsoleteAttribute translates to Deprecated attribute + if (field.GetField() != null && field.GetField().IsDefined(context.Resolver.ResolveCoreType(typeof(ObsoleteAttribute).FullName), false)) + attributes.Deprecated(); + } + + /// + /// Adds the RuntimeVisibleTypeAnnotations attribute for a field. + /// + /// + /// + /// + /// + void AddRuntimeVisibleTypeAnnotationsAttribute(ClassFileBuilder builder, RuntimeJavaType type, RuntimeJavaField field, AttributeTableBuilder attributes) + { + var blob = new BlobBuilder(); + var encoder = new TypeAnnotationTableEncoder(blob); + if (ImportTypeAnnotations(builder, ref encoder, type, type.GetFieldRawTypeAnnotations(field))) + attributes.Attribute(AttributeName.RuntimeVisibleTypeAnnotations, blob); + } + + /// + /// Adds the RuntimeVisibleAnnotations attribute for a field. + /// + /// + /// + /// + /// + void AddRuntimeVisibleAnnotationsAttribute(ClassFileBuilder builder, RuntimeJavaType type, RuntimeJavaField field, AttributeTableBuilder attributes) + { + var blob = new BlobBuilder(); + var encoder = new AnnotationTableEncoder(blob); + if (EncodeAnnotations(builder, ref encoder, field.GetField())) + attributes.Attribute(AttributeName.RuntimeVisibleAnnotations, blob); + } + + /// + /// Encodes the RuntimeVisibleAnnotations attribute from the specified source. + /// + /// + /// + /// + bool EncodeAnnotations(ClassFileBuilder builder, ref AnnotationTableEncoder encoder, MemberInfo source) + { + var any = false; - AddAnnotations(writer, m, mw.GetMethod()); - AddParameterAnnotations(writer, m, mw.GetMethod()); - AddTypeAnnotations(writer, m, tw, tw.GetMethodRawTypeAnnotations(mw)); +#if !FIRST_PASS && !EXPORTER + if (source != null) + { + foreach (var cad in CustomAttributeData.GetCustomAttributes(source)) + { + var ann = GetAnnotation(cad); + if (ann != null) + { + EncodeAnnotation(builder, ref encoder, ann); + any = true; + } } } +#endif + + return any; + } + + /// + /// Encodes the RuntimeVisibleParameterAnnotations attribute from the specified source. + /// + /// + /// + /// + bool EncodeParameterAnnotations(ClassFileBuilder builder, ref ParameterAnnotationTableEncoder encoder, MethodBase source) + { + var any = false; - bool hasSerialVersionUID = false; - foreach (RuntimeJavaField fw in tw.GetFields()) +#if !FIRST_PASS && !EXPORTER + if (source != null) { - if (!fw.IsHideFromReflection) + var parameters = source.GetParameters(); + if (parameters.Length > 0) { - bool isSerialVersionUID = includeSerialVersionUID && fw.IsSerialVersionUID; - hasSerialVersionUID |= isSerialVersionUID; - if (fw.IsPublic || fw.IsProtected || isSerialVersionUID || includeNonPublicMembers) + for (int i = 0; i < parameters.Length; i++) { - object constant = null; - if (fw.GetField() != null && fw.GetField().IsLiteral && (fw.FieldTypeWrapper.IsPrimitive || fw.FieldTypeWrapper == context.JavaBase.TypeOfJavaLangString)) + encoder.ParameterAnnotation(e2 => { - constant = fw.GetField().GetRawConstantValue(); - if (fw.GetField().FieldType.IsEnum) + foreach (var cad in CustomAttributeData.GetCustomAttributes(parameters[i])) { - constant = EnumHelper.GetPrimitiveValue(context, EnumHelper.GetUnderlyingType(fw.GetField().FieldType), constant); + var ann = GetAnnotation(cad); + if (ann != null) + { + EncodeAnnotation(builder, ref e2, ann); + any = true; + } } - } - FieldOrMethod f = writer.AddField(fw.Modifiers, fw.Name, fw.Signature.Replace('.', '/'), constant); - string sig = tw.GetGenericFieldSignature(fw); - if (sig != null) - { - f.AddAttribute(writer.MakeStringAttribute("Signature", sig)); - } - if (fw.GetField() != null && fw.GetField().IsDefined(context.Resolver.ResolveCoreType(typeof(ObsoleteAttribute).FullName), false)) - { - f.AddAttribute(new DeprecatedAttribute(writer)); - } - AddAnnotations(writer, f, fw.GetField()); - AddTypeAnnotations(writer, f, tw, tw.GetFieldRawTypeAnnotations(fw)); + }); } } } - if (includeSerialVersionUID && !hasSerialVersionUID && IsSerializable(tw)) +#endif + + return any; + } + + /// + /// Encodes the RuntimeVisibleTypeAnnotations attribute from the specified binary source. + /// + /// + /// + /// + /// + /// + bool ImportTypeAnnotations(ClassFileBuilder builder, ref TypeAnnotationTableEncoder encoder, RuntimeJavaType type, byte[] typeAnnotations) + { +#if !FIRST_PASS && !EXPORTER + if (typeAnnotations != null) + { + var reader = new ClassFormatReader(typeAnnotations); + if (TypeAnnotationTable.TryRead(ref reader, out var table) == false) + throw new Exception(); + + table.EncodeTo(new ConstantHandleMap(type.GetConstantPool(), builder.Constants), ref encoder); + return table.Count > 0; + } +#endif + + return false; + } + + /// + /// Maps handles from a set of allowed primitive types in a view array to a new pool. + /// + class ConstantHandleMap : IConstantHandleMap + { + + readonly object[] view; + readonly IConstantPool pool; + + /// + /// Initializes a new instance. + /// + /// + /// + public ConstantHandleMap(object[] view, IConstantPool pool) + { + this.view = view; + this.pool = pool; + } + + public Constant Get(ConstantHandle handle) + { + return handle.Kind switch + { + ConstantKind.Utf8 => Get((Utf8ConstantHandle)handle), + ConstantKind.Integer => Get((IntegerConstantHandle)handle), + ConstantKind.Float => Get((FloatConstantHandle)handle), + ConstantKind.Long => Get((LongConstantHandle)handle), + ConstantKind.Double => Get((DoubleConstantHandle)handle), + ConstantKind.Class => Get((ClassConstantHandle)handle), + ConstantKind.String => Get((StringConstantHandle)handle), + ConstantKind.Fieldref => Get((FieldrefConstantHandle)handle), + ConstantKind.Methodref => Get((MethodrefConstantHandle)handle), + ConstantKind.InterfaceMethodref => Get((InterfaceMethodrefConstantHandle)handle), + ConstantKind.NameAndType => Get((NameAndTypeConstantHandle)handle), + ConstantKind.MethodHandle => Get((MethodHandleConstantHandle)handle), + ConstantKind.MethodType => Get((MethodTypeConstantHandle)handle), + ConstantKind.Dynamic => Get((DynamicConstantHandle)handle), + ConstantKind.InvokeDynamic => Get((InvokeDynamicConstantHandle)handle), + ConstantKind.Module => Get((ModuleConstantHandle)handle), + ConstantKind.Package => Get((PackageConstantHandle)handle), + _ => Get((IntegerConstantHandle)handle), + }; + } + + public RefConstant Get(RefConstantHandle handle) + { + throw new NotImplementedException(); + } + + public Utf8Constant Get(Utf8ConstantHandle handle) + { + if (view[handle.Slot] is not string s) + throw new Exception(); + + return new Utf8Constant(s); + } + + public IntegerConstant Get(IntegerConstantHandle handle) + { + if (view[handle.Slot] is not int i) + throw new Exception(); + + return new IntegerConstant(i); + } + + public FloatConstant Get(FloatConstantHandle handle) + { + if (view[handle.Slot] is not float f) + throw new Exception(); + + return new FloatConstant(f); + } + + public LongConstant Get(LongConstantHandle handle) + { + if (view[handle.Slot] is not long j) + throw new Exception(); + + return new LongConstant(j); + } + + public DoubleConstant Get(DoubleConstantHandle handle) + { + if (view[handle.Slot] is not double d) + throw new Exception(); + + return new DoubleConstant(d); + } + + public ClassConstant Get(ClassConstantHandle handle) + { + throw new NotImplementedException(); + } + + public StringConstant Get(StringConstantHandle handle) + { + if (view[handle.Slot] is not string s) + throw new Exception(); + + return new StringConstant(s); + } + + public FieldrefConstant Get(FieldrefConstantHandle handle) + { + throw new NotImplementedException(); + } + + public MethodrefConstant Get(MethodrefConstantHandle handle) + { + throw new NotImplementedException(); + } + + public InterfaceMethodrefConstant Get(InterfaceMethodrefConstantHandle handle) + { + throw new NotImplementedException(); + } + + public NameAndTypeConstant Get(NameAndTypeConstantHandle handle) + { + throw new NotImplementedException(); + } + + public MethodHandleConstant Get(MethodHandleConstantHandle handle) + { + throw new NotImplementedException(); + } + + public MethodTypeConstant Get(MethodTypeConstantHandle handle) + { + throw new NotImplementedException(); + } + + public DynamicConstant Get(DynamicConstantHandle handle) + { + throw new NotImplementedException(); + } + + public InvokeDynamicConstant Get(InvokeDynamicConstantHandle handle) + { + throw new NotImplementedException(); + } + + public ModuleConstant Get(ModuleConstantHandle handle) + { + throw new NotImplementedException(); + } + + public PackageConstant Get(PackageConstantHandle handle) + { + throw new NotImplementedException(); + } + + public ConstantHandle Map(ConstantHandle handle) + { + return pool.Import(this, handle); + } + + public Utf8ConstantHandle Map(Utf8ConstantHandle handle) + { + return pool.Import(this, handle); + } + + public IntegerConstantHandle Map(IntegerConstantHandle handle) + { + return pool.Import(this, handle); + } + + public FloatConstantHandle Map(FloatConstantHandle handle) + { + return pool.Import(this, handle); + } + + public LongConstantHandle Map(LongConstantHandle handle) { - // class is serializable but doesn't have an explicit serialVersionUID, so we add the field to record - // the serialVersionUID as we see it (mainly to make the Japi reports more realistic) - writer.AddField(Modifiers.Private | Modifiers.Static | Modifiers.Final, "serialVersionUID", "J", SerialVersionUID.Compute(tw)); + return pool.Import(this, handle); } - AddMetaAnnotations(writer, tw); - writer.Write(stream); - } - private void AddAnnotations(ClassFileWriter writer, IAttributeOwner target, MemberInfo source) - { -#if !FIRST_PASS && !EXPORTER - if (source != null) + public DoubleConstantHandle Map(DoubleConstantHandle handle) { - RuntimeVisibleAnnotationsAttribute attr = null; - foreach (CustomAttributeData cad in CustomAttributeData.GetCustomAttributes(source)) - { - object[] ann = GetAnnotation(cad); - if (ann != null) - { - if (attr == null) - { - attr = new RuntimeVisibleAnnotationsAttribute(writer); - } - attr.Add(ann); - } - } - if (attr != null) - { - target.AddAttribute(attr); - } + return pool.Import(this, handle); } -#endif - } - private void AddParameterAnnotations(ClassFileWriter writer, FieldOrMethod target, MethodBase source) - { -#if !FIRST_PASS && !EXPORTER - if (source != null) + public ClassConstantHandle Map(ClassConstantHandle handle) { - RuntimeVisibleParameterAnnotationsAttribute attr = null; - ParameterInfo[] parameters = source.GetParameters(); - for (int i = 0; i < parameters.Length; i++) - { - RuntimeVisibleAnnotationsAttribute param = null; - foreach (CustomAttributeData cad in CustomAttributeData.GetCustomAttributes(parameters[i])) - { - object[] ann = GetAnnotation(cad); - if (ann != null) - { - if (param == null) - { - if (attr == null) - { - attr = new RuntimeVisibleParameterAnnotationsAttribute(writer); - for (int j = 0; j < i; j++) - { - attr.Add(new RuntimeVisibleAnnotationsAttribute(writer)); - } - } - param = new RuntimeVisibleAnnotationsAttribute(writer); - } - param.Add(ann); - } - } - if (attr != null) - { - attr.Add(param ?? new RuntimeVisibleAnnotationsAttribute(writer)); - } - } - if (attr != null) - { - target.AddAttribute(attr); - } + return pool.Import(this, handle); } -#endif - } - private void AddTypeAnnotations(ClassFileWriter writer, IAttributeOwner target, RuntimeJavaType tw, byte[] typeAnnotations) - { -#if !FIRST_PASS && !EXPORTER - if (typeAnnotations != null) + public StringConstantHandle Map(StringConstantHandle handle) { - typeAnnotations = (byte[])typeAnnotations.Clone(); - object[] constantPool = tw.GetConstantPool(); - try - { - int pos = 0; - ushort num_annotations = ReadUInt16BE(typeAnnotations, ref pos); - for (int i = 0; i < num_annotations; i++) - { - FixupTypeAnnotationConstantPoolIndexes(writer, typeAnnotations, constantPool, ref pos); - } - } - catch (IndexOutOfRangeException) - { - // if the attribute is malformed, we add it anyway and hope the Java parser will agree and throw the right error - } - target.AddAttribute(new RuntimeVisibleTypeAnnotationsAttribute(writer, typeAnnotations)); + return pool.Import(this, handle); } -#endif - } - private void FixupTypeAnnotationConstantPoolIndexes(ClassFileWriter writer, byte[] typeAnnotations, object[] constantPool, ref int pos) - { - switch (typeAnnotations[pos++]) // target_type + public FieldrefConstantHandle Map(FieldrefConstantHandle handle) { - case 0x00: - case 0x01: - case 0x16: - pos++; - break; - case 0x10: - case 0x11: - case 0x12: - case 0x17: - pos += 2; - break; - case 0x13: - case 0x14: - case 0x15: - break; - default: - throw new IndexOutOfRangeException(); + return pool.Import(this, handle); } - byte path_length = typeAnnotations[pos++]; - pos += path_length * 2; - FixupAnnotationConstantPoolIndexes(writer, typeAnnotations, constantPool, ref pos); - } - private void FixupAnnotationConstantPoolIndexes(ClassFileWriter writer, byte[] typeAnnotations, object[] constantPool, ref int pos) - { - FixupConstantPoolIndex(writer, typeAnnotations, constantPool, ref pos); - ushort num_components = ReadUInt16BE(typeAnnotations, ref pos); - for (int i = 0; i < num_components; i++) + public MethodrefConstantHandle Map(MethodrefConstantHandle handle) { - FixupConstantPoolIndex(writer, typeAnnotations, constantPool, ref pos); - FixupAnnotationComponentValueConstantPoolIndexes(writer, typeAnnotations, constantPool, ref pos); + return pool.Import(this, handle); } - } - private void FixupConstantPoolIndex(ClassFileWriter writer, byte[] typeAnnotations, object[] constantPool, ref int pos) - { - ushort index = ReadUInt16BE(typeAnnotations, ref pos); - object item = constantPool[index]; - if (item is int) + public InterfaceMethodrefConstantHandle Map(InterfaceMethodrefConstantHandle handle) { - index = writer.AddInt((int)item); + return pool.Import(this, handle); } - else if (item is long) + + public NameAndTypeConstantHandle Map(NameAndTypeConstantHandle handle) { - index = writer.AddLong((long)item); + return pool.Import(this, handle); } - else if (item is float) + + public MethodHandleConstantHandle Map(MethodHandleConstantHandle handle) { - index = writer.AddFloat((float)item); + return pool.Import(this, handle); } - else if (item is double) + + public MethodTypeConstantHandle Map(MethodTypeConstantHandle handle) { - index = writer.AddDouble((double)item); + return pool.Import(this, handle); } - else if (item is string) + + public DynamicConstantHandle Map(DynamicConstantHandle handle) { - index = writer.AddUtf8((string)item); + return pool.Import(this, handle); } - else + + public InvokeDynamicConstantHandle Map(InvokeDynamicConstantHandle handle) { - throw new IndexOutOfRangeException(); - } - typeAnnotations[pos - 2] = (byte)(index >> 8); - typeAnnotations[pos - 1] = (byte)(index >> 0); - } - - private void FixupAnnotationComponentValueConstantPoolIndexes(ClassFileWriter writer, byte[] typeAnnotations, object[] constantPool, ref int pos) - { - switch ((char)typeAnnotations[pos++]) // tag - { - case 'B': - case 'C': - case 'D': - case 'F': - case 'I': - case 'J': - case 'S': - case 'Z': - case 's': - case 'c': - FixupConstantPoolIndex(writer, typeAnnotations, constantPool, ref pos); - break; - case 'e': - FixupConstantPoolIndex(writer, typeAnnotations, constantPool, ref pos); - FixupConstantPoolIndex(writer, typeAnnotations, constantPool, ref pos); - break; - case '@': - FixupAnnotationConstantPoolIndexes(writer, typeAnnotations, constantPool, ref pos); - break; - case '[': - ushort num_values = ReadUInt16BE(typeAnnotations, ref pos); - for (int i = 0; i < num_values; i++) - { - FixupAnnotationComponentValueConstantPoolIndexes(writer, typeAnnotations, constantPool, ref pos); - } - break; - default: - throw new IndexOutOfRangeException(); + return pool.Import(this, handle); + } + + public ModuleConstantHandle Map(ModuleConstantHandle handle) + { + return pool.Import(this, handle); + } + + public PackageConstantHandle Map(PackageConstantHandle handle) + { + return pool.Import(this, handle); } - } - private ushort ReadUInt16BE(byte[] buf, ref int pos) - { - ushort s = (ushort)((buf[pos] << 8) + buf[pos + 1]); - pos += 2; - return s; } #if !FIRST_PASS && !EXPORTER - private object[] GetAnnotation(CustomAttributeData cad) + + /// + /// Extracts our internal annotation format data from a custom attribute. + /// + /// + /// + object[] GetAnnotation(CustomAttributeData cad) { - if (cad.ConstructorArguments.Count == 1 && cad.ConstructorArguments[0].ArgumentType == typeof(object[]) && - (cad.Constructor.DeclaringType.BaseType == typeof(ikvm.@internal.AnnotationAttributeBase) - || cad.Constructor.DeclaringType == typeof(DynamicAnnotationAttribute))) + // attribute is either a AnnotationAttributeBase or a DynamicAnnotationAttribute with a single object[] in our internal annotation format + if (cad.ConstructorArguments.Count == 1 && cad.ConstructorArguments[0].ArgumentType == typeof(object[]) && (cad.Constructor.DeclaringType.BaseType == typeof(ikvm.@internal.AnnotationAttributeBase) || cad.Constructor.DeclaringType == typeof(DynamicAnnotationAttribute))) { return UnpackArray((IList)cad.ConstructorArguments[0].Value); } - else if (cad.Constructor.DeclaringType.BaseType == typeof(ikvm.@internal.AnnotationAttributeBase)) + + if (cad.Constructor.DeclaringType.BaseType == typeof(ikvm.@internal.AnnotationAttributeBase)) { - string annotationType = GetAnnotationInterface(cad); + var annotationType = GetAnnotationInterface(cad); if (annotationType != null) { // this is a custom attribute annotation applied in a non-Java module - List list = new List(); - list.Add(AnnotationDefaultAttribute.TAG_ANNOTATION); + var list = new List(); + list.Add(IKVM.Attributes.AnnotationDefaultAttribute.TAG_ANNOTATION); list.Add("L" + annotationType.Replace('.', '/') + ";"); - ParameterInfo[] parameters = cad.Constructor.GetParameters(); + + var parameters = cad.Constructor.GetParameters(); for (int i = 0; i < parameters.Length; i++) { list.Add(parameters[i].Name); - list.Add(EncodeAnnotationValue(cad.ConstructorArguments[i])); + list.Add(GetAnnotationValue(cad.ConstructorArguments[i])); } - foreach (CustomAttributeNamedArgument arg in cad.NamedArguments) + + foreach (var arg in cad.NamedArguments) { list.Add(arg.MemberInfo.Name); - list.Add(EncodeAnnotationValue(arg.TypedValue)); + list.Add(GetAnnotationValue(arg.TypedValue)); } + return list.ToArray(); } } + return null; } - private string GetAnnotationInterface(CustomAttributeData cad) + string GetAnnotationInterface(CustomAttributeData cad) { - object[] attr = cad.Constructor.DeclaringType.GetCustomAttributes(typeof(IKVM.Attributes.ImplementsAttribute), false); + var attr = cad.Constructor.DeclaringType.GetCustomAttributes(typeof(IKVM.Attributes.ImplementsAttribute), false); if (attr.Length == 1) { - string[] interfaces = ((IKVM.Attributes.ImplementsAttribute)attr[0]).Interfaces; + var interfaces = ((IKVM.Attributes.ImplementsAttribute)attr[0]).Interfaces; if (interfaces.Length == 1) - { return interfaces[0]; - } } + return null; } - private object EncodeAnnotationValue(CustomAttributeTypedArgument arg) + /// + /// Extract our internal annotation format from a typed argument. + /// + /// + /// + /// + object GetAnnotationValue(CustomAttributeTypedArgument arg) { + // argument is directly an enum, so we encode it as a TAG_ENUM if (arg.ArgumentType.IsEnum) { // if GetWrapperFromType returns null, we've got an ikvmc synthesized .NET enum nested inside a Java enum - RuntimeJavaType tw = context.ClassLoaderFactory.GetJavaTypeFromType(arg.ArgumentType) ?? context.ClassLoaderFactory.GetJavaTypeFromType(arg.ArgumentType.DeclaringType); - return new object[] { AnnotationDefaultAttribute.TAG_ENUM, EncodeTypeName(tw), Enum.GetName(arg.ArgumentType, arg.Value) }; + var tw = context.ClassLoaderFactory.GetJavaTypeFromType(arg.ArgumentType) ?? context.ClassLoaderFactory.GetJavaTypeFromType(arg.ArgumentType.DeclaringType); + return new object[] { IKVM.Attributes.AnnotationDefaultAttribute.TAG_ENUM, EncodeTypeName(tw), Enum.GetName(arg.ArgumentType, arg.Value) }; } - else if (arg.Value is Type) + + // argument is directly a type, so we encode it as a TAG_CLASS + if (arg.Value is Type type) { - return new object[] { AnnotationDefaultAttribute.TAG_CLASS, EncodeTypeName(context.ClassLoaderFactory.GetJavaTypeFromType((Type)arg.Value)) }; + return new object[] { IKVM.Attributes.AnnotationDefaultAttribute.TAG_CLASS, EncodeTypeName(context.ClassLoaderFactory.GetJavaTypeFromType(type)) }; } - else if (arg.ArgumentType.IsArray) + + // argument is directly an array, so we encode it a a TAG_ARRAY + if (arg.ArgumentType.IsArray) { - IList array = (IList)arg.Value; - object[] arr = new object[array.Count + 1]; - arr[0] = AnnotationDefaultAttribute.TAG_ARRAY; + var array = (IList)arg.Value; + var arr = new object[array.Count + 1]; + arr[0] = IKVM.Attributes.AnnotationDefaultAttribute.TAG_ARRAY; for (int i = 0; i < array.Count; i++) + arr[i + 1] = GetAnnotationValue(array[i]); + + return arr; + + } + + return arg.Value; + } + + /// + /// Encodes multiple objects in our internal annotation format. + /// + /// + /// + /// + void EncodeAnnotation(ClassFileBuilder builder, ref AnnotationTableEncoder encoder, object[] annotation) + { + encoder.Annotation(e => + { + e.Annotation(builder.Constants.GetOrAddUtf8((string)annotation[1]), e2 => + { + for (int i = 2; i < annotation.Length; i += 2) + e2.Element(builder.Constants.GetOrAddUtf8((string)annotation[i]), e3 => EncodeElementValue(builder, ref e3, annotation[i + 1])); + }); + }); + } + + void EncodeElementValue(ClassFileBuilder builder, ref ElementValueEncoder encoder, object value) + { + if (value is object[] v) + { + if (((byte)v[0]) == IKVM.Attributes.AnnotationDefaultAttribute.TAG_ENUM) { - arr[i + 1] = EncodeAnnotationValue(array[i]); + encoder.Enum(builder.Constants.GetOrAddUtf8(DecodeTypeName((string)v[1])), builder.Constants.GetOrAddUtf8((string)v[2])); + return; } - return arr; + + if (((byte)v[0]) == IKVM.Attributes.AnnotationDefaultAttribute.TAG_ARRAY) + { + encoder.Array(e => + { + for (int i = 1; i < v.Length; i++) + e.ElementValue(e2 => EncodeElementValue(builder, ref e2, v[i])); + }); + + return; + } + + if (((byte)v[0]) == IKVM.Attributes.AnnotationDefaultAttribute.TAG_CLASS) + { + encoder.Class(builder.Constants.GetOrAddUtf8((string)v[1])); + return; + } + + if (((byte)v[0]) == IKVM.Attributes.AnnotationDefaultAttribute.TAG_ANNOTATION) + { + encoder.Annotation(e => + { + e.Annotation(builder.Constants.GetOrAddUtf8(DecodeTypeName((string)v[1])), e2 => + { + for (int i = 2; i < v.Length; i++) + e2.Element(builder.Constants.GetOrAddUtf8((string)v[i]), e3 => EncodeElementValue(builder, ref e3, v[i + 1])); + }); + }); + + return; + } + + throw new InvalidOperationException(); } - else + + if (value is bool z) + { + encoder.Boolean(builder.Constants.GetOrAddInteger(z ? 1 : 0)); + return; + } + + if (value is byte b) + { + encoder.Byte(builder.Constants.GetOrAddInteger(unchecked((sbyte)b))); + return; + } + + if (value is char c) + { + encoder.Char(builder.Constants.GetOrAddInteger(c)); + return; + } + + if (value is short s) + { + encoder.Short(builder.Constants.GetOrAddInteger(s)); + return; + } + + if (value is int i) + { + encoder.Integer(builder.Constants.GetOrAddInteger(i)); + return; + } + + if (value is long j) + { + encoder.Long(builder.Constants.GetOrAddLong(j)); + return; + } + + if (value is float f) + { + encoder.Float(builder.Constants.GetOrAddFloat(f)); + return; + } + + if (value is double d) + { + encoder.Double(builder.Constants.GetOrAddDouble(d)); + return; + } + + if (value is string S) { - return arg.Value; + encoder.String(builder.Constants.GetOrAddUtf8(S)); + return; } + + throw new InvalidOperationException(); } - private static string EncodeTypeName(RuntimeJavaType tw) + static string EncodeTypeName(RuntimeJavaType tw) { return tw.SigName.Replace('.', '/'); } -#endif - private object[] UnpackArray(IList list) + static string DecodeTypeName(string typeName) { - object[] arr = new object[list.Count]; - for (int i = 0; i < arr.Length; i++) +#if !FIRST_PASS && !EXPORTER + int index = typeName.IndexOf(','); + if (index > 0) { - if (list[i].Value is IList) + // HACK if we have an assembly qualified type name we have to resolve it to a Java class name + // (at the very least we should use the right class loader here) + try { - arr[i] = UnpackArray((IList)list[i].Value); + typeName = "L" + java.lang.Class.forName(typeName.Substring(1, typeName.Length - 2).Replace('/', '.')).getName().Replace('.', '/') + ";"; } - else + catch { - arr[i] = list[i].Value; + } } +#endif + + return typeName; + } + +#endif + + object[] UnpackArray(IList list) + { + var arr = new object[list.Count]; + for (int i = 0; i < arr.Length; i++) + arr[i] = list[i].Value is IList l ? UnpackArray(l) : list[i].Value; + return arr; } - private int GetObsoleteCount(MethodBase mb) + int GetObsoleteCount(MethodBase mb) { #if EXPORTER return mb.__GetCustomAttributes(context.Resolver.ResolveCoreType(typeof(ObsoleteAttribute).FullName), false).Count; @@ -582,309 +1173,334 @@ private int GetObsoleteCount(MethodBase mb) #endif } - private CustomAttributeData GetAnnotationDefault(MethodBase mb) + CustomAttributeData GetAnnotationDefault(MethodBase mb) { #if EXPORTER - IList attr = CustomAttributeData.__GetCustomAttributes(mb, context.Resolver.ResolveRuntimeType(typeof(AnnotationDefaultAttribute).FullName), false); + var attr = CustomAttributeData.__GetCustomAttributes(mb, context.Resolver.ResolveRuntimeType(typeof(Attributes.AnnotationDefaultAttribute).FullName), false); return attr.Count == 1 ? attr[0] : null; #else - foreach (CustomAttributeData cad in CustomAttributeData.GetCustomAttributes(mb)) - { - if (cad.Constructor.DeclaringType == typeof(AnnotationDefaultAttribute)) - { + foreach (var cad in CustomAttributeData.GetCustomAttributes(mb)) + if (cad.Constructor.DeclaringType == typeof(Attributes.AnnotationDefaultAttribute)) return cad; - } - } + return null; #endif } - private string GetAssemblyName(RuntimeJavaType tw) + string GetAssemblyName(RuntimeJavaType tw) { - RuntimeClassLoader loader = tw.GetClassLoader(); - RuntimeAssemblyClassLoader acl = loader as RuntimeAssemblyClassLoader; + var loader = tw.GetClassLoader(); + var acl = loader as RuntimeAssemblyClassLoader; if (acl != null) - { return acl.GetAssembly(tw).FullName; - } else - { return ((RuntimeGenericClassLoader)loader).GetName(); - } } - private bool IsSerializable(RuntimeJavaType tw) + bool IsSerializable(RuntimeJavaType tw) { if (tw.Name == "java.io.Serializable") - { return true; - } + while (tw != null) { - foreach (RuntimeJavaType iface in tw.Interfaces) - { + foreach (var iface in tw.Interfaces) if (IsSerializable(iface)) - { return true; - } - } + tw = tw.BaseTypeWrapper; } + return false; } - private void AddMetaAnnotations(ClassFileWriter writer, RuntimeJavaType tw) + /// + /// Encodes a set of fixed annotations for a type. + /// + /// + /// + /// + /// + bool EncodeAnnotationsForType(ClassFileBuilder builder, ref AnnotationTableEncoder encoder, RuntimeJavaType tw) { - RuntimeManagedJavaType.AttributeAnnotationJavaTypeBase attributeAnnotation = tw as RuntimeManagedJavaType.AttributeAnnotationJavaTypeBase; - if (attributeAnnotation != null) + if (tw is RuntimeManagedJavaType.AttributeAnnotationJavaTypeBase attributeAnnotation) { - // TODO write the annotation directly, instead of going thru the object[] encoding - RuntimeVisibleAnnotationsAttribute annot = new RuntimeVisibleAnnotationsAttribute(writer); - annot.Add(new object[] { - AnnotationDefaultAttribute.TAG_ANNOTATION, - "Ljava/lang/annotation/Retention;", - "value", - new object[] { AnnotationDefaultAttribute.TAG_ENUM, "Ljava/lang/annotation/RetentionPolicy;", "RUNTIME" } - }); - AttributeTargets validOn = attributeAnnotation.AttributeTargets; - List targets = new List(); - targets.Add(AnnotationDefaultAttribute.TAG_ARRAY); + encoder.Annotation( + builder.Constants.GetOrAddUtf8("Ljava/lang/annotation/Retention;"), e => e + .Enum( + builder.Constants.GetOrAddUtf8("value"), + builder.Constants.GetOrAddUtf8("Ljava/lang/annotation/RetentionPolicy;"), + builder.Constants.GetOrAddUtf8("RUNTIME"))); + + var validOn = attributeAnnotation.AttributeTargets; + var elementTypes = new List(); + if ((validOn & (AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Delegate | AttributeTargets.Assembly)) != 0) - { - targets.Add(new object[] { AnnotationDefaultAttribute.TAG_ENUM, "Ljava/lang/annotation/ElementType;", "TYPE" }); - } + elementTypes.Add("TYPE"); + if ((validOn & AttributeTargets.Constructor) != 0) - { - targets.Add(new object[] { AnnotationDefaultAttribute.TAG_ENUM, "Ljava/lang/annotation/ElementType;", "CONSTRUCTOR" }); - } + elementTypes.Add("CONSTRUCTOR"); + if ((validOn & AttributeTargets.Field) != 0) - { - targets.Add(new object[] { AnnotationDefaultAttribute.TAG_ENUM, "Ljava/lang/annotation/ElementType;", "FIELD" }); - } + elementTypes.Add("FIELD"); + if ((validOn & (AttributeTargets.Method | AttributeTargets.ReturnValue)) != 0) - { - targets.Add(new object[] { AnnotationDefaultAttribute.TAG_ENUM, "Ljava/lang/annotation/ElementType;", "METHOD" }); - } + elementTypes.Add("METHOD"); + if ((validOn & AttributeTargets.Parameter) != 0) - { - targets.Add(new object[] { AnnotationDefaultAttribute.TAG_ENUM, "Ljava/lang/annotation/ElementType;", "PARAMETER" }); - } - annot.Add(new object[] { - AnnotationDefaultAttribute.TAG_ANNOTATION, - "Ljava/lang/annotation/Target;", - "value", - targets.ToArray() - }); + elementTypes.Add("PARAMETER"); + + encoder.Annotation( + builder.Constants.GetOrAddUtf8("Ljava/lang/annotation/Target;"), e => e + .Element( + builder.Constants.GetOrAddUtf8("value"), e2 => e2 + .Array(e3 => + { + foreach (var elementType in elementTypes) + e3.Enum(builder.Constants.GetOrAddUtf8("Ljava/lang/annotation/ElementType;"), builder.Constants.GetOrAddUtf8(elementType)); + }))); + if (IsRepeatableAnnotation(tw)) { - annot.Add(new object[] { - AnnotationDefaultAttribute.TAG_ANNOTATION, - "Ljava/lang/annotation/Repeatable;", - "value", - new object[] { AnnotationDefaultAttribute.TAG_CLASS, "L" + (tw.Name + RuntimeManagedJavaType.AttributeAnnotationMultipleSuffix).Replace('.', '/') + ";" } - }); + encoder.Annotation( + builder.Constants.GetOrAddUtf8("Ljava/lang/annotation/Repeatable;"), e => e + .Class( + builder.Constants.GetOrAddUtf8("value"), + builder.Constants.GetOrAddUtf8("L" + (tw.Name + RuntimeManagedJavaType.AttributeAnnotationMultipleSuffix).Replace('.', '/') + ";"))); } - writer.AddAttribute(annot); + + return true; } + + return false; } - private bool IsRepeatableAnnotation(RuntimeJavaType tw) + bool IsRepeatableAnnotation(RuntimeJavaType tw) { - foreach (RuntimeJavaType nested in tw.InnerClasses) - { + foreach (var nested in tw.InnerClasses) if (nested.Name == tw.Name + RuntimeManagedJavaType.AttributeAnnotationMultipleSuffix) - { return true; - } - } + return false; } - private byte[] GetAnnotationDefault(ClassFileWriter classFile, RuntimeJavaType type) + /// + /// Encodes the annotation default value. + /// + /// + /// + /// + void EncodeAnnotationDefault(ClassFileBuilder builder, ref ElementValueEncoder encoder, CustomAttributeTypedArgument value) + { + EncodeElementValue(builder, ref encoder, value); + } + + /// + /// Encodes the element_value on the annotation default. + /// + /// + /// + /// + /// + void EncodeAnnotationDefault(ClassFileBuilder builder, ref ElementValueEncoder encoder, RuntimeJavaType type) { - MemoryStream mem = new MemoryStream(); - BigEndianStream bes = new BigEndianStream(mem); if (type == context.PrimitiveJavaTypeFactory.BOOLEAN) { - bes.WriteByte((byte)'Z'); - bes.WriteUInt16(classFile.AddInt(0)); + encoder.Boolean(builder.Constants.GetOrAddInteger(0)); } else if (type == context.PrimitiveJavaTypeFactory.BYTE) { - bes.WriteByte((byte)'B'); - bes.WriteUInt16(classFile.AddInt(0)); + encoder.Byte(builder.Constants.GetOrAddInteger(0)); } else if (type == context.PrimitiveJavaTypeFactory.CHAR) { - bes.WriteByte((byte)'C'); - bes.WriteUInt16(classFile.AddInt(0)); + encoder.Char(builder.Constants.GetOrAddInteger(0)); } else if (type == context.PrimitiveJavaTypeFactory.SHORT) { - bes.WriteByte((byte)'S'); - bes.WriteUInt16(classFile.AddInt(0)); + encoder.Short(builder.Constants.GetOrAddInteger(0)); } else if (type == context.PrimitiveJavaTypeFactory.INT) { - bes.WriteByte((byte)'I'); - bes.WriteUInt16(classFile.AddInt(0)); + encoder.Integer(builder.Constants.GetOrAddInteger(0)); } else if (type == context.PrimitiveJavaTypeFactory.FLOAT) { - bes.WriteByte((byte)'F'); - bes.WriteUInt16(classFile.AddFloat(0)); + encoder.Float(builder.Constants.GetOrAddFloat(0)); } else if (type == context.PrimitiveJavaTypeFactory.LONG) { - bes.WriteByte((byte)'J'); - bes.WriteUInt16(classFile.AddLong(0)); + encoder.Long(builder.Constants.GetOrAddLong(0)); } else if (type == context.PrimitiveJavaTypeFactory.DOUBLE) { - bes.WriteByte((byte)'D'); - bes.WriteUInt16(classFile.AddDouble(0)); + encoder.Double(builder.Constants.GetOrAddDouble(0)); } else if (type == context.JavaBase.TypeOfJavaLangString) { - bes.WriteByte((byte)'s'); - bes.WriteUInt16(classFile.AddUtf8("")); + encoder.String(builder.Constants.GetOrAddUtf8("")); } else if ((type.Modifiers & Modifiers.Enum) != 0) { - bes.WriteByte((byte)'e'); - bes.WriteUInt16(classFile.AddUtf8("L" + type.Name.Replace('.', '/') + ";")); - bes.WriteUInt16(classFile.AddUtf8("__unspecified")); + encoder.Enum(builder.Constants.GetOrAddUtf8("L" + type.Name.Replace('.', '/') + ";"), builder.Constants.GetOrAddUtf8("__unspecified")); } else if (type == context.JavaBase.TypeOfJavaLangClass) { - bes.WriteByte((byte)'c'); - bes.WriteUInt16(classFile.AddUtf8("Likvm/internal/__unspecified;")); + encoder.Class(builder.Constants.GetOrAddUtf8("Likvm/internal/__unspecified;")); } else if (type.IsArray) { - bes.WriteByte((byte)'['); - bes.WriteUInt16(0); + encoder.Array(e => { }); } else { throw new InvalidOperationException(); } - return mem.ToArray(); } - private byte[] GetAnnotationDefault(ClassFileWriter classFile, CustomAttributeTypedArgument value) + /// + /// Encodes a single element value into an element value table from a . + /// + /// + /// + /// + void EncodeElementValue(ClassFileBuilder builder, ref ElementValueTableEncoder encoder, CustomAttributeTypedArgument value) { - MemoryStream mem = new MemoryStream(); - BigEndianStream bes = new BigEndianStream(mem); - try - { - WriteAnnotationElementValue(classFile, bes, value); - } - catch (InvalidCastException) - { - Warning("Warning: incorrect annotation default value"); - } - catch (IndexOutOfRangeException) - { - Warning("Warning: incorrect annotation default value"); - } - return mem.ToArray(); + encoder.ElementValue(e => EncodeElementValue(builder, ref e, value)); } - private void WriteAnnotationElementValue(ClassFileWriter classFile, BigEndianStream bes, CustomAttributeTypedArgument value) + /// + /// Encodes a single element value into an elmeent value table from a . + /// + /// + /// + /// + void EncodeElementValue(ClassFileBuilder builder, ref ElementValueEncoder encoder, CustomAttributeTypedArgument value) { + // typed argument of bool type holds BOOLEAN if (value.ArgumentType == context.Types.Boolean) { - bes.WriteByte((byte)'Z'); - bes.WriteUInt16(classFile.AddInt((bool)value.Value ? 1 : 0)); + encoder.Boolean(builder.Constants.GetOrAddInteger((bool)value.Value ? 1 : 0)); + return; } - else if (value.ArgumentType == context.Types.Byte) + + // typed argument of byte type holds BYTE + if (value.ArgumentType == context.Types.Byte) { - bes.WriteByte((byte)'B'); - bes.WriteUInt16(classFile.AddInt((byte)value.Value)); + encoder.Byte(builder.Constants.GetOrAddInteger(unchecked((sbyte)(byte)value.Value))); + return; } - else if (value.ArgumentType == context.Types.Char) + + // typed argument of char type holds CHAR + if (value.ArgumentType == context.Types.Char) { - bes.WriteByte((byte)'C'); - bes.WriteUInt16(classFile.AddInt((char)value.Value)); + encoder.Char(builder.Constants.GetOrAddInteger((char)value.Value)); + return; } - else if (value.ArgumentType == context.Types.Int16) + + // typed argument of short type holds SHORT + if (value.ArgumentType == context.Types.Int16) { - bes.WriteByte((byte)'S'); - bes.WriteUInt16(classFile.AddInt((short)value.Value)); + encoder.Short(builder.Constants.GetOrAddInteger((short)value.Value)); + return; } - else if (value.ArgumentType == context.Types.Int32) + + // typed argument of int type holds INTEGER + if (value.ArgumentType == context.Types.Int32) { - bes.WriteByte((byte)'I'); - bes.WriteUInt16(classFile.AddInt((int)value.Value)); + encoder.Integer(builder.Constants.GetOrAddInteger((int)value.Value)); + return; } - else if (value.ArgumentType == context.Types.Single) + + // typed argument of float type holds SINGLE + if (value.ArgumentType == context.Types.Single) { - bes.WriteByte((byte)'F'); - bes.WriteUInt16(classFile.AddFloat((float)value.Value)); + encoder.Float(builder.Constants.GetOrAddFloat((float)value.Value)); + return; } - else if (value.ArgumentType == context.Types.Int64) + + // typed argument of long type holds LONG + if (value.ArgumentType == context.Types.Int64) { - bes.WriteByte((byte)'J'); - bes.WriteUInt16(classFile.AddLong((long)value.Value)); + encoder.Long(builder.Constants.GetOrAddLong((long)value.Value)); + return; } - else if (value.ArgumentType == context.Types.Double) + + // typed argument double type holds DOUBLE + if (value.ArgumentType == context.Types.Double) { - bes.WriteByte((byte)'D'); - bes.WriteUInt16(classFile.AddDouble((double)value.Value)); + encoder.Double(builder.Constants.GetOrAddDouble((double)value.Value)); + return; } - else if (value.ArgumentType == context.Types.String) + + // typed argument of string type holds STRING + if (value.ArgumentType == context.Types.String) { - bes.WriteByte((byte)'s'); - bes.WriteUInt16(classFile.AddUtf8((string)value.Value)); + encoder.String(builder.Constants.GetOrAddUtf8((string)value.Value)); + return; } - else if (value.ArgumentType == context.Types.Object.MakeArrayType()) + + // typed argument of array type holds ARRAY, CLASS, ENUM and ANNOTATION + if (value.ArgumentType == context.Types.Object.MakeArrayType()) { - var array = (IReadOnlyList)value.Value; - byte type = (byte)array[0].Value; - if (type == AnnotationDefaultAttribute.TAG_ARRAY) + // first argument holds type in tag format + var data = (IReadOnlyList)value.Value; + var type = (byte)data[0].Value; + + // tag of ARRAY indicates ARRAY + if (type == IKVM.Attributes.AnnotationDefaultAttribute.TAG_ARRAY) { - bes.WriteByte((byte)'['); - bes.WriteUInt16((ushort)(array.Count - 1)); - for (int i = 1; i < array.Count; i++) + encoder.Array(e => { - WriteAnnotationElementValue(classFile, bes, array[i]); - } + for (int i = 1; i < data.Count; i++) + EncodeElementValue(builder, ref e, data[i]); + }); + + return; } - else if (type == AnnotationDefaultAttribute.TAG_CLASS) + + // tag of CLASS indicates CLASS + if (type == IKVM.Attributes.AnnotationDefaultAttribute.TAG_CLASS) { - bes.WriteByte((byte)'c'); - bes.WriteUInt16(classFile.AddUtf8((string)array[1].Value)); + encoder.Class(builder.Constants.GetOrAddUtf8((string)data[1].Value)); + return; } - else if (type == AnnotationDefaultAttribute.TAG_ENUM) + + // tag of ENUM indicates ENUM + if (type == IKVM.Attributes.AnnotationDefaultAttribute.TAG_ENUM) { - bes.WriteByte((byte)'e'); - bes.WriteUInt16(classFile.AddUtf8((string)array[1].Value)); - bes.WriteUInt16(classFile.AddUtf8((string)array[2].Value)); + encoder.Enum(builder.Constants.GetOrAddUtf8((string)data[1].Value), builder.Constants.GetOrAddUtf8((string)data[2].Value)); + return; } - else if (type == AnnotationDefaultAttribute.TAG_ANNOTATION) + + // tag of ANNOTATION indicates ANNOTATION + if (type == IKVM.Attributes.AnnotationDefaultAttribute.TAG_ANNOTATION) { - bes.WriteByte((byte)'@'); - bes.WriteUInt16(classFile.AddUtf8((string)array[1].Value)); - bes.WriteUInt16((ushort)((array.Count - 2) / 2)); - for (int i = 2; i < array.Count; i += 2) + encoder.Annotation(e => { - bes.WriteUInt16(classFile.AddUtf8((string)array[i].Value)); - WriteAnnotationElementValue(classFile, bes, array[i + 1]); - } - } - else - { - Warning("Warning: incorrect annotation default element tag: " + type); + e.Annotation(builder.Constants.GetOrAddUtf8((string)data[1].Value), e2 => + { + for (int i = 2; i < data.Count; i += 2) + e2.Element(builder.Constants.GetOrAddUtf8((string)data[i].Value), e3 => EncodeElementValue(builder, ref e3, data[i + 1])); + }); + }); + + return; } + + Warning("Warning: incorrect annotation default element tag: " + type); + return; } - else - { - Warning("Warning: incorrect annotation default element type: " + value.ArgumentType); - } + + Warning("Warning: incorrect annotation default element type: " + value.ArgumentType); + return; } - private void Warning(string message) + /// + /// Emits a warning message. + /// + /// + void Warning(string message) { #if EXPORTER Console.Error.WriteLine(message); diff --git a/src/IKVM.Runtime/Vfs/VfsAssemblyClassFile.cs b/src/IKVM.Runtime/Vfs/VfsAssemblyClassFile.cs index f530b4e16a..224a48cdd9 100644 --- a/src/IKVM.Runtime/Vfs/VfsAssemblyClassFile.cs +++ b/src/IKVM.Runtime/Vfs/VfsAssemblyClassFile.cs @@ -38,7 +38,7 @@ byte[] GenerateClassFile() throw new NotImplementedException(); #else var stream = new MemoryStream(); - Context.Context.StubGenerator.WriteClass(stream, type, true, true, true, true, false); + Context.Context.StubGenerator.Write(stream, type, true, true, true, true, false); return stream.ToArray(); #endif } diff --git a/src/IKVM.Tests/Java/java/lang/ByteTests.cs b/src/IKVM.Tests/Java/java/lang/ByteTests.cs new file mode 100644 index 0000000000..648bfa4a16 --- /dev/null +++ b/src/IKVM.Tests/Java/java/lang/ByteTests.cs @@ -0,0 +1,78 @@ +using System.IO; +using System.Linq; + +using FluentAssertions; + +using IKVM.ByteCode; +using IKVM.ByteCode.Decoding; + +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace IKVM.Tests.Java.java.lang +{ + + [TestClass] + public class ByteTests + { + + [TestMethod] + public void TestMinMax() + { + unchecked((sbyte)global::java.lang.Byte.MIN_VALUE).Should().Be(-128); + unchecked((sbyte)global::java.lang.Byte.MAX_VALUE).Should().Be(127); + } + + [TestMethod] + public void TestMinMaxReflection() + { + ((sbyte)((global::java.lang.Class)typeof(global::java.lang.Byte)).getField("MIN_VALUE").getByte(null)).Should().Be(-128); + ((sbyte)((global::java.lang.Class)typeof(global::java.lang.Byte)).getField("MAX_VALUE").getByte(null)).Should().Be(127); + } + + [TestMethod] + public void TestStubFile() + { + using var res = ((global::java.lang.Class)typeof(global::java.lang.Byte)).getResourceAsStream("Byte.class"); + var mem = new MemoryStream(); + var buf = new byte[1024]; + var len = 0; + while ((len = res.read(buf)) > 0) + mem.Write(buf, 0, len); + + mem.Position = 0; + + using var cls = ClassFile.Read(mem); + + foreach (var field in cls.Fields) + { + if (cls.Constants.Get(field.Name).Value == "MIN_VALUE") + { + field.AccessFlags.Should().HaveFlag(AccessFlag.Static); + field.AccessFlags.Should().HaveFlag(AccessFlag.Final); + cls.Constants.Get(field.Descriptor).Value.Should().Be("B"); + var c = field.Attributes.First(i => cls.Constants.Get(i.Name).Value == AttributeName.ConstantValue); + var h = ((ConstantValueAttribute)c).Value; + var z = cls.Constants.Get(h); + z.Kind.Should().Be(ConstantKind.Integer); + ((IntegerConstant)z).Value.Should().Be(-128); + continue; + } + + if (cls.Constants.Get(field.Name).Value == "MAX_VALUE") + { + field.AccessFlags.Should().HaveFlag(AccessFlag.Static); + field.AccessFlags.Should().HaveFlag(AccessFlag.Final); + cls.Constants.Get(field.Descriptor).Value.Should().Be("B"); + var c = field.Attributes.First(i => cls.Constants.Get(i.Name).Value == AttributeName.ConstantValue); + var h = ((ConstantValueAttribute)c).Value; + var z = cls.Constants.Get(h); + z.Kind.Should().Be(ConstantKind.Integer); + ((IntegerConstant)z).Value.Should().Be(127); + continue; + } + } + } + + } + +} diff --git a/src/IKVM.Tools.Exporter/IkvmExporterInternal.cs b/src/IKVM.Tools.Exporter/IkvmExporterInternal.cs index b4fbf8bb7f..5c183d22fb 100644 --- a/src/IKVM.Tools.Exporter/IkvmExporterInternal.cs +++ b/src/IKVM.Tools.Exporter/IkvmExporterInternal.cs @@ -387,7 +387,7 @@ static void WriteClass(IkvmExporterOptions options, RuntimeJavaType tw) entry.LastWriteTime = new DateTime(1980, 01, 01, 0, 0, 0, DateTimeKind.Utc); using Stream stream = entry.Open(); - tw.Context.StubGenerator.WriteClass(stream, tw, options.IncludeNonPublicTypes, options.IncludeNonPublicInterfaces, options.IncludeNonPublicMembers, options.IncludeParameterNames, options.SerialVersionUID); + tw.Context.StubGenerator.Write(stream, tw, options.IncludeNonPublicTypes, options.IncludeNonPublicInterfaces, options.IncludeNonPublicMembers, options.IncludeParameterNames, options.SerialVersionUID); } static bool ExportNamespace(IList namespaces, Type type) diff --git a/src/IKVM.Util/IKVM.Util.csproj b/src/IKVM.Util/IKVM.Util.csproj index 4b20341d19..795ca12928 100644 --- a/src/IKVM.Util/IKVM.Util.csproj +++ b/src/IKVM.Util/IKVM.Util.csproj @@ -8,7 +8,7 @@ - +