diff --git a/IK.VM.NET/ClassFile.cs b/IK.VM.NET/ClassFile.cs index 960afd39..0b983131 100644 --- a/IK.VM.NET/ClassFile.cs +++ b/IK.VM.NET/ClassFile.cs @@ -484,11 +484,11 @@ class ClassFile } } - internal string NetExpTypeAttribute + internal string NetExpAssemblyAttribute { get { - Attribute attr = GetAttribute("IK.VM.NET.Type"); + Attribute attr = GetAttribute("IKVM.NET.Assembly"); if(attr != null) { return ((ConstantPoolItemUtf8)GetConstantPoolItem(attr.Data.ReadUInt16())).Value; diff --git a/IK.VM.NET/ClassLoaderWrapper.cs b/IK.VM.NET/ClassLoaderWrapper.cs index b12b19f7..7fc8c285 100644 --- a/IK.VM.NET/ClassLoaderWrapper.cs +++ b/IK.VM.NET/ClassLoaderWrapper.cs @@ -126,7 +126,7 @@ class ClassLoaderWrapper this.javaClassLoader = javaClassLoader; if(javaClassLoader != null && loadClassDelegate == null) { - loadClassDelegate = (LoadClassDelegate)Delegate.CreateDelegate(typeof(LoadClassDelegate), GetType("java.lang.VMClass"), "__loadClassHelper"); + loadClassDelegate = (LoadClassDelegate)Delegate.CreateDelegate(typeof(LoadClassDelegate), GetType("java.lang.VMClass"), "loadClassHelper"); } } @@ -141,6 +141,11 @@ class ClassLoaderWrapper return (TypeWrapper[])((ArrayList)ghosts[wrapper.Name]).ToArray(typeof(TypeWrapper)); } + internal static bool IsRemappedType(Type type) + { + return typeToTypeWrapper[type] is RemappedTypeWrapper; + } + internal void LoadRemappedTypes() { nativeMethods = new Hashtable(); @@ -161,7 +166,9 @@ class ClassLoaderWrapper baseWrapper = null; } TypeWrapper tw = new RemappedTypeWrapper(this, modifiers, name, type, new TypeWrapper[0], baseWrapper); + Debug.Assert(!types.ContainsKey(name)); types.Add(name, tw); + Debug.Assert(!typeToTypeWrapper.ContainsKey(tw.Type)); typeToTypeWrapper.Add(tw.Type, tw); } // find the ghost interfaces @@ -301,16 +308,44 @@ class ClassLoaderWrapper Type t = Type.GetType(name); if(t != null) { - return GetCompiledTypeWrapper(t); + if(t.Assembly.IsDefined(typeof(JavaAssemblyAttribute), false)) + { + return GetWrapperFromType(t); + } + else + { + // HACK weird way to load the .NET type wrapper that always works + // (for remapped types as well, because netexp uses this way of + // loading types, we need the remapped types to appear in their + // .NET "warped" form). + return LoadClassByDottedName(DotNetTypeWrapper.GetName(t)); + } } } + // TODO why is this check here and not at the top of the method? if(name != "") { - type = GetBootstrapType(name); - } - if(type != null) - { - return type; + Type t = GetBootstrapTypeRaw(name); + if(t != null) + { + return GetWrapperFromBootstrapType(t); + } + type = DotNetTypeWrapper.LoadDotNetTypeWrapper(name); + if(type != null) + { + Debug.Assert(type.Name == name, type.Name + " != " + name); + Debug.Assert(!types.ContainsKey(name), name); + types.Add(name, type); + return type; + } + // NOTE it is important that this is done last, because otherwise we will + // load the netexp generated fake types (e.g. delegate inner interface) instead + // of having DotNetTypeWrapper generating it. + type = GetTypeWrapperCompilerHook(name); + if(type != null) + { + return type; + } } if(javaClassLoader == null) { @@ -347,34 +382,45 @@ class ClassLoaderWrapper } } - private TypeWrapper GetCompiledTypeWrapper(Type type) + private TypeWrapper GetWrapperFromBootstrapType(Type type) { - TypeWrapper.AssertFinished(type); + Debug.Assert(GetWrapperFromTypeFast(type) == null); + Debug.Assert(!type.IsArray); + Debug.Assert(!(type.Assembly is AssemblyBuilder)); // only the bootstrap classloader can own compiled types Debug.Assert(this == GetBootstrapClassLoader()); - string name = NativeCode.java.lang.VMClass.getName(type); - TypeWrapper wrapper = (TypeWrapper)types[name]; - if(wrapper == null) + TypeWrapper wrapper = null; + if(type.Assembly.IsDefined(typeof(JavaAssemblyAttribute), false)) { - wrapper = new CompiledTypeWrapper(name, type); - types.Add(name, wrapper); - typeToTypeWrapper[type] = wrapper; - } - else if(wrapper is RemappedTypeWrapper) - { - // When remapped types are loaded by their original name (e.g. System.Object) - // we end up here, and we make a CompiledTypeWrapper for it that reflects on - // the original type (note that you can never encounter these types anywhere, - // except when explicitly loaded with Class.forName) - name = type.FullName; + string name = CompiledTypeWrapper.GetName(type); wrapper = (TypeWrapper)types[name]; if(wrapper == null) { - // TODO instead of using CompiledTypeWrapper here, we probably should - // have a subclass that converts all instance methods to static methods (and - // makes the class appear final with only a private constructor) + // since this type was compiled from Java source, we have to look for our + // attributes wrapper = new CompiledTypeWrapper(name, type); - types.Add(name, wrapper); + Debug.Assert(wrapper.Name == name); + Debug.Assert(!types.ContainsKey(wrapper.Name), wrapper.Name); + types.Add(wrapper.Name, wrapper); + Debug.Assert(!typeToTypeWrapper.ContainsKey(type)); + typeToTypeWrapper.Add(type, wrapper); + } + } + else + { + string name = DotNetTypeWrapper.GetName(type); + wrapper = (TypeWrapper)types[name]; + if(wrapper == null) + { + // since this type was not compiled from Java source, we don't need to + // look for our attributes, but we do need to filter unrepresentable + // stuff (and transform some other stuff) + wrapper = new DotNetTypeWrapper(type); + Debug.Assert(wrapper.Name == name); + Debug.Assert(!types.ContainsKey(wrapper.Name), wrapper.Name); + types.Add(wrapper.Name, wrapper); + Debug.Assert(!typeToTypeWrapper.ContainsKey(type)); + typeToTypeWrapper.Add(type, wrapper); } } return wrapper; @@ -398,18 +444,11 @@ class ClassLoaderWrapper return t; } } - // HACK we also try mscorlib and this assembly (for the remapped types) - // TODO this should be fixed by making the map.xml type names for .NET types assembly qualified - return Type.GetType(name); + return null; } - internal virtual TypeWrapper GetBootstrapType(string name) + internal virtual TypeWrapper GetTypeWrapperCompilerHook(string name) { - Type t = GetBootstrapTypeRaw(name); - if(t != null) - { - return GetCompiledTypeWrapper(t); - } return null; } @@ -454,10 +493,12 @@ class ClassLoaderWrapper modifiers |= Modifiers.Public; } wrapper = new ArrayTypeWrapper(array, modifiers, name, this); + Debug.Assert(!types.ContainsKey(name)); types.Add(name, wrapper); if(!(elementType is TypeBuilder)) { - typeToTypeWrapper[array] = wrapper; + Debug.Assert(!typeToTypeWrapper.ContainsKey(array)); + typeToTypeWrapper.Add(array, wrapper); } } return wrapper; @@ -510,14 +551,24 @@ class ClassLoaderWrapper { throw JavaException.IncompatibleClassChangeError("Class {0} has interface {1} as superclass", f.Name, baseType.Name); } - string dotnetType = f.NetExpTypeAttribute; - if(dotnetType != null) + string dotnetAssembly = f.NetExpAssemblyAttribute; + if(dotnetAssembly != null) { - type = new NetExpTypeWrapper(f, dotnetType, baseType); + // The sole purpose of the netexp class is to let us load the assembly that the class lives in, + // once we've done that, all types in it become visible. + Assembly.Load(dotnetAssembly); + types.Remove(f.Name); + type = GetBootstrapClassLoader().LoadClassByDottedNameFast(f.Name); + if(type == null) + { + throw JavaException.NoClassDefFoundError("{0} (loaded through NetExp class)", f.Name); + } + return type; } else { type = new DynamicTypeWrapper(f, this, nativeMethods); + Debug.Assert(!dynamicTypes.ContainsKey(type.Type.FullName)); dynamicTypes.Add(type.Type.FullName, type); } Debug.Assert(types[f.Name] == null); @@ -856,7 +907,8 @@ class ClassLoaderWrapper // if we found it, store it in the map if(wrapper != null) { - typeToTypeWrapper[type] = wrapper; + Debug.Assert(!typeToTypeWrapper.ContainsKey(type)); + typeToTypeWrapper.Add(type, wrapper); } } return wrapper; @@ -880,58 +932,14 @@ class ClassLoaderWrapper } wrapper = GetWrapperFromType(elem); // HACK this is a lame way of creating the array wrapper - if(wrapper.IsPrimitive) - { - string elemType; - if(wrapper == PrimitiveTypeWrapper.BYTE) - { - elemType = "B"; - } - else if(wrapper == PrimitiveTypeWrapper.BOOLEAN) - { - elemType = "Z"; - } - else if(wrapper == PrimitiveTypeWrapper.SHORT) - { - elemType = "S"; - } - else if(wrapper == PrimitiveTypeWrapper.CHAR) - { - elemType = "C"; - } - else if(wrapper == PrimitiveTypeWrapper.INT) - { - elemType = "I"; - } - else if(wrapper == PrimitiveTypeWrapper.LONG) - { - elemType = "J"; - } - else if(wrapper == PrimitiveTypeWrapper.FLOAT) - { - elemType = "F"; - } - else if(wrapper == PrimitiveTypeWrapper.DOUBLE) - { - elemType = "D"; - } - else - { - throw new InvalidOperationException(); - } - return wrapper.GetClassLoader().LoadClassByDottedName(new String('[', rank) + elemType); - } - else - { - return wrapper.GetClassLoader().LoadClassByDottedName(new String('[', rank) + "L" + wrapper.Name + ";"); - } + return wrapper.GetClassLoader().LoadClassByDottedName(new String('[', rank) + wrapper.SigName); } // if the wrapper doesn't already exist, that must mean that the type // is a .NET type (or a pre-compiled Java class), which means that it // was "loaded" by the bootstrap classloader // TODO think up a scheme to deal with .NET types that have the same name. Since all .NET types // appear in the boostrap classloader, we need to devise a scheme to mangle the class name - return GetBootstrapClassLoader().GetCompiledTypeWrapper(type); + return GetBootstrapClassLoader().GetWrapperFromBootstrapType(type); } return wrapper; } @@ -939,6 +947,7 @@ class ClassLoaderWrapper internal static void SetWrapperForType(Type type, TypeWrapper wrapper) { TypeWrapper.AssertFinished(type); + Debug.Assert(!typeToTypeWrapper.ContainsKey(type)); typeToTypeWrapper.Add(type, wrapper); } diff --git a/IK.VM.NET/CodeEmitter.cs b/IK.VM.NET/CodeEmitter.cs index 45e15ba9..3efcb776 100644 --- a/IK.VM.NET/CodeEmitter.cs +++ b/IK.VM.NET/CodeEmitter.cs @@ -151,7 +151,7 @@ public abstract class CodeEmitter { return new CodeEmitter.OpCodeEmitter(OpCodes.Ldnull); } - else if(constant is int || constant is uint || + else if(constant is int || constant is short || constant is ushort || constant is byte || constant is sbyte || constant is char || @@ -159,6 +159,10 @@ public abstract class CodeEmitter { return CodeEmitter.Create(OpCodes.Ldc_I4, ((IConvertible)constant).ToInt32(null)); } + else if(constant is uint) + { + return CodeEmitter.Create(OpCodes.Ldc_I4, unchecked((int)((IConvertible)constant).ToUInt32(null))); + } else if(constant is string) { return CodeEmitter.Create(OpCodes.Ldstr, (string)constant); @@ -171,17 +175,29 @@ public abstract class CodeEmitter { return CodeEmitter.Create(OpCodes.Ldc_R8, (double)constant); } - else if(constant is long || constant is ulong) + else if(constant is long) { return CodeEmitter.Create(OpCodes.Ldc_I8, (long)constant); } + else if(constant is ulong) + { + return CodeEmitter.Create(OpCodes.Ldc_I8, unchecked((long)(ulong)constant)); + } else if(constant is Enum) { Type underlying = Enum.GetUnderlyingType(constant.GetType()); - if(underlying == typeof(long) || underlying == typeof(ulong)) + if(underlying == typeof(long)) { return CodeEmitter.Create(OpCodes.Ldc_I8, ((IConvertible)constant).ToInt64(null)); } + if(underlying == typeof(ulong)) + { + return CodeEmitter.Create(OpCodes.Ldc_I8, unchecked((long)((IConvertible)constant).ToUInt64(null))); + } + else if(underlying == typeof(uint)) + { + return CodeEmitter.Create(OpCodes.Ldc_I4, unchecked((int)((IConvertible)constant).ToUInt32(null))); + } else { return CodeEmitter.Create(OpCodes.Ldc_I4, ((IConvertible)constant).ToInt32(null)); diff --git a/IK.VM.NET/MemberWrapper.cs b/IK.VM.NET/MemberWrapper.cs index 90099fbb..a6e393a2 100644 --- a/IK.VM.NET/MemberWrapper.cs +++ b/IK.VM.NET/MemberWrapper.cs @@ -531,8 +531,9 @@ sealed class FieldWrapper : MemberWrapper internal readonly CodeEmitter EmitSet; private FieldInfo field; private TypeWrapper fieldType; + private static System.Collections.Hashtable warnOnce; - private FieldWrapper(TypeWrapper declaringType, TypeWrapper fieldType, string name, string sig, Modifiers modifiers, CodeEmitter emitGet, CodeEmitter emitSet) + private FieldWrapper(TypeWrapper declaringType, TypeWrapper fieldType, string name, string sig, Modifiers modifiers, FieldInfo field, CodeEmitter emitGet, CodeEmitter emitSet) : base(declaringType, modifiers, false) { Debug.Assert(fieldType != null); @@ -543,10 +544,48 @@ sealed class FieldWrapper : MemberWrapper this.name = name; this.sig = sig; this.fieldType = fieldType; + this.field = field; this.EmitGet = emitGet; this.EmitSet = emitSet; } + // HACK used (indirectly thru NativeCode.java.lang.Field.getConstant) by netexp to find out if the + // field is a constant (and if it is its value) + internal object GetConstant() + { + // NOTE only pritimives and string can be literals in Java (because the other "primitives" (like uint), + // are treated as NonPrimitiveValueTypes) + TypeWrapper java_lang_String = ClassLoaderWrapper.GetBootstrapClassLoader().LoadClassByDottedName("java.lang.String"); + if(field != null && (fieldType.IsPrimitive || fieldType == java_lang_String) && field.IsLiteral) + { + // NOTE .NET BUG this causes the type initializer to run and we don't want that. + // TODO may need to find a workaround, for now we just spit out a warning (only shows up during netexp) + if(field.DeclaringType.TypeInitializer != null) + { + // HACK lame way to support a command line switch to suppress this warning + if(Environment.CommandLine.IndexOf("-noTypeInitWarning") == -1) + { + if(warnOnce == null) + { + warnOnce = new System.Collections.Hashtable(); + } + if(!warnOnce.ContainsKey(field.DeclaringType.FullName)) + { + warnOnce.Add(field.DeclaringType.FullName, null); + Console.WriteLine("Warning: Running type initializer for {0} due to .NET bug", field.DeclaringType.FullName); + } + } + } + object val = field.GetValue(null); + if(val != null && !(val is string)) + { + return NativeCode.java.lang.reflect.JavaWrapper.Box(val); + } + return val; + } + return null; + } + internal static FieldWrapper FromCookie(IntPtr cookie) { return (FieldWrapper)FromCookieImpl(cookie); @@ -679,9 +718,9 @@ sealed class FieldWrapper : MemberWrapper } } - internal static FieldWrapper Create(TypeWrapper declaringType, TypeWrapper fieldType, string name, string sig, Modifiers modifiers, CodeEmitter getter, CodeEmitter setter) + internal static FieldWrapper Create(TypeWrapper declaringType, TypeWrapper fieldType, string name, string sig, Modifiers modifiers, FieldInfo fi, CodeEmitter getter, CodeEmitter setter) { - return new FieldWrapper(declaringType, fieldType, name, sig, modifiers, getter, setter); + return new FieldWrapper(declaringType, fieldType, name, sig, modifiers, fi, getter, setter); } internal static FieldWrapper Create(TypeWrapper declaringType, TypeWrapper fieldType, FieldInfo fi, string sig, Modifiers modifiers) @@ -697,7 +736,7 @@ sealed class FieldWrapper : MemberWrapper { emitGet += CodeEmitter.NoClassDefFoundError(fieldType.Name); emitSet += CodeEmitter.NoClassDefFoundError(fieldType.Name); - return new FieldWrapper(declaringType, fieldType, fi.Name, sig, modifiers, emitGet, emitSet); + return new FieldWrapper(declaringType, fieldType, fi.Name, sig, modifiers, fi, emitGet, emitSet); } if(fieldType.IsNonPrimitiveValueType) { @@ -712,7 +751,7 @@ sealed class FieldWrapper : MemberWrapper // TODO shouldn't we use += here (for volatile fields inside of value types)? emitGet = new VolatileLongDoubleGetter(fi); emitSet = new VolatileLongDoubleSetter(fi); - return new FieldWrapper(declaringType, fieldType, fi.Name, sig, modifiers, emitGet, emitSet); + return new FieldWrapper(declaringType, fieldType, fi.Name, sig, modifiers, fi, emitGet, emitSet); } emitGet += CodeEmitter.Volatile; emitSet += CodeEmitter.Volatile; @@ -731,7 +770,7 @@ sealed class FieldWrapper : MemberWrapper { emitGet += CodeEmitter.Create(OpCodes.Box, fieldType.Type); } - return new FieldWrapper(declaringType, fieldType, fi.Name, sig, modifiers, emitGet, emitSet); + return new FieldWrapper(declaringType, fieldType, fi.Name, sig, modifiers, fi, emitGet, emitSet); } private void LookupField() @@ -751,7 +790,7 @@ sealed class FieldWrapper : MemberWrapper internal void SetValue(object obj, object val) { // TODO this is a broken implementation (for one thing, it needs to support redirection) - if(field == null) + if(field == null || field is FieldBuilder) { LookupField(); } @@ -761,7 +800,7 @@ sealed class FieldWrapper : MemberWrapper internal object GetValue(object obj) { // TODO this is a broken implementation (for one thing, it needs to support redirection) - if(field == null) + if(field == null || field is FieldBuilder) { LookupField(); } diff --git a/IK.VM.NET/TypeWrapper.cs b/IK.VM.NET/TypeWrapper.cs index a77fbea5..01217c29 100644 --- a/IK.VM.NET/TypeWrapper.cs +++ b/IK.VM.NET/TypeWrapper.cs @@ -47,7 +47,7 @@ sealed class MethodDescriptor { } - private MethodDescriptor(ClassLoaderWrapper classLoader, string name, string sig, TypeWrapper[] args, TypeWrapper ret) + internal MethodDescriptor(ClassLoaderWrapper classLoader, string name, string sig, TypeWrapper[] args, TypeWrapper ret) { Debug.Assert(classLoader != null); // class name in the sig should be dotted @@ -178,6 +178,11 @@ sealed class MethodDescriptor } else { + if(type.IsByRef) + { + type = type.Assembly.GetType(type.GetElementType().FullName + "[]", true); + // TODO test type for unsupported types + } name = GetSigNameFromType(type); typeWrapper = ClassLoaderWrapper.GetWrapperFromType(type); } @@ -300,6 +305,8 @@ sealed class MethodDescriptor } } + // TODO ensure that FromMethodBase is only used on statically compiled Java types, and + // remove support for ByRef internal static MethodDescriptor FromMethodBase(MethodBase mb) { System.Text.StringBuilder sb = new System.Text.StringBuilder(); @@ -348,6 +355,7 @@ class EmitHelper internal static void RunClassConstructor(ILGenerator ilgen, Type type) { + // TODO RunClassConstructor requires full trust, so we need to use a different mechanism... ilgen.Emit(OpCodes.Ldtoken, type); ilgen.Emit(OpCodes.Call, typeof(System.Runtime.CompilerServices.RuntimeHelpers).GetMethod("RunClassConstructor")); } @@ -436,7 +444,7 @@ class AttributeHelper } // NOTE Java doesn't support non-virtual methods, but we set the Final modifier for // non-virtual methods to approximate the semantics - if(mb.IsFinal || (!mb.IsStatic && !mb.IsVirtual && !mb.IsConstructor)) + if((mb.IsFinal || !mb.IsVirtual) && !mb.IsStatic && !mb.IsConstructor) { modifiers |= Modifiers.Final; } @@ -444,14 +452,20 @@ class AttributeHelper { modifiers |= Modifiers.Abstract; } + else + { + // Some .NET interfaces (like System._AppDomain) have synchronized methods, + // Java doesn't allow synchronized on an abstract methods, so we ignore it for + // abstract methods. + if((mb.GetMethodImplementationFlags() & MethodImplAttributes.Synchronized) != 0) + { + modifiers |= Modifiers.Synchronized; + } + } if(mb.IsStatic) { modifiers |= Modifiers.Static; } - if((mb.GetMethodImplementationFlags() & MethodImplAttributes.Synchronized) != 0) - { - modifiers |= Modifiers.Synchronized; - } if((mb.Attributes & MethodAttributes.PinvokeImpl) != 0) { modifiers |= Modifiers.Native; @@ -597,6 +611,15 @@ class AttributeHelper CustomAttributeBuilder attrib = new CustomAttributeBuilder(typeof(UnloadableTypeAttribute).GetConstructor(new Type[] { typeof(string) }), new object[] { name }); field.SetCustomAttribute(attrib); } + + internal static void SetInnerClass(TypeBuilder typeBuilder, string innerClass, string outerClass, string name, Modifiers modifiers) + { + Type[] argTypes = new Type[] { typeof(string), typeof(string), typeof(string), typeof(Modifiers) }; + object[] args = new object[] { innerClass, outerClass, name, modifiers }; + ConstructorInfo ci = typeof(InnerClassAttribute).GetConstructor(argTypes); + CustomAttributeBuilder customAttributeBuilder = new CustomAttributeBuilder(ci, args); + typeBuilder.SetCustomAttribute(customAttributeBuilder); + } } abstract class TypeWrapper @@ -861,6 +884,15 @@ abstract class TypeWrapper } } + // the name of the type as it appears in a Java signature string (e.g. "Ljava.lang.Object;" or "I") + internal virtual string SigName + { + get + { + return "L" + this.Name + ";"; + } + } + internal string PackageName { get @@ -1361,22 +1393,32 @@ class UnloadableTypeWrapper : TypeWrapper class PrimitiveTypeWrapper : TypeWrapper { - internal static readonly PrimitiveTypeWrapper BYTE = new PrimitiveTypeWrapper(typeof(sbyte)); - internal static readonly PrimitiveTypeWrapper CHAR = new PrimitiveTypeWrapper(typeof(char)); - internal static readonly PrimitiveTypeWrapper DOUBLE = new PrimitiveTypeWrapper(typeof(double)); - internal static readonly PrimitiveTypeWrapper FLOAT = new PrimitiveTypeWrapper(typeof(float)); - internal static readonly PrimitiveTypeWrapper INT = new PrimitiveTypeWrapper(typeof(int)); - internal static readonly PrimitiveTypeWrapper LONG = new PrimitiveTypeWrapper(typeof(long)); - internal static readonly PrimitiveTypeWrapper SHORT = new PrimitiveTypeWrapper(typeof(short)); - internal static readonly PrimitiveTypeWrapper BOOLEAN = new PrimitiveTypeWrapper(typeof(bool)); - internal static readonly PrimitiveTypeWrapper VOID = new PrimitiveTypeWrapper(typeof(void)); + internal static readonly PrimitiveTypeWrapper BYTE = new PrimitiveTypeWrapper(typeof(sbyte), "B"); + internal static readonly PrimitiveTypeWrapper CHAR = new PrimitiveTypeWrapper(typeof(char), "C"); + internal static readonly PrimitiveTypeWrapper DOUBLE = new PrimitiveTypeWrapper(typeof(double), "D"); + internal static readonly PrimitiveTypeWrapper FLOAT = new PrimitiveTypeWrapper(typeof(float), "F"); + internal static readonly PrimitiveTypeWrapper INT = new PrimitiveTypeWrapper(typeof(int), "I"); + internal static readonly PrimitiveTypeWrapper LONG = new PrimitiveTypeWrapper(typeof(long), "J"); + internal static readonly PrimitiveTypeWrapper SHORT = new PrimitiveTypeWrapper(typeof(short), "S"); + internal static readonly PrimitiveTypeWrapper BOOLEAN = new PrimitiveTypeWrapper(typeof(bool), "Z"); + internal static readonly PrimitiveTypeWrapper VOID = new PrimitiveTypeWrapper(typeof(void), "V"); private readonly Type type; + private readonly string sigName; - private PrimitiveTypeWrapper(Type type) + private PrimitiveTypeWrapper(Type type, string sigName) : base(Modifiers.Public | Modifiers.Abstract | Modifiers.Final, null, null, null) { this.type = type; + this.sigName = sigName; + } + + internal override string SigName + { + get + { + return sigName; + } } internal override ClassLoaderWrapper GetClassLoader() @@ -1721,16 +1763,11 @@ class DynamicTypeWrapper : TypeWrapper { declaringTypeWrapper = classFile.GetConstantPoolClassType(innerclasses[i].outerClass, wrapper.GetClassLoader()); reflectiveModifiers = innerclasses[i].accessFlags; - Type[] argTypes = new Type[] { typeof(string), typeof(string), typeof(string), typeof(Modifiers) }; - object[] args = new object[] { + AttributeHelper.SetInnerClass(typeBuilder, classFile.GetConstantPoolClass(innerclasses[i].innerClass), classFile.GetConstantPoolClass(innerclasses[i].outerClass), innerclasses[i].name == 0 ? null : classFile.GetConstantPoolUtf8String(innerclasses[i].name), - reflectiveModifiers - }; - ConstructorInfo ci = typeof(InnerClassAttribute).GetConstructor(argTypes); - CustomAttributeBuilder customAttributeBuilder = new CustomAttributeBuilder(ci, args); - typeBuilder.SetCustomAttribute(customAttributeBuilder); + reflectiveModifiers); } } } @@ -2227,7 +2264,7 @@ class DynamicTypeWrapper : TypeWrapper // when non-blank final fields are updated, the JIT normally doesn't see that (because the // constant value is inlined), so we emulate that behavior by emitting a Pop CodeEmitter emitSet = CodeEmitter.Pop; - fields[i] = FieldWrapper.Create(wrapper, fld.GetFieldType(wrapper.GetClassLoader()), fld.Name, fld.Signature, fld.Modifiers, emitGet, emitSet); + fields[i] = FieldWrapper.Create(wrapper, fld.GetFieldType(wrapper.GetClassLoader()), fld.Name, fld.Signature, fld.Modifiers, field, emitGet, emitSet); } else { @@ -2292,7 +2329,7 @@ class DynamicTypeWrapper : TypeWrapper { emitSet += CodeEmitter.Create(OpCodes.Stfld, field); } - fields[i] = FieldWrapper.Create(wrapper, fld.GetFieldType(wrapper.GetClassLoader()), fld.Name, fld.Signature, fld.Modifiers, emitGet, emitSet); + fields[i] = FieldWrapper.Create(wrapper, fld.GetFieldType(wrapper.GetClassLoader()), fld.Name, fld.Signature, fld.Modifiers, field, emitGet, emitSet); } else { @@ -3232,7 +3269,7 @@ class RemappedTypeWrapper : TypeWrapper } CodeEmitter setter = CodeEmitter.Throw("java.lang.IllegalAccessError", "Redirected field " + this.Name + "." + fieldName + " is read-only"); // HACK we abuse RetTypeWrapperFromSig - FieldWrapper fw = FieldWrapper.Create(this, GetClassLoader().RetTypeWrapperFromSig("()" + fieldSig), fieldName, fieldSig, modifiers, getter, setter); + FieldWrapper fw = FieldWrapper.Create(this, GetClassLoader().RetTypeWrapperFromSig("()" + fieldSig), fieldName, fieldSig, modifiers, null, getter, setter); AddField(fw); } } @@ -3515,199 +3552,31 @@ class RemappedTypeWrapper : TypeWrapper } } -class NetExpTypeWrapper : TypeWrapper -{ - private readonly ClassFile classFile; - private readonly Type type; - - // TODO consider constructing modifiers from .NET type instead of the netexp class - public NetExpTypeWrapper(ClassFile f, string dotnetType, TypeWrapper baseType) - : base(f.Modifiers, f.Name, baseType, ClassLoaderWrapper.GetBootstrapClassLoader()) - { - this.classFile = f; - // TODO if the type isn't found, it should be handled differently - type = Type.GetType(dotnetType, true); - } - - public override TypeWrapper[] Interfaces - { - get - { - // TODO resolve the interfaces! - return TypeWrapper.EmptyArray; - } - } - - public override TypeWrapper[] InnerClasses - { - get - { - // TODO resolve the inner classes! - return TypeWrapper.EmptyArray; - } - } - - public override TypeWrapper DeclaringTypeWrapper - { - get - { - // TODO resolve the outer class! - return null; - } - } - - protected override FieldWrapper GetFieldImpl(string fieldName) - { - // HACK this is a totally broken quick & dirty implementation - // TODO clean this up, add error checking and whatnot - FieldInfo field = type.GetField(fieldName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance); - if(!AttributeHelper.IsHideFromReflection(field)) - { - return FieldWrapper.Create(this, ClassLoaderWrapper.GetWrapperFromType(field.FieldType), field, MethodDescriptor.GetFieldSigName(field), AttributeHelper.GetModifiers(field)); - } - return null; - } - - private class DelegateConstructorEmitter : CodeEmitter - { - private ConstructorInfo delegateConstructor; - private MethodInfo method; - - internal DelegateConstructorEmitter(ConstructorInfo delegateConstructor, MethodInfo method) - { - this.delegateConstructor = delegateConstructor; - this.method = method; - } - - internal override void Emit(ILGenerator ilgen) - { - ilgen.Emit(OpCodes.Dup); - ilgen.Emit(OpCodes.Ldvirtftn, method); - ilgen.Emit(OpCodes.Newobj, delegateConstructor); - } - } - - private class RefArgConverter : CodeEmitter - { - private Type[] args; - - internal RefArgConverter(Type[] args) - { - this.args = args; - } - - internal override void Emit(ILGenerator ilgen) - { - LocalBuilder[] locals = new LocalBuilder[args.Length]; - for(int i = args.Length - 1; i >= 0; i--) - { - Type type = args[i]; - if(type.IsByRef) - { - type = type.Assembly.GetType(type.GetElementType().FullName + "[]", true); - } - locals[i] = ilgen.DeclareLocal(type); - ilgen.Emit(OpCodes.Stloc, locals[i]); - } - for(int i = 0; i < args.Length; i++) - { - ilgen.Emit(OpCodes.Ldloc, locals[i]); - if(args[i].IsByRef) - { - ilgen.Emit(OpCodes.Ldc_I4_0); - ilgen.Emit(OpCodes.Ldelema, args[i].GetElementType()); - } - } - } - } - - protected override MethodWrapper GetMethodImpl(MethodDescriptor md) - { - // special case for delegate constructors! - if(md.Name == "" && type.IsSubclassOf(typeof(MulticastDelegate))) - { - // TODO set method flags - MethodWrapper method = new MethodWrapper(this, md, null, null, Modifiers.Public, false); - // TODO what class loader should we use? - TypeWrapper iface = ClassLoaderWrapper.GetBootstrapClassLoader().LoadClassByDottedName(classFile.Name + "$Method"); - iface.Finish(); - method.EmitNewobj = new DelegateConstructorEmitter(type.GetConstructor(new Type[] { typeof(object), typeof(IntPtr) }), iface.Type.GetMethod("Invoke")); - return method; - } - // HACK this is a totally broken quick & dirty implementation - // TODO clean this up, add error checking and whatnot - ClassFile.Method[] methods = classFile.Methods; - for(int i = 0; i < methods.Length; i++) - { - if(methods[i].Name == md.Name && methods[i].Signature == md.Signature) - { - bool hasByRefArgs = false; - Type[] args; - string[] sig = methods[i].NetExpSigAttribute; - if(sig == null) - { - args = md.ArgTypes; - } - else - { - args = new Type[sig.Length]; - for(int j = 0; j < sig.Length; j++) - { - args[j] = Type.GetType(sig[j], true); - if(args[j].IsByRef) - { - hasByRefArgs = true; - } - } - } - MethodBase method; - if(md.Name == "") - { - method = type.GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, CallingConventions.Standard, args, null); - } - else - { - method = type.GetMethod(md.Name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance, null, CallingConventions.Standard, args, null); - } - if(method != null) - { - // TODO we can decode the actual method attributes, or we can use them from the NetExp class, what is - // preferred? - MethodWrapper mw = MethodWrapper.Create(this, md, method, method, AttributeHelper.GetModifiers(method), AttributeHelper.IsHideFromReflection(method)); - if(hasByRefArgs) - { - mw.EmitCall = new RefArgConverter(args) + mw.EmitCall; - mw.EmitCallvirt = new RefArgConverter(args) + mw.EmitCallvirt; - mw.EmitNewobj = new RefArgConverter(args) + mw.EmitNewobj; - } - return mw; - } - } - } - return null; - } - - public override Type Type - { - get - { - return type; - } - } - - public override void Finish() - { - } -} - +// TODO CompiledTypeWrapper & DotNetTypeWrapper should have a common base class class CompiledTypeWrapper : TypeWrapper { private readonly Type type; private TypeWrapper[] interfaces; private TypeWrapper[] innerclasses; + internal static string GetName(Type type) + { + Debug.Assert(type.Assembly.IsDefined(typeof(JavaAssemblyAttribute), false)); + if(type.IsDefined(typeof(HideFromReflectionAttribute), false)) + { + return ClassLoaderWrapper.GetWrapperFromType(type.BaseType).Name; + } + // look for our custom attribute, that contains the real name of the type (for inner classes) + Object[] attribs = type.GetCustomAttributes(typeof(InnerClassAttribute), false); + if(attribs.Length == 1) + { + return ((InnerClassAttribute)attribs[0]).InnerClassName; + } + return type.FullName; + } + // TODO consider resolving the baseType lazily - private static TypeWrapper GetBaseTypeWrapper(Type type) + internal static TypeWrapper GetBaseTypeWrapper(Type type) { if(type.IsInterface) { @@ -3727,12 +3596,15 @@ class CompiledTypeWrapper : TypeWrapper internal CompiledTypeWrapper(string name, Type type) : base(GetModifiers(type), name, GetBaseTypeWrapper(type), ClassLoaderWrapper.GetBootstrapClassLoader()) { + Debug.Assert(!type.IsDefined(typeof(HideFromReflectionAttribute), false)); Debug.Assert(!(type is TypeBuilder)); Debug.Assert(!type.IsArray); + Debug.Assert(!ClassLoaderWrapper.IsRemappedType(type)); + this.type = type; } - private static Modifiers GetModifiers(Type type) + internal static Modifiers GetModifiers(Type type) { try { @@ -3922,7 +3794,7 @@ class CompiledTypeWrapper : TypeWrapper emitSet = CodeEmitter.Nop; } } - return FieldWrapper.Create(this, ClassLoaderWrapper.GetWrapperFromType(fieldType), name, MethodDescriptor.GetFieldSigName(field), modifiers, emitGet, emitSet); + return FieldWrapper.Create(this, ClassLoaderWrapper.GetWrapperFromType(fieldType), name, MethodDescriptor.GetFieldSigName(field), modifiers, field, emitGet, emitSet); } protected override FieldWrapper GetFieldImpl(string fieldName) @@ -4071,6 +3943,555 @@ class CompiledTypeWrapper : TypeWrapper } } +class DotNetTypeWrapper : TypeWrapper +{ + private const string NamePrefix = "cli."; + private const string DelegateInterfaceSuffix = "$Method"; + private readonly Type type; + private bool membersPublished; + private TypeWrapper[] innerClasses; + private TypeWrapper outerClass; + + private static Modifiers GetModifiers(Type type) + { + Modifiers mods = CompiledTypeWrapper.GetModifiers(type); + if(ClassLoaderWrapper.IsRemappedType(type) && !type.IsInterface) + { + mods |= Modifiers.Final; + } + return mods; + } + + // NOTE when this is called on a remapped type, the "warped" underlying type name is returned. + // E.g. GetName(typeof(object)) returns "cli.System.Object". + internal static string GetName(Type type) + { + Debug.Assert(!type.Assembly.IsDefined(typeof(JavaAssemblyAttribute), false), type.FullName); + + // TODO a fully reversible name mangling should be used (all characters not supported by Java should be escaped) + return NamePrefix + type.FullName.Replace('+', '$'); + } + + // this method should only be called once for each name, it doesn't do any caching or duplicate prevention + internal static TypeWrapper LoadDotNetTypeWrapper(string name) + { + if(name.StartsWith(NamePrefix)) + { + name = name.Substring(NamePrefix.Length); + Type type = LoadTypeFromLoadedAssemblies(name); + if(type != null) + { + return new DotNetTypeWrapper(type); + } + if(name.EndsWith(DelegateInterfaceSuffix)) + { + Type delegateType = LoadTypeFromLoadedAssemblies(name.Substring(0, name.Length - DelegateInterfaceSuffix.Length)); + if(delegateType.IsSubclassOf(typeof(Delegate))) + { + ModuleBuilder moduleBuilder = ClassLoaderWrapper.GetBootstrapClassLoader().ModuleBuilder; + TypeBuilder typeBuilder = moduleBuilder.DefineType(NamePrefix + name, TypeAttributes.Public | TypeAttributes.Interface | TypeAttributes.Abstract); + AttributeHelper.SetInnerClass(typeBuilder, NamePrefix + name, NamePrefix + delegateType.FullName, "Method", Modifiers.Public | Modifiers.Interface | Modifiers.Static | Modifiers.Abstract); + MethodInfo invoke = delegateType.GetMethod("Invoke"); + if(invoke != null) + { + ParameterInfo[] parameters = invoke.GetParameters(); + Type[] args = new Type[parameters.Length]; + for(int i = 0; i < args.Length; i++) + { + // HACK if the delegate has pointer args, we cannot handle them, but it is already + // to late to refuse to load the class, so we replace pointers with IntPtr. + // This is not a solution, because if the delegate would be instantiated the generated + // code would be invalid. + if(parameters[i].ParameterType.IsPointer) + { + args[i] = typeof(IntPtr); + } + else + { + args[i] = parameters[i].ParameterType; + } + } + typeBuilder.DefineMethod("Invoke", MethodAttributes.Public | MethodAttributes.Abstract | MethodAttributes.Virtual, CallingConventions.Standard, invoke.ReturnType, args); + return new CompiledTypeWrapper(NamePrefix + name, typeBuilder.CreateType()); + } + } + } + } + return null; + } + + private static Type LoadTypeFromLoadedAssemblies(string name) + { + foreach(Assembly a in AppDomain.CurrentDomain.GetAssemblies()) + { + // HACK we also look inside Java assemblies, because precompiled delegate interfaces might have ended up there + if(!(a is AssemblyBuilder)) + { + Type t = a.GetType(name); + if(t != null) + { + return t; + } + // HACK we might be looking for an inner classes + t = a.GetType(name.Replace('$', '+')); + if(t != null) + { + return t; + } + } + } + return null; + } + + internal DotNetTypeWrapper(Type type) + : base(GetModifiers(type), GetName(type), CompiledTypeWrapper.GetBaseTypeWrapper(type), ClassLoaderWrapper.GetBootstrapClassLoader()) + { + Debug.Assert(!(type.IsByRef), type.FullName); + Debug.Assert(!(type.IsPointer), type.FullName); + Debug.Assert(!(type.IsArray), type.FullName); + Debug.Assert(!(type is TypeBuilder), type.FullName); + Debug.Assert(!(type.Assembly.IsDefined(typeof(JavaAssemblyAttribute), false))); + + this.type = type; + } + + private void LazyPublishMembers() + { + // special support for enums + if(type.IsEnum) + { + // TODO handle unsigned underlying type + TypeWrapper fieldType = ClassLoaderWrapper.GetWrapperFromType(Enum.GetUnderlyingType(type)); + FieldInfo[] fields = type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Static); + for(int i = 0; i < fields.Length; i++) + { + if(fields[i].FieldType == type) + { + // TODO handle name/signature clash + AddField(FieldWrapper.Create(this, fieldType, fields[i].Name, fieldType.SigName, Modifiers.Public | Modifiers.Static | Modifiers.Final, fields[i], CodeEmitter.CreateLoadConstant(fields[i].GetValue(null)), CodeEmitter.Pop)); + } + } + CodeEmitter getter = CodeEmitter.Create(OpCodes.Unbox, type) + CodeEmitter.Create(OpCodes.Ldobj, type); + CodeEmitter setter = CodeEmitter.Pop + CodeEmitter.Pop; + FieldWrapper fw = FieldWrapper.Create(this, fieldType, "Value", fieldType.SigName, Modifiers.Public | Modifiers.Final, null, getter, setter); + AddField(fw); + MethodWrapper mw = new MethodWrapper(this, MethodDescriptor.FromNameSig(GetClassLoader(), "wrap", "(" + fieldType.SigName + ")" + this.SigName), null, null, Modifiers.Static | Modifiers.Public, false); + mw.EmitCall = CodeEmitter.Create(OpCodes.Box, type); + AddMethod(mw); + } + else + { + bool isRemapped = ClassLoaderWrapper.IsRemappedType(type) && !type.IsInterface; + + FieldInfo[] fields = type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance); + for(int i = 0; i < fields.Length; i++) + { + // TODO for remapped types, instance fields need to be converted to static getter/setter methods + if(fields[i].FieldType.IsPointer) + { + // skip, pointer fields are not supported + } + else + { + // TODO handle name/signature clash + AddField(CreateFieldWrapper(AttributeHelper.GetModifiers(fields[i]), fields[i].Name, fields[i].FieldType, fields[i], null)); + } + } + + // special case for delegate constructors! + if(!type.IsAbstract && type.IsSubclassOf(typeof(Delegate))) + { + TypeWrapper iface = GetClassLoader().LoadClassByDottedName(this.Name + DelegateInterfaceSuffix); + Debug.Assert(iface is CompiledTypeWrapper); + iface.Finish(); + MethodDescriptor md = MethodDescriptor.FromNameSig(GetClassLoader(), "", "(" + iface.SigName + ")V"); + // TODO set method flags + MethodWrapper method = new MethodWrapper(this, md, null, null, Modifiers.Public, false); + method.EmitNewobj = new DelegateConstructorEmitter(type.GetConstructor(new Type[] { typeof(object), typeof(IntPtr) }), iface.Type.GetMethod("Invoke")); + AddMethod(method); + innerClasses = new TypeWrapper[] { iface }; + } + + ConstructorInfo[] constructors = type.GetConstructors(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance); + for(int i = 0; i < constructors.Length; i++) + { + MethodDescriptor md = MakeMethodDescriptor(constructors[i], isRemapped); + if(md != null) + { + // TODO handle name/signature clash + AddMethod(CreateMethodWrapper(md, constructors[i], isRemapped)); + } + } + + MethodInfo[] methods = type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance); + for(int i = 0; i < methods.Length; i++) + { + MethodDescriptor md = MakeMethodDescriptor(methods[i], isRemapped); + if(md != null) + { + // TODO handle name/signature clash + AddMethod(CreateMethodWrapper(md, methods[i], isRemapped)); + } + } + } + } + + private MethodDescriptor MakeMethodDescriptor(MethodBase mb, bool isRemapped) + { + System.Text.StringBuilder sb = new System.Text.StringBuilder(); + sb.Append('('); + ParameterInfo[] parameters = mb.GetParameters(); + int bias = (isRemapped && !mb.IsStatic && !mb.IsConstructor) ? 1 : 0; + TypeWrapper[] args = new TypeWrapper[parameters.Length + bias]; + if(bias == 1) + { + args[0] = ClassLoaderWrapper.GetWrapperFromType(mb.DeclaringType); + sb.Append(args[0].SigName); + } + for(int i = 0; i < parameters.Length; i++) + { + Type type = parameters[i].ParameterType; + if(type.IsPointer) + { + return null; + } + if(type.IsByRef) + { + type = type.Assembly.GetType(type.GetElementType().FullName + "[]", true); + } + TypeWrapper tw = ClassLoaderWrapper.GetWrapperFromType(type); + args[i + bias] = tw; + sb.Append(tw.SigName); + } + sb.Append(')'); + if(mb is ConstructorInfo) + { + TypeWrapper ret = PrimitiveTypeWrapper.VOID; + string name; + if(mb.IsStatic) + { + name = ""; + } + else if(isRemapped) + { + name = "__new"; + ret = ClassLoaderWrapper.GetWrapperFromType(mb.DeclaringType); + } + else + { + name = ""; + } + sb.Append(ret.SigName); + return new MethodDescriptor(GetClassLoader(), name, sb.ToString(), args, ret); + } + else + { + Type type = ((MethodInfo)mb).ReturnType; + if(type.IsPointer) + { + return null; + } + TypeWrapper ret = ClassLoaderWrapper.GetWrapperFromType(type); + sb.Append(ret.SigName); + return new MethodDescriptor(GetClassLoader(), mb.Name, sb.ToString(), args, ret); + } + } + + public override TypeWrapper[] Interfaces + { + get + { + // remapped type cannot be instantiated, so it wouldn't make sense to implement + // interfaces + if(ClassLoaderWrapper.IsRemappedType(Type) && !Type.IsInterface) + { + return TypeWrapper.EmptyArray; + } + Type[] interfaces = type.GetInterfaces(); + TypeWrapper[] interfaceWrappers = new TypeWrapper[interfaces.Length]; + for(int i = 0; i < interfaces.Length; i++) + { + interfaceWrappers[i] = ClassLoaderWrapper.GetWrapperFromType(interfaces[i]); + } + return interfaceWrappers; + } + } + + public override TypeWrapper[] InnerClasses + { + get + { + lock(this) + { + if(innerClasses == null) + { + Type[] nestedTypes = type.GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic); + innerClasses = new TypeWrapper[nestedTypes.Length]; + for(int i = 0; i < nestedTypes.Length; i++) + { + innerClasses[i] = ClassLoaderWrapper.GetWrapperFromType(nestedTypes[i]); + } + } + } + return innerClasses; + } + } + + public override TypeWrapper DeclaringTypeWrapper + { + get + { + if(outerClass == null) + { + Type outer = type.DeclaringType; + if(outer != null) + { + outerClass = ClassLoaderWrapper.GetWrapperFromType(outer); + } + } + return outerClass; + } + } + + internal override Modifiers ReflectiveModifiers + { + get + { + if(DeclaringTypeWrapper != null) + { + return Modifiers | Modifiers.Static; + } + return Modifiers; + } + } + + // TODO support NonPrimitiveValueTypes + // TODO why doesn't this use the standard FieldWrapper.Create? + private FieldWrapper CreateFieldWrapper(Modifiers modifiers, string name, Type fieldType, FieldInfo field, MethodInfo getter) + { + CodeEmitter emitGet; + CodeEmitter emitSet; + if((modifiers & Modifiers.Static) != 0) + { + if(getter != null) + { + emitGet = CodeEmitter.Create(OpCodes.Call, getter); + } + else + { + // if field is a literal, we must emit an ldc instead of a ldsfld + if(field.IsLiteral) + { + emitGet = CodeEmitter.CreateLoadConstant(field.GetValue(null)); + } + else + { + emitGet = CodeEmitter.Create(OpCodes.Ldsfld, field); + } + } + if(field != null && !field.IsLiteral) + { + emitSet = CodeEmitter.Create(OpCodes.Stsfld, field); + } + else + { + // TODO what happens when you try to set a final field? + // through reflection: java.lang.IllegalAccessException: Field is final + // through code: java.lang.IllegalAccessError: Field . is final + emitSet = CodeEmitter.Nop; + } + } + else + { + if(getter != null) + { + emitGet = CodeEmitter.Create(OpCodes.Callvirt, getter); + } + else + { + // TODO is it possible to have literal instance fields? + emitGet = CodeEmitter.Create(OpCodes.Ldfld, field); + } + if(field != null) + { + emitSet = CodeEmitter.Create(OpCodes.Stfld, field); + } + else + { + // TODO what happens when you try to set a final field through reflection? + // see above + emitSet = CodeEmitter.Nop; + } + } + return FieldWrapper.Create(this, ClassLoaderWrapper.GetWrapperFromType(fieldType), name, MethodDescriptor.GetFieldSigName(field), modifiers, field, emitGet, emitSet); + } + + // TODO why doesn't this use the standard MethodWrapper.Create? + private MethodWrapper CreateMethodWrapper(MethodDescriptor md, MethodBase mb, bool isRemapped) + { + ParameterInfo[] parameters = mb.GetParameters(); + Type[] args = new Type[parameters.Length]; + bool hasByRefArgs = false; + for(int i = 0; i < parameters.Length; i++) + { + args[i] = parameters[i].ParameterType; + if(parameters[i].ParameterType.IsByRef) + { + hasByRefArgs = true; + } + } + Modifiers mods = AttributeHelper.GetModifiers(mb); + if(isRemapped) + { + // all methods are static and final doesn't make sense + mods |= Modifiers.Static; + mods &= ~Modifiers.Final; + } + MethodWrapper method = new MethodWrapper(this, md, mb, null, mods, false); + if(mb is ConstructorInfo) + { + if(isRemapped) + { + method.EmitCall = CodeEmitter.Create(OpCodes.Newobj, (ConstructorInfo)mb); + } + else + { + method.EmitCall = CodeEmitter.Create(OpCodes.Call, (ConstructorInfo)mb); + method.EmitNewobj = CodeEmitter.Create(OpCodes.Newobj, (ConstructorInfo)mb); + if(this.IsNonPrimitiveValueType) + { + method.EmitNewobj += CodeEmitter.Create(OpCodes.Box, this.Type); + } + } + } + else + { + bool nonPrimitiveValueType = md.RetTypeWrapper.IsNonPrimitiveValueType; + method.EmitCall = CodeEmitter.Create(OpCodes.Call, (MethodInfo)mb); + if(nonPrimitiveValueType) + { + method.EmitCall += CodeEmitter.Create(OpCodes.Box, md.RetTypeWrapper.Type); + } + if(!mb.IsStatic) + { + method.EmitCallvirt = CodeEmitter.Create(OpCodes.Callvirt, (MethodInfo)mb); + if(nonPrimitiveValueType) + { + method.EmitCallvirt += CodeEmitter.Create(OpCodes.Box, md.RetTypeWrapper.Type); + } + } + } + if(hasByRefArgs) + { + method.EmitCall = new RefArgConverter(args) + method.EmitCall; + method.EmitCallvirt = new RefArgConverter(args) + method.EmitCallvirt; + method.EmitNewobj = new RefArgConverter(args) + method.EmitNewobj; + } + return method; + } + + private class DelegateConstructorEmitter : CodeEmitter + { + private ConstructorInfo delegateConstructor; + private MethodInfo method; + + internal DelegateConstructorEmitter(ConstructorInfo delegateConstructor, MethodInfo method) + { + this.delegateConstructor = delegateConstructor; + this.method = method; + } + + internal override void Emit(ILGenerator ilgen) + { + ilgen.Emit(OpCodes.Dup); + ilgen.Emit(OpCodes.Ldvirtftn, method); + ilgen.Emit(OpCodes.Newobj, delegateConstructor); + } + } + + private class RefArgConverter : CodeEmitter + { + private Type[] args; + + internal RefArgConverter(Type[] args) + { + this.args = args; + } + + internal override void Emit(ILGenerator ilgen) + { + LocalBuilder[] locals = new LocalBuilder[args.Length]; + for(int i = args.Length - 1; i >= 0; i--) + { + Type type = args[i]; + if(type.IsByRef) + { + type = type.Assembly.GetType(type.GetElementType().FullName + "[]", true); + } + locals[i] = ilgen.DeclareLocal(type); + ilgen.Emit(OpCodes.Stloc, locals[i]); + } + for(int i = 0; i < args.Length; i++) + { + ilgen.Emit(OpCodes.Ldloc, locals[i]); + if(args[i].IsByRef) + { + ilgen.Emit(OpCodes.Ldc_I4_0); + ilgen.Emit(OpCodes.Ldelema, args[i].GetElementType()); + } + } + } + } + + protected override FieldWrapper GetFieldImpl(string fieldName) + { + lock(this) + { + if(!membersPublished) + { + membersPublished = true; + LazyPublishMembers(); + return GetFieldWrapper(fieldName); + } + } + return null; + } + + protected override MethodWrapper GetMethodImpl(MethodDescriptor md) + { + lock(this) + { + if(!membersPublished) + { + membersPublished = true; + LazyPublishMembers(); + return GetMethodWrapper(md, false); + } + } + return null; + } + + public override Type Type + { + get + { + return type; + } + } + + public override void Finish() + { + lock(this) + { + if(!membersPublished) + { + membersPublished = true; + LazyPublishMembers(); + } + } + } +} + class ArrayTypeWrapper : TypeWrapper { private static TypeWrapper[] interfaces; @@ -4101,6 +4522,15 @@ class ArrayTypeWrapper : TypeWrapper AddMethod(mw); } + internal override string SigName + { + get + { + // for arrays the signature name is the same as the normal name + return Name; + } + } + public override TypeWrapper[] Interfaces { get diff --git a/IK.VM.NET/classpath.cs b/IK.VM.NET/classpath.cs index d9279c57..ece8da66 100644 --- a/IK.VM.NET/classpath.cs +++ b/IK.VM.NET/classpath.cs @@ -179,6 +179,10 @@ namespace NativeCode.java { return Activator.CreateInstance(java_lang_Byte, new object[] { o }); } + else if(o is byte) + { + return Activator.CreateInstance(java_lang_Byte, new object[] { (sbyte)(byte)o }); + } else if(o is bool) { return Activator.CreateInstance(java_lang_Boolean, new object[] { o }); @@ -187,6 +191,10 @@ namespace NativeCode.java { return Activator.CreateInstance(java_lang_Short, new object[] { o }); } + else if(o is ushort) + { + return Activator.CreateInstance(java_lang_Short, new object[] { (short)(ushort)o }); + } else if(o is char) { return Activator.CreateInstance(java_lang_Character, new object[] { o }); @@ -195,10 +203,18 @@ namespace NativeCode.java { return Activator.CreateInstance(java_lang_Integer, new object[] { o }); } + else if(o is uint) + { + return Activator.CreateInstance(java_lang_Integer, new object[] { (int)(uint)o }); + } else if(o is long) { return Activator.CreateInstance(java_lang_Long, new object[] { o }); } + else if(o is ulong) + { + return Activator.CreateInstance(java_lang_Long, new object[] { (long)(ulong)o }); + } else if(o is float) { return Activator.CreateInstance(java_lang_Float, new object[] { o }); @@ -207,6 +223,38 @@ namespace NativeCode.java { return Activator.CreateInstance(java_lang_Double, new object[] { o }); } + else if(o is Enum) + { + Type enumType = Enum.GetUnderlyingType(o.GetType()); + if(enumType == typeof(byte) || enumType == typeof(sbyte)) + { + return JavaWrapper.Box((sbyte)((IConvertible)o).ToInt32(null)); + } + else if(enumType == typeof(short) || enumType == typeof(ushort)) + { + return JavaWrapper.Box((short)((IConvertible)o).ToInt32(null)); + } + else if(enumType == typeof(int)) + { + return JavaWrapper.Box(((IConvertible)o).ToInt32(null)); + } + else if(enumType == typeof(uint)) + { + return JavaWrapper.Box(unchecked((int)((IConvertible)o).ToUInt32(null))); + } + else if(enumType == typeof(long)) + { + return JavaWrapper.Box(((IConvertible)o).ToInt64(null)); + } + else if(enumType == typeof(ulong)) + { + return JavaWrapper.Box(unchecked((long)((IConvertible)o).ToUInt64(null))); + } + else + { + throw new InvalidOperationException(); + } + } else { throw new NotImplementedException(o.GetType().FullName); @@ -327,6 +375,14 @@ namespace NativeCode.java public class Field { + // HACK this is used by netexp to query the constant value of a field + public static object getConstant(object field) + { + // HACK we use reflection to extract the fieldCookie from the java.lang.reflect.Field object + FieldWrapper wrapper = (FieldWrapper)field.GetType().GetField("fieldCookie", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(field); + return wrapper.GetConstant(); + } + public static string GetName(object fieldCookie) { FieldWrapper wrapper = (FieldWrapper)fieldCookie; @@ -951,28 +1007,28 @@ namespace NativeCode.java return null; } - public static Type getPrimitiveType(char type) + public static object getPrimitiveClass(char type) { switch(type) { case 'Z': - return typeof(bool); + return VMClass.getClassFromType(typeof(bool)); case 'B': - return typeof(sbyte); + return VMClass.getClassFromType(typeof(sbyte)); case 'C': - return typeof(char); + return VMClass.getClassFromType(typeof(char)); case 'D': - return typeof(double); + return VMClass.getClassFromType(typeof(double)); case 'F': - return typeof(float); + return VMClass.getClassFromType(typeof(float)); case 'I': - return typeof(int); + return VMClass.getClassFromType(typeof(int)); case 'J': - return typeof(long); + return VMClass.getClassFromType(typeof(long)); case 'S': - return typeof(short); + return VMClass.getClassFromType(typeof(short)); case 'V': - return typeof(void); + return VMClass.getClassFromType(typeof(void)); default: throw new InvalidOperationException(); } @@ -990,7 +1046,7 @@ namespace NativeCode.java throw JavaException.NoClassDefFoundError("{0} (wrong name: {1})", name, classFile.Name); } TypeWrapper type = ClassLoaderWrapper.GetClassLoaderWrapper(classLoader).DefineClass(classFile); - object clazz = VMClass.CreateInstance(null, type); + object clazz = VMClass.CreateClassInstance(type); if(protectionDomain != null) { // TODO cache the FieldInfo @@ -1008,8 +1064,9 @@ namespace NativeCode.java public class VMClass { private static Hashtable map = new Hashtable(); - private static MethodInfo createClass; - private static MethodInfo getTypeMethod; + private delegate object CreateClassDelegate(object typeWrapper); + private static CreateClassDelegate CreateClass; + private static MethodInfo getWrapper; public static void throwException(Exception e) { @@ -1038,20 +1095,27 @@ namespace NativeCode.java return null; } - internal static object CreateInstance(Type type, TypeWrapper wrapper) + internal static object CreateClassInstance(TypeWrapper wrapper) { - TypeWrapper.AssertFinished(type); - if(createClass == null) + if(CreateClass == null) { - createClass = ClassLoaderWrapper.GetType("java.lang.VMClass").GetMethod("createClass", BindingFlags.Static | BindingFlags.NonPublic); + CreateClass = (CreateClassDelegate)Delegate.CreateDelegate(typeof(CreateClassDelegate), ClassLoaderWrapper.GetType("java.lang.VMClass").GetMethod("createClass", BindingFlags.Static | BindingFlags.Public)); + // HACK to make sure we don't run into any problems creating class objects for classes that + // participate in the VMClass static initialization, we first do a bogus call to initialize + // the machinery (I ran into this when running netexp on classpath.dll) + CreateClass(null); + lock(map.SyncRoot) + { + object o = map[wrapper]; + if(o != null) + { + return o; + } + } } - object clazz = createClass.Invoke(null, new object[] { type, wrapper }); + object clazz = CreateClass(wrapper); lock(map.SyncRoot) { - if(type != null) - { - map.Add(type, clazz); - } if(wrapper != null) { map.Add(wrapper, clazz); @@ -1060,11 +1124,21 @@ namespace NativeCode.java return clazz; } - public static bool IsAssignableFrom(Object w1, Object w2) + public static bool IsAssignableFrom(object w1, object w2) { return ((TypeWrapper)w2).IsAssignableTo((TypeWrapper)w1); } + public static bool IsInterface(object wrapper) + { + return ((TypeWrapper)wrapper).IsInterface; + } + + public static bool IsArray(object wrapper) + { + return ((TypeWrapper)wrapper).IsArray; + } + public static object GetSuperClassFromWrapper(object wrapper) { TypeWrapper baseWrapper = ((TypeWrapper)wrapper).BaseTypeWrapper; @@ -1093,13 +1167,6 @@ namespace NativeCode.java ((TypeWrapper)wrapper).Finish(); Type type = ((TypeWrapper)wrapper).Type; TypeWrapper.AssertFinished(type); - lock(map.SyncRoot) - { - // NOTE since this method can be called multiple times (or after getClassFromType has added - // the Class to the map), we don't use Add() here, but the indexer because that can handle - // "overwriting" the existing association (which should always be the same as the new one) - map[type] = clazz; - } return type; } @@ -1110,11 +1177,13 @@ namespace NativeCode.java public static Type getType(object clazz) { - if(getTypeMethod == null) + if(getWrapper == null) { - getTypeMethod = ClassLoaderWrapper.GetType("java.lang.VMClass").GetMethod("getTypeFromClass", BindingFlags.NonPublic | BindingFlags.Static); + getWrapper = ClassLoaderWrapper.GetType("java.lang.VMClass").GetMethod("getWrapperFromClass", BindingFlags.NonPublic | BindingFlags.Static); } - return (Type)getTypeMethod.Invoke(null, new object[] { clazz }); + TypeWrapper wrapper = (TypeWrapper)getWrapper.Invoke(null, new object[] { clazz }); + wrapper.Finish(); + return wrapper.Type; } internal static object getClassFromWrapper(TypeWrapper wrapper) @@ -1124,12 +1193,7 @@ namespace NativeCode.java object clazz = map[wrapper]; if(clazz == null) { - // Maybe the Class object was already constructed from the type - clazz = map[wrapper.Type]; - if(clazz == null) - { - clazz = CreateInstance(null, wrapper); - } + clazz = CreateClassInstance(wrapper); } return clazz; } @@ -1142,71 +1206,61 @@ namespace NativeCode.java { return null; } - lock(map.SyncRoot) - { - object clazz = map[type]; - if(clazz == null) - { - // maybe the Class object was constructed from the wrapper - TypeWrapper wrapper = ClassLoaderWrapper.GetWrapperFromTypeFast(type); - if(wrapper != null) - { - clazz = map[wrapper]; - if(clazz != null) - { - map.Add(type, clazz); - return clazz; - } - } - // NOTE we need to get the bootstrap classloader to trigger its construction (if it - // hasn't been created yet), because otherwise CreateInstance will do that and this - // causes the same class object to be created multiple times) - ClassLoaderWrapper.GetBootstrapClassLoader(); - clazz = map[type]; - if(clazz == null) - { - // if this type is an override stub (e.g. java.lang.Object), we need to return the - // class object for the parent type - // NOTE we first check if type isn't an array, because Type.IsDefined throws an exception - // when called on an array type (?) - if(!type.IsArray && type.IsDefined(typeof(HideFromReflectionAttribute), false)) - { - clazz = getClassFromType(type.BaseType); - map.Add(type, clazz); - } - else - { - // TODO should we specify the wrapper? - // NOTE CreateInstance adds the Class to the "map" - clazz = CreateInstance(type, null); - } - } - } - return clazz; - } + return getClassFromWrapper(ClassLoaderWrapper.GetWrapperFromType(type)); } - public static string getName(Type type) + public static string GetName(object wrapper) { - return GetName(type, null); + TypeWrapper typeWrapper = (TypeWrapper)wrapper; + if(typeWrapper.IsPrimitive) + { + if(typeWrapper == PrimitiveTypeWrapper.VOID) + { + return "void"; + } + else if(typeWrapper == PrimitiveTypeWrapper.BYTE) + { + return "byte"; + } + else if(typeWrapper == PrimitiveTypeWrapper.BOOLEAN) + { + return "boolean"; + } + else if(typeWrapper == PrimitiveTypeWrapper.SHORT) + { + return "short"; + } + else if(typeWrapper == PrimitiveTypeWrapper.CHAR) + { + return "char"; + } + else if(typeWrapper == PrimitiveTypeWrapper.INT) + { + return "int"; + } + else if(typeWrapper == PrimitiveTypeWrapper.LONG) + { + return "long"; + } + else if(typeWrapper == PrimitiveTypeWrapper.FLOAT) + { + return "float"; + } + else if(typeWrapper == PrimitiveTypeWrapper.DOUBLE) + { + return "double"; + } + else + { + throw new InvalidOperationException(); + } + } + return typeWrapper.Name; } - public static string GetName(Type type, object wrapperType) + internal static string getName(Type type) { - if(type == null) - { - string name = ((TypeWrapper)wrapperType).Name; - // HACK name is null for primitives - if(name != null) - { - return name; - } - type = ((TypeWrapper)wrapperType).Type; - } - if(wrapperType == null) - { - wrapperType = ClassLoaderWrapper.GetWrapperFromTypeFast(type); - } + TypeWrapper wrapperType = ClassLoaderWrapper.GetWrapperFromTypeFast(type); if(wrapperType != null) { string name = ((TypeWrapper)wrapperType).Name; @@ -1256,7 +1310,8 @@ namespace NativeCode.java } else { - return type.FullName; + // HACK we're assuming for the time being that Java code cannot define new value types + return DotNetTypeWrapper.GetName(type); } } else if(type.IsArray) @@ -1307,12 +1362,13 @@ namespace NativeCode.java } else { - sb.Append(type.FullName); + // HACK we're assuming for the time being that Java code cannot define new value types + sb.Append(DotNetTypeWrapper.GetName(type)); } } else { - sb.Append('L').Append(GetName(type, null)).Append(';'); + sb.Append('L').Append(getName(type)).Append(';'); } return sb.ToString(); } @@ -1333,32 +1389,38 @@ namespace NativeCode.java { return ((InnerClassAttribute)attribs[0]).InnerClassName; } - return type.FullName; + if(type.Assembly is System.Reflection.Emit.AssemblyBuilder || type.Assembly.IsDefined(typeof(JavaAssemblyAttribute), false)) + { + return type.FullName; + } + else + { + return DotNetTypeWrapper.GetName(type); + } } } [StackTraceInfo(Hidden = true)] - public static void initializeType(Type type) - { - RuntimeHelpers.RunClassConstructor(type.TypeHandle); - } - - public static object getClassLoader0(Type type, object wrapper) - { - if(wrapper != null) - { - return ((TypeWrapper)wrapper).GetClassLoader().GetJavaClassLoader(); - } - return ClassLoaderWrapper.GetClassLoader(type).GetJavaClassLoader(); - } - - public static object[] GetDeclaredMethods(Type type, object cwrapper, bool getMethods, bool publicOnly) + public static void initialize(object cwrapper) + { + TypeWrapper wrapper = (TypeWrapper)cwrapper; + wrapper.Finish(); + RuntimeHelpers.RunClassConstructor(wrapper.Type.TypeHandle); + } + + public static object getClassLoader0(object wrapper) + { + return ((TypeWrapper)wrapper).GetClassLoader().GetJavaClassLoader(); + } + + public static object getClassLoaderFromType(Type type) + { + return ClassLoaderWrapper.GetWrapperFromType(type).GetClassLoader().GetJavaClassLoader(); + } + + public static object[] GetDeclaredMethods(object cwrapper, bool getMethods, bool publicOnly) { TypeWrapper wrapper = (TypeWrapper)cwrapper; - if(wrapper == null) - { - wrapper = ClassLoaderWrapper.GetWrapperFromType(type); - } // we need to finish the type otherwise all methods will not be in the method map yet wrapper.Finish(); // we need to look through the array for unloadable types, because we may not let them @@ -1400,13 +1462,9 @@ namespace NativeCode.java return (MethodWrapper[])list.ToArray(typeof(MethodWrapper)); } - public static object[] GetDeclaredFields(Type type, object cwrapper, bool publicOnly) + public static object[] GetDeclaredFields(object cwrapper, bool publicOnly) { TypeWrapper wrapper = (TypeWrapper)cwrapper; - if(wrapper == null) - { - wrapper = ClassLoaderWrapper.GetWrapperFromType(type); - } // we need to finish the type otherwise all fields will not be in the field map yet wrapper.Finish(); // we need to look through the array for unloadable types, because we may not let them @@ -1434,13 +1492,9 @@ namespace NativeCode.java return fields; } - public static object[] GetDeclaredClasses(Type type, object cwrapper, bool publicOnly) + public static object[] GetDeclaredClasses(object cwrapper, bool publicOnly) { TypeWrapper wrapper = (TypeWrapper)cwrapper; - if(wrapper == null) - { - wrapper = ClassLoaderWrapper.GetWrapperFromType(type); - } // NOTE to get at the InnerClasses we need to finish the type wrapper.Finish(); TypeWrapper[] wrappers = wrapper.InnerClasses; @@ -1476,13 +1530,9 @@ namespace NativeCode.java return innerclasses; } - public static object GetDeclaringClass(Type type, object cwrapper) + public static object GetDeclaringClass(object cwrapper) { TypeWrapper wrapper = (TypeWrapper)cwrapper; - if(wrapper == null) - { - wrapper = ClassLoaderWrapper.GetWrapperFromType(type); - } // before we can call DeclaringTypeWrapper, we need to finish the type wrapper.Finish(); TypeWrapper declaring = wrapper.DeclaringTypeWrapper; @@ -1497,14 +1547,11 @@ namespace NativeCode.java return getClassFromWrapper(declaring); } - public static object[] GetInterfaces(Type type, object cwrapper) + public static object[] GetInterfaces(object cwrapper) { TypeWrapper wrapper = (TypeWrapper)cwrapper; - if(wrapper == null) - { - wrapper = ClassLoaderWrapper.GetWrapperFromType(type); - } // we need to finish the type otherwise all fields will not be in the field map yet + // TODO this should not be needed (make sure it isn't and remove) wrapper.Finish(); TypeWrapper[] interfaceWrappers = wrapper.Interfaces; object[] interfaces = new object[interfaceWrappers.Length]; @@ -1515,13 +1562,9 @@ namespace NativeCode.java return interfaces; } - public static int GetModifiers(Type type, Object cwrapper) + public static int GetModifiers(Object cwrapper) { TypeWrapper wrapper = (TypeWrapper)cwrapper; - if(wrapper == null) - { - wrapper = ClassLoaderWrapper.GetWrapperFromType(type); - } // NOTE ReflectiveModifiers is only available for finished types wrapper.Finish(); // NOTE we don't return the modifiers from the TypeWrapper, because for inner classes diff --git a/IK.VM.NET/compiler.cs b/IK.VM.NET/compiler.cs index a85acd0b..c66ea19f 100644 --- a/IK.VM.NET/compiler.cs +++ b/IK.VM.NET/compiler.cs @@ -960,7 +960,7 @@ class Compiler if(instr.NormalizedOpCode == NormalizedByteCode.__invokespecial && cpi.Name == "" && VerifierTypeWrapper.IsNew(type)) { TypeWrapper[] args = cpi.GetArgTypes(classLoader); - CastInterfaceArgs(args, i, true, false); + CastInterfaceArgs(args, i, false, false); } else { diff --git a/IK.VM.NET/map.xml b/IK.VM.NET/map.xml index 891bca14..4b1ad2d3 100644 --- a/IK.VM.NET/map.xml +++ b/IK.VM.NET/map.xml @@ -27,23 +27,22 @@ - + - + - + - + - @@ -68,7 +67,7 @@ - + @@ -104,9 +103,9 @@ - + - +
- + @@ -129,7 +128,7 @@ - + @@ -139,7 +138,7 @@ - + @@ -299,12 +298,12 @@ - + - + @@ -335,20 +334,20 @@ - + - + - + @@ -357,47 +356,47 @@ - + - + - + - + - + - + - + - + - + - + - + - + @@ -449,5 +448,15 @@ + + + + + + + + + + diff --git a/IK.VM.NET/mapxml.cs b/IK.VM.NET/mapxml.cs index b1b8e700..bd8b2572 100644 --- a/IK.VM.NET/mapxml.cs +++ b/IK.VM.NET/mapxml.cs @@ -20,7 +20,7 @@ obj11.Name = "notifyAll"; obj11.Sig = "()V"; obj11.Modifiers = (MapXml.MapModifiers)17; MapXml.Redirect obj15 = new MapXml.Redirect(); -obj15.Class = "System.Threading.Monitor"; +obj15.Class = "System.Threading.Monitor, mscorlib"; obj15.Name = "PulseAll"; obj15.Sig = "(Ljava.lang.Object;)V"; obj15.Type = "static"; @@ -31,7 +31,7 @@ obj20.Name = "notify"; obj20.Sig = "()V"; obj20.Modifiers = (MapXml.MapModifiers)17; MapXml.Redirect obj24 = new MapXml.Redirect(); -obj24.Class = "System.Threading.Monitor"; +obj24.Class = "System.Threading.Monitor, mscorlib"; obj24.Name = "Pulse"; obj24.Sig = "(Ljava.lang.Object;)V"; obj24.Type = "static"; @@ -44,7 +44,7 @@ obj29.Modifiers = (MapXml.MapModifiers)17; MapXml.InstructionList obj33 = new MapXml.InstructionList(); MapXml.Instruction[] obj34 = new MapXml.Instruction[2]; MapXml.Call obj35 = new MapXml.Call(); -obj35.type = "System.Threading.Monitor"; +obj35.type = "System.Threading.Monitor, mscorlib"; obj35.Name = "Wait"; obj35.Sig = "(Ljava.lang.Object;)Z"; obj34[0] = obj35; @@ -55,7 +55,7 @@ obj29.invokevirtual = obj33; MapXml.InstructionList obj40 = new MapXml.InstructionList(); MapXml.Instruction[] obj41 = new MapXml.Instruction[2]; MapXml.Call obj42 = new MapXml.Call(); -obj42.type = "System.Threading.Monitor"; +obj42.type = "System.Threading.Monitor, mscorlib"; obj42.Name = "Wait"; obj42.Sig = "(Ljava.lang.Object;)Z"; obj41[0] = obj42; @@ -138,7 +138,7 @@ MapXml.Instruction[] obj99 = new MapXml.Instruction[7]; MapXml.Dup obj100 = new MapXml.Dup(); obj99[0] = obj100; MapXml.IsInst obj101 = new MapXml.IsInst(); -obj101.type = "java.lang.Cloneable"; +obj101.Class = "java.lang.Cloneable"; obj99[1] = obj101; MapXml.BrTrue obj103 = new MapXml.BrTrue(); obj103.Name = "ok"; @@ -216,13 +216,13 @@ MapXml.Instruction[] obj152 = new MapXml.Instruction[9]; MapXml.Dup obj153 = new MapXml.Dup(); obj152[0] = obj153; MapXml.IsInst obj154 = new MapXml.IsInst(); -obj154.type = "System.String"; +obj154.type = "System.String, mscorlib"; obj152[1] = obj154; MapXml.BrFalse obj156 = new MapXml.BrFalse(); obj156.Name = "skip"; obj152[2] = obj156; MapXml.Castclass obj158 = new MapXml.Castclass(); -obj158.type = "System.String"; +obj158.type = "System.String, mscorlib"; obj152[3] = obj158; MapXml.Call obj160 = new MapXml.Call(); obj160.Class = "java.lang.StringHelper"; @@ -268,7 +268,7 @@ obj2.Methods = obj10; obj1[0] = obj2; MapXml.Class obj187 = new MapXml.Class(); obj187.Name = "java.lang.String"; -obj187.Type = "System.String"; +obj187.Type = "System.String, mscorlib"; obj187.Modifiers = (MapXml.MapModifiers)17; MapXml.Constructor[] obj191 = new MapXml.Constructor[12]; MapXml.Constructor obj192 = new MapXml.Constructor(); @@ -280,7 +280,7 @@ MapXml.Ldstr obj197 = new MapXml.Ldstr(); obj197.Value = ""; obj196[0] = obj197; MapXml.Call obj199 = new MapXml.Call(); -obj199.type = "System.String"; +obj199.type = "System.String, mscorlib"; obj199.Name = "Copy"; obj196[1] = obj199; obj195.invoke = obj196; @@ -308,7 +308,7 @@ MapXml.Constructor obj216 = new MapXml.Constructor(); obj216.Sig = "(Ljava.lang.String;)V"; obj216.Modifiers = (MapXml.MapModifiers)1; MapXml.Redirect obj219 = new MapXml.Redirect(); -obj219.Class = "System.String"; +obj219.Class = "System.String, mscorlib"; obj219.Name = "Copy"; obj219.Sig = "(Ljava.lang.String;)Ljava.lang.String;"; obj219.Type = "static"; @@ -808,7 +808,7 @@ obj606.Modifiers = (MapXml.MapModifiers)9; MapXml.InstructionList obj610 = new MapXml.InstructionList(); MapXml.Instruction[] obj611 = new MapXml.Instruction[1]; MapXml.NewObj obj612 = new MapXml.NewObj(); -obj612.type = "System.String"; +obj612.type = "System.String, mscorlib"; obj612.Name = ".ctor"; obj612.Sig = "([C)V"; obj611[0] = obj612; @@ -822,7 +822,7 @@ obj616.Modifiers = (MapXml.MapModifiers)9; MapXml.InstructionList obj620 = new MapXml.InstructionList(); MapXml.Instruction[] obj621 = new MapXml.Instruction[1]; MapXml.NewObj obj622 = new MapXml.NewObj(); -obj622.type = "System.String"; +obj622.type = "System.String, mscorlib"; obj622.Name = ".ctor"; obj622.Sig = "([CII)V"; obj621[0] = obj622; @@ -908,7 +908,7 @@ obj682.Modifiers = (MapXml.MapModifiers)1; MapXml.InstructionList obj685 = new MapXml.InstructionList(); MapXml.Instruction[] obj686 = new MapXml.Instruction[2]; MapXml.Call obj687 = new MapXml.Call(); -obj687.type = "ExceptionHelper"; +obj687.type = "ExceptionHelper, ik.vm.net"; obj687.Name = "get_NullString"; obj686[0] = obj687; MapXml.Call obj690 = new MapXml.Call(); @@ -925,7 +925,7 @@ obj694.Modifiers = (MapXml.MapModifiers)1; MapXml.InstructionList obj697 = new MapXml.InstructionList(); MapXml.Instruction[] obj698 = new MapXml.Instruction[2]; MapXml.Call obj699 = new MapXml.Call(); -obj699.type = "ExceptionHelper"; +obj699.type = "ExceptionHelper, ik.vm.net"; obj699.Name = "FilterMessage"; obj698[0] = obj699; MapXml.Call obj702 = new MapXml.Call(); @@ -946,7 +946,7 @@ obj711.Name = "x"; obj711.type = "System.Exception"; obj710[0] = obj711; MapXml.Call obj714 = new MapXml.Call(); -obj714.type = "ExceptionHelper"; +obj714.type = "ExceptionHelper, ik.vm.net"; obj714.Name = "FilterMessage"; obj710[1] = obj714; MapXml.LdLoc obj717 = new MapXml.LdLoc(); @@ -973,7 +973,7 @@ MapXml.LdLoc obj731 = new MapXml.LdLoc(); obj731.Name = "x"; obj727[1] = obj731; MapXml.Call obj733 = new MapXml.Call(); -obj733.type = "ExceptionHelper"; +obj733.type = "ExceptionHelper, ik.vm.net"; obj733.Name = "GetMessageFromCause"; obj727[2] = obj733; MapXml.LdLoc obj736 = new MapXml.LdLoc(); @@ -995,7 +995,7 @@ obj743.Sig = "()V"; obj743.Modifiers = (MapXml.MapModifiers)1; obj743.Type = "virtual"; MapXml.Redirect obj748 = new MapXml.Redirect(); -obj748.Class = "ExceptionHelper"; +obj748.Class = "ExceptionHelper, ik.vm.net"; obj748.Sig = "(Ljava.lang.Throwable;)V"; obj748.Type = "static"; obj743.redirect = obj748; @@ -1006,7 +1006,7 @@ obj752.Sig = "(Ljava.io.PrintStream;)V"; obj752.Modifiers = (MapXml.MapModifiers)1; obj752.Type = "virtual"; MapXml.Redirect obj757 = new MapXml.Redirect(); -obj757.Class = "ExceptionHelper"; +obj757.Class = "ExceptionHelper, ik.vm.net"; obj757.Sig = "(Ljava.lang.Throwable;Ljava.lang.Object;)V"; obj757.Type = "static"; obj752.redirect = obj757; @@ -1017,7 +1017,7 @@ obj761.Sig = "(Ljava.io.PrintWriter;)V"; obj761.Modifiers = (MapXml.MapModifiers)1; obj761.Type = "virtual"; MapXml.Redirect obj766 = new MapXml.Redirect(); -obj766.Class = "ExceptionHelper"; +obj766.Class = "ExceptionHelper, ik.vm.net"; obj766.Sig = "(Ljava.lang.Throwable;Ljava.lang.Object;)V"; obj766.Type = "static"; obj761.redirect = obj766; @@ -1028,7 +1028,7 @@ obj770.Sig = "()Ljava.lang.String;"; obj770.Modifiers = (MapXml.MapModifiers)1; obj770.Type = "virtual"; MapXml.Redirect obj775 = new MapXml.Redirect(); -obj775.Class = "ExceptionHelper"; +obj775.Class = "ExceptionHelper, ik.vm.net"; obj775.Sig = "(Ljava.lang.Throwable;)Ljava.lang.String;"; obj775.Type = "static"; obj770.redirect = obj775; @@ -1039,7 +1039,7 @@ obj779.Sig = "()Ljava.lang.String;"; obj779.Modifiers = (MapXml.MapModifiers)1; obj779.Type = "virtual"; MapXml.Redirect obj784 = new MapXml.Redirect(); -obj784.Class = "ExceptionHelper"; +obj784.Class = "ExceptionHelper, ik.vm.net"; obj784.Sig = "(Ljava.lang.Throwable;)Ljava.lang.String;"; obj784.Type = "static"; obj779.redirect = obj784; @@ -1050,7 +1050,7 @@ obj788.Sig = "()Ljava.lang.Throwable;"; obj788.Modifiers = (MapXml.MapModifiers)1; obj788.Type = "virtual"; MapXml.Redirect obj793 = new MapXml.Redirect(); -obj793.Class = "ExceptionHelper"; +obj793.Class = "ExceptionHelper, ik.vm.net"; obj793.Sig = "(Ljava.lang.Throwable;)Ljava.lang.Throwable;"; obj793.Type = "static"; obj788.redirect = obj793; @@ -1061,7 +1061,7 @@ obj797.Sig = "(Ljava.lang.Throwable;)Ljava.lang.Throwable;"; obj797.Modifiers = (MapXml.MapModifiers)1; obj797.Type = "virtual"; MapXml.Redirect obj802 = new MapXml.Redirect(); -obj802.Class = "ExceptionHelper"; +obj802.Class = "ExceptionHelper, ik.vm.net"; obj802.Sig = "(Ljava.lang.Throwable;Ljava.lang.Throwable;)Ljava.lang.Throwable;"; obj802.Type = "static"; obj797.redirect = obj802; @@ -1072,7 +1072,7 @@ obj806.Sig = "()Ljava.lang.Throwable;"; obj806.Modifiers = (MapXml.MapModifiers)1; obj806.Type = "virtual"; MapXml.Redirect obj811 = new MapXml.Redirect(); -obj811.Class = "ExceptionHelper"; +obj811.Class = "ExceptionHelper, ik.vm.net"; obj811.Sig = "(Ljava.lang.Throwable;)Ljava.lang.Throwable;"; obj811.Type = "static"; obj806.redirect = obj811; @@ -1083,7 +1083,7 @@ obj815.Sig = "()[Ljava.lang.StackTraceElement;"; obj815.Modifiers = (MapXml.MapModifiers)1; obj815.Type = "virtual"; MapXml.Redirect obj820 = new MapXml.Redirect(); -obj820.Class = "ExceptionHelper"; +obj820.Class = "ExceptionHelper, ik.vm.net"; obj820.Sig = "(Ljava.lang.Throwable;)[Ljava.lang.StackTraceElement;"; obj820.Type = "static"; obj815.redirect = obj820; @@ -1094,7 +1094,7 @@ obj824.Sig = "([Ljava.lang.StackTraceElement;)V"; obj824.Modifiers = (MapXml.MapModifiers)1; obj824.Type = "virtual"; MapXml.Redirect obj829 = new MapXml.Redirect(); -obj829.Class = "ExceptionHelper"; +obj829.Class = "ExceptionHelper, ik.vm.net"; obj829.Sig = "(Ljava.lang.Throwable;[Ljava.lang.StackTraceElement;)V"; obj829.Type = "static"; obj824.redirect = obj829; @@ -1105,7 +1105,7 @@ obj833.Sig = "()Ljava.lang.String;"; obj833.Modifiers = (MapXml.MapModifiers)1; obj833.Type = "virtual"; MapXml.Redirect obj838 = new MapXml.Redirect(); -obj838.Class = "ExceptionHelper"; +obj838.Class = "ExceptionHelper, ik.vm.net"; obj838.Sig = "(Ljava.lang.Throwable;)Ljava.lang.String;"; obj838.Type = "static"; obj833.redirect = obj838; @@ -1189,7 +1189,7 @@ obj860[7] = obj893; obj856.Methods = obj860; obj1[4] = obj856; obj0.remappings = obj1; -MapXml.Class[] obj899 = new MapXml.Class[3]; +MapXml.Class[] obj899 = new MapXml.Class[4]; MapXml.Class obj900 = new MapXml.Class(); obj900.Name = "java.lang.Runtime"; obj900.Modifiers = (MapXml.MapModifiers)0; @@ -1260,6 +1260,34 @@ obj936.invoke = obj940; obj935[0] = obj936; obj932.Methods = obj935; obj899[2] = obj932; +MapXml.Class obj946 = new MapXml.Class(); +obj946.Name = "ikvm.lang.ByteArrayHack"; +obj946.Modifiers = (MapXml.MapModifiers)0; +MapXml.Method[] obj949 = new MapXml.Method[2]; +MapXml.Method obj950 = new MapXml.Method(); +obj950.Name = "cast"; +obj950.Sig = "([B)[Lcli.System.Byte;"; +obj950.Modifiers = (MapXml.MapModifiers)0; +MapXml.Instruction[] obj954 = new MapXml.Instruction[2]; +MapXml.LdArg_0 obj955 = new MapXml.LdArg_0(); +obj954[0] = obj955; +MapXml.Ret obj956 = new MapXml.Ret(); +obj954[1] = obj956; +obj950.invoke = obj954; +obj949[0] = obj950; +MapXml.Method obj957 = new MapXml.Method(); +obj957.Name = "cast"; +obj957.Sig = "([Lcli.System.Byte;)[B"; +obj957.Modifiers = (MapXml.MapModifiers)0; +MapXml.Instruction[] obj961 = new MapXml.Instruction[2]; +MapXml.LdArg_0 obj962 = new MapXml.LdArg_0(); +obj961[0] = obj962; +MapXml.Ret obj963 = new MapXml.Ret(); +obj961[1] = obj963; +obj957.invoke = obj961; +obj949[1] = obj957; +obj946.Methods = obj949; +obj899[3] = obj946; obj0.nativeMethods = obj899; return obj0; } diff --git a/IK.VM.NET/remapper.cs b/IK.VM.NET/remapper.cs index bdc7998f..97cad95c 100644 --- a/IK.VM.NET/remapper.cs +++ b/IK.VM.NET/remapper.cs @@ -58,7 +58,7 @@ namespace MapXml { Debug.Assert(Class == null && type != null); Type[] argTypes = ClassLoaderWrapper.GetBootstrapClassLoader().ArgTypeListFromSig(Sig); - emitter = CodeEmitter.Create(opcode, ClassLoaderWrapper.GetType(type).GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, CallingConventions.Standard, argTypes, null)); + emitter = CodeEmitter.Create(opcode, Type.GetType(type, true).GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, CallingConventions.Standard, argTypes, null)); } else { @@ -77,11 +77,11 @@ namespace MapXml if(Sig != null) { Type[] argTypes = ClassLoaderWrapper.GetBootstrapClassLoader().ArgTypeListFromSig(Sig); - emitter = CodeEmitter.Create(opcode, ClassLoaderWrapper.GetType(type).GetMethod(Name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static, null, argTypes, null)); + emitter = CodeEmitter.Create(opcode, Type.GetType(type, true).GetMethod(Name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static, null, argTypes, null)); } else { - emitter = CodeEmitter.Create(opcode, ClassLoaderWrapper.GetType(type).GetMethod(Name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static)); + emitter = CodeEmitter.Create(opcode, Type.GetType(type, true).GetMethod(Name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static)); } } } @@ -168,7 +168,7 @@ namespace MapXml } else { - typeType = ClassLoaderWrapper.GetType(type); + typeType = Type.GetType(type, true); } } ilgen.Emit(opcode, typeType != null ? typeType : typeWrapper.Type); @@ -296,7 +296,7 @@ namespace MapXml Debug.Assert(Class == null ^ type == null); if(type != null) { - typeType = ClassLoaderWrapper.GetType(type); + typeType = Type.GetType(type, true); } else { diff --git a/IK.VM.NET/vm.cs b/IK.VM.NET/vm.cs index edbe977c..83dd5bc2 100644 --- a/IK.VM.NET/vm.cs +++ b/IK.VM.NET/vm.cs @@ -29,6 +29,7 @@ using System.Collections; using System.Xml; using System.Diagnostics; using OpenSystem.Java; +using System.Text.RegularExpressions; public class JVM { @@ -145,7 +146,6 @@ public class JVM private string assembly; private string path; private AssemblyBuilder assemblyBuilder; - private ModuleBuilder moduleBuilder; internal CompilerClassLoader(string path, string assembly, Hashtable classes) : base(null) @@ -157,26 +157,23 @@ public class JVM protected override ModuleBuilder CreateModuleBuilder() { - if(moduleBuilder == null) + AssemblyName name = new AssemblyName(); + name.Name = assembly; + assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.RunAndSave); + CustomAttributeBuilder ikvmAssemblyAttr = new CustomAttributeBuilder(typeof(JavaAssemblyAttribute).GetConstructor(Type.EmptyTypes), new object[0]); + assemblyBuilder.SetCustomAttribute(ikvmAssemblyAttr); + ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(path, JVM.Debug); + if(JVM.Debug) { - AssemblyName name = new AssemblyName(); - name.Name = assembly; - assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.RunAndSave); - CustomAttributeBuilder ikvmAssemblyAttr = new CustomAttributeBuilder(typeof(JavaAssemblyAttribute).GetConstructor(Type.EmptyTypes), new object[0]); - assemblyBuilder.SetCustomAttribute(ikvmAssemblyAttr); - moduleBuilder = assemblyBuilder.DefineDynamicModule(path, JVM.Debug); - if(JVM.Debug) - { - CustomAttributeBuilder debugAttr = new CustomAttributeBuilder(typeof(DebuggableAttribute).GetConstructor(new Type[] { typeof(bool), typeof(bool) }), new object[] { true, true }); - moduleBuilder.SetCustomAttribute(debugAttr); - } + CustomAttributeBuilder debugAttr = new CustomAttributeBuilder(typeof(DebuggableAttribute).GetConstructor(new Type[] { typeof(bool), typeof(bool) }), new object[] { true, true }); + moduleBuilder.SetCustomAttribute(debugAttr); } return moduleBuilder; } - internal override TypeWrapper GetBootstrapType(string name) + internal override TypeWrapper GetTypeWrapperCompilerHook(string name) { - TypeWrapper type = base.GetBootstrapType(name); + TypeWrapper type = base.GetTypeWrapperCompilerHook(name); if(type == null) { ClassFile f = (ClassFile)classes[name]; @@ -201,11 +198,7 @@ public class JVM internal void AddResources(Hashtable resources) { - if(moduleBuilder == null) - { - // this happens if the module contains no clases - CreateModuleBuilder(); - } + ModuleBuilder moduleBuilder = this.ModuleBuilder; foreach(DictionaryEntry d in resources) { byte[] buf = (byte[])d.Value; @@ -218,7 +211,7 @@ public class JVM } } - public static void Compile(string path, string assembly, string mainClass, PEFileKinds target, byte[][] classes, string[] references, bool nojni, Hashtable resources) + public static void Compile(string path, string assembly, string mainClass, PEFileKinds target, byte[][] classes, string[] references, bool nojni, Hashtable resources, string[] classesToExclude) { isStaticCompiler = true; noJniStubs = nojni; @@ -232,12 +225,29 @@ public class JVM { ClassFile f = new ClassFile(classes[i], 0, classes[i].Length, null); string name = f.Name; + bool excluded = false; + for(int j = 0; j < classesToExclude.Length; j++) + { + if(Regex.IsMatch(name, classesToExclude[j])) + { + excluded = true; + //Console.WriteLine("Excluding: {0} on rule {1}", name, (String)classesToExclude[j]); + break; + } + } +// if (!excluded) +// Console.WriteLine("Adding: {0}", name); +// else +// Console.WriteLine("Not Adding: {0}", name); if(h.ContainsKey(name)) { Console.Error.WriteLine("Duplicate class name: {0}", name); return; } - h[name] = f; + if(!excluded) + { + h[name] = f; + } } // make sure all inner classes have a reference to their outer class @@ -246,7 +256,7 @@ public class JVM foreach(ClassFile classFile in h.Values) { // don't handle inner classes for NetExp types - if(classFile.NetExpTypeAttribute == null) + if(classFile.NetExpAssemblyAttribute == null) { ClassFile.InnerClass[] innerClasses = classFile.InnerClasses; if(innerClasses != null) diff --git a/classpath/System.Xml.jar b/classpath/System.Xml.jar index 4c7e5df4..1037a911 100644 Binary files a/classpath/System.Xml.jar and b/classpath/System.Xml.jar differ diff --git a/classpath/System.jar b/classpath/System.jar index a53fdef5..be3a461b 100644 Binary files a/classpath/System.jar and b/classpath/System.jar differ diff --git a/classpath/gnu/java/net/protocol/ikvmres/Handler.java b/classpath/gnu/java/net/protocol/ikvmres/Handler.java index 8b2a86e5..1699dc1a 100644 --- a/classpath/gnu/java/net/protocol/ikvmres/Handler.java +++ b/classpath/gnu/java/net/protocol/ikvmres/Handler.java @@ -24,8 +24,8 @@ package gnu.java.net.protocol.ikvmres; -import system.io.*; -import system.reflection.*; +import cli.System.IO.*; +import cli.System.Reflection.*; import java.net.*; import java.io.*; import java.io.IOException; @@ -56,8 +56,8 @@ class IkvmresURLConnection extends URLConnection { throw new IOException("resource " + resource + " not found in assembly " + assembly); } - byte[] b = new byte[system.runtime.interopservices.Marshal.SizeOf(fi.get_FieldType())]; - system.runtime.compilerservices.RuntimeHelpers.InitializeArray((system.Array)(Object)b, fi.get_FieldHandle()); + byte[] b = new byte[cli.System.Runtime.InteropServices.Marshal.SizeOf(fi.get_FieldType())]; + cli.System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray((cli.System.Array)(Object)b, fi.get_FieldHandle()); inputStream = new ByteArrayInputStream(b); connected = true; } diff --git a/classpath/ikvm/lang/ByteArrayHack.java b/classpath/ikvm/lang/ByteArrayHack.java new file mode 100644 index 00000000..55440604 --- /dev/null +++ b/classpath/ikvm/lang/ByteArrayHack.java @@ -0,0 +1,9 @@ +package ikvm.lang; + +public final class ByteArrayHack +{ + private ByteArrayHack() {} + + public static native cli.System.Byte[] cast(byte[] b); + public static native byte[] cast(cli.System.Byte[] b); +} diff --git a/classpath/ikvm/lang/DotNetProcess.java b/classpath/ikvm/lang/DotNetProcess.java index 89315402..7656923c 100644 --- a/classpath/ikvm/lang/DotNetProcess.java +++ b/classpath/ikvm/lang/DotNetProcess.java @@ -26,14 +26,14 @@ package ikvm.lang; import java.io.InputStream; import java.io.OutputStream; import java.io.File; -import system.text.StringBuilder; -import system.diagnostics.ProcessStartInfo; +import cli.System.Text.StringBuilder; +import cli.System.Diagnostics.ProcessStartInfo; public class DotNetProcess extends Process { - private system.diagnostics.Process proc; + private cli.System.Diagnostics.Process proc; - private DotNetProcess(system.diagnostics.Process proc) + private DotNetProcess(cli.System.Diagnostics.Process proc) { this.proc = proc; } @@ -72,10 +72,10 @@ public class DotNetProcess extends Process { try { - if(false) throw new system.InvalidOperationException(); + if(false) throw new cli.System.InvalidOperationException(); proc.Kill(); } - catch(system.InvalidOperationException x) + catch(cli.System.InvalidOperationException x) { } } @@ -119,6 +119,6 @@ public class DotNetProcess extends Process } } // TODO map the exceptions - return new DotNetProcess(system.diagnostics.Process.Start(si)); + return new DotNetProcess(cli.System.Diagnostics.Process.Start(si)); } } diff --git a/classpath/java/io/FileDescriptor.java b/classpath/java/io/FileDescriptor.java index 7d8fb396..19a657c8 100644 --- a/classpath/java/io/FileDescriptor.java +++ b/classpath/java/io/FileDescriptor.java @@ -38,8 +38,9 @@ exception statement from your version. */ package java.io; -import system.Console; -import system.io.*; +import cli.System.Console; +import cli.System.IO.*; +import ikvm.lang.ByteArrayHack; /** * This class represents an opaque file handle as a Java class. It should @@ -91,12 +92,12 @@ public final class FileDescriptor } try { - if(false) throw new system.io.IOException(); + if(false) throw new cli.System.IO.IOException(); stream.Flush(); } - catch(system.io.IOException x) + catch(cli.System.IO.IOException x) { - throw new SyncFailedException(x.get_Message()); + throw new SyncFailedException(x.getMessage()); } } @@ -115,11 +116,11 @@ public final class FileDescriptor try { stream.Close(); - if(false) throw new system.io.IOException(); + if(false) throw new cli.System.IO.IOException(); } - catch(system.io.IOException x) + catch(cli.System.IO.IOException x) { - throw new IOException(x.get_Message()); + throw new IOException(x.getMessage()); } } stream = null; @@ -171,23 +172,23 @@ public final class FileDescriptor default: throw new IllegalArgumentException("Invalid mode value: " + mode); } - if(false) throw new system.io.IOException(); - if(false) throw new system.security.SecurityException(); - if(false) throw new system.UnauthorizedAccessException(); - stream = system.io.File.Open(demanglePath(path), fileMode, fileAccess, FileShare.ReadWrite); + if(false) throw new cli.System.IO.IOException(); + if(false) throw new cli.System.Security.SecurityException(); + if(false) throw new cli.System.UnauthorizedAccessException(); + stream = cli.System.IO.File.Open(demanglePath(path), FileMode.wrap(fileMode), FileAccess.wrap(fileAccess), FileShare.wrap(FileShare.ReadWrite)); } - catch(system.security.SecurityException x1) + catch(cli.System.Security.SecurityException x1) { - throw new SecurityException(x1.get_Message()); + throw new SecurityException(x1.getMessage()); } - catch(system.io.IOException x2) + catch(cli.System.IO.IOException x2) { - throw new FileNotFoundException(x2.get_Message()); + throw new FileNotFoundException(x2.getMessage()); } - catch(system.UnauthorizedAccessException x3) + catch(cli.System.UnauthorizedAccessException x3) { // this is caused by "name" being a directory instead of a file - throw new FileNotFoundException(x3.get_Message()); + throw new FileNotFoundException(x3.getMessage()); } // TODO map al the other exceptions as well... } @@ -199,12 +200,12 @@ public final class FileDescriptor try { - if(false) throw new system.io.IOException(); + if(false) throw new cli.System.IO.IOException(); return stream.get_Position(); } - catch(system.io.IOException x) + catch(cli.System.IO.IOException x) { - throw new IOException(x.get_Message()); + throw new IOException(x.getMessage()); } // TODO map al the other exceptions as well... } @@ -216,12 +217,12 @@ public final class FileDescriptor try { - if(false) throw new system.io.IOException(); + if(false) throw new cli.System.IO.IOException(); return stream.get_Length(); } - catch(system.io.IOException x) + catch(cli.System.IO.IOException x) { - throw new IOException(x.get_Message()); + throw new IOException(x.getMessage()); } // TODO map al the other exceptions as well... } @@ -237,12 +238,12 @@ public final class FileDescriptor try { - if(false) throw new system.io.IOException(); + if(false) throw new cli.System.IO.IOException(); stream.SetLength(len); } - catch(system.io.IOException x) + catch(cli.System.IO.IOException x) { - throw new IOException(x.get_Message()); + throw new IOException(x.getMessage()); } // TODO map al the other exceptions as well... } @@ -257,17 +258,17 @@ public final class FileDescriptor try { - if(false) throw new system.io.IOException(); - long newpos = stream.Seek(offset, whence); + if(false) throw new cli.System.IO.IOException(); + long newpos = stream.Seek(offset, SeekOrigin.wrap(whence)); if(stopAtEof && newpos > stream.get_Length()) { - newpos = stream.Seek(0, SeekOrigin.End); + newpos = stream.Seek(0, SeekOrigin.wrap(SeekOrigin.End)); } return newpos; } - catch(system.io.IOException x) + catch(cli.System.IO.IOException x) { - throw new IOException(x.get_Message()); + throw new IOException(x.getMessage()); } // TODO map al the other exceptions as well... } @@ -279,12 +280,12 @@ public final class FileDescriptor try { - if(false) throw new system.io.IOException(); + if(false) throw new cli.System.IO.IOException(); return stream.ReadByte(); } - catch(system.io.IOException x) + catch(cli.System.IO.IOException x) { - throw new IOException(x.get_Message()); + throw new IOException(x.getMessage()); } // TODO map al the other exceptions as well... } @@ -305,37 +306,25 @@ public final class FileDescriptor try { - if(false) throw new system.io.IOException(); - int count = stream.Read(buf, offset, len); + if(false) throw new cli.System.IO.IOException(); + int count = stream.Read(ByteArrayHack.cast(buf), offset, len); if(count == 0) { count = -1; } return count; } - catch(system.io.IOException x) + catch(cli.System.IO.IOException x) { - throw new IOException(x.get_Message()); + throw new IOException(x.getMessage()); } // TODO map al the other exceptions as well... } synchronized void write(int b) throws IOException { - if(stream == null) - { - throw new IOException("Invalid FileDescriptor"); - } - try - { - if(false) throw new system.io.IOException(); - stream.WriteByte((byte)b); - } - catch(system.io.IOException x) - { - throw new IOException(x.get_Message()); - } - // TODO map al the other exceptions as well... + // HACK we can't call WriteByte because it takes a cli.System.Byte + write(new byte[] { (byte)b }, 0, 1); } synchronized void write(byte[] buf, int offset, int len) throws IOException @@ -354,12 +343,12 @@ public final class FileDescriptor try { - if(false) throw new system.io.IOException(); - stream.Write(buf, offset, len); + if(false) throw new cli.System.IO.IOException(); + stream.Write(ByteArrayHack.cast(buf), offset, len); } - catch(system.io.IOException x) + catch(cli.System.IO.IOException x) { - throw new IOException(x.get_Message()); + throw new IOException(x.getMessage()); } // TODO map al the other exceptions as well... } @@ -371,17 +360,17 @@ public final class FileDescriptor try { - if(false) throw new system.io.IOException(); - if(false) throw new system.NotSupportedException(); + if(false) throw new cli.System.IO.IOException(); + if(false) throw new cli.System.NotSupportedException(); if(stream.get_CanSeek()) return (int)Math.min(Integer.MAX_VALUE, Math.max(0, stream.get_Length() - stream.get_Position())); return 0; } - catch(system.io.IOException x) + catch(cli.System.IO.IOException x) { - throw new IOException(x.get_Message()); + throw new IOException(x.getMessage()); } - catch(system.NotSupportedException x1) + catch(cli.System.NotSupportedException x1) { // this means we have a broken Stream, because if CanSeek returns true, it must // support Length and Position diff --git a/classpath/java/lang/ObjectHelper.java b/classpath/java/lang/ObjectHelper.java index 9cc99c12..f1f464e0 100644 --- a/classpath/java/lang/ObjectHelper.java +++ b/classpath/java/lang/ObjectHelper.java @@ -44,12 +44,12 @@ public class ObjectHelper } if(timeout == 0 && nanos == 0) { - system.threading.Monitor.Wait(o); + cli.System.Threading.Monitor.Wait(o); } else { // TODO handle time span calculation overflow - system.threading.Monitor.Wait(o, new system.TimeSpan(timeout * 10000 + (nanos + 99) / 100)); + cli.System.Threading.Monitor.Wait(o, new cli.System.TimeSpan(timeout * 10000 + (nanos + 99) / 100)); } } diff --git a/classpath/java/lang/StringHelper.java b/classpath/java/lang/StringHelper.java index 43420920..0e7fceeb 100644 --- a/classpath/java/lang/StringHelper.java +++ b/classpath/java/lang/StringHelper.java @@ -293,25 +293,24 @@ public final class StringHelper public static String substring(String s, int off, int end) { - return ((system.String)(Object)s).Substring(off, end - off); + return cli.System.String.Substring(s, off, end - off); } - public static boolean startsWith(String si, String prefix, int toffset) + public static boolean startsWith(String s, String prefix, int toffset) { if(toffset < 0) { return false; } - system.String s = (system.String)(Object)si; - s = (system.String)(Object)s.Substring(Math.min(s.get_Length(), toffset)); - return s.StartsWith(prefix); + s = cli.System.String.Substring(s, Math.min(s.length(), toffset)); + return cli.System.String.StartsWith(s, prefix); } public static char charAt(String s, int index) { try { - return ((system.String)(Object)s).get_Chars(index); + return cli.System.String.get_Chars(s, index); } // NOTE the System.IndexOutOfRangeException thrown by get_Chars, is translated by our // exception handling code to an ArrayIndexOutOfBoundsException, so we catch that. @@ -323,7 +322,7 @@ public final class StringHelper public static void getChars(String s, int srcBegin, int srcEnd, char[] dst, int dstBegin) { - ((system.String)(Object)s).CopyTo(srcBegin, dst, dstBegin, srcEnd - srcBegin); + cli.System.String.CopyTo(s, srcBegin, dst, dstBegin, srcEnd - srcBegin); } // this exposes the package accessible "count" field (for use by StringBuffer) @@ -344,31 +343,28 @@ public final class StringHelper return 0; } - public static int indexOf(String si, char ch, int fromIndex) + public static int indexOf(String s, char ch, int fromIndex) { // Java allow fromIndex to both below zero or above the length of the string, .NET doesn't - system.String s = (system.String)(Object)si; - return s.IndexOf(ch, Math.max(0, Math.min(s.get_Length(), fromIndex))); + return cli.System.String.IndexOf(s, ch, Math.max(0, Math.min(s.length(), fromIndex))); } - public static int indexOf(String si, String o, int fromIndex) + public static int indexOf(String s, String o, int fromIndex) { // Java allow fromIndex to both below zero or above the length of the string, .NET doesn't - system.String s = (system.String)(Object)si; - return s.IndexOf(o, Math.max(0, Math.min(s.get_Length(), fromIndex))); + return cli.System.String.IndexOf(s, o, Math.max(0, Math.min(s.length(), fromIndex))); } - public static int lastIndexOf(String si, char ch, int fromIndex) + public static int lastIndexOf(String s, char ch, int fromIndex) { - system.String s = (system.String)(Object)si; // start by dereferencing s, to make sure we throw a NullPointerException if s is null - int len = s.get_Length(); + int len = s.length(); if(fromIndex < 0) { return -1; } // Java allow fromIndex to be above the length of the string, .NET doesn't - return s.LastIndexOf(ch, Math.min(len - 1, fromIndex)); + return cli.System.String.LastIndexOf(s, ch, Math.min(len - 1, fromIndex)); } public static int lastIndexOf(String s, String o) @@ -376,11 +372,10 @@ public final class StringHelper return lastIndexOf(s, o, s.length()); } - public static int lastIndexOf(String si, String o, int fromIndex) + public static int lastIndexOf(String s, String o, int fromIndex) { - system.String s = (system.String)(Object)si; // start by dereferencing s, to make sure we throw a NullPointerException if s is null - int len = s.get_Length(); + int len = s.length(); if(fromIndex < 0) { return -1; @@ -390,7 +385,7 @@ public final class StringHelper return Math.min(len, fromIndex); } // Java allow fromIndex to be above the length of the string, .NET doesn't - return s.LastIndexOf(o, Math.min(len - 1, fromIndex + o.length() - 1)); + return cli.System.String.LastIndexOf(s, o, Math.min(len - 1, fromIndex + o.length() - 1)); } public static String concat(String s1, String s2) @@ -401,7 +396,7 @@ public final class StringHelper { return s1; } - return system.String.Concat(s1, s2); + return cli.System.String.Concat(s1, s2); } public static void getBytes(String s, int srcBegin, int srcEnd, byte dst[], int dstBegin) @@ -501,7 +496,7 @@ public final class StringHelper public static String valueOf(char c) { - return new system.String(c, 1).ToString(); + return cli.System.String.__new(c, 1); } public static String valueOf(float f) @@ -531,11 +526,11 @@ public final class StringHelper public static int hashCode(String s) { - system.String ns = (system.String)(Object)s; int h = 0; - for(int i = 0; i < ns.get_Length(); i++) + int len = s.length(); + for(int i = 0; i < len; i++) { - h = h *31 + ns.get_Chars(i); + h = h *31 + cli.System.String.get_Chars(s, i); } return h; } diff --git a/classpath/java/lang/VMClass.java b/classpath/java/lang/VMClass.java index c3b5f8e9..69f3f459 100644 --- a/classpath/java/lang/VMClass.java +++ b/classpath/java/lang/VMClass.java @@ -40,8 +40,8 @@ package java.lang; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; -import system.*; -import system.reflection.*; +import cli.System.*; +import cli.System.Reflection.*; /* * This class is a reference version, mainly for compiling a class library @@ -57,366 +57,345 @@ import system.reflection.*; */ final class VMClass { - /** The .NET type */ - private Type type; - private Object wrapper; + private Object wrapper; // the corresponding TypeWrapper private Class clazz; - public static native Class getClassFromType(Type t); - private static native Type getTypeFromWrapper(Object clazz, Object wrapper); - private static native Object getWrapperFromType(Type t); - - private static Type getTypeFromClass(Class c) + // NOTE this is used in classpath.cs to go from a Class object to a TypeWrapper + private static Object getWrapperFromClass(Class c) { - return c.vmClass.getType(); + return c.vmClass.wrapper; } - private Type getType() - { - if(type == null) - { - type = getTypeFromWrapper(clazz, wrapper); - } - return type; - } - private Object getWrapper() - { - if(wrapper == null) - { - wrapper = getWrapperFromType(type); - } - return wrapper; - } + private VMClass(Object wrapper) + { + this.wrapper = wrapper; + } - private VMClass(Type type, Object wrapper) - { - this.type = type; - this.wrapper = wrapper; - } - - private static Class createClass(Type type, Object wrapper) - { - VMClass vmClass = new VMClass(type, wrapper); - Class c = new Class(vmClass); - vmClass.clazz = c; - return c; - } + // HACK public because we want to create a delegate to call it + public static Object createClass(Object wrapper) + { + VMClass vmClass = new VMClass(wrapper); + Class c = new Class(vmClass); + vmClass.clazz = c; + return c; + } // HACK we need a way to call ClassLoader.loadClass() from C#, so we need this helper method - public static Object __loadClassHelper(Object loader, String name) throws java.lang.ClassNotFoundException + // and its public because we want to create a delegate to call it + public static Object loadClassHelper(Object loader, String name) throws java.lang.ClassNotFoundException { - return ((ClassLoader)loader).loadClass(name).vmClass.getWrapper(); + return ((ClassLoader)loader).loadClass(name).vmClass.wrapper; } - /** - * Discover whether an Object is an instance of this Class. Think of it - * as almost like o instanceof (this class). - * - * @param o the Object to check - * @return whether o is an instance of this class - * @since 1.1 - */ - boolean isInstance(Object o) - { - // TODO this needs to be implemented by the "native" code, because - // remapped types can appear to implement interfaces that they don't - // actually implement - return getType().IsInstanceOfType(o); - } + /** + * Discover whether an Object is an instance of this Class. Think of it + * as almost like o instanceof (this class). + * + * @param o the Object to check + * @return whether o is an instance of this class + * @since 1.1 + */ + boolean isInstance(Object o) + { + return o != null && clazz.isAssignableFrom(o.getClass()); + } - /** - * Discover whether an instance of the Class parameter would be an - * instance of this Class as well. Think of doing - * isInstance(c.newInstance()) or even - * c.newInstance() instanceof (this class). While this - * checks widening conversions for objects, it must be exact for primitive - * types. - * - * @param c the class to check - * @return whether an instance of c would be an instance of this class - * as well - * @throws NullPointerException if c is null - * @since 1.1 - */ - boolean isAssignableFrom(Class c) - { - // this needs to be implemented by the "native" code, because - // remapped types can appear to implement interfaces that they don't - // actually implement - return IsAssignableFrom(getWrapper(), c.vmClass.getWrapper()); - } - private static native boolean IsAssignableFrom(Object w1, Object w2); + /** + * Discover whether an instance of the Class parameter would be an + * instance of this Class as well. Think of doing + * isInstance(c.newInstance()) or even + * c.newInstance() instanceof (this class). While this + * checks widening conversions for objects, it must be exact for primitive + * types. + * + * @param c the class to check + * @return whether an instance of c would be an instance of this class + * as well + * @throws NullPointerException if c is null + * @since 1.1 + */ + boolean isAssignableFrom(Class c) + { + // this is implemented by the "native" code, because + // remapped types can appear to implement interfaces that they don't + // actually implement + return IsAssignableFrom(wrapper, c.vmClass.wrapper); + } + private static native boolean IsAssignableFrom(Object w1, Object w2); - /** - * Check whether this class is an interface or not. Array types are not - * interfaces. - * - * @return whether this class is an interface or not - */ - boolean isInterface() - { - return getType().get_IsInterface(); - } + /** + * Check whether this class is an interface or not. Array types are not + * interfaces. + * + * @return whether this class is an interface or not + */ + boolean isInterface() + { + return IsInterface(wrapper); + } + private static native boolean IsInterface(Object wrapper); - /** - * Return whether this class is a primitive type. A primitive type class - * is a class representing a kind of "placeholder" for the various - * primitive types, or void. You can access the various primitive type - * classes through java.lang.Boolean.TYPE, java.lang.Integer.TYPE, etc., - * or through boolean.class, int.class, etc. - * - * @return whether this class is a primitive type - * @see Boolean#TYPE - * @see Byte#TYPE - * @see Character#TYPE - * @see Short#TYPE - * @see Integer#TYPE - * @see Long#TYPE - * @see Float#TYPE - * @see Double#TYPE - * @see Void#TYPE - * @since 1.1 - */ - boolean isPrimitive() - { - return clazz == boolean.class || - clazz == byte.class || - clazz == char.class || - clazz == short.class || - clazz == int.class || - clazz == long.class || - clazz == float.class || - clazz == double.class || - clazz == void.class; - } + /** + * Return whether this class is a primitive type. A primitive type class + * is a class representing a kind of "placeholder" for the various + * primitive types, or void. You can access the various primitive type + * classes through java.lang.Boolean.TYPE, java.lang.Integer.TYPE, etc., + * or through boolean.class, int.class, etc. + * + * @return whether this class is a primitive type + * @see Boolean#TYPE + * @see Byte#TYPE + * @see Character#TYPE + * @see Short#TYPE + * @see Integer#TYPE + * @see Long#TYPE + * @see Float#TYPE + * @see Double#TYPE + * @see Void#TYPE + * @since 1.1 + */ + boolean isPrimitive() + { + return clazz == boolean.class || + clazz == byte.class || + clazz == char.class || + clazz == short.class || + clazz == int.class || + clazz == long.class || + clazz == float.class || + clazz == double.class || + clazz == void.class; + } - /** - * Get the name of this class, separated by dots for package separators. - * Primitive types and arrays are encoded as: - *
-	* boolean             Z
-	* byte                B
-	* char                C
-	* short               S
-	* int                 I
-	* long                J
-	* float               F
-	* double              D
-	* void                V
-	* array type          [element type
-	* class or interface, alone: <dotted name>
-	* class or interface, as element type: L<dotted name>;
-	*
-	* @return the name of this class
-	*/
-	String getName()
-	{
-		// getName() is used by the classloader, so it shouldn't trigger a resolve of the class
-		return GetName(type, wrapper);
-	}
-	private static native String GetName(Type type, Object wrapper);
+    /**
+     * Get the name of this class, separated by dots for package separators.
+     * Primitive types and arrays are encoded as:
+     * 
+     * boolean             Z
+     * byte                B
+     * char                C
+     * short               S
+     * int                 I
+     * long                J
+     * float               F
+     * double              D
+     * void                V
+     * array type          [element type
+     * class or interface, alone: <dotted name>
+     * class or interface, as element type: L<dotted name>;
+     *
+     * @return the name of this class
+     */
+    String getName()
+    {
+	// getName() is used by the classloader, so it shouldn't trigger a resolve of the class
+	return GetName(wrapper);
+    }
+    private static native String GetName(Object wrapper);
 
-	/**
-	* Get the direct superclass of this class.  If this is an interface,
-	* Object, a primitive type, or void, it will return null. If this is an
-	* array type, it will return Object.
-	*
-	* @return the direct superclass of this class
-	*/
-	Class getSuperclass()
-	{
-		return (Class)GetSuperClassFromWrapper(getWrapper());
-	}
-	private native static Object GetSuperClassFromWrapper(Object wrapper);
+    /**
+     * Get the direct superclass of this class.  If this is an interface,
+     * Object, a primitive type, or void, it will return null. If this is an
+     * array type, it will return Object.
+     *
+     * @return the direct superclass of this class
+     */
+    Class getSuperclass()
+    {
+	return (Class)GetSuperClassFromWrapper(wrapper);
+    }
+    private native static Object GetSuperClassFromWrapper(Object wrapper);
 
-	/**
-	* Get the interfaces this class directly implements, in the
-	* order that they were declared. This returns an empty array, not null,
-	* for Object, primitives, void, and classes or interfaces with no direct
-	* superinterface. Array types return Cloneable and Serializable.
-	*
-	* @return the interfaces this class directly implements
-	*/
-	Class[] getInterfaces()
-	{
-		Object[] interfaces = GetInterfaces(type, wrapper);
-		Class[] interfacesClass = new Class[interfaces.length];
-		System.arraycopy(interfaces, 0, interfacesClass, 0, interfaces.length);
-		return interfacesClass;
-	}
-	private static native Object[] GetInterfaces(Type type, Object wrapper);
+    /**
+     * Get the interfaces this class directly implements, in the
+     * order that they were declared. This returns an empty array, not null,
+     * for Object, primitives, void, and classes or interfaces with no direct
+     * superinterface. Array types return Cloneable and Serializable.
+     *
+     * @return the interfaces this class directly implements
+     */
+    Class[] getInterfaces()
+    {
+	Object[] interfaces = GetInterfaces(wrapper);
+	Class[] interfacesClass = new Class[interfaces.length];
+	System.arraycopy(interfaces, 0, interfacesClass, 0, interfaces.length);
+	return interfacesClass;
+    }
+    private static native Object[] GetInterfaces(Object wrapper);
 
-	/**
-	* If this is an array, get the Class representing the type of array.
-	* Examples: "[[Ljava.lang.String;" would return "[Ljava.lang.String;", and
-	* calling getComponentType on that would give "java.lang.String".  If
-	* this is not an array, returns null.
-	*
-	* @return the array type of this class, or null
-	* @see Array
-	* @since 1.1
-	*/
-	Class getComponentType()
-	{
-		// .NET array types can have unfinished element types, but we don't
-		// want to expose those, so we may need to finish the type
-		return (Class)getComponentClassFromWrapper(getWrapper());
-	}
-	private static native Object getComponentClassFromWrapper(Object wrapper);
+    /**
+     * If this is an array, get the Class representing the type of array.
+     * Examples: "[[Ljava.lang.String;" would return "[Ljava.lang.String;", and
+     * calling getComponentType on that would give "java.lang.String".  If
+     * this is not an array, returns null.
+     *
+     * @return the array type of this class, or null
+     * @see Array
+     * @since 1.1
+     */
+    Class getComponentType()
+    {
+	// .NET array types can have unfinished element types, but we don't
+	// want to expose those, so we may need to finish the type
+	return (Class)getComponentClassFromWrapper(wrapper);
+    }
+    private static native Object getComponentClassFromWrapper(Object wrapper);
 
-	/**
-	* Get the modifiers of this class.  These can be decoded using Modifier,
-	* and is limited to one of public, protected, or private, and any of
-	* final, static, abstract, or interface. An array class has the same
-	* public, protected, or private modifier as its component type, and is
-	* marked final but not an interface. Primitive types and void are marked
-	* public and final, but not an interface.
-	*
-	* @return the modifiers of this class
-	* @see Modifer
-	* @since 1.1
-	*/
-	int getModifiers()
-	{
-		return GetModifiers(type, wrapper);
-	}
-	private static native int GetModifiers(Type type, Object wrapper);
+    /**
+     * Get the modifiers of this class.  These can be decoded using Modifier,
+     * and is limited to one of public, protected, or private, and any of
+     * final, static, abstract, or interface. An array class has the same
+     * public, protected, or private modifier as its component type, and is
+     * marked final but not an interface. Primitive types and void are marked
+     * public and final, but not an interface.
+     *
+     * @return the modifiers of this class
+     * @see Modifer
+     * @since 1.1
+     */
+    int getModifiers()
+    {
+	return GetModifiers(wrapper);
+    }
+    private static native int GetModifiers(Object wrapper);
 
-	/**
-	* If this is a nested or inner class, return the class that declared it.
-	* If not, return null.
-	*
-	* @return the declaring class of this class
-	* @since 1.1
-	*/
-	Class getDeclaringClass()
-	{
-		return (Class)GetDeclaringClass(type, wrapper);
-	}
-	private native static Object GetDeclaringClass(Type type, Object wrapper);
+    /**
+     * If this is a nested or inner class, return the class that declared it.
+     * If not, return null.
+     *
+     * @return the declaring class of this class
+     * @since 1.1
+     */
+    Class getDeclaringClass()
+    {
+	return (Class)GetDeclaringClass(wrapper);
+    }
+    private native static Object GetDeclaringClass(Object wrapper);
 
-	/**
-	* Like getDeclaredClasses() but without the security checks.
-	*
-	* @param pulicOnly Only public classes should be returned
-	*/
-	Class[] getDeclaredClasses(boolean publicOnly)
-	{
-		Object[] classes = GetDeclaredClasses(type, wrapper, publicOnly);
-		Class[] classesClass = new Class[classes.length];
-		System.arraycopy(classes, 0, classesClass, 0, classes.length);
-		return classesClass;
-	}
-	private static native Object[] GetDeclaredClasses(Type type, Object wrapper, boolean publicOnly);
+    /**
+     * Like getDeclaredClasses() but without the security checks.
+     *
+     * @param pulicOnly Only public classes should be returned
+     */
+    Class[] getDeclaredClasses(boolean publicOnly)
+    {
+	Object[] classes = GetDeclaredClasses(wrapper, publicOnly);
+	Class[] classesClass = new Class[classes.length];
+	System.arraycopy(classes, 0, classesClass, 0, classes.length);
+	return classesClass;
+    }
+    private static native Object[] GetDeclaredClasses(Object wrapper, boolean publicOnly);
 
-	/**
-	* Like getDeclaredFields() but without the security checks.
-	*
-	* @param pulicOnly Only public fields should be returned
-	*/
-	Field[] getDeclaredFields(boolean publicOnly)
+    /**
+     * Like getDeclaredFields() but without the security checks.
+     *
+     * @param pulicOnly Only public fields should be returned
+     */
+    Field[] getDeclaredFields(boolean publicOnly)
+    {
+	Object[] fieldCookies = GetDeclaredFields(wrapper, publicOnly);
+	Field[] fields = new Field[fieldCookies.length];
+	for(int i = 0; i < fields.length; i++)
 	{
-		Object[] fieldCookies = GetDeclaredFields(type, wrapper, publicOnly);
-		Field[] fields = new Field[fieldCookies.length];
-		for(int i = 0; i < fields.length; i++)
-		{
-			fields[i] = new Field(clazz, fieldCookies[i]);
-		}
-		return fields;
+	    fields[i] = new Field(clazz, fieldCookies[i]);
 	}
-	private static native Object[] GetDeclaredFields(Type type, Object wrapper, boolean publicOnly);
+	return fields;
+    }
+    private static native Object[] GetDeclaredFields(Object wrapper, boolean publicOnly);
 
-	/**
-	* Like getDeclaredMethods() but without the security checks.
-	*
-	* @param pulicOnly Only public methods should be returned
-	*/
-	Method[] getDeclaredMethods(boolean publicOnly)
+    /**
+     * Like getDeclaredMethods() but without the security checks.
+     *
+     * @param pulicOnly Only public methods should be returned
+     */
+    Method[] getDeclaredMethods(boolean publicOnly)
+    {
+	Object[] methodCookies = GetDeclaredMethods(wrapper, true, publicOnly);
+	Method[] methods = new Method[methodCookies.length];
+	for(int i = 0; i < methodCookies.length; i++)
 	{
-		Object[] methodCookies = GetDeclaredMethods(type, wrapper, true, publicOnly);
-		Method[] methods = new Method[methodCookies.length];
-		for(int i = 0; i < methodCookies.length; i++)
-		{
-			methods[i] = new Method(clazz, methodCookies[i]);
-		}
-		return methods;
+	    methods[i] = new Method(clazz, methodCookies[i]);
 	}
-	private static native Object[] GetDeclaredMethods(Type type, Object wrapper, boolean methods, boolean publicOnly);
+	return methods;
+    }
+    private static native Object[] GetDeclaredMethods(Object wrapper, boolean methods, boolean publicOnly);
 
-	/**
-	* Like getDeclaredConstructors() but without
-	* the security checks.
-	*
-	* @param pulicOnly Only public constructors should be returned
-	*/
-	Constructor[] getDeclaredConstructors(boolean publicOnly)
+    /**
+     * Like getDeclaredConstructors() but without
+     * the security checks.
+     *
+     * @param pulicOnly Only public constructors should be returned
+     */
+    Constructor[] getDeclaredConstructors(boolean publicOnly)
+    {
+	Object[] methodCookies = GetDeclaredMethods(wrapper, false, publicOnly);
+	Constructor[] constructors = new Constructor[methodCookies.length];
+	for(int i = 0; i < methodCookies.length; i++)
 	{
-		Object[] methodCookies = GetDeclaredMethods(type, wrapper, false, publicOnly);
-		Constructor[] constructors = new Constructor[methodCookies.length];
-		for(int i = 0; i < methodCookies.length; i++)
-		{
-			constructors[i] = new Constructor(clazz, methodCookies[i]);
-		}
-		return constructors;
+	    constructors[i] = new Constructor(clazz, methodCookies[i]);
 	}
+	return constructors;
+    }
 
-	/**
-	* Return the class loader of this class.
-	*
-	* @return the class loader
-	*/
-	ClassLoader getClassLoader()
-	{
-	    // getClassLoader() can be used by the classloader, so it shouldn't trigger a resolve of the class
-	    return getClassLoader0(type, wrapper);
-	}
-	private static native ClassLoader getClassLoader0(Type type, Object wrapper);
+    /**
+     * Return the class loader of this class.
+     *
+     * @return the class loader
+     */
+    ClassLoader getClassLoader()
+    {
+	// getClassLoader() can be used by the classloader, so it shouldn't trigger a resolve of the class
+	return getClassLoader0(wrapper);
+    }
+    private static native ClassLoader getClassLoader0(Object wrapper);
 
-	/**
-	* VM implementors are free to make this method a noop if 
-	* the default implementation is acceptable.
-	*
-	* @param name the name of the class to find
-	* @return the Class object representing the class or null for noop
-	* @throws ClassNotFoundException if the class was not found by the
-	*         classloader
-	* @throws LinkageError if linking the class fails
-	* @throws ExceptionInInitializerError if the class loads, but an exception
-	*         occurs during initialization
-	*/
-	static Class forName(String name) throws ClassNotFoundException
+    /**
+     * VM implementors are free to make this method a noop if 
+     * the default implementation is acceptable.
+     *
+     * @param name the name of the class to find
+     * @return the Class object representing the class or null for noop
+     * @throws ClassNotFoundException if the class was not found by the
+     *         classloader
+     * @throws LinkageError if linking the class fails
+     * @throws ExceptionInInitializerError if the class loads, but an exception
+     *         occurs during initialization
+     */
+    static Class forName(String name) throws ClassNotFoundException
+    {
+	// if we ever get back to using a separate assembly for each class loader, it
+	// might be faster to use Assembly.GetCallingAssembly here...
+	cli.System.Diagnostics.StackFrame frame = new cli.System.Diagnostics.StackFrame(1);
+	// HACK a lame way to deal with potential inlining of this method (or Class.forName)
+	if(frame.GetMethod().get_Name().equals("forName"))
 	{
-		// if we ever get back to using a separate assembly for each class loader, it
-		// might be faster to use Assembly.GetCallingAssembly here...
-		system.diagnostics.StackFrame frame = new system.diagnostics.StackFrame(1);
-	    // HACK a lame way to deal with potential inlining of this method (or Class.forName)
-	    if(frame.GetMethod().get_Name().equals("forName"))
-	    {
-		frame = new system.diagnostics.StackFrame(2);
-	    }
-		ClassLoader cl = getClassLoader0(frame.GetMethod().get_DeclaringType(), null);
-		return Class.forName(name, true, cl);
+	    frame = new cli.System.Diagnostics.StackFrame(2);
 	}
+	ClassLoader cl = getClassLoaderFromType(frame.GetMethod().get_DeclaringType());
+	return Class.forName(name, true, cl);
+    }
+    private static native ClassLoader getClassLoaderFromType(Type type);
 
     void initialize()
     {
-	initializeType(getType());
+	initialize(wrapper);
     }
+    private static native void initialize(Object wrapper);
 
-	static native Class loadArrayClass(String name, Object classLoader);
-	static native Class loadBootstrapClass(String name, boolean initialize);
-	private static native void initializeType(Type type);
+    static native Class loadArrayClass(String name, Object classLoader);
+    static native Class loadBootstrapClass(String name, boolean initialize);
 
     static native void throwException(Throwable t);
 
-	/**
-	* Return whether this class is an array type.
-	*
-	* @return 1 if this class is an array type, 0 otherwise, -1 if unsupported
-	* operation
-	*/
-	int isArray()
-	{
-		return getType().get_IsArray() ? 1 : 0;
-	}
-} // class VMClass
+    /**
+     * Return whether this class is an array type.
+     *
+     * @return 1 if this class is an array type, 0 otherwise, -1 if unsupported
+     * operation
+     */
+    int isArray()
+    {
+	return IsArray(wrapper) ? 1 : 0;
+    }
+    private static native boolean IsArray(Object wrapper);
+}
diff --git a/classpath/java/lang/VMClassLoader.java b/classpath/java/lang/VMClassLoader.java
index 8eb3e366..610cf5f0 100644
--- a/classpath/java/lang/VMClassLoader.java
+++ b/classpath/java/lang/VMClassLoader.java
@@ -46,8 +46,8 @@ import java.util.Map;
 import java.util.HashMap;
 import java.lang.reflect.Constructor;
 import gnu.java.lang.SystemClassLoader;
-import system.*;
-import system.reflection.*;
+import cli.System.*;
+import cli.System.Reflection.*;
 
 /**
  * java.lang.VMClassLoader is a package-private helper for VMs to implement
@@ -217,12 +217,7 @@ final class VMClassLoader
    * @param type the primitive type
    * @return a "bogus" class representing the primitive type
    */
-	static final Class getPrimitiveClass(char type)
-	{
-		return VMClass.getClassFromType(getPrimitiveType(type));
-	}
-	
-	private static native system.Type getPrimitiveType(char type);
+	static native Class getPrimitiveClass(char type);
 
   /**
    * The system default for assertion status. This is used for all system
diff --git a/classpath/java/lang/VMDouble.java b/classpath/java/lang/VMDouble.java
index 500a8f14..b59e57c7 100644
--- a/classpath/java/lang/VMDouble.java
+++ b/classpath/java/lang/VMDouble.java
@@ -28,7 +28,7 @@ final class VMDouble
 {
     static double longBitsToDouble(long v)
     {
-	return system.BitConverter.Int64BitsToDouble(v);
+	return cli.System.BitConverter.Int64BitsToDouble(v);
     }
 
     static long doubleToLongBits(double v)
@@ -37,11 +37,11 @@ final class VMDouble
 	{
 	    return 0x7ff8000000000000L;
 	}
-	return system.BitConverter.DoubleToInt64Bits(v);
+	return cli.System.BitConverter.DoubleToInt64Bits(v);
     }
 
     static long doubleToRawLongBits(double v)
     {
-	return system.BitConverter.DoubleToInt64Bits(v);
+	return cli.System.BitConverter.DoubleToInt64Bits(v);
     }
 }
diff --git a/classpath/java/lang/VMFloat.java b/classpath/java/lang/VMFloat.java
index 45d9a7bf..d1f47d53 100644
--- a/classpath/java/lang/VMFloat.java
+++ b/classpath/java/lang/VMFloat.java
@@ -28,7 +28,7 @@ final class VMFloat
 {
     static float intBitsToFloat(int v)
     {
-	return system.BitConverter.ToSingle(system.BitConverter.GetBytes(v), 0);
+	return cli.System.BitConverter.ToSingle(cli.System.BitConverter.GetBytes(v), 0);
     }
 
     static int floatToIntBits(float v)
@@ -37,11 +37,11 @@ final class VMFloat
 	{
 	    return 0x7fc00000;
 	}
-	return system.BitConverter.ToInt32(system.BitConverter.GetBytes(v), 0);
+	return cli.System.BitConverter.ToInt32(cli.System.BitConverter.GetBytes(v), 0);
     }
 
     static int floatToRawIntBits(float v)
     {
-	return system.BitConverter.ToInt32(system.BitConverter.GetBytes(v), 0);
+	return cli.System.BitConverter.ToInt32(cli.System.BitConverter.GetBytes(v), 0);
     }
 }
diff --git a/classpath/java/lang/VMThread.java b/classpath/java/lang/VMThread.java
index 693853c9..c28ad9e5 100644
--- a/classpath/java/lang/VMThread.java
+++ b/classpath/java/lang/VMThread.java
@@ -115,21 +115,21 @@ final class VMThread
 	    thread.stillborn = t;
     }
 
-    private static system.LocalDataStoreSlot localDataStoreSlot = system.threading.Thread.AllocateDataSlot();
-    private system.threading.Thread nativeThread;
+    private static cli.System.LocalDataStoreSlot localDataStoreSlot = cli.System.Threading.Thread.AllocateDataSlot();
+    private cli.System.Threading.Thread nativeThread;
 
     /*native*/ void start(long stacksize)
     {
-	system.threading.ThreadStart starter = new system.threading.ThreadStart(
-	    new system.threading.ThreadStart.Method()
+	cli.System.Threading.ThreadStart starter = new cli.System.Threading.ThreadStart(
+	    new cli.System.Threading.ThreadStart.Method()
 	{
 	    public void Invoke()
 	    {
-		system.threading.Thread.SetData(localDataStoreSlot, thread);
+		cli.System.Threading.Thread.SetData(localDataStoreSlot, thread);
 		run();
 	    }
 	});
-	nativeThread = new system.threading.Thread(starter);
+	nativeThread = new cli.System.Threading.Thread(starter);
 	nativeThread.set_Name(thread.name);
 	nativeThread.set_IsBackground(thread.daemon);
 	nativeSetPriority(thread.priority);
@@ -149,7 +149,7 @@ final class VMThread
 	    try
 	    {
 		if(false) throw new InterruptedException();
-		system.threading.Thread.Sleep(0);
+		cli.System.Threading.Thread.Sleep(0);
 		return false;
 	    }
 	    catch(InterruptedException x)
@@ -179,23 +179,23 @@ final class VMThread
     {
 	if(priority == Thread.MIN_PRIORITY)
 	{
-	    nativeThread.set_Priority(system.threading.ThreadPriority.Lowest);
+	    nativeThread.set_Priority(cli.System.Threading.ThreadPriority.wrap(cli.System.Threading.ThreadPriority.Lowest));
 	}
 	else if(priority > Thread.MIN_PRIORITY && priority < Thread.NORM_PRIORITY)
 	{
-	    nativeThread.set_Priority(system.threading.ThreadPriority.BelowNormal);
+	    nativeThread.set_Priority(cli.System.Threading.ThreadPriority.wrap(cli.System.Threading.ThreadPriority.BelowNormal));
 	}
 	else if(priority == Thread.NORM_PRIORITY)
 	{
-	    nativeThread.set_Priority(system.threading.ThreadPriority.Normal);
+	    nativeThread.set_Priority(cli.System.Threading.ThreadPriority.wrap(cli.System.Threading.ThreadPriority.Normal));
 	}
 	else if(priority > Thread.NORM_PRIORITY && priority < Thread.MAX_PRIORITY)
 	{
-	    nativeThread.set_Priority(system.threading.ThreadPriority.AboveNormal);
+	    nativeThread.set_Priority(cli.System.Threading.ThreadPriority.wrap(cli.System.Threading.ThreadPriority.AboveNormal));
 	}
 	else if(priority == Thread.MAX_PRIORITY)
 	{
-	    nativeThread.set_Priority(system.threading.ThreadPriority.Highest);
+	    nativeThread.set_Priority(cli.System.Threading.ThreadPriority.wrap(cli.System.Threading.ThreadPriority.Highest));
 	}
     }
 
@@ -206,37 +206,37 @@ final class VMThread
 
     /*native*/ static Thread currentThread()
     {
-	Thread javaThread = (Thread)system.threading.Thread.GetData(localDataStoreSlot);
+	Thread javaThread = (Thread)cli.System.Threading.Thread.GetData(localDataStoreSlot);
 	if(javaThread == null)
 	{
 	    // threads created outside of Java always run in the root thread group
 	    // TODO if the thread dies, it needs to be removed from the root ThreadGroup   
 	    // and any other threads waiting to join it, should be released.
-	    system.threading.Thread nativeThread = system.threading.Thread.get_CurrentThread();
+	    cli.System.Threading.Thread nativeThread = cli.System.Threading.Thread.get_CurrentThread();
 	    VMThread vmThread = new VMThread(null);
 	    vmThread.nativeThread = nativeThread;
 	    int priority = Thread.NORM_PRIORITY;
-	    switch(nativeThread.get_Priority())
+	    switch(nativeThread.get_Priority().Value)
 	    {
-		case system.threading.ThreadPriority.Lowest:
+		case cli.System.Threading.ThreadPriority.Lowest:
 		    priority = Thread.MIN_PRIORITY;
 		    break;
-		case system.threading.ThreadPriority.BelowNormal:
+		case cli.System.Threading.ThreadPriority.BelowNormal:
 		    priority = 3;
 		    break;
-		case system.threading.ThreadPriority.Normal:
+		case cli.System.Threading.ThreadPriority.Normal:
 		    priority = Thread.NORM_PRIORITY;
 		    break;
-		case system.threading.ThreadPriority.AboveNormal:
+		case cli.System.Threading.ThreadPriority.AboveNormal:
 		    priority = 7;
 		    break;
-		case system.threading.ThreadPriority.Highest:
+		case cli.System.Threading.ThreadPriority.Highest:
 		    priority = Thread.MAX_PRIORITY;
 		    break;
 	    }
 	    javaThread = new Thread(vmThread, nativeThread.get_Name(), priority, nativeThread.get_IsBackground());
 	    vmThread.thread = javaThread;
-	    system.threading.Thread.SetData(localDataStoreSlot, javaThread);
+	    cli.System.Threading.Thread.SetData(localDataStoreSlot, javaThread);
 	    javaThread.group = ThreadGroup.root;
 	    javaThread.group.addThread(javaThread);
 	    InheritableThreadLocal.newChildThread(javaThread);
@@ -246,20 +246,20 @@ final class VMThread
 
     static /*native*/ void yield()
     {
-	system.threading.Thread.Sleep(0);
+	cli.System.Threading.Thread.Sleep(0);
     }
 
     static /*native*/ void sleep(long ms, int ns) throws InterruptedException
     {
 	try
 	{
-	    if(false) throw new system.threading.ThreadInterruptedException();
+	    if(false) throw new cli.System.Threading.ThreadInterruptedException();
 	    // TODO guard against ms and ns overflowing
-	    system.threading.Thread.Sleep(new system.TimeSpan(ms * 10000 + (ns + 99) / 100));
+	    cli.System.Threading.Thread.Sleep(new cli.System.TimeSpan(ms * 10000 + (ns + 99) / 100));
 	}
-	catch(system.threading.ThreadInterruptedException x)
+	catch(cli.System.Threading.ThreadInterruptedException x)
 	{
-	    throw new InterruptedException(x.get_Message());
+	    throw new InterruptedException(x.getMessage());
 	}
     }
 
@@ -270,7 +270,7 @@ final class VMThread
 	    synchronized(currentThread())
 	    {
 		if(false) throw new InterruptedException();
-		system.threading.Thread.Sleep(0);
+		cli.System.Threading.Thread.Sleep(0);
 	    }
 	    return false;
 	}
@@ -292,7 +292,7 @@ final class VMThread
 	    // NOTE Wait causes the lock to be released temporarily, which isn't what we want
 	    if(false) throw new IllegalMonitorStateException();
 	    if(false) throw new InterruptedException();
-	    system.threading.Monitor.Wait(obj, 0);
+	    cli.System.Threading.Monitor.Wait(obj, 0);
 	    return true;
 	}
 	catch(IllegalMonitorStateException x)
@@ -302,7 +302,7 @@ final class VMThread
 	catch(InterruptedException x1)
 	{
 	    // Since we "consumed" the interrupt, we have to interrupt ourself again
-	    system.threading.Thread.get_CurrentThread().Interrupt();
+	    cli.System.Threading.Thread.get_CurrentThread().Interrupt();
 	    return true;
 	}
     }
diff --git a/classpath/java/lang/reflect/Constructor.java b/classpath/java/lang/reflect/Constructor.java
index 003f4d4e..199268d8 100644
--- a/classpath/java/lang/reflect/Constructor.java
+++ b/classpath/java/lang/reflect/Constructor.java
@@ -38,8 +38,6 @@ exception statement from your version. */
 
 package java.lang.reflect;
 
-import system.reflection.*;
-
 /**
  * The Constructor class represents a constructor of a class. It also allows
  * dynamic creation of an object, via reflection. Invocation on Constructor
@@ -162,7 +160,7 @@ public final class Constructor
 	 */
 	public boolean equals(Object o)
 	{
-		if(o instanceof ConstructorInfo)
+		if(o instanceof Constructor)
 		{
 			return methodCookie == ((Constructor)o).methodCookie;
 		}
diff --git a/classpath/java/lang/reflect/Method.java b/classpath/java/lang/reflect/Method.java
index cd3ed027..100168f9 100644
--- a/classpath/java/lang/reflect/Method.java
+++ b/classpath/java/lang/reflect/Method.java
@@ -38,8 +38,6 @@ exception statement from your version. */
 
 package java.lang.reflect;
 
-import system.reflection.*;
-
 /**
  * The Method class represents a member method of a class. It also allows
  * dynamic invocation, via reflection. This works for both static and
diff --git a/classpath/java/net/PlainDatagramSocketImpl.java b/classpath/java/net/PlainDatagramSocketImpl.java
index b2c863ed..3a163c50 100644
--- a/classpath/java/net/PlainDatagramSocketImpl.java
+++ b/classpath/java/net/PlainDatagramSocketImpl.java
@@ -39,9 +39,10 @@ exception statement from your version. */
 package java.net;
 
 import java.io.IOException;
-import system.net.*;
-import system.net.sockets.*;
+import cli.System.Net.*;
+import cli.System.Net.Sockets.*;
 import ikvm.lang.CIL;
+import ikvm.lang.ByteArrayHack;
 
 /**
 * This is the default socket implementation for datagram sockets.
@@ -70,12 +71,12 @@ public class PlainDatagramSocketImpl extends DatagramSocketImpl
 
 	private static class MyUdpClient extends UdpClient
 	{
-		MyUdpClient(system.net.IPEndPoint ep)
+		MyUdpClient(cli.System.Net.IPEndPoint ep)
 		{
 			super(ep);
 		}
 
-		system.net.sockets.Socket getSocket()
+		cli.System.Net.Sockets.Socket getSocket()
 		{
 			return super.get_Client();
 		}
@@ -153,7 +154,7 @@ public class PlainDatagramSocketImpl extends DatagramSocketImpl
 	{
 		// TODO error handling
 		int len = packet.getLength();
-		if(socket.Send(packet.getData(), len, new IPEndPoint(PlainSocketImpl.getAddressFromInetAddress(packet.getAddress()), packet.getPort())) != len)
+		if(socket.Send(ByteArrayHack.cast(packet.getData()), len, new IPEndPoint(PlainSocketImpl.getAddressFromInetAddress(packet.getAddress()), packet.getPort())) != len)
 		{
 			// TODO
 			throw new IOException();
@@ -183,13 +184,13 @@ public class PlainDatagramSocketImpl extends DatagramSocketImpl
 	{
 	    try
 	    {
-		if(false) throw new system.net.sockets.SocketException();
+		if(false) throw new cli.System.Net.Sockets.SocketException();
 		byte[] data = packet.getData();
 		int length = packet.getLength();
-		system.net.IPEndPoint[] remoteEP = new system.net.IPEndPoint[] {
-		    new system.net.IPEndPoint(0, 0)
+		cli.System.Net.IPEndPoint[] remoteEP = new cli.System.Net.IPEndPoint[] {
+		    new cli.System.Net.IPEndPoint(0, 0)
 		};
-		byte[] buf = socket.Receive(remoteEP);
+		byte[] buf = ByteArrayHack.cast(socket.Receive(remoteEP));
 		System.arraycopy(buf, 0, data, 0, Math.min(length, buf.length));
 		// I think the spec says that the Length property of DatagramPacket
 		// contains the number of bytes in the network packet (even if
@@ -201,10 +202,10 @@ public class PlainDatagramSocketImpl extends DatagramSocketImpl
 		packet.setAddress(remoteAddress);
 		packet.setPort(remoteEP[0].get_Port());
 	    }
-	    catch(system.net.sockets.SocketException x)
+	    catch(cli.System.Net.Sockets.SocketException x)
 	    {
 		// TODO error handling
-		throw new IOException(x.get_Message());
+		throw new IOException(x.getMessage());
 	    }
 	}
 
@@ -221,13 +222,13 @@ public class PlainDatagramSocketImpl extends DatagramSocketImpl
 	{
 		try
 		{
-			if(false) throw new system.net.sockets.SocketException();
-			socket.JoinMulticastGroup(new system.net.IPAddress(PlainSocketImpl.getAddressFromInetAddress(addr)));
+			if(false) throw new cli.System.Net.Sockets.SocketException();
+			socket.JoinMulticastGroup(new cli.System.Net.IPAddress(PlainSocketImpl.getAddressFromInetAddress(addr)));
 		}
-		catch(system.net.sockets.SocketException x)
+		catch(cli.System.Net.Sockets.SocketException x)
 		{
 			// TODO error handling
-			throw new IOException(x.get_Message());
+			throw new IOException(x.getMessage());
 		}
 	}
 
@@ -244,13 +245,13 @@ public class PlainDatagramSocketImpl extends DatagramSocketImpl
 	{
 		try
 		{
-			if(false) throw new system.net.sockets.SocketException();
-			socket.DropMulticastGroup(new system.net.IPAddress(PlainSocketImpl.getAddressFromInetAddress(addr)));
+			if(false) throw new cli.System.Net.Sockets.SocketException();
+			socket.DropMulticastGroup(new cli.System.Net.IPAddress(PlainSocketImpl.getAddressFromInetAddress(addr)));
 		}
-		catch(system.net.sockets.SocketException x)
+		catch(cli.System.Net.Sockets.SocketException x)
 		{
 			// TODO error handling
-			throw new IOException(x.get_Message());
+			throw new IOException(x.getMessage());
 		}
 	}
 
@@ -335,20 +336,20 @@ public class PlainDatagramSocketImpl extends DatagramSocketImpl
 	{
 		try
 		{
-			if(false) throw new system.net.sockets.SocketException();
+			if(false) throw new cli.System.Net.Sockets.SocketException();
 			switch(option_id)
 			{
 				case IP_TTL:
-					return new Integer(CIL.unbox_int(socket.getSocket().GetSocketOption(SocketOptionLevel.IP, SocketOptionName.IpTimeToLive)));
+					return new Integer(CIL.unbox_int(socket.getSocket().GetSocketOption(SocketOptionLevel.wrap(SocketOptionLevel.IP), SocketOptionName.wrap(SocketOptionName.IpTimeToLive))));
 				case SocketOptions.SO_TIMEOUT:
-				        return new Integer(CIL.unbox_int(socket.getSocket().GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout)));
+				        return new Integer(CIL.unbox_int(socket.getSocket().GetSocketOption(SocketOptionLevel.wrap(SocketOptionLevel.Socket), SocketOptionName.wrap(SocketOptionName.ReceiveTimeout))));
 				default:
 					throw new Error("getOption(" + option_id + ") not implemented");
 			}
 		}
-		catch(system.net.sockets.SocketException x)
+		catch(cli.System.Net.Sockets.SocketException x)
 		{
-			throw new SocketException(x.get_Message());
+			throw new SocketException(x.getMessage());
 		}
 	}
 
@@ -366,26 +367,26 @@ public class PlainDatagramSocketImpl extends DatagramSocketImpl
 	{
 		try
 		{
-			if(false) throw new system.net.sockets.SocketException();
+			if(false) throw new cli.System.Net.Sockets.SocketException();
 			switch(option_id)
 			{
 				case IP_TTL:
-					socket.getSocket().SetSocketOption(SocketOptionLevel.IP, SocketOptionName.IpTimeToLive, ((Integer)val).intValue());
+					socket.getSocket().SetSocketOption(SocketOptionLevel.wrap(SocketOptionLevel.IP), SocketOptionName.wrap(SocketOptionName.IpTimeToLive), ((Integer)val).intValue());
 					break;
 				case SocketOptions.SO_TIMEOUT:
-				        socket.getSocket().SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, ((Integer)val).intValue());
-					socket.getSocket().SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, ((Integer)val).intValue());
+				        socket.getSocket().SetSocketOption(SocketOptionLevel.wrap(SocketOptionLevel.Socket), SocketOptionName.wrap(SocketOptionName.ReceiveTimeout), ((Integer)val).intValue());
+					socket.getSocket().SetSocketOption(SocketOptionLevel.wrap(SocketOptionLevel.Socket), SocketOptionName.wrap(SocketOptionName.SendTimeout), ((Integer)val).intValue());
 					break;
 				case SocketOptions.SO_REUSEADDR:
-					socket.getSocket().SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, ((Boolean)val).booleanValue() ? 1 : 0);
+					socket.getSocket().SetSocketOption(SocketOptionLevel.wrap(SocketOptionLevel.Socket), SocketOptionName.wrap(SocketOptionName.ReuseAddress), ((Boolean)val).booleanValue() ? 1 : 0);
 					break;
 				default:
 					throw new Error("setOption(" + option_id + ") not implemented");
 			}
 		}
-		catch(system.net.sockets.SocketException x)
+		catch(cli.System.Net.Sockets.SocketException x)
 		{
-			throw new SocketException(x.get_Message());
+			throw new SocketException(x.getMessage());
 		}
 	}
 
diff --git a/classpath/java/net/PlainSocketImpl.java b/classpath/java/net/PlainSocketImpl.java
index 28f7a724..0963f483 100644
--- a/classpath/java/net/PlainSocketImpl.java
+++ b/classpath/java/net/PlainSocketImpl.java
@@ -41,9 +41,10 @@ package java.net;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.io.IOException;
-import system.net.*;
-import system.net.sockets.*;
+import cli.System.Net.*;
+import cli.System.Net.Sockets.*;
 import ikvm.lang.CIL;
+import ikvm.lang.ByteArrayHack;
 
 /**
   * Unless the application installs its own SocketImplFactory, this is the
@@ -60,7 +61,7 @@ class PlainSocketImpl extends SocketImpl
 	/**
 	 * This is the native file descriptor for this socket
 	 */
-	private system.net.sockets.Socket socket;
+	private cli.System.Net.Sockets.Socket socket;
 
 
 	/**
@@ -80,8 +81,8 @@ class PlainSocketImpl extends SocketImpl
 	{
 		try
 		{
-			if(false) throw new system.net.sockets.SocketException();
-			system.net.sockets.Socket accept = socket.Accept();
+			if(false) throw new cli.System.Net.Sockets.SocketException();
+			cli.System.Net.Sockets.Socket accept = socket.Accept();
 			((PlainSocketImpl)impl).socket = accept;
 			IPEndPoint remoteEndPoint = ((IPEndPoint)accept.get_RemoteEndPoint());
 			long remoteIP = remoteEndPoint.get_Address().get_Address();
@@ -90,10 +91,10 @@ class PlainSocketImpl extends SocketImpl
 			impl.port = remoteEndPoint.get_Port();
 			impl.localport = ((IPEndPoint)accept.get_LocalEndPoint()).get_Port();
 		}
-		catch(system.net.sockets.SocketException x)
+		catch(cli.System.Net.Sockets.SocketException x)
 		{
 			// TODO error handling
-			throw new IOException(x.get_Message());
+			throw new IOException(x.getMessage());
 		}
 	}
 
@@ -109,13 +110,13 @@ class PlainSocketImpl extends SocketImpl
 	{
 		try
 		{
-			if(false) throw new system.net.sockets.SocketException();
+			if(false) throw new cli.System.Net.Sockets.SocketException();
 			return socket.get_Available();
 		}
-		catch(system.net.sockets.SocketException x)
+		catch(cli.System.Net.Sockets.SocketException x)
 		{
 			// TODO error handling
-			throw new IOException(x.get_Message());
+			throw new IOException(x.getMessage());
 		}
 	}
 
@@ -132,14 +133,14 @@ class PlainSocketImpl extends SocketImpl
 	{
 		try
 		{
-			if(false) throw new system.net.sockets.SocketException();
+			if(false) throw new cli.System.Net.Sockets.SocketException();
 			socket.Bind(new IPEndPoint(getAddressFromInetAddress(addr), port));
 			this.address = addr;
 		}
-		catch(system.net.sockets.SocketException x)
+		catch(cli.System.Net.Sockets.SocketException x)
 		{
 			// TODO error handling
-			throw new IOException(x.get_Message());
+			throw new IOException(x.getMessage());
 		}
 	}
 
@@ -162,13 +163,13 @@ class PlainSocketImpl extends SocketImpl
 	{
 		try
 		{
-			if(false) throw new system.net.sockets.SocketException();
+			if(false) throw new cli.System.Net.Sockets.SocketException();
 			socket.Close();
 		}
-		catch(system.net.sockets.SocketException x)
+		catch(cli.System.Net.Sockets.SocketException x)
 		{
 			// TODO error handling
-			throw new IOException(x.get_Message());
+			throw new IOException(x.getMessage());
 		}
 	}
 
@@ -184,16 +185,16 @@ class PlainSocketImpl extends SocketImpl
 	{
 		try
 		{
-			if(false) throw new system.net.sockets.SocketException();
+			if(false) throw new cli.System.Net.Sockets.SocketException();
 			socket.Connect(new IPEndPoint(getAddressFromInetAddress(addr), port));
 			this.address = addr;
 			this.port = port;
 			this.localport = ((IPEndPoint)socket.get_LocalEndPoint()).get_Port();
 		}
-		catch(system.net.sockets.SocketException x)
+		catch(cli.System.Net.Sockets.SocketException x)
 		{
 			// TODO error handling
-			throw new IOException(x.get_Message());
+			throw new IOException(x.getMessage());
 		}
 	}
 
@@ -229,13 +230,13 @@ class PlainSocketImpl extends SocketImpl
 		}
 		try
 		{
-			if(false) throw new system.net.sockets.SocketException();
-			socket = new system.net.sockets.Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
+			if(false) throw new cli.System.Net.Sockets.SocketException();
+			socket = new cli.System.Net.Sockets.Socket(AddressFamily.wrap(AddressFamily.InterNetwork), SocketType.wrap(SocketType.Stream), ProtocolType.wrap(ProtocolType.Tcp));
 		}
-		catch(system.net.sockets.SocketException x)
+		catch(cli.System.Net.Sockets.SocketException x)
 		{
 			// TODO error handling
-			throw new IOException(x.get_Message());
+			throw new IOException(x.getMessage());
 		}
 	}
 
@@ -253,14 +254,14 @@ class PlainSocketImpl extends SocketImpl
 	{
 		try
 		{
-			if(false) throw new system.net.sockets.SocketException();
+			if(false) throw new cli.System.Net.Sockets.SocketException();
 			socket.Listen(queuelen);
 			localport = ((IPEndPoint)socket.get_LocalEndPoint()).get_Port();
 		}
-		catch(system.net.sockets.SocketException x)
+		catch(cli.System.Net.Sockets.SocketException x)
 		{
 			// TODO error handling
-			throw new IOException(x.get_Message());
+			throw new IOException(x.getMessage());
 		}
 	}
 
@@ -277,13 +278,13 @@ class PlainSocketImpl extends SocketImpl
 	{
 		try
 		{
-			if(false) throw new system.net.sockets.SocketException();
-			return socket.Receive(buf, offset, len, SocketFlags.None);
+			if(false) throw new cli.System.Net.Sockets.SocketException();
+			return socket.Receive(ByteArrayHack.cast(buf), offset, len, SocketFlags.wrap(SocketFlags.None));
 		}
-		catch(system.net.sockets.SocketException x)
+		catch(cli.System.Net.Sockets.SocketException x)
 		{
 			// TODO error handling
-			throw new IOException(x.get_Message());
+			throw new IOException(x.getMessage());
 		}
 	}
 
@@ -298,13 +299,13 @@ class PlainSocketImpl extends SocketImpl
 	{
 		try
 		{
-			if(false) throw new system.net.sockets.SocketException();
-			socket.Send(buf, offset, len, SocketFlags.None);
+			if(false) throw new cli.System.Net.Sockets.SocketException();
+			socket.Send(ByteArrayHack.cast(buf), offset, len, SocketFlags.wrap(SocketFlags.None));
 		}
-		catch(system.net.sockets.SocketException x)
+		catch(cli.System.Net.Sockets.SocketException x)
 		{
 			// TODO error handling
-			throw new IOException(x.get_Message());
+			throw new IOException(x.getMessage());
 		}
 	}
 
@@ -323,56 +324,56 @@ class PlainSocketImpl extends SocketImpl
 	{
 		try
 		{
-			if(false) throw new system.net.sockets.SocketException();
+			if(false) throw new cli.System.Net.Sockets.SocketException();
 			switch(option_id)
 			{
 				case SocketOptions.TCP_NODELAY:
-					socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, ((Boolean)val).booleanValue() ? 1 : 0);
+					socket.SetSocketOption(SocketOptionLevel.wrap(SocketOptionLevel.Tcp), SocketOptionName.wrap(SocketOptionName.NoDelay), ((Boolean)val).booleanValue() ? 1 : 0);
 					break;
 				case SocketOptions.SO_KEEPALIVE:
-					socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, ((Boolean)val).booleanValue() ? 1 : 0);
+					socket.SetSocketOption(SocketOptionLevel.wrap(SocketOptionLevel.Socket), SocketOptionName.wrap(SocketOptionName.KeepAlive), ((Boolean)val).booleanValue() ? 1 : 0);
 					break;
 				case SocketOptions.SO_TIMEOUT:
-					socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, ((Integer)val).intValue());
-					socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, ((Integer)val).intValue());
+					socket.SetSocketOption(SocketOptionLevel.wrap(SocketOptionLevel.Socket), SocketOptionName.wrap(SocketOptionName.ReceiveTimeout), ((Integer)val).intValue());
+					socket.SetSocketOption(SocketOptionLevel.wrap(SocketOptionLevel.Socket), SocketOptionName.wrap(SocketOptionName.SendTimeout), ((Integer)val).intValue());
 					break;
 				case SocketOptions.SO_LINGER:
 				{
-					system.net.sockets.LingerOption linger;
+					cli.System.Net.Sockets.LingerOption linger;
 					if(val instanceof Boolean)
 					{
-						linger = new system.net.sockets.LingerOption(false, 0);
+						linger = new cli.System.Net.Sockets.LingerOption(false, 0);
 					}
 					else
 					{
-						linger = new system.net.sockets.LingerOption(true, ((Integer)val).intValue());
+						linger = new cli.System.Net.Sockets.LingerOption(true, ((Integer)val).intValue());
 					}
-					socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, linger);
+					socket.SetSocketOption(SocketOptionLevel.wrap(SocketOptionLevel.Socket), SocketOptionName.wrap(SocketOptionName.Linger), linger);
 					break;
 				}
 				case SocketOptions.SO_OOBINLINE:
-					socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.OutOfBandInline, ((Boolean)val).booleanValue() ? 1 : 0);
+					socket.SetSocketOption(SocketOptionLevel.wrap(SocketOptionLevel.Socket), SocketOptionName.wrap(SocketOptionName.OutOfBandInline), ((Boolean)val).booleanValue() ? 1 : 0);
 					break;
 				case SocketOptions.SO_SNDBUF:
-					socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendBuffer, ((Integer)val).intValue());
+					socket.SetSocketOption(SocketOptionLevel.wrap(SocketOptionLevel.Socket), SocketOptionName.wrap(SocketOptionName.SendBuffer), ((Integer)val).intValue());
 					break;
 				case SocketOptions.SO_RCVBUF:
-					socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer, ((Integer)val).intValue());
+					socket.SetSocketOption(SocketOptionLevel.wrap(SocketOptionLevel.Socket), SocketOptionName.wrap(SocketOptionName.ReceiveBuffer), ((Integer)val).intValue());
 					break;
 				case SocketOptions.SO_REUSEADDR:
-					socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, ((Boolean)val).booleanValue() ? 1 : 0);
+					socket.SetSocketOption(SocketOptionLevel.wrap(SocketOptionLevel.Socket), SocketOptionName.wrap(SocketOptionName.ReuseAddress), ((Boolean)val).booleanValue() ? 1 : 0);
 					break;
 				case SocketOptions.IP_TOS:
-					socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.TypeOfService, ((Integer)val).intValue());
+					socket.SetSocketOption(SocketOptionLevel.wrap(SocketOptionLevel.IP), SocketOptionName.wrap(SocketOptionName.TypeOfService), ((Integer)val).intValue());
 					break;
 				default:
 					throw new Error("Socket.setOption(" + option_id + ") not implemented");
 			}
 		}
-		catch(system.net.sockets.SocketException x)
+		catch(cli.System.Net.Sockets.SocketException x)
 		{
 			// TODO error handling
-			throw new SocketException(x.get_Message());
+			throw new SocketException(x.getMessage());
 		}
 	}
 
@@ -391,7 +392,7 @@ class PlainSocketImpl extends SocketImpl
 	{
 		try
 		{
-			if(false) throw new system.net.sockets.SocketException();
+			if(false) throw new cli.System.Net.Sockets.SocketException();
 			switch(option_id)
 			{
 				case SocketOptions.SO_BINDADDR:
@@ -404,14 +405,14 @@ class PlainSocketImpl extends SocketImpl
 						throw new SocketException(x.getMessage());
 					}
 				case SocketOptions.TCP_NODELAY:
-					return new Boolean(CIL.unbox_int(socket.GetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay)) != 0);
+					return new Boolean(CIL.unbox_int(socket.GetSocketOption(SocketOptionLevel.wrap(SocketOptionLevel.Tcp), SocketOptionName.wrap(SocketOptionName.NoDelay))) != 0);
 				case SocketOptions.SO_KEEPALIVE:
-					return new Boolean(CIL.unbox_int(socket.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive)) != 0);
+					return new Boolean(CIL.unbox_int(socket.GetSocketOption(SocketOptionLevel.wrap(SocketOptionLevel.Socket), SocketOptionName.wrap(SocketOptionName.KeepAlive))) != 0);
 				case SocketOptions.SO_TIMEOUT:
-					return new Integer(CIL.unbox_int(socket.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout)));
+					return new Integer(CIL.unbox_int(socket.GetSocketOption(SocketOptionLevel.wrap(SocketOptionLevel.Socket), SocketOptionName.wrap(SocketOptionName.ReceiveTimeout))));
 				case SocketOptions.SO_LINGER:
 				{
-					system.net.sockets.LingerOption linger = (system.net.sockets.LingerOption)socket.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger);
+					cli.System.Net.Sockets.LingerOption linger = (cli.System.Net.Sockets.LingerOption)socket.GetSocketOption(SocketOptionLevel.wrap(SocketOptionLevel.Socket), SocketOptionName.wrap(SocketOptionName.Linger));
 					if(linger.get_Enabled())
 					{
 						return new Integer(linger.get_LingerTime());
@@ -419,29 +420,29 @@ class PlainSocketImpl extends SocketImpl
 					return Boolean.FALSE;
 				}
 				case SocketOptions.SO_OOBINLINE:
-					return new Integer(CIL.unbox_int(socket.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.OutOfBandInline)));
+					return new Integer(CIL.unbox_int(socket.GetSocketOption(SocketOptionLevel.wrap(SocketOptionLevel.Socket), SocketOptionName.wrap(SocketOptionName.OutOfBandInline))));
 				case SocketOptions.SO_SNDBUF:
-					return new Integer(CIL.unbox_int(socket.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendBuffer)));
+					return new Integer(CIL.unbox_int(socket.GetSocketOption(SocketOptionLevel.wrap(SocketOptionLevel.Socket), SocketOptionName.wrap(SocketOptionName.SendBuffer))));
 				case SocketOptions.SO_RCVBUF:
-					return new Integer(CIL.unbox_int(socket.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer)));
+					return new Integer(CIL.unbox_int(socket.GetSocketOption(SocketOptionLevel.wrap(SocketOptionLevel.Socket), SocketOptionName.wrap(SocketOptionName.ReceiveBuffer))));
 				case SocketOptions.SO_REUSEADDR:
-					return new Boolean(CIL.unbox_int(socket.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress)) != 0);
+					return new Boolean(CIL.unbox_int(socket.GetSocketOption(SocketOptionLevel.wrap(SocketOptionLevel.Socket), SocketOptionName.wrap(SocketOptionName.ReuseAddress))) != 0);
 				case SocketOptions.IP_TOS:
-					return new Integer(CIL.unbox_int(socket.GetSocketOption(SocketOptionLevel.IP, SocketOptionName.TypeOfService)));
+					return new Integer(CIL.unbox_int(socket.GetSocketOption(SocketOptionLevel.wrap(SocketOptionLevel.IP), SocketOptionName.wrap(SocketOptionName.TypeOfService))));
 				default:
 					throw new Error("Socket.getOption(" + option_id + ") not implemented");
 			}
 		}
-		catch(system.net.sockets.SocketException x)
+		catch(cli.System.Net.Sockets.SocketException x)
 		{
 			// TODO error handling
-			throw new SocketException(x.get_Message());
+			throw new SocketException(x.getMessage());
 		}
 	}
 
-	private static byte[] getLocalAddress(system.net.sockets.Socket socket)
+	private static byte[] getLocalAddress(cli.System.Net.Sockets.Socket socket)
 	{
-	    int address = (int)((system.net.IPEndPoint)socket.get_LocalEndPoint()).get_Address().get_Address();
+	    int address = (int)((cli.System.Net.IPEndPoint)socket.get_LocalEndPoint()).get_Address().get_Address();
 	    return new byte[] { (byte)address, (byte)(address >> 8), (byte)(address >> 16), (byte)(address >> 24) };
 	}
 
diff --git a/classpath/mscorlib.jar b/classpath/mscorlib.jar
index 3180288b..bd5358b8 100644
Binary files a/classpath/mscorlib.jar and b/classpath/mscorlib.jar differ
diff --git a/classpath/sun/misc/Ref.java b/classpath/sun/misc/Ref.java
index 1f2eafeb..c45e5aa6 100644
--- a/classpath/sun/misc/Ref.java
+++ b/classpath/sun/misc/Ref.java
@@ -24,7 +24,7 @@
 
 package sun.misc;
 
-import system.WeakReference;
+import cli.System.WeakReference;
 
 public abstract class Ref
 {
diff --git a/ikvm.build b/ikvm.build
index 55db09e1..20fdd94d 100644
--- a/ikvm.build
+++ b/ikvm.build
@@ -4,10 +4,10 @@
         
         
         
-        
         
         
         
         
+        
     
 
diff --git a/ikvmc/Compiler.cs b/ikvmc/Compiler.cs
index 18b1b0b8..2baf9174 100644
--- a/ikvmc/Compiler.cs
+++ b/ikvmc/Compiler.cs
@@ -60,6 +60,7 @@ class Compiler
 		string outputfile = null;
 		string main = null;
 		bool nojni = false;
+		ArrayList classesToExclude = new ArrayList();
 		ArrayList references = new ArrayList();
 		ArrayList arglist = GetArgs(args);
 		if(arglist.Count == 0)
@@ -77,6 +78,8 @@ class Compiler
 			Console.Error.WriteLine("    -recurse:     Recurse directory and include matching files");
 			Console.Error.WriteLine("    -nojni                  Do not generate JNI stub for native methods");
 			Console.Error.WriteLine("    -resource:= Include file as Java resource");
+			Console.Error.WriteLine("    -exclude:     A file containing a list of classes to exclude");
+			Console.Error.WriteLine("    -debug                  Creates debugging information for the output file");
 			return 1;
 		}
 		ArrayList classes = new ArrayList();
@@ -151,6 +154,14 @@ class Compiler
 				{
 					nojni = true;
 				}
+				else if(s.StartsWith("-exclude:"))
+				{
+					ProcessExclusionFile(classesToExclude, s.Substring(9));
+				}
+				else if(s == "-debug")
+				{
+					JVM.Debug = true;
+				}
 				else
 				{
 					Console.Error.WriteLine("Warning: Unrecognized option: {0}", s);
@@ -190,7 +201,7 @@ class Compiler
 		}
 		try
 		{
-			JVM.Compile(outputfile, assemblyname, main, target, (byte[][])classes.ToArray(typeof(byte[])), (string[])references.ToArray(typeof(string)), nojni, resources);
+			JVM.Compile(outputfile, assemblyname, main, target, (byte[][])classes.ToArray(typeof(byte[])), (string[])references.ToArray(typeof(string)), nojni, resources, (string[])classesToExclude.ToArray(typeof(string)));
 			return 0;
 		}
 		catch(Exception x)
@@ -263,14 +274,21 @@ class Compiler
 				else
 				{
 					// include as resource
-					using(FileStream fs = new FileStream(file, FileMode.Open))
+					try 
 					{
-						byte[] b = new byte[fs.Length];
-						fs.Read(b, 0, b.Length);
-						// HACK very lame way to extract the resource name (by chopping off the base directory)
-						string name = file.Substring(baseDir.FullName.Length + 1);
-						name = name.Replace('\\', '/');
-						resources.Add(name, b);
+						using(FileStream fs = new FileStream(file, FileMode.Open))
+						{
+							byte[] b = new byte[fs.Length];
+							fs.Read(b, 0, b.Length);
+							// HACK very lame way to extract the resource name (by chopping off the base directory)
+							string name = file.Substring(baseDir.FullName.Length + 1);
+							name = name.Replace('\\', '/');
+							resources.Add(name, b);
+						}
+					}
+					catch(UnauthorizedAccessException)
+					{
+						Console.Error.WriteLine("Warning: Error reading file {0}: Access Denied", file);
 					}
 				}
 				break;
@@ -289,4 +307,28 @@ class Compiler
 			Recurse(classes, resources, baseDir, sub, spec);
 		}
 	}
+
+	//This processes an exclusion file with a single regular expression per line
+	private static void ProcessExclusionFile(ArrayList classesToExclude, String filename)
+	{
+		try 
+		{
+			using(StreamReader file = new StreamReader(filename))
+			{
+				String line;
+				while((line = file.ReadLine()) != null)
+				{
+					line = line.Trim();
+					if(!line.StartsWith("//") && line.Length != 0)
+					{
+						classesToExclude.Add(line);
+					}
+				}
+			}
+		} 
+		catch(FileNotFoundException) 
+		{
+			Console.Error.WriteLine("Warning: Could not find exclusion file '{0}'", filename);
+		}
+	}
 }
diff --git a/netexp/ClassFileWriter.cs b/netexp/ClassFileWriter.cs
index eda0dfb7..279d5640 100644
--- a/netexp/ClassFileWriter.cs
+++ b/netexp/ClassFileWriter.cs
@@ -568,7 +568,23 @@ class ClassFileWriter
 		if(constantValue != null)
 		{
 			ushort constantValueIndex;
-			if(constantValue is int)
+			if(constantValue is sbyte)
+			{
+				constantValueIndex = AddInt((sbyte)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);
 			}
diff --git a/netexp/NetExp.cs b/netexp/NetExp.cs
index 85d38139..a639c659 100644
--- a/netexp/NetExp.cs
+++ b/netexp/NetExp.cs
@@ -25,8 +25,9 @@ using System;
 using System.Reflection;
 using System.IO;
 using System.Text;
-using System.Collections;
 using ICSharpCode.SharpZipLib.Zip;
+using java.lang;
+using java.lang.reflect;
 
 public class NetExp
 {
@@ -39,6 +40,10 @@ public class NetExp
 		{
 			assembly = Assembly.LoadFrom(args[0]);
 		}
+		else
+		{
+			assembly = Assembly.LoadWithPartialName(args[0]);
+		}
 		if(assembly == null)
 		{
 			Console.Error.WriteLine("Error: Assembly \"{0}\" not found", args[0]);
@@ -46,299 +51,19 @@ public class NetExp
 		else
 		{
 			zipFile = new ZipOutputStream(new FileStream(assembly.GetName().Name + ".jar", FileMode.Create));
+			// HACK if we're doing the "classpath" assembly, also include the remapped types
+			// java.lang.Object and java.lang.Throwable are automatic, because of the $OverrideStub
+			if(args[0] == "classpath")
+			{
+				ProcessClass(assembly.FullName, Class.forName("java.lang.String"), null);
+				ProcessClass(assembly.FullName, Class.forName("java.lang.Comparable"), null);
+			}
 			ProcessAssembly(assembly);
 			zipFile.Close();
 		}
-	}
-
-	private static void ProcessAssembly(Assembly assembly)
-	{
-		object[] attribs = assembly.GetCustomAttributes(typeof(CLSCompliantAttribute), false);
-		bool assemblyIsCLSCompliant = true;
-		if(attribs.Length != 1)
-		{
-			assemblyIsCLSCompliant = false;
-			Console.Error.WriteLine("Warning: assembly has no (or multiple) CLS compliance attribute");
-		}
-		else if(!((CLSCompliantAttribute)attribs[0]).IsCompliant)
-		{
-			assemblyIsCLSCompliant = false;
-			Console.Error.WriteLine("Warning: assembly is marked as non-CLS compliant");
-		}
-		foreach(Type t in assembly.GetTypes())
-		{
-			bool typeIsCLSCompliant = true;
-			if(assemblyIsCLSCompliant)
-			{
-				attribs = t.GetCustomAttributes(typeof(CLSCompliantAttribute), false);
-				if(attribs.Length == 1)
-				{
-					typeIsCLSCompliant = ((CLSCompliantAttribute)attribs[0]).IsCompliant;
-				}
-			}
-			if(t.IsPublic && typeIsCLSCompliant)
-			{
-				ProcessType(t);
-			}
-		}
-	}
-
-	private static object UnwrapEnum(object o)
-	{
-		// is there a way to generically convert a boxed enum to its boxed underlying value?
-		Type underlyingType = Enum.GetUnderlyingType(o.GetType());
-		if (underlyingType == typeof(long))
-		{
-			o = (long)o;
-		}	
-		else if(underlyingType == typeof(int))
-		{
-			o = (int)o;
-		}
-		else if(underlyingType == typeof(short))
-		{
-			o = (short)o;
-		}
-		else if (underlyingType == typeof(sbyte))
-		{
-			o = (sbyte)o;
-		}
-		else if (underlyingType == typeof(ulong))
-		{
-			o = (ulong)o;
-		}		
-		else if (underlyingType == typeof(uint))
-		{
-			o = (uint)o;
-		}
-		else if (underlyingType == typeof(ushort))
-		{
-			o = (ushort)o;
-		}
-		else if (underlyingType == typeof(byte))
-		{
-			o = (byte)o;
-		}
-		else
-		{
-			throw new NotImplementedException(o.GetType().Name);
-		}
-		return o;
-	}
-
-	private static string ClassName(Type t)
-	{
-		if(t == typeof(object))
-		{
-			return "java/lang/Object";
-		}
-		else if(t == typeof(string))
-		{
-			return "java/lang/String";
-		}
-		string name = t.FullName;
-		int lastDot = name.LastIndexOf('.');
-		if(lastDot > 0)
-		{
-			name = name.Substring(0, lastDot).ToLower() + name.Substring(lastDot);
-		}
-		return name.Replace('.', '/');
-	}
-
-	// returns the mapped type in signature format (e.g. Ljava/lang/String;)
-	private static string SigType(Type t)
-	{
-		if(t.IsByRef)
-		{
-			return "[" + SigType(t.GetElementType());
-		}
-		if(t.IsEnum)
-		{
-			t = Enum.GetUnderlyingType(t);
-		}
-		if(t == typeof(void))
-		{
-			return "V";
-		}
-		else if(t == typeof(byte) || t == typeof(sbyte))
-		{
-			return "B";
-		}
-		else if(t == typeof(bool))
-		{
-			return "Z";
-		}
-		else if(t == typeof(short) || t == typeof(ushort))
-		{
-			return "S";
-		}
-		else if(t == typeof(char))
-		{
-			return "C";
-		}
-		else if(t == typeof(int) || t == typeof(uint))
-		{
-			return "I";
-		}
-		else if(t == typeof(long) || t == typeof(ulong))
-		{
-			return "J";
-		}
-		else if(t == typeof(float))
-		{
-			return "F";
-		}
-		else if(t == typeof(double))
-		{
-			return "D";
-		}
-		else if(t == typeof(IntPtr))
-		{
-			// HACK
-			return "I";
-		}
-		else if(t.IsArray)
-		{
-			StringBuilder sb = new StringBuilder();
-			while(t.IsArray)
-			{
-				sb.Append('[');
-				t = t.GetElementType();
-			}
-			sb.Append(SigType(t));
-			return sb.ToString();
-		}
-		else if(!t.IsPrimitive)
-		{
-			return "L" + ClassName(t) + ";";
-		}
-		else
-		{
-			throw new NotImplementedException(t.FullName);
-		}
-	}
-
-	private static void ProcessType(Type type)
-	{
-		if(type == typeof(object))// || type == typeof(string))
-		{
-			// special case for System.Object & System.String, don't emit those
-			return;
-		}
-		string name = ClassName(type);
-		if(type == typeof(string))
-		{
-			name = "system/String";
-		}
-		string super;
-		if(type.BaseType == null)
-		{
-			// in .NET interfaces don't have a baseType, but in Java they "extend" java/lang/Object
-			super = "java/lang/Object";
-		}
-		else
-		{
-			if(type == typeof(Exception))
-			{
-				super = "java/lang/Throwable";
-			}
-			else
-			{
-				super = ClassName(type.BaseType);
-			}
-		}
-		Modifiers mods = Modifiers.Public | Modifiers.Super;
-		if(type.IsInterface)
-		{
-			mods |= Modifiers.Interface;
-		}
-		if(type.IsSealed)
-		{
-			mods |= Modifiers.Final;
-		}
-		if(type.IsAbstract)
-		{
-			mods |= Modifiers.Abstract;
-		}
-		ClassFileWriter f = new ClassFileWriter(mods, name, super);
-		f.AddStringAttribute("IK.VM.NET.Type", type.AssemblyQualifiedName);
-		FieldInfo[] fields = type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
-		Hashtable clashtable = new Hashtable();
-		for(int i = 0; i < fields.Length; i++)
-		{
-			if(fields[i].IsPublic || fields[i].IsFamily)
-			{
-				object[] attribs = fields[i].GetCustomAttributes(typeof(CLSCompliantAttribute), false);
-				if(attribs.Length == 1 && !((CLSCompliantAttribute)attribs[0]).IsCompliant)
-				{
-					// skip non-CLS compliant field
-				}
-				else
-				{
-					ProcessField(type, f, fields[i], clashtable);
-				}
-			}
-		}
-		clashtable.Clear();
-		ConstructorInfo[] constructors = type.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
-		for(int i = 0; i < constructors.Length; i++)
-		{
-			if(constructors[i].IsPublic || constructors[i].IsFamily)
-			{
-				object[] attribs = constructors[i].GetCustomAttributes(typeof(CLSCompliantAttribute), false);
-				if(attribs.Length == 1 && !((CLSCompliantAttribute)attribs[0]).IsCompliant)
-				{
-					// skip non-CLS compliant constructor
-				}
-				else
-				{
-					ProcessMethod(type, f, constructors[i], clashtable);
-				}
-			}
-		}
-		MethodInfo[] methods = type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly);
-		for(int i = 0; i < methods.Length; i++)
-		{
-			if(methods[i].IsPublic || methods[i].IsFamily)
-			{
-				object[] attribs = methods[i].GetCustomAttributes(typeof(CLSCompliantAttribute), false);
-				if(attribs.Length == 1 && !((CLSCompliantAttribute)attribs[0]).IsCompliant)
-				{
-					// skip non-CLS compliant method
-				}
-				else
-				{
-					ProcessMethod(type, f, methods[i], clashtable);
-				}
-			}
-		}
-		// for delegates we have to construct the inner interface
-		if(type.IsSubclassOf(typeof(MulticastDelegate)))
-		{
-			InnerClassesAttribute innerclasses = new InnerClassesAttribute(f);
-			string outer = ClassName(type);
-			innerclasses.Add(outer + "$Method", outer, "Method", 0x609);
-			f.AddAttribute(innerclasses);
-			// now we construct the inner interface type
-			ClassFileWriter iface = new ClassFileWriter(Modifiers.Interface | Modifiers.Public | Modifiers.Abstract, outer + "$Method", "java/lang/Object");
-			MethodInfo invoke = type.GetMethod("Invoke");
-			StringBuilder sb = new StringBuilder();
-			sb.Append('(');
-			ParameterInfo[] parameters = invoke.GetParameters();
-			for(int i = 0; i < parameters.Length; i++)
-			{
-				sb.Append(SigType(parameters[i].ParameterType));
-			}
-			sb.Append(')');
-			sb.Append(SigType(invoke.ReturnType));
-			// TODO IK.VM.NET.Sig must be set here as well
-			iface.AddMethod(Modifiers.Public | Modifiers.Abstract, "Invoke", sb.ToString());
-			innerclasses = new InnerClassesAttribute(iface);
-			innerclasses.Add(outer + "$Method", outer, "Method", 0x609);
-			iface.AddAttribute(innerclasses);
-			WriteClass(outer + "$Method.class", iface);
-		}
-		WriteClass(name + ".class", f);
+		// HACK if we run on the "classpath" assembly, the awt thread gets started,
+		// so we force an exit here
+		Environment.Exit(0);
 	}
 
 	private static void WriteClass(string name, ClassFileWriter c)
@@ -347,164 +72,219 @@ public class NetExp
 		c.Write(zipFile);
 	}
 
-	private static void ProcessField(Type type, ClassFileWriter f, FieldInfo fi, Hashtable clashtable)
+	private class MyClassLoader : ClassLoader
 	{
-		Modifiers access;
-		if(fi.IsPublic)
+		public Class loadClass(Type type)
 		{
-			access = Modifiers.Public;
-		}
-		else
-		{
-			access = Modifiers.Protected;
-		}
-		object v = null;
-		if(fi.IsLiteral)
-		{
-			v = fi.GetValue(null);
-			if(v is Enum)
-			{
-				v = UnwrapEnum(v);
-			}
-			if(v is byte)
-			{
-				v = (int)(byte)v;
-			}
-			else if (v is sbyte)
-			{
-				v = (int)(sbyte)v;
-			}
-			else if(v is char)
-			{
-				v = (int)(char)v;
-			}
-			else if(v is short)
-			{
-				v = (int)(short)v;
-			}
-			else if(v is ushort)
-			{
-				v = (int)(ushort)v;
-			}
-			else if(v is bool)
-			{
-				v = ((bool)v) ? 1 : 0;
-			}
-			else if(v is int || v is uint || v is ulong || v is long || v is float || v is double || v is string)
-			{
-			}
-			else
-			{
-				throw new NotImplementedException(v.GetType().FullName);
-			}
-			access |= Modifiers.Static | Modifiers.Final;
-		}
-		else
-		{
-			if(fi.IsInitOnly)
-			{
-				access |= Modifiers.Final;
-			}
-			if(fi.IsStatic)
-			{
-				access |= Modifiers.Static;
-			}
-			if(type.IsEnum)
-			{
-				// we don't want the value__ field
-				return;
-			}
-		}
-		string sig = SigType(fi.FieldType);
-		string key = fi.Name + sig;
-		if(clashtable.ContainsKey(key))
-		{
-			// TODO instead of skipping, we should mangle the name
-			Console.Error.WriteLine("Skipping field " + type.FullName + "." + fi.Name + " (type " + sig + ") because it clashes");
-		}
-		else
-		{
-			clashtable.Add(key, key);
-			f.AddField(access, fi.Name, sig, v);
+			return base.loadClass(type.AssemblyQualifiedName);
 		}
 	}
 
-	private static void ProcessMethod(Type type, ClassFileWriter f, MethodBase mb, Hashtable clashtable)
+	private static void ProcessAssembly(Assembly assembly)
 	{
-		Modifiers access = 0;
-		if(!mb.IsAbstract)
+		// HACK we use our own class loader to prevent class initialization
+		MyClassLoader loader = new MyClassLoader();
+		foreach(Type t in assembly.GetTypes())
 		{
-			access = Modifiers.Native;
+			if(t.IsPublic)
+			{
+				ProcessClass(assembly.FullName, loader.loadClass(t), null);
+			}
 		}
-		if(mb.IsPublic)
+	}
+
+	private static void ProcessClass(string assemblyName, Class c, Class outer)
+	{
+		string name = c.getName().Replace('.', '/');
+		//Console.WriteLine(name);
+		string super = null;
+		if(c.getSuperclass() != null)
 		{
-			access |= Modifiers.Public;
+			super = c.getSuperclass().getName().Replace('.', '/');
 		}
-		else
+		if(c.isInterface())
 		{
-			access |= Modifiers.Protected;
+			super = "java/lang/Object";
 		}
-		if(mb.IsFinal || !mb.IsVirtual)
+		ClassFileWriter f = new ClassFileWriter((Modifiers)c.getModifiers(), name, super);
+		f.AddStringAttribute("IKVM.NET.Assembly", assemblyName);
+		InnerClassesAttribute innerClassesAttribute = null;
+		if(outer != null)
 		{
-			access |= Modifiers.Final;
+			innerClassesAttribute = new InnerClassesAttribute(f);
+			innerClassesAttribute.Add(name, outer.getName().Replace('.', '/'), null, (ushort)Modifiers.Public);
 		}
-		if(mb.IsStatic)
+		Class[] innerClasses = c.getDeclaredClasses();
+		for(int i = 0; i < innerClasses.Length; i++)
 		{
-			access |= Modifiers.Static;
+			Modifiers mods = (Modifiers)innerClasses[i].getModifiers();
+			if((mods & (Modifiers.Public | Modifiers.Protected)) != 0)
+			{
+				if(innerClassesAttribute == null)
+				{
+					innerClassesAttribute = new InnerClassesAttribute(f);
+				}
+				string namePart = innerClasses[i].getName();
+				namePart = namePart.Substring(namePart.LastIndexOf('$') + 1);
+				innerClassesAttribute.Add(innerClasses[i].getName().Replace('.', '/'), name, namePart, (ushort)innerClasses[i].getModifiers());
+				ProcessClass(assemblyName, innerClasses[i], c);
+			}
 		}
-		if(mb.IsAbstract)
+		Constructor[] constructors = c.getDeclaredConstructors();
+		for(int i = 0; i < constructors.Length; i++)
 		{
-			access |= Modifiers.Abstract;
+			Modifiers mods = (Modifiers)constructors[i].getModifiers();
+			if((mods & (Modifiers.Public | Modifiers.Protected)) != 0)
+			{
+				f.AddMethod(mods | Modifiers.Native, "", MakeSig(constructors[i].getParameterTypes(), java.lang.Void.TYPE));
+			}
 		}
-		// special case for delegate constructors!
-		if(mb.IsConstructor && type.IsSubclassOf(typeof(MulticastDelegate)))
+		Method[] methods = c.getDeclaredMethods();
+		for(int i = 0; i < methods.Length; i++)
 		{
-			access &= ~Modifiers.Final;
-			f.AddMethod(access, "", "(L" + ClassName(type) + "$Method;)V");
-			return;
+			Modifiers mods = (Modifiers)methods[i].getModifiers();
+			if((mods & (Modifiers.Public | Modifiers.Protected)) != 0)
+			{
+				if((mods & Modifiers.Abstract) == 0)
+				{
+					mods |= Modifiers.Native;
+				}
+				f.AddMethod(mods, methods[i].getName(), MakeSig(methods[i].getParameterTypes(), methods[i].getReturnType()));
+			}
 		}
-		// HACK the native signature is really is very lame way of storing the signature
-		// TODO only store it when it doesn't match the Java sig and split it into parts (instead of one giant string)
-		StringBuilder nativesig = new StringBuilder();
+		Field[] fields = c.getDeclaredFields();
+		for(int i = 0; i < fields.Length; i++)
+		{
+			Modifiers mods = (Modifiers)fields[i].getModifiers();
+			if((mods & (Modifiers.Public | Modifiers.Protected)) != 0)
+			{
+				object constantValue = null;
+				// HACK we only look for constants on static final fields, to trigger less static initializers
+				if((mods & (Modifiers.Final | Modifiers.Static)) == (Modifiers.Final | Modifiers.Static))
+				{
+					// HACK we use a non-standard API to get constant value
+					// NOTE we can't use Field.get() because that will run the static initializer and
+					// also won't allow us to see the difference between constants and blank final fields.
+					constantValue = NativeCode.java.lang.reflect.Field.getConstant(fields[i]);
+					if(constantValue != null)
+					{
+						if(constantValue is java.lang.Boolean)
+						{
+							constantValue = ((java.lang.Boolean)constantValue).booleanValue();
+						}
+						else if(constantValue is java.lang.Byte)
+						{
+							constantValue = ((java.lang.Byte)constantValue).byteValue();
+						}
+						else if(constantValue is java.lang.Short)
+						{
+							constantValue = ((java.lang.Short)constantValue).shortValue();
+						}
+						else if(constantValue is java.lang.Character)
+						{
+							constantValue = ((java.lang.Character)constantValue).charValue();
+						}
+						else if(constantValue is java.lang.Integer)
+						{
+							constantValue = ((java.lang.Integer)constantValue).intValue();
+						}
+						else if(constantValue is java.lang.Long)
+						{
+							constantValue = ((java.lang.Long)constantValue).longValue();
+						}
+						else if(constantValue is java.lang.Float)
+						{
+							constantValue = ((java.lang.Float)constantValue).floatValue();
+						}
+						else if(constantValue is java.lang.Double)
+						{
+							constantValue = ((java.lang.Double)constantValue).doubleValue();
+						}
+						else if(constantValue is string)
+						{
+							// no conversion needed
+						}
+						else
+						{
+							throw new InvalidOperationException();
+						}
+					}
+				}
+				f.AddField(mods, fields[i].getName(), ClassToSig(fields[i].getType()), constantValue);
+			}
+		}
+		if(innerClassesAttribute != null)
+		{
+			f.AddAttribute(innerClassesAttribute);
+		}
+		WriteClass(name + ".class", f);
+	}
+
+	private static string MakeSig(Class[] args, Class ret)
+	{
 		StringBuilder sb = new StringBuilder();
 		sb.Append('(');
-		ParameterInfo[] parameters = mb.GetParameters();
-		string sep = "";
-		for(int i = 0; i < parameters.Length; i++)
+		for(int i = 0; i < args.Length; i++)
 		{
-			if(parameters[i].ParameterType.IsPointer)
-			{
-				// Java doesn't support pointer parameters
-				return;
-			}
-			sb.Append(SigType(parameters[i].ParameterType));
-			nativesig.Append(sep).Append(parameters[i].ParameterType.AssemblyQualifiedName);
-			sep = "|";
+			sb.Append(ClassToSig(args[i]));
 		}
 		sb.Append(')');
-		if(mb.IsConstructor)
+		sb.Append(ClassToSig(ret));
+		return sb.ToString();
+	}
+
+	private static string ClassToSig(Class c)
+	{
+		if(c.isPrimitive())
 		{
-			// HACK constructors may not be final in Java
-			access &= ~Modifiers.Final;
-			sb.Append('V');
+			if(c == java.lang.Void.TYPE)
+			{
+				return "V";
+			}
+			else if(c == java.lang.Byte.TYPE)
+			{
+				return "B";
+			}
+			else if(c == java.lang.Boolean.TYPE)
+			{
+				return "Z";
+			}
+			else if(c == java.lang.Short.TYPE)
+			{
+				return "S";
+			}
+			else if(c == java.lang.Character.TYPE)
+			{
+				return "C";
+			}
+			else if(c == java.lang.Integer.TYPE)
+			{
+				return "I";
+			}
+			else if(c == java.lang.Long.TYPE)
+			{
+				return "J";
+			}
+			else if(c == java.lang.Float.TYPE)
+			{
+				return "F";
+			}
+			else if(c == java.lang.Double.TYPE)
+			{
+				return "D";
+			}
+			else
+			{
+				throw new InvalidOperationException();
+			}
+		}
+		else if(c.isArray())
+		{
+			return "[" + ClassToSig(c.getComponentType());
 		}
 		else
 		{
-			sb.Append(SigType(((MethodInfo)mb).ReturnType));
-		}
-		string name = mb.IsConstructor ? "" : mb.Name;
-		string sig = sb.ToString();
-		string key = name + sig;
-		if(clashtable.ContainsKey(key))
-		{
-			// TODO instead of skipping, we should mangle the name
-			Console.Error.WriteLine("Skipping method " + type.FullName + "." + name + sig + " because it clashes");
-		}
-		else
-		{
-			clashtable.Add(key, key);
-			f.AddMethod(access, name, sig)
-				.AddAttribute(new StringAttribute(f.AddUtf8("IK.VM.NET.Sig"), f.AddUtf8(nativesig.ToString())));
+			return "L" + c.getName().Replace('.', '/') + ";";
 		}
 	}
 }
diff --git a/netexp/netexp.build b/netexp/netexp.build
index 4179b08b..c92c1823 100644
--- a/netexp/netexp.build
+++ b/netexp/netexp.build
@@ -6,6 +6,9 @@
                 
             
             
+                
+                
+                
                 
             
         
diff --git a/netexp/netexp.csproj b/netexp/netexp.csproj
index 05768416..d04ccd0f 100644
--- a/netexp/netexp.csproj
+++ b/netexp/netexp.csproj
@@ -84,6 +84,21 @@
                     AssemblyName = "SharpZipLib"
                     HintPath = "..\bin\SharpZipLib.dll"
                 />
+                
+                
+