diff options
Diffstat (limited to 'ikvmstub')
-rw-r--r-- | ikvmstub/ClassFileWriter.cs | 927 | ||||
-rw-r--r-- | ikvmstub/FakeClassLibrary.cs | 121 | ||||
-rw-r--r-- | ikvmstub/SerialVersionUID.cs | 181 | ||||
-rw-r--r-- | ikvmstub/ikvmstub.8.csproj | 48 | ||||
-rw-r--r-- | ikvmstub/ikvmstub.build | 26 | ||||
-rw-r--r-- | ikvmstub/ikvmstub.cs | 617 |
6 files changed, 1767 insertions, 153 deletions
diff --git a/ikvmstub/ClassFileWriter.cs b/ikvmstub/ClassFileWriter.cs new file mode 100644 index 00000000..197746ac --- /dev/null +++ b/ikvmstub/ClassFileWriter.cs @@ -0,0 +1,927 @@ +/* + Copyright (C) 2002 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; +using IKVM.Attributes; + +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 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); + } + } + + enum Constant + { + Utf8 = 1, + Integer = 3, + Float = 4, + Long = 5, + Double = 6, + Class = 7, + String = 8, + Fieldref = 9, + Methodref = 10, + InterfaceMethodref = 11, + NameAndType = 12 + } + + abstract class ConstantPoolItem + { + public abstract void Write(BigEndianStream bes); + } + + 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); + } + } + + 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); + } + } + + 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); + } + } + + 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); + } + } + + 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); + } + } + + 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); + } + } + + 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); + } + } + + 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); + } + } + + 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); + } + } + + 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); + } + } + + sealed class DeprecatedAttribute : ClassFileAttribute + { + internal DeprecatedAttribute(ClassFileWriter classFile) + : base(classFile.AddUtf8("Deprecated")) + { + } + + public override void Write(BigEndianStream bes) + { + base.Write(bes); + bes.WriteUInt32(0); + } + } + + 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); + } + } + + 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); + } + } + + sealed class InnerClassesAttribute : ClassFileAttribute + { + private ClassFileWriter classFile; + private ArrayList classes = new ArrayList(); + + 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); + } + } + + sealed class ExceptionsAttribute : ClassFileAttribute + { + private ClassFileWriter classFile; + private ArrayList classes = new ArrayList(); + + 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); + } + } + } + + 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 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((string)arr[1])); + bes.WriteUInt16(classFile.AddUtf8((string)arr[2])); + return; + } + else if (AnnotationDefaultAttribute.TAG_ARRAY.Equals(arr[0])) + { + bes.WriteByte(AnnotationDefaultAttribute.TAG_ARRAY); + object[] elemarr = (object[])arr[1]; + bes.WriteUInt16((ushort)elemarr.Length); + foreach (object elem in elemarr) + { + WriteElementValue(bes, elem); + } + return; + } + } + throw new NotImplementedException(val.GetType().FullName); + } + + public override void Write(BigEndianStream bes) + { + base.Write(bes); + bes.WriteUInt32((uint)(mem.Length + 2)); + bes.WriteUInt16(count); + foreach (byte b in mem.ToArray()) + { + bes.WriteByte(b); + } + } + } + + 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); + } + } + } + + sealed class FieldOrMethod + { + private Modifiers access_flags; + private ushort name_index; + private ushort descriptor_index; + private ArrayList attribs = new ArrayList(); + + 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++) + { + ((ClassFileAttribute)attribs[i]).Write(bes); + } + } + } + + 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 + } + } + + sealed class ClassFileWriter + { + private ArrayList cplist = new ArrayList(); + private Hashtable cphashtable = new Hashtable(); + private ArrayList fields = new ArrayList(); + private ArrayList methods = new ArrayList(); + private ArrayList attribs = new ArrayList(); + private ArrayList interfaces = new ArrayList(); + private Modifiers access_flags; + private ushort this_class; + private ushort super_class; + private ushort minorVersion; + private 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) + { + object index = cphashtable[cpi]; + if (index == null) + { + index = (ushort)cplist.Add(cpi); + if (cpi is ConstantPoolItemDouble || cpi is ConstantPoolItemLong) + { + cplist.Add(null); + } + cphashtable[cpi] = index; + } + return (ushort)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); + for (int i = 1; i < cplist.Count; i++) + { + ConstantPoolItem cpi = (ConstantPoolItem)cplist[i]; + 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((ushort)interfaces[i]); + } + // fields count + bes.WriteUInt16((ushort)fields.Count); + for (int i = 0; i < fields.Count; i++) + { + ((FieldOrMethod)fields[i]).Write(bes); + } + // methods count + bes.WriteUInt16((ushort)methods.Count); + for (int i = 0; i < methods.Count; i++) + { + ((FieldOrMethod)methods[i]).Write(bes); + } + // attributes count + bes.WriteUInt16((ushort)attribs.Count); + for (int i = 0; i < attribs.Count; i++) + { + ((ClassFileAttribute)attribs[i]).Write(bes); + } + } + } +} diff --git a/ikvmstub/FakeClassLibrary.cs b/ikvmstub/FakeClassLibrary.cs new file mode 100644 index 00000000..7eef5f0f --- /dev/null +++ b/ikvmstub/FakeClassLibrary.cs @@ -0,0 +1,121 @@ +/* + 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; +using System.Collections.Generic; +using System.Text; +using IKVM.Attributes; + +[module: JavaModule] +[assembly: RemappedClass("java.lang.Object", typeof(object))] +[assembly: RemappedClass("java.lang.Throwable", typeof(Exception))] +[assembly: RemappedClass("java.lang.String", typeof(string))] +[assembly: RemappedClass("java.lang.Comparable", typeof(IComparable))] + +namespace java.lang +{ + [RemappedType(typeof(object))] + public abstract class Object + { + public abstract int hashCode(); + public abstract bool equals(object obj); + protected abstract object clone(); + public abstract string toString(); + protected abstract void finalize(); + } + + [RemappedType(typeof(Exception))] + public abstract class Throwable : Exception + { + // object methods + public abstract int hashCode(); + public abstract bool equals(object obj); + protected abstract object clone(); + public abstract string toString(); + protected abstract void finalize(); + + // throwable methods + public abstract string getMessage(); + public abstract string getLocalizedMessage(); + public abstract Throwable getCause(); + public abstract Throwable initCause(Throwable cause); + public abstract void printStackTrace(); + public abstract void printStackTrace(java.io.PrintStream s); + public abstract void printStackTrace(java.io.PrintWriter s); + public abstract Throwable fillInStackTrace(); + public abstract StackTraceElement[] getStackTrace(); + public abstract void setStackTrace(StackTraceElement[] stackTrace); + } + + [RemappedType(typeof(string))] + public class String + { + } + + [RemappedType(typeof(IComparable))] + public interface Comparable : IComparable + { + } + + public class Class + { + } + + public interface CharSequence + { + } + + public interface Cloneable + { + } + + public class Enum + { + } + + public class StackTraceElement + { + } + + namespace annotation + { + public interface Annotation + { + } + } +} + +namespace java.io +{ + public interface Serializable + { + } + + public class PrintStream + { + } + + public class PrintWriter + { + } +} diff --git a/ikvmstub/SerialVersionUID.cs b/ikvmstub/SerialVersionUID.cs new file mode 100644 index 00000000..255a0ff8 --- /dev/null +++ b/ikvmstub/SerialVersionUID.cs @@ -0,0 +1,181 @@ +/* + 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; +using System.Collections.Generic; +using System.IO; +using System.Text; +using IKVM.Attributes; +using IKVM.Internal; +using Type = IKVM.Reflection.Type; + +namespace IKVM.StubGen +{ + static class SerialVersionUID + { + private readonly static System.Security.Cryptography.SHA1Managed sha1 = new System.Security.Cryptography.SHA1Managed(); + + internal static long Compute(TypeWrapper tw) + { + MemoryStream mem = new MemoryStream(); + BigEndianStream 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); + byte[] buf = sha1.ComputeHash(mem.ToArray()); + long hash = 0; + for (int i = 7; i >= 0; i--) + { + hash <<= 8; + hash |= buf[i]; + } + return hash; + } + + private static void WriteClassName(BigEndianStream bes, TypeWrapper tw) + { + bes.WriteUtf8(tw.Name); + } + + private static void WriteModifiers(BigEndianStream bes, TypeWrapper tw) + { + Modifiers mods = tw.ReflectiveModifiers & (Modifiers.Public | Modifiers.Final | Modifiers.Interface | Modifiers.Abstract); + if ((mods & Modifiers.Interface) != 0) + { + mods &= ~Modifiers.Abstract; + if (HasJavaMethods(tw)) + { + mods |= Modifiers.Abstract; + } + } + bes.WriteUInt32((uint)mods); + } + + private static bool HasJavaMethods(TypeWrapper tw) + { + foreach (MethodWrapper mw in tw.GetMethods()) + { + if (!mw.IsHideFromReflection && mw.Name != StringConstants.CLINIT) + { + return true; + } + } + return false; + } + + private static void WriteInterfaces(BigEndianStream bes, TypeWrapper tw) + { + TypeWrapper[] interfaces = (TypeWrapper[])tw.Interfaces.Clone(); + Array.Sort(interfaces, delegate(TypeWrapper tw1, TypeWrapper tw2) { return String.CompareOrdinal(tw1.Name, tw2.Name); }); + foreach (TypeWrapper iface in interfaces) + { + bes.WriteUtf8(iface.Name); + } + } + + private static void WriteFields(BigEndianStream bes, TypeWrapper tw) + { + List<FieldWrapper> list = new List<FieldWrapper>(); + foreach (FieldWrapper fw in tw.GetFields()) + { + if (!fw.IsHideFromReflection) + { + list.Add(fw); + } + } + list.Sort(delegate(FieldWrapper fw1, FieldWrapper fw2) { return String.CompareOrdinal(fw1.Name, fw2.Name); }); + foreach (FieldWrapper fw in list) + { + Modifiers 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('.', '/')); + } + } + } + + private static void WriteStaticInitializer(BigEndianStream bes, TypeWrapper tw) + { + Type type = tw.TypeAsTBD; + if (!type.IsArray && type.TypeInitializer != null) + { + if (!AttributeHelper.IsHideFromJava(type.TypeInitializer)) + { + bes.WriteUtf8("<clinit>"); + bes.WriteUInt32((uint)Modifiers.Static); + bes.WriteUtf8("()V"); + } + } + } + + private static void WriteConstructors(BigEndianStream bes, TypeWrapper tw) + { + List<MethodWrapper> list = new List<MethodWrapper>(); + foreach (MethodWrapper mw in tw.GetMethods()) + { + if (mw.Name == StringConstants.INIT && !mw.IsHideFromReflection && !mw.IsPrivate) + { + list.Add(mw); + } + } + list.Sort(delegate(MethodWrapper mw1, MethodWrapper mw2) { return String.CompareOrdinal(mw1.Signature, mw2.Signature); }); + foreach (MethodWrapper mw in list) + { + Modifiers mods = mw.Modifiers & (Modifiers.Public | Modifiers.Private | Modifiers.Protected | Modifiers.Static | Modifiers.Final | Modifiers.Synchronized | Modifiers.Native | Modifiers.Abstract | Modifiers.Strictfp); + bes.WriteUtf8(mw.Name); + bes.WriteUInt32((uint)mods); + bes.WriteUtf8(mw.Signature); + } + } + + private static void WriteMethods(BigEndianStream bes, TypeWrapper tw) + { + List<MethodWrapper> list = new List<MethodWrapper>(); + foreach (MethodWrapper mw in tw.GetMethods()) + { + if (mw.Name != StringConstants.INIT && !mw.IsHideFromReflection && !mw.IsPrivate) + { + list.Add(mw); + } + } + list.Sort(delegate(MethodWrapper mw1, MethodWrapper mw2) { + if (mw1.Name == mw2.Name) + return String.CompareOrdinal(mw1.Signature, mw2.Signature); + return String.CompareOrdinal(mw1.Name, mw2.Name); + }); + foreach (MethodWrapper mw in list) + { + Modifiers mods = mw.Modifiers & (Modifiers.Public | Modifiers.Private | Modifiers.Protected | Modifiers.Static | Modifiers.Final | Modifiers.Synchronized | Modifiers.Native | Modifiers.Abstract | Modifiers.Strictfp); + bes.WriteUtf8(mw.Name); + bes.WriteUInt32((uint)mods); + bes.WriteUtf8(mw.Signature); + } + } + } +} diff --git a/ikvmstub/ikvmstub.8.csproj b/ikvmstub/ikvmstub.8.csproj index 3d13dac0..5b8be175 100644 --- a/ikvmstub/ikvmstub.8.csproj +++ b/ikvmstub/ikvmstub.8.csproj @@ -36,7 +36,7 @@ <CheckForOverflowUnderflow>false</CheckForOverflowUnderflow> <ConfigurationOverrideFile> </ConfigurationOverrideFile> - <DefineConstants>TRACE;DEBUG;WHIDBEY</DefineConstants> + <DefineConstants>TRACE;DEBUG;IKVM_REF_EMIT;STUB_GENERATOR</DefineConstants> <DocumentationFile> </DocumentationFile> <DebugSymbols>true</DebugSymbols> @@ -53,13 +53,9 @@ <ErrorReport>prompt</ErrorReport> </PropertyGroup> <ItemGroup> - <Reference Include="IKVM.OpenJDK.Core, Version=0.39.3280.0, Culture=neutral, processorArchitecture=MSIL"> + <Reference Include="ICSharpCode.SharpZipLib, Version=0.84.0.0, Culture=neutral, PublicKeyToken=1b03e6acf1164f73"> <SpecificVersion>False</SpecificVersion> - <HintPath>..\bin\IKVM.OpenJDK.Core.dll</HintPath> - </Reference> - <Reference Include="IKVM.OpenJDK.Util, Version=0.39.3280.0, Culture=neutral, processorArchitecture=MSIL"> - <SpecificVersion>False</SpecificVersion> - <HintPath>..\bin\IKVM.OpenJDK.Util.dll</HintPath> + <HintPath>..\bin\ICSharpCode.SharpZipLib.dll</HintPath> </Reference> <Reference Include="System"> <Name>System</Name> @@ -72,14 +68,46 @@ <Compile Include="AssemblyInfo.cs"> <SubType>Code</SubType> </Compile> + <Compile Include="ClassFileWriter.cs" /> + <Compile Include="FakeClassLibrary.cs" /> <Compile Include="ikvmstub.cs"> <SubType>Code</SubType> </Compile> + <Compile Include="..\runtime\AssemblyClassLoader.cs" /> + <Compile Include="..\runtime\attributes.cs"> + <SubType>Code</SubType> + </Compile> + <Compile Include="..\runtime\ClassLoaderWrapper.cs"> + <SubType>Code</SubType> + </Compile> + <Compile Include="..\runtime\CoreClasses.cs"> + <SubType>Code</SubType> + </Compile> + <Compile Include="..\runtime\DotNetTypeWrapper.cs" /> + <Compile Include="..\runtime\JavaException.cs"> + <SubType>Code</SubType> + </Compile> + <Compile Include="..\runtime\MemberWrapper.cs"> + <SubType>Code</SubType> + </Compile> + <Compile Include="..\runtime\profiler.cs"> + <SubType>Code</SubType> + </Compile> + <Compile Include="..\runtime\ReflectUtil.cs" /> + <Compile Include="..\runtime\tracer.cs" /> + <Compile Include="..\runtime\Types.cs" /> + <Compile Include="..\runtime\TypeWrapper.cs"> + <SubType>Code</SubType> + </Compile> + <Compile Include="..\runtime\vm.cs"> + <SubType>Code</SubType> + </Compile> + <Compile Include="SerialVersionUID.cs" /> </ItemGroup> <ItemGroup> - <ProjectReference Include="..\runtime\IKVM.Runtime.8.csproj"> - <Project>{F5C7B588-0403-4AF2-A4DE-5697DE21BC2C}</Project> - <Name>IKVM.Runtime.8</Name> + <ProjectReference Include="..\reflect\IKVM.Reflection.csproj"> + <Project>{4CB170EF-DFE6-4A56-9E1B-A85449E827A7}</Project> + <Name>IKVM.Reflection</Name> </ProjectReference> </ItemGroup> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> diff --git a/ikvmstub/ikvmstub.build b/ikvmstub/ikvmstub.build index 9210bceb..969b52a9 100644 --- a/ikvmstub/ikvmstub.build +++ b/ikvmstub/ikvmstub.build @@ -1,19 +1,35 @@ <?xml version="1.0"?> <project name="ikvmstub" default="ikvmstub"> <target name="ikvmstub"> - <property name="defs" value="TRACE" /> + <property name="defs" value="STUB_GENERATOR;IKVM_REF_EMIT;TRACE" /> <if test="${property::exists('signed')}"> <property name="defs" value="${defs};${signed}" /> </if> <csc target="exe" output="../bin/ikvmstub.exe" define="${defs}"> <sources> <include name="../CommonAssemblyInfo.cs" /> - <include name="*.cs" /> + <include name="../runtime/AssemblyClassLoader.cs" /> + <include name="../runtime/attributes.cs" /> + <include name="../runtime/ClassLoaderWrapper.cs" /> + <include name="../runtime/CoreClasses.cs" /> + <include name="../runtime/DotNetTypeWrapper.cs" /> + <include name="../runtime/JavaException.cs" /> + <include name="../runtime/MemberWrapper.cs" /> + <include name="../runtime/profiler.cs" /> + <include name="../runtime/ReflectUtil.cs" /> + <include name="../runtime/tracer.cs" /> + <include name="../runtime/Types.cs" /> + <include name="../runtime/TypeWrapper.cs" /> + <include name="../runtime/vm.cs" /> + <include name="AssemblyInfo.cs" /> + <include name="ClassFileWriter.cs" /> + <include name="FakeClassLibrary.cs" /> + <include name="ikvmstub.cs" /> + <include name="SerialVersionUID.cs" /> </sources> <references> - <include name="../bin/IKVM.OpenJDK.Core.dll" asis="true" /> - <include name="../bin/IKVM.OpenJDK.Util.dll" asis="true" /> - <include name="../bin/IKVM.Runtime.dll" asis="true" /> + <include name="../bin/ICSharpCode.SharpZipLib.dll" asis="true" /> + <include name="../bin/IKVM.Reflection.dll" asis="true" /> </references> </csc> </target> diff --git a/ikvmstub/ikvmstub.cs b/ikvmstub/ikvmstub.cs index 80ea6b9a..7c10c5ab 100644 --- a/ikvmstub/ikvmstub.cs +++ b/ikvmstub/ikvmstub.cs @@ -1,5 +1,5 @@ /* - Copyright (C) 2002-2009 Jeroen Frijters + Copyright (C) 2002-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 @@ -22,25 +22,29 @@ */ using System; -using System.Reflection; using System.IO; using System.Collections.Generic; -using java.util.zip; -using java.lang.reflect; +using ICSharpCode.SharpZipLib.Zip; +using IKVM.Attributes; +using IKVM.Internal; +using IKVM.Reflection; +using Type = IKVM.Reflection.Type; +using ResolveEventArgs = IKVM.Reflection.ResolveEventArgs; +using ResolveEventHandler = IKVM.Reflection.ResolveEventHandler; -public class NetExp +static class NetExp { private static int zipCount; private static ZipOutputStream zipFile; - private static Dictionary<string, NetExp> done = new Dictionary<string, NetExp>(); - private static Dictionary<string, java.lang.Class> todo = new Dictionary<string, java.lang.Class>(); + private static Dictionary<string, string> done = new Dictionary<string, string>(); + private static Dictionary<string, TypeWrapper> todo = new Dictionary<string, TypeWrapper>(); private static FileInfo file; + private static bool includeSerialVersionUID; - public static int Main(string[] args) + static int Main(string[] args) { IKVM.Internal.Tracer.EnableTraceConsoleListener(); IKVM.Internal.Tracer.EnableTraceForDebug(); - java.lang.System.setProperty("ikvm.stubgen.skipNonPublicInterfaces", "true"); string assemblyNameOrPath = null; bool continueOnError = false; bool autoLoadSharedClassLoaderAssemblies = false; @@ -50,7 +54,7 @@ public class NetExp { if(s == "-serialver") { - java.lang.System.setProperty("ikvm.stubgen.serialver", "true"); + includeSerialVersionUID = true; } else if(s == "-skiperror") { @@ -65,7 +69,7 @@ public class NetExp string path = s.Substring(s.IndexOf(':') + 1); try { - Assembly.ReflectionOnlyLoadFrom(path); + StaticCompiler.Universe.LoadFile(path); } catch (Exception x) { @@ -88,7 +92,7 @@ public class NetExp } if(assemblyNameOrPath == null) { - Console.Error.WriteLine(ikvm.runtime.Startup.getVersionAndCopyrightInfo()); + Console.Error.WriteLine(GetVersionAndCopyrightInfo()); Console.Error.WriteLine(); Console.Error.WriteLine("usage: ikvmstub [-serialver] [-skiperror] <assemblyNameOrPath>"); return 1; @@ -105,15 +109,19 @@ public class NetExp } if(file != null && file.Exists) { - AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += new ResolveEventHandler(CurrentDomain_ReflectionOnlyAssemblyResolve); - assembly = Assembly.ReflectionOnlyLoadFrom(assemblyNameOrPath); + StaticCompiler.Universe.AssemblyResolve += new ResolveEventHandler(Universe_AssemblyResolve); + assembly = StaticCompiler.LoadFile(assemblyNameOrPath); } else { #pragma warning disable 618 // Assembly.LoadWithPartialName is obsolete - assembly = Assembly.LoadWithPartialName(assemblyNameOrPath); + System.Reflection.Assembly asm = System.Reflection.Assembly.LoadWithPartialName(assemblyNameOrPath); #pragma warning restore + if (asm != null) + { + assembly = StaticCompiler.Universe.LoadFile(asm.Location); + } } int rc = 0; if(assembly == null) @@ -122,15 +130,16 @@ public class NetExp } else { - if (assembly.ReflectionOnly && IsJavaModule(assembly.ManifestModule)) + if (assembly.ReflectionOnly && AttributeHelper.IsJavaModule(assembly.ManifestModule)) { Console.Error.WriteLine("Warning: Running ikvmstub on ikvmc compiled assemblies is not supported."); } try { - using (zipFile = new ZipOutputStream(new java.io.FileOutputStream(assembly.GetName().Name + ".jar"))) + JVM.CoreAssembly = StaticCompiler.Universe.Import(typeof(NetExp)).Assembly; + using (zipFile = new ZipOutputStream(new FileStream(assembly.GetName().Name + ".jar", FileMode.Create))) { - zipFile.setComment(ikvm.runtime.Startup.getVersionAndCopyrightInfo()); + zipFile.SetComment(GetVersionAndCopyrightInfo()); try { List<Assembly> assemblies = new List<Assembly>(); @@ -151,18 +160,13 @@ public class NetExp } } } - catch (ReflectionTypeLoadException x) + catch (TypeLoadException x) { Console.WriteLine(x); - Console.WriteLine("LoaderExceptions:"); - foreach (Exception n in x.LoaderExceptions) - { - Console.WriteLine(n); - } } catch (System.Exception x) { - java.lang.Throwable.instancehelper_printStackTrace(ikvm.runtime.Util.mapException(x)); + Console.WriteLine(x); if (!continueOnError) { @@ -189,16 +193,23 @@ public class NetExp return rc; } - private static bool IsJavaModule(Module module) + private static string GetVersionAndCopyrightInfo() { - foreach (CustomAttributeData cad in CustomAttributeData.GetCustomAttributes(module)) + System.Reflection.Assembly asm = System.Reflection.Assembly.GetEntryAssembly(); + object[] desc = asm.GetCustomAttributes(typeof(System.Reflection.AssemblyTitleAttribute), false); + if (desc.Length == 1) { - if (cad.Constructor.DeclaringType.FullName == "IKVM.Attributes.JavaModuleAttribute") + object[] copyright = asm.GetCustomAttributes(typeof(System.Reflection.AssemblyCopyrightAttribute), false); + if (copyright.Length == 1) { - return true; + return string.Format("{0} version {1}{2}{3}{2}http://www.ikvm.net/", + ((System.Reflection.AssemblyTitleAttribute)desc[0]).Title, + asm.GetName().Version, + Environment.NewLine, + ((System.Reflection.AssemblyCopyrightAttribute)copyright[0]).Copyright); } } - return false; + return ""; } private static void LoadSharedClassLoaderAssemblies(Assembly assembly, List<Assembly> assemblies) @@ -213,7 +224,7 @@ public class NetExp int assemblyCount = rdr.ReadInt32(); for (int i = 0; i < assemblyCount; i++) { - AssemblyName name = new AssemblyName(rdr.ReadString()); + string name = rdr.ReadString(); int typeCount = rdr.ReadInt32(); if (typeCount > 0) { @@ -223,11 +234,11 @@ public class NetExp } try { - assemblies.Add(Assembly.Load(name)); + assemblies.Add(StaticCompiler.Load(name)); } catch { - Console.WriteLine("Warning: Unable to load shared class loader assembly: {0}", name.Name); + Console.WriteLine("Warning: Unable to load shared class loader assembly: {0}", name); } } } @@ -235,71 +246,366 @@ public class NetExp } } - private static Assembly CurrentDomain_ReflectionOnlyAssemblyResolve(object sender, ResolveEventArgs args) + private static Assembly Universe_AssemblyResolve(object sender, ResolveEventArgs args) { - foreach(Assembly a in AppDomain.CurrentDomain.ReflectionOnlyGetAssemblies()) - { - if(args.Name.StartsWith(a.GetName().Name + ", ")) - { - return a; - } - } string path = args.Name; int index = path.IndexOf(','); - if(index > 0) + if (index > 0) { path = path.Substring(0, index); } path = file.DirectoryName + Path.DirectorySeparatorChar + path + ".dll"; - if(File.Exists(path)) + if (File.Exists(path)) + { + return StaticCompiler.LoadFile(path); + } + try + { + return StaticCompiler.LoadFile(System.Reflection.Assembly.Load(args.Name).Location); + } + catch { - return Assembly.ReflectionOnlyLoadFrom(path); } - return Assembly.ReflectionOnlyLoad(args.Name); + return null; } - private static void WriteClass(java.lang.Class c) + private static void WriteClass(TypeWrapper tw) { - string name = c.getName().Replace('.', '/'); - java.io.InputStream inp = c.getResourceAsStream("/" + name + ".class"); - if(inp == null) + string name = tw.Name.Replace('.', '/'); + string super = null; + if (tw.IsInterface) + { + super = "java/lang/Object"; + } + else if (tw.BaseTypeWrapper != null) + { + super = tw.BaseTypeWrapper.Name.Replace('.', '/'); + } + IKVM.StubGen.ClassFileWriter writer = new IKVM.StubGen.ClassFileWriter(tw.Modifiers, name, super, 0, 49); + foreach (TypeWrapper iface in tw.Interfaces) { - Console.Error.WriteLine("Class {0} not found", name); - return; + if (iface.IsPublic) + { + writer.AddInterface(iface.Name.Replace('.', '/')); + } } - byte[] buf = new byte[inp.available()]; - if(inp.read(buf) != buf.Length || inp.read() != -1) + IKVM.StubGen.InnerClassesAttribute innerClassesAttribute = null; + if (tw.DeclaringTypeWrapper != null) { - throw new NotImplementedException(); + TypeWrapper outer = tw.DeclaringTypeWrapper; + string innername = name; + int idx = name.LastIndexOf('$'); + if (idx >= 0) + { + innername = innername.Substring(idx + 1); + } + innerClassesAttribute = new IKVM.StubGen.InnerClassesAttribute(writer); + innerClassesAttribute.Add(name, outer.Name.Replace('.', '/'), innername, (ushort)tw.ReflectiveModifiers); } + foreach (TypeWrapper inner in tw.InnerClasses) + { + if (inner.IsPublic) + { + if (innerClassesAttribute == null) + { + innerClassesAttribute = new IKVM.StubGen.InnerClassesAttribute(writer); + } + string namePart = inner.Name; + namePart = namePart.Substring(namePart.LastIndexOf('$') + 1); + innerClassesAttribute.Add(inner.Name.Replace('.', '/'), name, namePart, (ushort)inner.ReflectiveModifiers); + } + } + if (innerClassesAttribute != null) + { + writer.AddAttribute(innerClassesAttribute); + } + string genericTypeSignature = tw.GetGenericSignature(); + if (genericTypeSignature != null) + { + writer.AddStringAttribute("Signature", genericTypeSignature); + } + writer.AddStringAttribute("IKVM.NET.Assembly", GetAssemblyName(tw)); + if (tw.TypeAsBaseType.IsDefined(StaticCompiler.Universe.Import(typeof(ObsoleteAttribute)), false)) + { + writer.AddAttribute(new IKVM.StubGen.DeprecatedAttribute(writer)); + } + foreach (MethodWrapper mw in tw.GetMethods()) + { + if (!mw.IsHideFromReflection && (mw.IsPublic || mw.IsProtected)) + { + IKVM.StubGen.FieldOrMethod m; + if (mw.Name == "<init>") + { + m = writer.AddMethod(mw.Modifiers, mw.Name, mw.Signature.Replace('.', '/')); + IKVM.StubGen.CodeAttribute code = new IKVM.StubGen.CodeAttribute(writer); + code.MaxLocals = (ushort)(mw.GetParameters().Length * 2 + 1); + code.MaxStack = 3; + ushort index1 = writer.AddClass("java/lang/UnsatisfiedLinkError"); + ushort index2 = writer.AddString("ikvmstub generated stubs can only be used on IKVM.NET"); + ushort index3 = writer.AddMethodRef("java/lang/UnsatisfiedLinkError", "<init>", "(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 + { + m = writer.AddMethod(mw.Modifiers | Modifiers.Native, mw.Name, mw.Signature.Replace('.', '/')); + if (mw.IsOptionalAttributeAnnotationValue) + { + m.AddAttribute(new IKVM.StubGen.AnnotationDefaultClassFileAttribute(writer, GetAnnotationDefault(writer, mw.ReturnType))); + } + } + MethodBase mb = mw.GetMethod(); + if (mb != null) + { + ThrowsAttribute throws = AttributeHelper.GetThrows(mb); + if (throws != null) + { + IKVM.StubGen.ExceptionsAttribute attrib = new IKVM.StubGen.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(ex.FullName.Replace('.', '/')); + } + } + m.AddAttribute(attrib); + } + if (mb.IsDefined(StaticCompiler.Universe.Import(typeof(ObsoleteAttribute)), false)) + { + m.AddAttribute(new IKVM.StubGen.DeprecatedAttribute(writer)); + } + } + string sig = tw.GetGenericMethodSignature(mw); + if (sig != null) + { + m.AddAttribute(writer.MakeStringAttribute("Signature", sig)); + } + } + } + bool hasSerialVersionUID = false; + foreach (FieldWrapper fw in tw.GetFields()) + { + if (!fw.IsHideFromReflection) + { + bool isSerialVersionUID = includeSerialVersionUID && fw.Name == "serialVersionUID" && fw.FieldTypeWrapper == PrimitiveTypeWrapper.LONG; + hasSerialVersionUID |= isSerialVersionUID; + if (fw.IsPublic || fw.IsProtected || isSerialVersionUID) + { + object constant = null; + if (fw.GetField() != null && fw.GetField().IsLiteral && (fw.FieldTypeWrapper.IsPrimitive || fw.FieldTypeWrapper == CoreClasses.java.lang.String.Wrapper)) + { + constant = fw.GetField().GetRawConstantValue(); + if (fw.GetField().FieldType.IsEnum) + { + constant = EnumHelper.GetPrimitiveValue(EnumHelper.GetUnderlyingType(fw.GetField().FieldType), constant); + } + } + IKVM.StubGen.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(StaticCompiler.Universe.Import(typeof(ObsoleteAttribute)), false)) + { + f.AddAttribute(new IKVM.StubGen.DeprecatedAttribute(writer)); + } + } + } + } + if (includeSerialVersionUID && !hasSerialVersionUID && IsSerializable(tw)) + { + // 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", IKVM.StubGen.SerialVersionUID.Compute(tw)); + } + AddMetaAnnotations(writer, tw); zipCount++; - zipFile.putNextEntry(new ZipEntry(name + ".class")); - zipFile.write(buf, 0, buf.Length); + zipFile.PutNextEntry(new ZipEntry(name + ".class")); + writer.Write(zipFile); + } + + private static string GetAssemblyName(TypeWrapper tw) + { + ClassLoaderWrapper loader = tw.GetClassLoader(); + AssemblyClassLoader acl = loader as AssemblyClassLoader; + if (acl != null) + { + return acl.GetAssembly(tw).FullName; + } + else + { + return ((GenericClassLoader)loader).GetName(); + } + } + + private static bool IsSerializable(TypeWrapper tw) + { + if (tw.Name == "java.io.Serializable") + { + return true; + } + while (tw != null) + { + foreach (TypeWrapper iface in tw.Interfaces) + { + if (IsSerializable(iface)) + { + return true; + } + } + tw = tw.BaseTypeWrapper; + } + return false; + } + + private static void AddMetaAnnotations(IKVM.StubGen.ClassFileWriter writer, TypeWrapper tw) + { + DotNetTypeWrapper.AttributeAnnotationTypeWrapperBase attributeAnnotation = tw as DotNetTypeWrapper.AttributeAnnotationTypeWrapperBase; + if (attributeAnnotation != null) + { + // TODO write the annotation directly, instead of going thru the object[] encoding + IKVM.StubGen.RuntimeVisibleAnnotationsAttribute annot = new IKVM.StubGen.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<object[]> targets = new List<object[]>(); + 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" }); + } + if ((validOn & AttributeTargets.Constructor) != 0) + { + targets.Add(new object[] { AnnotationDefaultAttribute.TAG_ENUM, "Ljava/lang/annotation/ElementType;", "CONSTRUCTOR" }); + } + if ((validOn & AttributeTargets.Field) != 0) + { + targets.Add(new object[] { AnnotationDefaultAttribute.TAG_ENUM, "Ljava/lang/annotation/ElementType;", "FIELD" }); + } + if ((validOn & (AttributeTargets.Method | AttributeTargets.ReturnValue)) != 0) + { + targets.Add(new object[] { AnnotationDefaultAttribute.TAG_ENUM, "Ljava/lang/annotation/ElementType;", "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", + new object[] { AnnotationDefaultAttribute.TAG_ARRAY, targets.ToArray() } + }); + writer.AddAttribute(annot); + } + } + + private static byte[] GetAnnotationDefault(IKVM.StubGen.ClassFileWriter classFile, TypeWrapper type) + { + MemoryStream mem = new MemoryStream(); + IKVM.StubGen.BigEndianStream bes = new IKVM.StubGen.BigEndianStream(mem); + if (type == PrimitiveTypeWrapper.BOOLEAN) + { + bes.WriteByte((byte)'Z'); + bes.WriteUInt16(0); + } + else if(type == PrimitiveTypeWrapper.BYTE) + { + bes.WriteByte((byte)'B'); + bes.WriteUInt16(classFile.AddInt(0)); + } + else if(type == PrimitiveTypeWrapper.CHAR) + { + bes.WriteByte((byte)'C'); + bes.WriteUInt16(classFile.AddInt(0)); + } + else if(type == PrimitiveTypeWrapper.SHORT) + { + bes.WriteByte((byte)'S'); + bes.WriteUInt16(classFile.AddInt(0)); + } + else if(type == PrimitiveTypeWrapper.INT) + { + bes.WriteByte((byte)'I'); + bes.WriteUInt16(classFile.AddInt(0)); + } + else if(type == PrimitiveTypeWrapper.FLOAT) + { + bes.WriteByte((byte)'F'); + bes.WriteUInt16(classFile.AddFloat(0)); + } + else if(type == PrimitiveTypeWrapper.LONG) + { + bes.WriteByte((byte)'J'); + bes.WriteUInt16(classFile.AddLong(0)); + } + else if (type == PrimitiveTypeWrapper.DOUBLE) + { + bes.WriteByte((byte)'D'); + bes.WriteUInt16(classFile.AddDouble(0)); + } + else if (type == CoreClasses.java.lang.String.Wrapper) + { + bes.WriteByte((byte)'s'); + bes.WriteUInt16(classFile.AddUtf8("")); + } + else if ((type.Modifiers & Modifiers.Enum) != 0) + { + bes.WriteByte((byte)'e'); + bes.WriteUInt16(classFile.AddUtf8("L" + type.Name.Replace('.', '/') + ";")); + bes.WriteUInt16(classFile.AddUtf8("__unspecified")); + } + else if (type == CoreClasses.java.lang.Class.Wrapper) + { + bes.WriteByte((byte)'c'); + bes.WriteUInt16(classFile.AddUtf8("Likvm/internal/__unspecified;")); + } + else if (type.IsArray) + { + bes.WriteByte((byte)'['); + bes.WriteUInt16(0); + } + else + { + throw new InvalidOperationException(); + } + return mem.ToArray(); } private static int ProcessAssembly(Assembly assembly, bool continueOnError) { int rc = 0; - foreach(System.Type t in assembly.GetTypes()) + foreach (Type t in assembly.GetTypes()) { - if(t.IsPublic) + if (t.IsPublic && !AttributeHelper.IsHideFromJava(t) && (!t.IsGenericType || !AttributeHelper.IsJavaModule(t.Module))) { - java.lang.Class c; - // NOTE we use getClassFromTypeHandle instead of getFriendlyClassFromType, to make sure - // we don't get the remapped types when we're processing System.Object, System.String, - // System.Throwable and System.IComparable. - // NOTE we can't use getClassFromTypeHandle for ReflectionOnly assemblies - // (because Type.TypeHandle is not supported by ReflectionOnly types), but this - // isn't a problem because mscorlib is never loaded in the ReflectionOnly context. - if(assembly.ReflectionOnly) + TypeWrapper c; + if (ClassLoaderWrapper.IsRemappedType(t) || t.IsPrimitive || t == Types.Void) { - c = ikvm.runtime.Util.getFriendlyClassFromType(t); + c = DotNetTypeWrapper.GetWrapperFromDotNetType(t); } else { - c = ikvm.runtime.Util.getClassFromTypeHandle(t.TypeHandle); + c = ClassLoaderWrapper.GetWrapperFromType(t); } - if(c != null) + if (c != null) { AddToExportList(c); } @@ -309,12 +615,12 @@ public class NetExp do { keepGoing = false; - foreach(java.lang.Class c in new List<java.lang.Class>(todo.Values)) + foreach (TypeWrapper c in new List<TypeWrapper>(todo.Values)) { - if(!done.ContainsKey(c.getName())) + if(!done.ContainsKey(c.Name)) { keepGoing = true; - done.Add(c.getName(), null); + done.Add(c.Name, null); try { @@ -325,7 +631,7 @@ public class NetExp if (continueOnError) { rc = 1; - java.lang.Throwable.instancehelper_printStackTrace(ikvm.runtime.Util.mapException(x)); + Console.WriteLine(x); } else { @@ -339,109 +645,144 @@ public class NetExp return rc; } - private static void AddToExportList(java.lang.Class c) + private static void AddToExportList(TypeWrapper c) { - while(c.isArray()) - { - c = c.getComponentType(); - } - todo[c.getName()] = c; + todo[c.Name] = c; } - private static bool IsGenericType(java.lang.Class c) + private static bool IsNonVectorArray(TypeWrapper tw) { - System.Type t = ikvm.runtime.Util.getInstanceTypeFromClass(c); - while(t == null && c.getDeclaringClass() != null) - { - // dynamic only inner class, so we look at the declaring class - c = c.getDeclaringClass(); - t = ikvm.runtime.Util.getInstanceTypeFromClass(c); - } - return t.IsGenericType; + return !tw.IsArray && tw.TypeAsBaseType.IsArray; } - private static bool IsNonVectorArray(java.lang.Class c) + private static void AddToExportListIfNeeded(TypeWrapper tw) { - System.Type t = ikvm.runtime.Util.getInstanceTypeFromClass(c); - return t.IsArray && !c.isArray(); - } - - private static void AddToExportListIfNeeded(java.lang.reflect.Type type) - { - java.lang.Class c = type as java.lang.Class; - if (c != null) - { - if (IsGenericType(c) || IsNonVectorArray(c) || (c.getModifiers() & Modifier.PUBLIC) == 0) - { - AddToExportList(c); - } - } - // we only handle ParameterizedType, because that is the only one needed for rt.jar - // (because javax.swing.tree.DefaultTreeSelectionModel has a protected method with a parameter - // of type Vector<javax.swing.tree.PathPlaceHolder> where javax.swing.tree.PathPlaceHolder is a package private class) - java.lang.reflect.ParameterizedType pt = type as java.lang.reflect.ParameterizedType; - if (pt != null) + if ((tw.TypeAsTBD != null && tw.TypeAsTBD.IsGenericType) || IsNonVectorArray(tw) || !tw.IsPublic) { - AddToExportListIfNeeded(pt.getActualTypeArguments()); + AddToExportList(tw); } } - private static void AddToExportListIfNeeded(java.lang.reflect.Type[] classes) + private static void AddToExportListIfNeeded(TypeWrapper[] types) { - foreach(java.lang.reflect.Type c in classes) + foreach (TypeWrapper tw in types) { - AddToExportListIfNeeded(c); + AddToExportListIfNeeded(tw); } } - private static void ProcessClass(java.lang.Class c) + private static void ProcessClass(TypeWrapper tw) { - java.lang.Class superclass = c.getSuperclass(); - if(superclass != null) - { - AddToExportListIfNeeded(c.getGenericSuperclass()); - } - foreach(java.lang.reflect.Type iface in c.getGenericInterfaces()) + TypeWrapper superclass = tw.BaseTypeWrapper; + if (superclass != null) { - AddToExportListIfNeeded(iface); + AddToExportListIfNeeded(superclass); } - java.lang.Class outerClass = c.getDeclaringClass(); - if(outerClass != null) + AddToExportListIfNeeded(tw.Interfaces); + TypeWrapper outerClass = tw.DeclaringTypeWrapper; + if (outerClass != null) { AddToExportList(outerClass); } - foreach(java.lang.Class innerClass in c.getDeclaredClasses()) + foreach (TypeWrapper innerClass in tw.InnerClasses) { - int mods = innerClass.getModifiers(); - if((mods & (Modifier.PUBLIC | Modifier.PROTECTED)) != 0) + if (innerClass.IsPublic) { AddToExportList(innerClass); } } - foreach(Constructor constructor in c.getDeclaredConstructors()) + foreach (MethodWrapper mw in tw.GetMethods()) { - int mods = constructor.getModifiers(); - if((mods & (Modifier.PUBLIC | Modifier.PROTECTED)) != 0) + if (mw.IsPublic || mw.IsProtected) { - AddToExportListIfNeeded(constructor.getGenericParameterTypes()); + AddToExportListIfNeeded(mw.ReturnType); + AddToExportListIfNeeded(mw.GetParameters()); } } - foreach(Method method in c.getDeclaredMethods()) + foreach (FieldWrapper fw in tw.GetFields()) { - int mods = method.getModifiers(); - if((mods & (Modifier.PUBLIC | Modifier.PROTECTED)) != 0) + if (fw.IsPublic || fw.IsProtected) { - AddToExportListIfNeeded(method.getGenericParameterTypes()); - AddToExportListIfNeeded(method.getGenericReturnType()); + AddToExportListIfNeeded(fw.FieldTypeWrapper); } } - foreach(Field field in c.getDeclaredFields()) + } +} + +static class Intrinsics +{ + internal static bool IsIntrinsic(MethodWrapper methodWrapper) + { + return false; + } +} + +static class StaticCompiler +{ + internal static readonly Universe Universe = new Universe(); + private static Assembly runtimeAssembly; + + internal static Type GetRuntimeType(string typeName) + { + if (runtimeAssembly == null) { - int mods = field.getModifiers(); - if((mods & (Modifier.PUBLIC | Modifier.PROTECTED)) != 0) + runtimeAssembly = Universe.Import(typeof(NetExp)).Assembly; + } + return runtimeAssembly.GetType(typeName, true); + } + + internal static Assembly LoadFile(string fileName) + { + if (AssemblyName.GetAssemblyName(fileName).Name == "mscorlib") + { + try { - AddToExportListIfNeeded(field.getGenericType()); + Universe.LoadMscorlib(fileName); } + catch { } } + return Universe.LoadFile(fileName); + } + + internal static Assembly Load(string name) + { + return Universe.Load(name); + } +} + +static class FakeTypes +{ + private static readonly Type genericType; + + class Holder<T> { } + + static FakeTypes() + { + genericType = StaticCompiler.Universe.Import(typeof(Holder<>)); + } + + internal static Type GetAttributeType(Type type) + { + return genericType.MakeGenericType(type); + } + + internal static Type GetAttributeReturnValueType(Type type) + { + return genericType.MakeGenericType(type); + } + + internal static Type GetAttributeMultipleType(Type type) + { + return genericType.MakeGenericType(type); + } + + internal static Type GetDelegateType(Type type) + { + return genericType.MakeGenericType(type); + } + + internal static Type GetEnumType(Type type) + { + return genericType.MakeGenericType(type); } } |