This commit is contained in:
jfrijters 2004-03-16 17:10:09 +00:00
Родитель 18aacac574
Коммит 9a08682b9c
26 изменённых файлов: 980 добавлений и 520 удалений

Просмотреть файл

@ -163,6 +163,12 @@ public class ByteCodeHelper
return wrapper;
}
[StackTraceInfo(Hidden = true)]
public static object DynamicClassLiteral(RuntimeTypeHandle type, string clazz)
{
return NativeCode.java.lang.VMClass.getClassFromWrapper(LoadTypeWrapper(type, clazz));
}
[StackTraceInfo(Hidden = true)]
public static object DynamicCast(object obj, RuntimeTypeHandle type, string clazz)
{

Просмотреть файл

@ -40,6 +40,7 @@ class ClassFile
private string sourceFile;
private bool sourceFileCached;
private ClassFile outerClass;
private int majorVersion;
private static readonly char[] illegalcharacters = { '<', '>' };
internal class ClassFormatError : ApplicationException
@ -67,11 +68,15 @@ class ClassFile
{
throw new ClassFormatError("Bad magic number");
}
int minor = br.ReadUInt16();
int major = br.ReadUInt16();
if(major < 45 || major > 48)
int minorVersion = br.ReadUInt16();
majorVersion = br.ReadUInt16();
if(majorVersion < 45 || majorVersion > 49)
{
throw new UnsupportedClassVersionError(major + "." + minor);
throw new UnsupportedClassVersionError(majorVersion + "." + minorVersion);
}
if(majorVersion == 49)
{
Tracer.Warning(Tracer.Runtime, "WARNING: Support for JDK 1.5 is experimental");
}
int constantpoolcount = br.ReadUInt16();
constantpool = new ConstantPoolItem[constantpoolcount];
@ -240,6 +245,14 @@ class ClassFile
// }
}
internal int MajorVersion
{
get
{
return majorVersion;
}
}
// NOTE this property is only used when statically compiling
// (and it is set by the static compiler's class loader in vm.cs)
internal ClassFile OuterClass
@ -559,7 +572,8 @@ class ClassFile
Long,
Float,
Double,
String
String,
Class
}
internal abstract class ConstantPoolItem
@ -655,6 +669,11 @@ class ClassFile
}
return typeWrapper;
}
internal override ConstantType GetConstantType()
{
return ConstantType.Class;
}
}
private static TypeWrapper LoadClassHelper(ClassLoaderWrapper classLoader, string name)
@ -699,93 +718,6 @@ class ClassFile
}
}
private static TypeWrapper SigDecoderWrapper(ClassLoaderWrapper classLoader, ref int index, string sig)
{
switch(sig[index++])
{
case 'B':
return PrimitiveTypeWrapper.BYTE;
case 'C':
return PrimitiveTypeWrapper.CHAR;
case 'D':
return PrimitiveTypeWrapper.DOUBLE;
case 'F':
return PrimitiveTypeWrapper.FLOAT;
case 'I':
return PrimitiveTypeWrapper.INT;
case 'J':
return PrimitiveTypeWrapper.LONG;
case 'L':
{
int pos = index;
index = sig.IndexOf(';', index) + 1;
return LoadClassHelper(classLoader, sig.Substring(pos, index - pos - 1));
}
case 'S':
return PrimitiveTypeWrapper.SHORT;
case 'Z':
return PrimitiveTypeWrapper.BOOLEAN;
case 'V':
return PrimitiveTypeWrapper.VOID;
case '[':
{
// TODO this can be optimized
string array = "[";
while(sig[index] == '[')
{
index++;
array += "[";
}
switch(sig[index])
{
case 'L':
{
int pos = index;
index = sig.IndexOf(';', index) + 1;
return LoadClassHelper(classLoader, array + sig.Substring(pos, index - pos));
}
case 'B':
case 'C':
case 'D':
case 'F':
case 'I':
case 'J':
case 'S':
case 'Z':
return LoadClassHelper(classLoader, array + sig[index++]);
default:
// TODO this should never happen, because ClassFile should validate the descriptors
throw new InvalidOperationException(sig.Substring(index));
}
}
default:
// TODO this should never happen, because ClassFile should validate the descriptors
throw new InvalidOperationException(sig.Substring(index));
}
}
private static TypeWrapper[] ArgTypeWrapperListFromSig(ClassLoaderWrapper classLoader, string sig)
{
if(sig[1] == ')')
{
return TypeWrapper.EmptyArray;
}
ArrayList list = new ArrayList();
for(int i = 1; sig[i] != ')';)
{
list.Add(SigDecoderWrapper(classLoader, ref i, sig));
}
TypeWrapper[] types = new TypeWrapper[list.Count];
list.CopyTo(types);
return types;
}
private static TypeWrapper RetTypeWrapperFromSig(ClassLoaderWrapper classLoader, string sig)
{
int index = sig.IndexOf(')') + 1;
return SigDecoderWrapper(classLoader, ref index, sig);
}
private class ConstantPoolItemDouble : ConstantPoolItem
{
private double d;
@ -1038,7 +970,7 @@ class ClassFile
{
if(argTypeWrappers == null)
{
argTypeWrappers = ArgTypeWrapperListFromSig(classLoader, descriptor);
argTypeWrappers = classLoader.ArgTypeWrapperListFromSig(descriptor);
}
return argTypeWrappers;
}
@ -1047,7 +979,7 @@ class ClassFile
{
if(retTypeWrapper == null)
{
retTypeWrapper = RetTypeWrapperFromSig(classLoader, descriptor);
retTypeWrapper = classLoader.RetTypeWrapperFromSig(descriptor);
}
return retTypeWrapper;
}
@ -1056,8 +988,7 @@ class ClassFile
{
if(fieldTypeWrapper == null)
{
// HACK
fieldTypeWrapper = RetTypeWrapperFromSig(classLoader, "()" + descriptor);
fieldTypeWrapper = classLoader.FieldTypeWrapperFromSig(descriptor);
}
return fieldTypeWrapper;
}
@ -1240,7 +1171,7 @@ class ClassFile
{
if(argTypeWrappers == null)
{
argTypeWrappers = ArgTypeWrapperListFromSig(classLoader, Signature);
argTypeWrappers = classLoader.ArgTypeWrapperListFromSig(Signature);
}
return argTypeWrappers;
}
@ -1249,7 +1180,7 @@ class ClassFile
{
if(retTypeWrapper == null)
{
retTypeWrapper = RetTypeWrapperFromSig(classLoader, Signature);
retTypeWrapper = classLoader.RetTypeWrapperFromSig(Signature);
}
return retTypeWrapper;
}
@ -1258,8 +1189,7 @@ class ClassFile
{
if(fieldTypeWrapper == null)
{
// HACK
fieldTypeWrapper = RetTypeWrapperFromSig(classLoader, "()" + Signature);
fieldTypeWrapper = classLoader.FieldTypeWrapperFromSig(Signature);
}
return fieldTypeWrapper;
}

Просмотреть файл

@ -73,6 +73,8 @@ class ClassLoaderWrapper
Debug.Assert(coreAssembly == null);
// HACK we need to find the "core" library, to figure out the remapped types
// TODO this approach fails if the core library was compiled as a module (ikvmc always generates an assembly
// and the assembly attributes end up on the assemblies main module that is deleted when ikvmc finishes)
foreach(Assembly asm in AppDomain.CurrentDomain.GetAssemblies())
{
object[] remapped = asm.GetCustomAttributes(typeof(RemappedClassAttribute), false);
@ -764,6 +766,12 @@ class ClassLoaderWrapper
}
}
internal TypeWrapper FieldTypeWrapperFromSig(string sig)
{
int index = 0;
return SigDecoderWrapper(ref index, sig);
}
internal TypeWrapper RetTypeWrapperFromSig(string sig)
{
int index = sig.IndexOf(')') + 1;

Просмотреть файл

@ -83,7 +83,7 @@ public class ExceptionHelper
}
}
// HACK this is used by starter.cs (ikvm.exe) to map exceptions that escape from main
// HACK this is used in ClassFile.cs and MemberWrapper.cs
public static Exception MapExceptionFast(Exception x)
{
try

Просмотреть файл

@ -138,6 +138,11 @@
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "CoreClasses.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "DoubleToString.cs"
SubType = "Code"
@ -163,11 +168,6 @@
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "ObjectHelper.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "profiler.cs"
SubType = "Code"

Просмотреть файл

@ -440,7 +440,7 @@ class MethodWrapper : MemberWrapper
// constructor
if(IsStatic)
{
MethodInfo method = this.originalMethod != null && !(this.originalMethod is MethodBuilder) ? (MethodInfo)this.originalMethod : DeclaringType.TypeAsTBD.GetMethod(md.Name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, md.ArgTypes, null);
MethodInfo method = this.originalMethod != null && !(this.originalMethod is MethodBuilder) ? (MethodInfo)this.originalMethod : DeclaringType.TypeAsTBD.GetMethod(md.Name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, md.ArgTypesDontUse, null);
try
{
return method.Invoke(null, args);
@ -460,7 +460,7 @@ class MethodWrapper : MemberWrapper
// NOTE this means that we cannot detect a NullPointerException when calling <init>
if(md.Name == "<init>")
{
ConstructorInfo constructor = this.originalMethod != null && !(this.originalMethod is ConstructorBuilder) ? (ConstructorInfo)this.originalMethod : DeclaringType.TypeAsTBD.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, CallingConventions.Standard, md.ArgTypes, null);
ConstructorInfo constructor = this.originalMethod != null && !(this.originalMethod is ConstructorBuilder) ? (ConstructorInfo)this.originalMethod : DeclaringType.TypeAsTBD.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, CallingConventions.Standard, md.ArgTypesDontUse, null);
try
{
if(obj != null)
@ -503,7 +503,7 @@ class MethodWrapper : MemberWrapper
{
if(method is MethodBuilder || method == null)
{
method = DeclaringType.TypeAsTBD.GetMethod(md.Name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, md.ArgTypes, null);
method = DeclaringType.TypeAsTBD.GetMethod(md.Name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, md.ArgTypesDontUse, null);
}
if(method == null)
{
@ -606,13 +606,12 @@ class FieldWrapper : MemberWrapper
}
// 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)
// field is a constant (and if it is, to get 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.LoadClassCritical("java.lang.String");
if(field != null && (fieldType.IsPrimitive || fieldType == java_lang_String) && field.IsLiteral)
if(field != null && (fieldType.IsPrimitive || fieldType == CoreClasses.java_lang_String) && field.IsLiteral)
{
ReflectionOnConstant.IssueWarning(field);
object val = field.GetValue(null);
@ -656,9 +655,8 @@ class FieldWrapper : MemberWrapper
private class VolatileLongDoubleGetter : CodeEmitter
{
private static MethodInfo getFieldFromHandle = typeof(FieldInfo).GetMethod("GetFieldFromHandle");
private static MethodInfo monitorEnter = typeof(System.Threading.Monitor).GetMethod("Enter");
private static MethodInfo monitorExit = typeof(System.Threading.Monitor).GetMethod("Exit");
private static MethodInfo volatileReadDouble = typeof(System.Threading.Thread).GetMethod("VolatileRead", new Type[] { Type.GetType("System.Double&") });
private static MethodInfo volatileReadLong = typeof(System.Threading.Thread).GetMethod("VolatileRead", new Type[] { Type.GetType("System.Int64&") });
private FieldInfo fi;
internal VolatileLongDoubleGetter(FieldInfo fi)
@ -668,37 +666,23 @@ class FieldWrapper : MemberWrapper
internal override void Emit(ILGenerator ilgen)
{
if(!fi.IsStatic)
ilgen.Emit(fi.IsStatic ? OpCodes.Ldsflda : OpCodes.Ldflda, fi);
if(fi.FieldType == typeof(double))
{
ilgen.Emit(OpCodes.Dup);
Label label = ilgen.DefineLabel();
ilgen.Emit(OpCodes.Brtrue, label);
ilgen.ThrowException(typeof(NullReferenceException));
ilgen.MarkLabel(label);
}
// HACK we lock on the FieldInfo object
ilgen.Emit(OpCodes.Ldtoken, fi);
ilgen.Emit(OpCodes.Call, getFieldFromHandle);
ilgen.Emit(OpCodes.Call, monitorEnter);
if(fi.IsStatic)
{
ilgen.Emit(OpCodes.Ldsfld, fi);
ilgen.Emit(OpCodes.Call, volatileReadDouble);
}
else
{
ilgen.Emit(OpCodes.Ldfld, fi);
Debug.Assert(fi.FieldType == typeof(long));
ilgen.Emit(OpCodes.Call, volatileReadLong);
}
ilgen.Emit(OpCodes.Ldtoken, fi);
ilgen.Emit(OpCodes.Call, getFieldFromHandle);
ilgen.Emit(OpCodes.Call, monitorExit);
}
}
private class VolatileLongDoubleSetter : CodeEmitter
{
private static MethodInfo getFieldFromHandle = typeof(FieldInfo).GetMethod("GetFieldFromHandle");
private static MethodInfo monitorEnter = typeof(System.Threading.Monitor).GetMethod("Enter");
private static MethodInfo monitorExit = typeof(System.Threading.Monitor).GetMethod("Exit");
private static MethodInfo volatileWriteDouble = typeof(System.Threading.Thread).GetMethod("VolatileWrite", new Type[] { Type.GetType("System.Double&"), typeof(double) });
private static MethodInfo volatileWriteLong = typeof(System.Threading.Thread).GetMethod("VolatileWrite", new Type[] { Type.GetType("System.Int64&"), typeof(long) });
private FieldInfo fi;
internal VolatileLongDoubleSetter(FieldInfo fi)
@ -708,32 +692,19 @@ class FieldWrapper : MemberWrapper
internal override void Emit(ILGenerator ilgen)
{
if(!fi.IsStatic)
LocalBuilder temp = ilgen.DeclareLocal(fi.FieldType);
ilgen.Emit(OpCodes.Stloc, temp);
ilgen.Emit(fi.IsStatic ? OpCodes.Ldsflda : OpCodes.Ldflda, fi);
ilgen.Emit(OpCodes.Ldloc, temp);
if(fi.FieldType == typeof(double))
{
LocalBuilder local = ilgen.DeclareLocal(fi.FieldType);
ilgen.Emit(OpCodes.Stloc, local);
ilgen.Emit(OpCodes.Dup);
Label label = ilgen.DefineLabel();
ilgen.Emit(OpCodes.Brtrue, label);
ilgen.ThrowException(typeof(NullReferenceException));
ilgen.MarkLabel(label);
ilgen.Emit(OpCodes.Ldloc, local);
}
// HACK we lock on the FieldInfo object
ilgen.Emit(OpCodes.Ldtoken, fi);
ilgen.Emit(OpCodes.Call, getFieldFromHandle);
ilgen.Emit(OpCodes.Call, monitorEnter);
if(fi.IsStatic)
{
ilgen.Emit(OpCodes.Stsfld, fi);
ilgen.Emit(OpCodes.Call, volatileWriteDouble);
}
else
{
ilgen.Emit(OpCodes.Stfld, fi);
Debug.Assert(fi.FieldType == typeof(long));
ilgen.Emit(OpCodes.Call, volatileWriteLong);
}
ilgen.Emit(OpCodes.Ldtoken, fi);
ilgen.Emit(OpCodes.Call, getFieldFromHandle);
ilgen.Emit(OpCodes.Call, monitorExit);
}
}

Просмотреть файл

@ -1,61 +0,0 @@
/*
Copyright (C) 2002 Jeroen Frijters
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
Jeroen Frijters
jeroen@frijters.net
*/
using System;
using System.Reflection;
public class ObjectHelper
{
public static object virtualclone(object o)
{
// TODO because Object.clone() is protected it is accessible from other classes in the java.lang package,
// so when they clone an array, we end up here (instead of being redirected to System.Array.Clone(), which
// the compiler normally does because Object.clone() is inaccessible)
if(o is Array)
{
return ((Array)o).Clone();
}
// TODO this doesn't happen very often, the only sensible pattern that I can think of that produces code
// that ends up here is as follows:
// class Base {
// public Base CloneMe() { return (Base)clone(); }
// }
// case Derived extends Base {
// protected object clone() { ... }
// }
// One way of implementing this is by calling the clone method thru reflection, not very fast, but
// since this is an uncommon scenario, we might be able to get away with it
MethodInfo clone = o.GetType().GetMethod("clone", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, null, Type.EmptyTypes, null);
if(clone != null)
{
return clone.Invoke(o, new object[0]);
}
TypeWrapper tw = ClassLoaderWrapper.GetWrapperFromType(o.GetType());
TypeWrapper cloneable = ClassLoaderWrapper.LoadClassCritical("java.lang.Cloneable");
if(!tw.ImplementsInterface(cloneable))
{
throw JavaException.CloneNotSupportedException();
}
return typeof(object).GetType().InvokeMember("MemberwiseClone", BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.NonPublic, null, o, new object[0]);
}
}

Просмотреть файл

@ -110,7 +110,7 @@ sealed class MethodDescriptor
// NOTE this exposes potentially unfinished types!
// HACK this should not be used and all existing uses should be reworked
internal Type[] ArgTypes
internal Type[] ArgTypesDontUse
{
get
{
@ -139,16 +139,6 @@ sealed class MethodDescriptor
}
}
// NOTE this exposes potentially unfinished types!
// HACK this should not be used and all existing uses should be reworked
internal Type RetType
{
get
{
return RetTypeForDefineMethod;
}
}
internal TypeWrapper RetTypeWrapper
{
get
@ -239,7 +229,7 @@ sealed class MethodDescriptor
else
{
name = "Ljava.lang.Object;";
typeWrapper = ClassLoaderWrapper.LoadClassCritical("java.lang.Object");
typeWrapper = CoreClasses.java_lang_Object;
}
}
@ -477,14 +467,16 @@ class AttributeHelper
internal static void ImplementsAttribute(TypeBuilder typeBuilder, TypeWrapper ifaceWrapper)
{
Type iface = ifaceWrapper.TypeAsTBD;
// we always want the "clean" type in the attribute, so for ghosts we use the wrapping value type instead
// of the nested interface
Type iface = ifaceWrapper.IsGhost ? ifaceWrapper.TypeAsTBD : ifaceWrapper.TypeAsBaseType;
if(implementsAttribute == null)
{
implementsAttribute = typeof(ImplementsAttribute).GetConstructor(new Type[] { typeof(Type) });
}
// FXBUG because SetCustomAttribute(CustomAttributeBuilder) incorrectly always stores the assembly qualified name
// we have our own version for when the type lives in the same assembly as the attribute. If we don't do this
// ikvmc will have problems accessing this attribute when it uses Assembly.LoadFrom to load an assembly.
// the .NET runtime will have problems resolving this type when the assembly is loaded in the LoadFrom context.
if(typeBuilder.Assembly.Equals(iface.Assembly))
{
typeBuilder.SetCustomAttribute(implementsAttribute, FreezeDryType(iface));
@ -642,7 +634,6 @@ class AttributeHelper
abstract class TypeWrapper
{
private static TypeWrapper java_lang_Object;
private readonly ClassLoaderWrapper classLoader;
private readonly string name; // java name (e.g. java.lang.Object)
private readonly Modifiers modifiers;
@ -1253,13 +1244,8 @@ abstract class TypeWrapper
}
return ImplementsInterface(baseType);
}
if(java_lang_Object == null)
{
// TODO cache java.lang.Object somewhere else
java_lang_Object = ClassLoaderWrapper.LoadClassCritical("java.lang.Object");
}
// NOTE this isn't just an optimization, it is also required when this is an interface
if(baseType == java_lang_Object)
if(baseType == CoreClasses.java_lang_Object)
{
return true;
}
@ -1334,12 +1320,12 @@ abstract class TypeWrapper
private void ImplementInterfaceMethodStubImpl(MethodDescriptor md, MethodBase ifmethod, TypeBuilder typeBuilder, DynamicTypeWrapper wrapper)
{
// HACK we're mangling the name to prevent subclasses from overriding this method
string mangledName = this.Name + "$" + ifmethod.Name + "$" + wrapper.Name;
// we're mangling the name to prevent subclasses from accidentally overriding this method
string mangledName = this.Name + "/" + ifmethod.Name;
MethodWrapper mce = wrapper.GetMethodWrapper(md, true);
if(mce != null && mce.HasUnloadableArgsOrRet)
{
// HACK for now we make it seem as if the method isn't there, we should be emitting
// TODO for now we make it seem as if the method isn't there, we should be emitting
// a stub that throws a NoClassDefFoundError
// NOTE AFAICT this can only happen when code explicitly messes around with the custom class loaders
// that violate the class loader rules.
@ -1379,7 +1365,7 @@ abstract class TypeWrapper
// NOTE methods inherited from base classes in a different assembly do *not* automatically implement
// interface methods, so we have to generate a stub here that doesn't do anything but call the base
// implementation
MethodBuilder mb = typeBuilder.DefineMethod(mangledName, MethodAttributes.Private | MethodAttributes.NewSlot | MethodAttributes.Virtual | MethodAttributes.Final, md.RetTypeForDefineMethod, md.ArgTypesForDefineMethod);
MethodBuilder mb = typeBuilder.DefineMethod(mangledName, MethodAttributes.NewSlot | MethodAttributes.Private | MethodAttributes.Virtual | MethodAttributes.Final, md.RetTypeForDefineMethod, md.ArgTypesForDefineMethod);
typeBuilder.DefineMethodOverride(mb, (MethodInfo)ifmethod);
AttributeHelper.HideFromReflection(mb);
ILGenerator ilGenerator = mb.GetILGenerator();
@ -2729,6 +2715,7 @@ class DynamicTypeWrapper : TypeWrapper
{
// HACK methods that have unloadable types in the signature do not have an underlying method, so we end
// up here
// TODO I don't think the above is true anymore, this needs to be tested...
continue;
}
ClassFile.Method m = classFile.Methods[i];
@ -3447,7 +3434,7 @@ class DynamicTypeWrapper : TypeWrapper
break;
}
// here are the complex rules for determining whether this method overrides the method we found
// RULE 1: final methods may not be overriden
// RULE 1: final methods may not be overridden
if(baseMce.IsFinal)
{
// NOTE we don't need to test for our method being private, because if it is
@ -3520,18 +3507,57 @@ class DynamicTypeWrapper : TypeWrapper
}
else
{
mb = typeBuilder.DefineMethod(name, attribs, retType, args);
// if we're overriding java.lang.Object.finalize we need to emit a stub to override System.Object.Finalize
if(baseMethod != null &&
baseMethod.Name == "finalize" &&
baseMethod.DeclaringType.FullName == "java.lang.Object" &&
md.Signature == "()V")
bool needFinalize = false;
bool needDispatch = false;
if(baseMethod != null && md.Name == "finalize" && md.Signature == "()V")
{
MethodBuilder finalize = typeBuilder.DefineMethod("Finalize", MethodAttributes.Family | MethodAttributes.Virtual, CallingConventions.Standard, typeof(void), Type.EmptyTypes);
if(baseMethod.Name == "Finalize")
{
baseMethod = null;
attribs |= MethodAttributes.NewSlot;
needFinalize = true;
needDispatch = true;
}
else if(baseMethod.DeclaringType == CoreClasses.java_lang_Object.TypeAsBaseType)
{
needFinalize = true;
needDispatch = true;
}
else if(m.IsFinal)
{
needFinalize = true;
needDispatch = false;
}
}
mb = typeBuilder.DefineMethod(name, attribs, retType, args);
// if we're overriding java.lang.Object.finalize we need to emit a stub to override System.Object.Finalize,
// or if we're subclassing a non-Java class that has a Finalize method, we need a new Finalize override
if(needFinalize)
{
MethodInfo baseFinalize = typeBuilder.BaseType.GetMethod("Finalize", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, null, Type.EmptyTypes, null);
MethodAttributes attr = MethodAttributes.Virtual;
// make sure we don't reduce accessibility
attr |= baseFinalize.IsPublic ? MethodAttributes.Public : MethodAttributes.Family;
if(m.IsFinal)
{
attr |= MethodAttributes.Final;
}
MethodBuilder finalize = typeBuilder.DefineMethod("Finalize", attr, CallingConventions.Standard, typeof(void), Type.EmptyTypes);
AttributeHelper.HideFromReflection(finalize);
ILGenerator ilgen = finalize.GetILGenerator();
// NOTE we're not calling the base class Finalize (that would be Object.Finalize, which doesn't do anything)
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Callvirt, mb);
if(needDispatch)
{
ilgen.BeginExceptionBlock();
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Callvirt, mb);
ilgen.BeginCatchBlock(typeof(object));
ilgen.EndExceptionBlock();
}
else
{
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Call, baseFinalize);
}
ilgen.Emit(OpCodes.Ret);
}
}
@ -3584,9 +3610,11 @@ class DynamicTypeWrapper : TypeWrapper
}
}
method = mb;
// since Java constructors (and static intializers) aren't allowed to be synchronized, we only check this here
if(m.IsSynchronized)
// since Java constructors aren't allowed to be synchronized, we only check this here
if(m.IsSynchronized && !m.IsStatic)
{
// NOTE for static methods we cannot get by with setting the MethodImplAttributes.Synchronized flag,
// we actually need to emit code to lock the Class object!
mb.SetImplementationFlags(method.GetMethodImplementationFlags() | MethodImplAttributes.Synchronized);
}
if(baseMethod != null && (explicitOverride || baseMethod.Name != name))
@ -3921,7 +3949,7 @@ class CompiledTypeWrapper : LazyTypeWrapper
else if(type.BaseType == null)
{
// System.Object must appear to be derived from java.lang.Object
return ClassLoaderWrapper.LoadClassCritical("java.lang.Object");
return CoreClasses.java_lang_Object;
}
else
{
@ -3934,7 +3962,7 @@ class CompiledTypeWrapper : LazyTypeWrapper
}
else
{
return ClassLoaderWrapper.LoadClassCritical("java.lang.Object");
return CoreClasses.java_lang_Object;
}
}
return ClassLoaderWrapper.GetWrapperFromType(type.BaseType);
@ -4482,7 +4510,7 @@ class DotNetTypeWrapper : LazyTypeWrapper
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.
// too 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)
@ -4920,6 +4948,18 @@ class DotNetTypeWrapper : LazyTypeWrapper
// TODO why doesn't this use the standard MethodWrapper.Create?
private MethodWrapper CreateMethodWrapper(MethodDescriptor md, MethodBase mb, bool isRemapped, bool privateInterfaceImplHack)
{
Modifiers mods = AttributeHelper.GetModifiers(mb, true);
if(md.Name == "Finalize" && md.Signature == "()V" && !mb.IsStatic &&
TypeAsBaseType.IsSubclassOf(CoreClasses.java_lang_Object.TypeAsBaseType))
{
// TODO if the .NET also has a "finalize" method, we need to hide that one (or rename it, or whatever)
MethodWrapper mw = new MethodWrapper(this, MethodDescriptor.FromNameSig(GetClassLoader(), "finalize", "()V"), mb, null, mods, false);
mw.SetDeclaredExceptions(new string[] { "java.lang.Throwable" });
mw.EmitCall = CodeEmitter.Create(OpCodes.Call, mb);
mw.EmitCallvirt = CodeEmitter.Create(OpCodes.Callvirt, mb);
mw.EmitNewobj = CodeEmitter.InternalError;
return mw;
}
ParameterInfo[] parameters = mb.GetParameters();
Type[] args = new Type[parameters.Length];
bool hasByRefArgs = false;
@ -4937,7 +4977,6 @@ class DotNetTypeWrapper : LazyTypeWrapper
hasByRefArgs = true;
}
}
Modifiers mods = AttributeHelper.GetModifiers(mb, true);
if(isRemapped)
{
// all methods are static and final doesn't make sense
@ -4983,7 +5022,7 @@ class DotNetTypeWrapper : LazyTypeWrapper
}
if(!mb.IsStatic)
{
method.EmitCallvirt = CodeEmitter.Create(OpCodes.Callvirt, (MethodInfo)mb);
method.EmitCallvirt = CodeEmitter.Create(this.IsNonPrimitiveValueType ? OpCodes.Call : OpCodes.Callvirt, (MethodInfo)mb);
if(nonPrimitiveValueType)
{
method.EmitCallvirt += CodeEmitter.CreateEmitBoxCall(md.RetTypeWrapper);
@ -5070,7 +5109,7 @@ class ArrayTypeWrapper : TypeWrapper
private Type type;
internal ArrayTypeWrapper(Type type, Modifiers modifiers, string name, ClassLoaderWrapper classLoader)
: base(modifiers, name, ClassLoaderWrapper.LoadClassCritical("java.lang.Object"), classLoader)
: base(modifiers, name, CoreClasses.java_lang_Object, classLoader)
{
this.type = type;
if(mdClone == null)

Просмотреть файл

@ -374,22 +374,6 @@ namespace NativeCode.java
return typeof(VMRuntime).Assembly.GetName().Version.ToString();
}
// public static string nativeGetLibname(string pathname, string libname)
// {
// if(Environment.OSVersion.ToString().IndexOf("Unix") >= 0)
// {
// return "lib" + libname + ".so";
// }
//
// // HACK this seems like a lame way of doing things, but in order to get Eclipse to work,
// // we have append .dll to the libname here
// if(!libname.ToUpper().EndsWith(".DLL"))
// {
// libname += ".dll";
// }
// return libname;
// }
public static int nativeLoad(string filename)
{
// TODO native libraries somehow need to be scoped by class loader
@ -579,7 +563,7 @@ namespace NativeCode.java
ar.Add(VMClass.getClassFromType(frame.GetMethod().DeclaringType));
}
}
return ar.ToArray(ClassLoaderWrapper.LoadClassCritical("java.lang.Class").TypeAsArrayType);
return ar.ToArray(CoreClasses.java_lang_Class.TypeAsArrayType);
}
public static object currentClassLoader()
@ -768,38 +752,30 @@ namespace NativeCode.java
return !BitConverter.IsLittleEndian;
}
private static long timebase = ((TimeZone.CurrentTimeZone.ToUniversalTime(DateTime.Now) - new DateTime(1970, 1, 1)).Ticks / 10000L) - Environment.TickCount;
public static long currentTimeMillis()
{
// NOTE this wraps after 24.9 days, but it is much faster than calling DateTime.Now every time
return timebase + Environment.TickCount;
const long january_1st_1970 = 62135596800000L;
return DateTime.UtcNow.Ticks / 10000L - january_1st_1970;
}
public static void setErr(object printStream)
{
TypeWrapper tw = ClassLoaderWrapper.LoadClassCritical("java.lang.System");
tw.Finish();
// NOTE we cannot use Java reflection, because the field is final
// TODO JNI reflection should also ignore the final-ness of a field, so once we've got that
// sorted out, we could use that mechanism
tw.TypeAsTBD.GetField("err", BindingFlags.Static | BindingFlags.NonPublic).SetValue(null, printStream);
FieldWrapper fw = tw.GetFieldWrapper("err", ClassLoaderWrapper.LoadClassCritical("java.io.PrintStream"));
}
public static void setIn(object inputStream)
{
TypeWrapper tw = ClassLoaderWrapper.LoadClassCritical("java.lang.System");
tw.Finish();
// NOTE we cannot use Java reflection, because the field is final
tw.TypeAsTBD.GetField("in", BindingFlags.Static | BindingFlags.NonPublic).SetValue(null, inputStream);
FieldWrapper fw = tw.GetFieldWrapper("in", ClassLoaderWrapper.LoadClassCritical("java.io.InputStream"));
fw.SetValue(null, inputStream);
}
public static void setOut(object printStream)
{
TypeWrapper tw = ClassLoaderWrapper.LoadClassCritical("java.lang.System");
tw.Finish();
// NOTE we cannot use Java reflection, because the field is final
tw.TypeAsTBD.GetField("out", BindingFlags.Static | BindingFlags.NonPublic).SetValue(null, printStream);
FieldWrapper fw = tw.GetFieldWrapper("in", ClassLoaderWrapper.LoadClassCritical("java.io.PrintStream"));
fw.SetValue(null, printStream);
}
public static int identityHashCode(object o)
@ -817,7 +793,7 @@ namespace NativeCode.java
{
if(!(assemblies[i] is NetSystem.Reflection.Emit.AssemblyBuilder))
{
if(assemblies[i].GetLoadedModules()[0].GetField(name) != null)
if(assemblies[i].GetManifestResourceInfo("ikvm:" + name) != null)
{
return assemblies[i];
}

Просмотреть файл

@ -64,11 +64,13 @@ class Compiler
private static CodeEmitter mapExceptionFastMethod;
private static CodeEmitter fillInStackTraceMethod;
private static MethodInfo getTypeFromHandleMethod = typeof(Type).GetMethod("GetTypeFromHandle");
private static MethodInfo getClassFromTypeMethod = typeof(NativeCode.java.lang.VMClass).GetMethod("getClassFromType");
private static MethodInfo multiANewArrayMethod = typeof(ByteCodeHelper).GetMethod("multianewarray");
private static MethodInfo monitorEnterMethod = typeof(System.Threading.Monitor).GetMethod("Enter");
private static MethodInfo monitorExitMethod = typeof(System.Threading.Monitor).GetMethod("Exit");
private static MethodInfo objectToStringMethod = typeof(object).GetMethod("ToString");
private static TypeWrapper java_lang_Object;
private static TypeWrapper java_lang_Class;
private static TypeWrapper java_lang_Throwable;
private static TypeWrapper java_lang_ThreadDeath;
private TypeWrapper clazz;
@ -86,8 +88,9 @@ class Compiler
mapExceptionMethod = exceptionHelper.GetMethodWrapper(MethodDescriptor.FromNameSig(exceptionHelper.GetClassLoader(), "MapException", "(Ljava.lang.Throwable;Lcli.System.Type;)Ljava.lang.Throwable;"), false).EmitCall;
mapExceptionFastMethod = exceptionHelper.GetMethodWrapper(MethodDescriptor.FromNameSig(exceptionHelper.GetClassLoader(), "MapExceptionFast", "(Ljava.lang.Throwable;)Ljava.lang.Throwable;"), false).EmitCall;
fillInStackTraceMethod = exceptionHelper.GetMethodWrapper(MethodDescriptor.FromNameSig(exceptionHelper.GetClassLoader(), "fillInStackTrace", "(Ljava.lang.Throwable;)Ljava.lang.Throwable;"), false).EmitCall;
java_lang_Throwable = ClassLoaderWrapper.LoadClassCritical("java.lang.Throwable");
java_lang_Object = ClassLoaderWrapper.LoadClassCritical("java.lang.Object");
java_lang_Throwable = CoreClasses.java_lang_Throwable;
java_lang_Object = CoreClasses.java_lang_Object;
java_lang_Class = CoreClasses.java_lang_Class;
java_lang_ThreadDeath = ClassLoaderWrapper.LoadClassCritical("java.lang.ThreadDeath");
}
@ -445,8 +448,24 @@ class Compiler
private sealed class ReturnCookie
{
internal Label Stub;
internal LocalBuilder Local;
private Label stub;
private LocalBuilder local;
internal ReturnCookie(Label stub, LocalBuilder local)
{
this.stub = stub;
this.local = local;
}
internal void EmitRet(ILGenerator ilgen)
{
ilgen.MarkLabel(stub);
if(local != null)
{
ilgen.Emit(OpCodes.Ldloc, local);
}
ilgen.Emit(OpCodes.Ret);
}
}
private sealed class BranchCookie
@ -593,7 +612,32 @@ class Compiler
return;
}
Profiler.Enter("Compile");
c.Compile(0, 0, null);
if(m.IsStatic && m.IsSynchronized)
{
ArrayList exits = new ArrayList();
// TODO consider caching the Class object in a static field
ilGenerator.Emit(OpCodes.Ldtoken, clazz.TypeAsTBD);
ilGenerator.Emit(OpCodes.Call, getTypeFromHandleMethod);
ilGenerator.Emit(OpCodes.Call, getClassFromTypeMethod);
ilGenerator.Emit(OpCodes.Dup);
LocalBuilder monitor = ilGenerator.DeclareLocal(typeof(object));
ilGenerator.Emit(OpCodes.Stloc, monitor);
ilGenerator.Emit(OpCodes.Call, monitorEnterMethod);
ilGenerator.BeginExceptionBlock();
c.Compile(0, 0, exits);
ilGenerator.BeginFinallyBlock();
ilGenerator.Emit(OpCodes.Ldloc, monitor);
ilGenerator.Emit(OpCodes.Call, monitorExitMethod);
ilGenerator.EndExceptionBlock();
foreach(ReturnCookie rc in exits)
{
rc.EmitRet(ilGenerator);
}
}
else
{
c.Compile(0, 0, null);
}
Profiler.Leave("Compile");
}
@ -809,14 +853,9 @@ class Compiler
ReturnCookie rc = exit as ReturnCookie;
if(rc != null)
{
if(exceptionIndex == 0)
if(exits == null)
{
ilGenerator.MarkLabel(rc.Stub);
if(rc.Local != null)
{
ilGenerator.Emit(OpCodes.Ldloc, rc.Local);
}
ilGenerator.Emit(OpCodes.Ret);
rc.EmitRet(ilGenerator);
}
else
{
@ -953,6 +992,24 @@ class Compiler
case ClassFile.ConstantType.String:
ilGenerator.Emit(OpCodes.Ldstr, cf.GetConstantPoolConstantString(constant));
break;
case ClassFile.ConstantType.Class:
{
TypeWrapper tw = cf.GetConstantPoolClassType(constant, classLoader);
if(tw.IsUnloadable)
{
ilGenerator.Emit(OpCodes.Ldtoken, clazz.TypeAsTBD);
ilGenerator.Emit(OpCodes.Ldstr, tw.Name);
ilGenerator.Emit(OpCodes.Call, typeof(ByteCodeHelper).GetMethod("DynamicClassLiteral"));
}
else
{
ilGenerator.Emit(OpCodes.Ldtoken, tw.IsRemapped ? tw.TypeAsBaseType : tw.TypeAsTBD);
ilGenerator.Emit(OpCodes.Call, getTypeFromHandleMethod);
ilGenerator.Emit(OpCodes.Call, getClassFromTypeMethod);
}
java_lang_Class.EmitCheckcast(clazz, ilGenerator);
break;
}
default:
throw new InvalidOperationException();
}
@ -1184,25 +1241,25 @@ class Compiler
case NormalizedByteCode.__freturn:
case NormalizedByteCode.__dreturn:
{
if(exceptionIndex != 0)
if(exits != null)
{
// if we're inside an exception block, copy TOS to local, emit "leave" and push item onto our "todo" list
ReturnCookie rc = new ReturnCookie();
LocalBuilder local = null;
if(instr.NormalizedOpCode != NormalizedByteCode.__return)
{
TypeWrapper retTypeWrapper = m.Method.GetRetType(classLoader);
rc.Local = ilGenerator.DeclareLocal(retTypeWrapper.TypeAsParameterType);
retTypeWrapper.EmitConvStackToParameterType(ilGenerator, ma.GetRawStackTypeWrapper(i, 0));
if(ma.GetRawStackTypeWrapper(i, 0).IsUnloadable)
{
ilGenerator.Emit(OpCodes.Castclass, retTypeWrapper.TypeAsParameterType);
}
ilGenerator.Emit(OpCodes.Stloc, rc.Local);
local = ilGenerator.DeclareLocal(retTypeWrapper.TypeAsParameterType);
ilGenerator.Emit(OpCodes.Stloc, local);
}
rc.Stub = ilGenerator.DefineLabel();
Label label = ilGenerator.DefineLabel();
// NOTE leave automatically discards any junk that may be on the stack
ilGenerator.Emit(OpCodes.Leave, rc.Stub);
exits.Add(rc);
ilGenerator.Emit(OpCodes.Leave, label);
exits.Add(new ReturnCookie(label, local));
}
else
{
@ -1211,10 +1268,7 @@ class Compiler
int stackHeight = ma.GetStackHeight(i);
if(instr.NormalizedOpCode == NormalizedByteCode.__return)
{
for(int j = 0; j < stackHeight; j++)
{
ilGenerator.Emit(OpCodes.Pop);
}
ilGenerator.Emit(OpCodes.Leave_S, (byte)0);
ilGenerator.Emit(OpCodes.Ret);
}
else
@ -1229,10 +1283,7 @@ class Compiler
{
LocalBuilder local = ilGenerator.DeclareLocal(retTypeWrapper.TypeAsParameterType);
ilGenerator.Emit(OpCodes.Stloc, local);
for(int j = 1; j < stackHeight; j++)
{
ilGenerator.Emit(OpCodes.Pop);
}
ilGenerator.Emit(OpCodes.Leave_S, (byte)0);
ilGenerator.Emit(OpCodes.Ldloc, local);
}
ilGenerator.Emit(OpCodes.Ret);
@ -2608,7 +2659,7 @@ class Compiler
// NOTE vmspec 5.4.3.4 clearly states that an interfacemethod may also refer to a method in Object
if(method == null)
{
method = ClassLoaderWrapper.LoadClassCritical("java.lang.Object").GetMethodWrapper(md, false);
method = java_lang_Object.GetMethodWrapper(md, false);
}
}
else

Просмотреть файл

@ -40,24 +40,24 @@ class Profiler
~Profiler()
{
Console.WriteLine("{0,-40}{1,10}{2,12}", "Event", "Count", "Time (ms)");
Console.WriteLine("{0,-40}{1,10}{2,12}", "-----", "-----", "---------");
Console.Error.WriteLine("{0,-40}{1,10}{2,12}", "Event", "Count", "Time (ms)");
Console.Error.WriteLine("{0,-40}{1,10}{2,12}", "-----", "-----", "---------");
long totalTime = 0;
foreach(DictionaryEntry e in counters)
{
Entry entry = (Entry)e.Value;
if(entry.Time == 0)
{
Console.WriteLine("{0,-40}{1,10}", e.Key, entry.Count);
Console.Error.WriteLine("{0,-40}{1,10}", e.Key, entry.Count);
}
else
{
totalTime += entry.Time / 10000;
Console.WriteLine("{0,-40}{1,10}{2,12}", e.Key, entry.Count, entry.Time / 10000);
Console.Error.WriteLine("{0,-40}{1,10}{2,12}", e.Key, entry.Count, entry.Time / 10000);
}
}
Console.WriteLine("{0,-40}{1,10}{2,12}", "", "", "---------");
Console.WriteLine("{0,-40}{1,10}{2,12}", "", "", totalTime);
Console.Error.WriteLine("{0,-40}{1,10}{2,12}", "", "", "---------");
Console.Error.WriteLine("{0,-40}{1,10}{2,12}", "", "", totalTime);
}
[Conditional("PROFILE")]

Просмотреть файл

@ -94,6 +94,46 @@ namespace MapXml
throw new InvalidOperationException();
}
}
// TODO this code is part of what Compiler.CastInterfaceArgs (in compiler.cs) does,
// it would be nice if we could avoid this duplication...
TypeWrapper[] argTypeWrappers = method.Descriptor.ArgTypeWrappers;
for(int i = 0; i < argTypeWrappers.Length; i++)
{
if(argTypeWrappers[i].IsGhost)
{
LocalBuilder[] temps = new LocalBuilder[argTypeWrappers.Length + (method.IsStatic ? 0 : 1)];
for(int j = temps.Length - 1; j >= 0; j--)
{
TypeWrapper tw;
if(method.IsStatic)
{
tw = argTypeWrappers[j];
}
else
{
if(j == 0)
{
tw = method.DeclaringType;
}
else
{
tw = argTypeWrappers[j - 1];
}
}
if(tw.IsGhost)
{
tw.EmitConvStackToParameterType(ilgen, tw);
}
temps[j] = ilgen.DeclareLocal(tw.TypeAsParameterType);
ilgen.Emit(OpCodes.Stloc, temps[j]);
}
for(int j = 0; j < temps.Length; j++)
{
ilgen.Emit(OpCodes.Ldloc, temps[j]);
}
break;
}
}
}
else
{
@ -471,7 +511,7 @@ namespace MapXml
internal override void Generate(Hashtable context, ILGenerator ilgen)
{
ClassLoaderWrapper.LoadClassCritical(Class).GetFieldWrapper(Name, ClassLoaderWrapper.GetBootstrapClassLoader().RetTypeWrapperFromSig("()" + Sig)).EmitSet.Emit(ilgen);
ClassLoaderWrapper.LoadClassCritical(Class).GetFieldWrapper(Name, ClassLoaderWrapper.GetBootstrapClassLoader().FieldTypeWrapperFromSig(Sig)).EmitSet.Emit(ilgen);
}
}

Просмотреть файл

@ -400,7 +400,7 @@ class InstructionState
TypeWrapper baseType = FindCommonBaseTypeHelper(elem1, elem2);
if(baseType == VerifierTypeWrapper.Invalid)
{
baseType = MethodAnalyzer.java_lang_Object;
baseType = CoreClasses.java_lang_Object;
rank--;
if(rank == 0)
{
@ -445,12 +445,12 @@ class InstructionState
foreach (TypeWrapper baseInterface in t1.Interfaces)
{
TypeWrapper commonBase = FindCommonBaseTypeHelper(baseInterface, t2);
if (commonBase != MethodAnalyzer.java_lang_Object)
if (commonBase != CoreClasses.java_lang_Object)
{
return commonBase;
}
}
return MethodAnalyzer.java_lang_Object;
return CoreClasses.java_lang_Object;
}
Stack st1 = new Stack();
Stack st2 = new Stack();
@ -995,9 +995,6 @@ class VerifierTypeWrapper : TypeWrapper
class MethodAnalyzer
{
internal static TypeWrapper java_lang_Object;
private static TypeWrapper java_lang_Throwable;
private static TypeWrapper java_lang_String;
private static TypeWrapper ByteArrayType;
private static TypeWrapper BooleanArrayType;
private static TypeWrapper ShortArrayType;
@ -1013,27 +1010,22 @@ class MethodAnalyzer
private TypeWrapper[] localTypes;
private bool[] aload_used;
static MethodAnalyzer()
{
ByteArrayType = PrimitiveTypeWrapper.BYTE.MakeArrayType(1);
BooleanArrayType = PrimitiveTypeWrapper.BOOLEAN.MakeArrayType(1);
ShortArrayType = PrimitiveTypeWrapper.SHORT.MakeArrayType(1);
CharArrayType = PrimitiveTypeWrapper.CHAR.MakeArrayType(1);
IntArrayType = PrimitiveTypeWrapper.INT.MakeArrayType(1);
FloatArrayType = PrimitiveTypeWrapper.FLOAT.MakeArrayType(1);
DoubleArrayType = PrimitiveTypeWrapper.DOUBLE.MakeArrayType(1);
LongArrayType = PrimitiveTypeWrapper.LONG.MakeArrayType(1);
}
internal MethodAnalyzer(TypeWrapper wrapper, ClassFile.Method.Code method, ClassLoaderWrapper classLoader)
{
this.classLoader = classLoader;
this.method = method;
lock(GetType())
{
if(java_lang_Throwable == null)
{
java_lang_Object = ClassLoaderWrapper.LoadClassCritical("java.lang.Object");
java_lang_Throwable = ClassLoaderWrapper.LoadClassCritical("java.lang.Throwable");
java_lang_String = ClassLoaderWrapper.LoadClassCritical("java.lang.String");
ByteArrayType = PrimitiveTypeWrapper.BYTE.MakeArrayType(1);
BooleanArrayType = PrimitiveTypeWrapper.BOOLEAN.MakeArrayType(1);
ShortArrayType = PrimitiveTypeWrapper.SHORT.MakeArrayType(1);
CharArrayType = PrimitiveTypeWrapper.CHAR.MakeArrayType(1);
IntArrayType = PrimitiveTypeWrapper.INT.MakeArrayType(1);
FloatArrayType = PrimitiveTypeWrapper.FLOAT.MakeArrayType(1);
DoubleArrayType = PrimitiveTypeWrapper.DOUBLE.MakeArrayType(1);
LongArrayType = PrimitiveTypeWrapper.LONG.MakeArrayType(1);
}
}
state = new InstructionState[method.Instructions.Length];
callsites = new ArrayList[method.Instructions.Length];
localTypes = new TypeWrapper[method.MaxLocals];
@ -1109,7 +1101,7 @@ class MethodAnalyzer
int catch_type = method.ExceptionTable[j].catch_type;
if(catch_type == 0)
{
ex.PushType(java_lang_Throwable);
ex.PushType(CoreClasses.java_lang_Throwable);
}
else
{
@ -1341,7 +1333,14 @@ class MethodAnalyzer
s.PushLong();
break;
case ClassFile.ConstantType.String:
s.PushType(java_lang_String);
s.PushType(CoreClasses.java_lang_String);
break;
case ClassFile.ConstantType.Class:
if(method.Method.ClassFile.MajorVersion < 49)
{
throw new VerifyError("Illegal type in constant pool");
}
s.PushType(CoreClasses.java_lang_Class);
break;
default:
// NOTE this is not a VerifyError, because it cannot happen (unless we have
@ -1848,7 +1847,7 @@ class MethodAnalyzer
s.GetLocalInt(instr.Arg1);
break;
case NormalizedByteCode.__athrow:
s.PopObjectType(java_lang_Throwable);
s.PopObjectType(CoreClasses.java_lang_Throwable);
break;
case NormalizedByteCode.__lookupswitch:
s.PopInt();
@ -2051,7 +2050,7 @@ class MethodAnalyzer
{
if(!VerifierTypeWrapper.IsNullOrUnloadable(l) && l.IsNonPrimitiveValueType)
{
l = java_lang_Object;
l = CoreClasses.java_lang_Object;
}
if(localTypes[j] == VerifierTypeWrapper.Invalid)
{

Просмотреть файл

@ -22,6 +22,7 @@
*/
using System;
using System.Resources;
using System.Reflection.Emit;
using System.Reflection;
using System.IO;
@ -241,10 +242,10 @@ public class JVM
byte[] buf = (byte[])d.Value;
if(buf.Length > 0)
{
moduleBuilder.DefineInitializedData((string)d.Key, buf, FieldAttributes.Public | FieldAttributes.Static);
IResourceWriter writer = moduleBuilder.DefineResource("ikvm:" + d.Key, "");
writer.AddResource("ikvm", buf);
}
}
moduleBuilder.CreateGlobalFunctions();
}
private static MethodAttributes MapMethodAccessModifiers(MapXml.MapModifiers mod)
@ -317,7 +318,9 @@ public class JVM
}
if(!redir.RetTypeWrapper.IsAssignableTo(md.RetTypeWrapper))
{
// HACK we're using a null context, is that safe?
// NOTE we're passing a null context, this is safe because the return type
// should always be loadable
Debug.CompareTo(!md.RetTypeWrapper.IsUnloadable);
md.RetTypeWrapper.EmitCheckcast(null, ilgen);
}
}
@ -347,6 +350,8 @@ public class JVM
{
return null;
}
// NOTE we cannot use CoreClasses.java_lang_Object here, because that would trigger a load
// of java.lang.String and java.lang.Throwable before we've got the remapping set up.
return ClassLoaderWrapper.LoadClassCritical("java.lang.Object");
}
@ -966,7 +971,7 @@ public class JVM
throw new InvalidOperationException("remapping field: " + f.Name + f.Sig + " not found");
}
// TODO emit an static helper method that enables access to the field at runtime
AddField(FieldWrapper.Create(this, GetClassLoader().RetTypeWrapperFromSig("()" + f.Sig), f.Name, f.Sig, (Modifiers)f.Modifiers, null, method.EmitCall, CodeEmitter.InternalError));
AddField(FieldWrapper.Create(this, GetClassLoader().FieldTypeWrapperFromSig(f.Sig), f.Name, f.Sig, (Modifiers)f.Modifiers, null, method.EmitCall, CodeEmitter.InternalError));
}
else if((f.Modifiers & MapXml.MapModifiers.Static) != 0)
{
@ -979,7 +984,7 @@ public class JVM
{
attr |= FieldAttributes.InitOnly;
}
FieldBuilder fb = tb.DefineField(f.Name, GetClassLoader().RetTypeWrapperFromSig("()" + f.Sig).TypeAsFieldType, attr);
FieldBuilder fb = tb.DefineField(f.Name, GetClassLoader().FieldTypeWrapperFromSig(f.Sig).TypeAsFieldType, attr);
object constant;
if(f.Constant != null)
{
@ -994,11 +999,11 @@ public class JVM
}
fb.SetConstant(constant);
CodeEmitter getter = CodeEmitter.CreateLoadConstant(constant);
AddField(FieldWrapper.Create(this, GetClassLoader().RetTypeWrapperFromSig("()" + f.Sig), f.Name, f.Sig, (Modifiers)f.Modifiers, fb, getter, CodeEmitter.InternalError, constant));
AddField(FieldWrapper.Create(this, GetClassLoader().FieldTypeWrapperFromSig(f.Sig), f.Name, f.Sig, (Modifiers)f.Modifiers, fb, getter, CodeEmitter.InternalError, constant));
}
else
{
AddField(FieldWrapper.Create(this, GetClassLoader().RetTypeWrapperFromSig("()" + f.Sig), fb, f.Sig, (Modifiers)f.Modifiers));
AddField(FieldWrapper.Create(this, GetClassLoader().FieldTypeWrapperFromSig(f.Sig), fb, f.Sig, (Modifiers)f.Modifiers));
}
}
else
@ -1092,7 +1097,7 @@ public class JVM
{
get
{
return equivalencyType.IsInterface ? equivalencyType : typeBuilder;
return typeBuilder;
}
}
@ -1103,6 +1108,15 @@ public class JVM
return typeBuilder;
}
}
internal override bool IsMapUnsafeException
{
get
{
// any remapped exceptions are automatically unsafe
return equivalencyType == typeof(Exception) || equivalencyType.IsSubclassOf(typeof(Exception));
}
}
}
internal void EmitRemappedTypes(MapXml.Root map)

Просмотреть файл

@ -46,7 +46,7 @@ namespace ikvm.awt
delegate void SetColor(Color c);
delegate java.awt.Dimension GetDimension();
public class NetToolkit : java.awt.Toolkit
public class NetToolkit : gnu.java.awt.ClasspathToolkit
{
private static java.awt.EventQueue eventQueue = new java.awt.EventQueue();
private static Form bogusForm;
@ -365,6 +365,109 @@ namespace ikvm.awt
}
return new NetLightweightComponentPeer(target);
}
public override java.awt.Font createFont(int format, java.io.InputStream stream)
{
throw new NotImplementedException();
}
public override gnu.java.awt.peer.ClasspathFontPeer getClasspathFontPeer(string name, java.util.Map attrs)
{
return new NetFontPeer(name, attrs);
}
public override java.awt.GraphicsEnvironment getLocalGraphicsEnvironment()
{
throw new NotImplementedException();
}
}
class NetFontPeer : gnu.java.awt.peer.ClasspathFontPeer
{
internal NetFontPeer(string name, java.util.Map attrs)
: base(name, attrs)
{
}
public override bool canDisplay(java.awt.Font param1, char param2)
{
throw new NotImplementedException();
}
public override int canDisplayUpTo(java.awt.Font param1, java.text.CharacterIterator param2, int param3, int param4)
{
throw new NotImplementedException();
}
public override java.awt.font.GlyphVector createGlyphVector(java.awt.Font param1, java.awt.font.FontRenderContext param2, int[] param3)
{
throw new NotImplementedException();
}
public override java.awt.font.GlyphVector createGlyphVector(java.awt.Font param1, java.awt.font.FontRenderContext param2, java.text.CharacterIterator param3)
{
throw new NotImplementedException();
}
public override sbyte getBaselineFor(java.awt.Font param1, char param2)
{
throw new NotImplementedException();
}
public override java.awt.FontMetrics getFontMetrics(java.awt.Font param)
{
throw new NotImplementedException();
}
public override string getGlyphName(java.awt.Font param1, int param2)
{
throw new NotImplementedException();
}
public override java.awt.font.LineMetrics getLineMetrics(java.awt.Font param1, java.text.CharacterIterator param2, int param3, int param4, java.awt.font.FontRenderContext param5)
{
throw new NotImplementedException();
}
public override java.awt.geom.Rectangle2D getMaxCharBounds(java.awt.Font param1, java.awt.font.FontRenderContext param2)
{
throw new NotImplementedException();
}
public override int getMissingGlyphCode(java.awt.Font param)
{
throw new NotImplementedException();
}
public override int getNumGlyphs(java.awt.Font param)
{
throw new NotImplementedException();
}
public override string getPostScriptName(java.awt.Font param)
{
throw new NotImplementedException();
}
public override java.awt.geom.Rectangle2D getStringBounds(java.awt.Font param1, java.text.CharacterIterator param2, int param3, int param4, java.awt.font.FontRenderContext param5)
{
throw new NotImplementedException();
}
public override bool hasUniformLineMetrics(java.awt.Font param)
{
throw new NotImplementedException();
}
public override java.awt.font.GlyphVector layoutGlyphVector(java.awt.Font param1, java.awt.font.FontRenderContext param2, char[] param3, int param4, int param5, int param6)
{
throw new NotImplementedException();
}
public override string getSubFamilyName(java.awt.Font param1, Locale param2)
{
throw new NotImplementedException();
}
}
class NetLightweightComponentPeer : NetComponentPeer, java.awt.peer.LightweightPeer
@ -1181,7 +1284,7 @@ namespace ikvm.awt
public java.awt.Image createImage(int width, int height)
{
throw new NotImplementedException();
return new NetBufferedImage(width, height);
}
public void disable()
@ -1191,7 +1294,13 @@ namespace ikvm.awt
public void dispose()
{
control.Parent = null;
control.Invoke(new SetVoid(disposeImpl));
}
private void disposeImpl()
{
// HACK we should dispose the control here, but that hangs in an infinite loop...
control.Hide();
}
public void enable()
@ -1281,7 +1390,7 @@ namespace ikvm.awt
public void paint(java.awt.Graphics graphics)
{
throw new NotImplementedException();
//throw new NotImplementedException();
}
public bool prepareImage(java.awt.Image img, int width, int height, ImageObserver ob)
@ -1781,13 +1890,15 @@ namespace ikvm.awt
{
throw new NotImplementedException();
}
public java.awt.Dimension preferredSize(int len)
{
throw new NotImplementedException();
}
public java.awt.Dimension getMinimumSize(int len)
{
throw new NotImplementedException();
return getPreferredSize(len);
}
public java.awt.Dimension getPreferredSize(int len)
@ -1803,6 +1914,7 @@ namespace ikvm.awt
{
throw new NotImplementedException();
}
public void setEchoCharacter(char echo_char)
{
throw new NotImplementedException();

Просмотреть файл

@ -24,11 +24,17 @@ java/net/SocketOutputStream.java
sun/misc/Ref.java
../../classpath/gnu/classpath/RawData.java
../../classpath/gnu/java/awt/BitMaskExtent.java
../../classpath/gnu/java/awt/BitwiseXORComposite.java
../../classpath/gnu/java/awt/Buffers.java
../../classpath/gnu/java/awt/ClasspathToolkit.java
../../classpath/gnu/java/awt/ComponentDataBlitOp.java
../../classpath/gnu/java/awt/EmbeddedWindow.java
../../classpath/gnu/java/awt/EmbeddedWindowSupport.java
../../classpath/gnu/java/awt/EventModifier.java
../../classpath/gnu/java/awt/image/ImageDecoder.java
../../classpath/gnu/java/awt/image/XBMDecoder.java
../../classpath/gnu/java/awt/peer/ClasspathFontPeer.java
../../classpath/gnu/java/awt/peer/EmbeddedWindowPeer.java
../../classpath/gnu/java/beans/BeanInfoEmbryo.java
../../classpath/gnu/java/beans/EmptyBeanInfo.java
../../classpath/gnu/java/beans/ExplicitBeanInfo.java
@ -215,21 +221,31 @@ sun/misc/Ref.java
../../classpath/gnu/java/locale/LocaleInformation_zh_TW.java
../../classpath/gnu/java/math/MPN.java
../../classpath/gnu/java/net/HeaderFieldHelper.java
../../classpath/gnu/java/net/URLParseError.java
../../classpath/gnu/java/net/content/text/plain.java
../../classpath/gnu/java/net/protocol/file/Connection.java
../../classpath/gnu/java/net/protocol/file/Handler.java
../../classpath/gnu/java/net/protocol/http/Connection.java
../../classpath/gnu/java/net/protocol/http/Handler.java
../../classpath/gnu/java/net/protocol/jar/Connection.java
../../classpath/gnu/java/net/protocol/jar/Handler.java
../../classpath/gnu/java/nio/ChannelInputStream.java
../../classpath/gnu/java/nio/ChannelOutputStream.java
../../classpath/gnu/java/nio/DatagramChannelImpl.java
../../classpath/gnu/java/nio/DatagramChannelSelectionKey.java
../../classpath/gnu/java/nio/FileLockImpl.java
../../classpath/gnu/java/nio/InputStreamChannel.java
../../classpath/gnu/java/nio/NIOConstants.java
../../classpath/gnu/java/nio/NIODatagramSocket.java
../../classpath/gnu/java/nio/NIOServerSocket.java
../../classpath/gnu/java/nio/NIOSocket.java
../../classpath/gnu/java/nio/OutputStreamChannel.java
../../classpath/gnu/java/nio/PipeImpl.java
../../classpath/gnu/java/nio/SelectionKeyImpl.java
../../classpath/gnu/java/nio/SelectorImpl.java
../../classpath/gnu/java/nio/SelectorProviderImpl.java
../../classpath/gnu/java/nio/ServerSocketChannelImpl.java
../../classpath/gnu/java/nio/ServerSocketChannelSelectionKey.java
../../classpath/gnu/java/nio/SocketChannelImpl.java
../../classpath/gnu/java/nio/SocketChannelSelectionKey.java
../../classpath/gnu/java/nio/charset/ISO_8859_1.java
@ -263,6 +279,7 @@ sun/misc/Ref.java
../../classpath/gnu/java/rmi/server/RMIHashes.java
../../classpath/gnu/java/rmi/server/RMIObjectInputStream.java
../../classpath/gnu/java/rmi/server/RMIObjectOutputStream.java
../../classpath/gnu/java/rmi/server/RMIVoidValue.java
../../classpath/gnu/java/rmi/server/UnicastConnection.java
../../classpath/gnu/java/rmi/server/UnicastConnectionManager.java
../../classpath/gnu/java/rmi/server/UnicastRef.java
@ -315,6 +332,30 @@ sun/misc/Ref.java
../../classpath/gnu/javax/rmi/CORBA/StubDelegateImpl.java
../../classpath/gnu/javax/rmi/CORBA/UtilDelegateImpl.java
../../classpath/gnu/javax/rmi/CORBA/ValueHandlerImpl.java
../../classpath/gnu/regexp/CharIndexed.java
../../classpath/gnu/regexp/CharIndexedCharArray.java
../../classpath/gnu/regexp/CharIndexedInputStream.java
../../classpath/gnu/regexp/CharIndexedString.java
../../classpath/gnu/regexp/CharIndexedStringBuffer.java
../../classpath/gnu/regexp/RE.java
../../classpath/gnu/regexp/REException.java
../../classpath/gnu/regexp/REFilterInputStream.java
../../classpath/gnu/regexp/REMatch.java
../../classpath/gnu/regexp/REMatchEnumeration.java
../../classpath/gnu/regexp/RESyntax.java
../../classpath/gnu/regexp/REToken.java
../../classpath/gnu/regexp/RETokenAny.java
../../classpath/gnu/regexp/RETokenBackRef.java
../../classpath/gnu/regexp/RETokenChar.java
../../classpath/gnu/regexp/RETokenEnd.java
../../classpath/gnu/regexp/RETokenEndSub.java
../../classpath/gnu/regexp/RETokenOneOf.java
../../classpath/gnu/regexp/RETokenPOSIX.java
../../classpath/gnu/regexp/RETokenRange.java
../../classpath/gnu/regexp/RETokenRepeated.java
../../classpath/gnu/regexp/RETokenStart.java
../../classpath/gnu/regexp/RETokenWordBoundary.java
../../classpath/gnu/regexp/UncheckedRE.java
../../classpath/java/applet/Applet.java
../../classpath/java/applet/AppletContext.java
../../classpath/java/applet/AppletStub.java
@ -1220,6 +1261,7 @@ sun/misc/Ref.java
../../classpath/java/text/DecimalFormatSymbols.java
../../classpath/java/text/FieldPosition.java
../../classpath/java/text/Format.java
../../classpath/java/text/FormatCharacterIterator.java
../../classpath/java/text/MessageFormat.java
../../classpath/java/text/NumberFormat.java
../../classpath/java/text/ParseException.java
@ -1240,6 +1282,7 @@ sun/misc/Ref.java
../../classpath/java/util/Collections.java
../../classpath/java/util/Comparator.java
../../classpath/java/util/ConcurrentModificationException.java
../../classpath/java/util/Currency.java
../../classpath/java/util/Date.java
../../classpath/java/util/Dictionary.java
../../classpath/java/util/EmptyStackException.java
@ -1461,7 +1504,60 @@ sun/misc/Ref.java
../../classpath/javax/naming/spi/StateFactory.java
../../classpath/javax/print/attribute/Attribute.java
../../classpath/javax/print/attribute/AttributeSet.java
../../classpath/javax/print/attribute/AttributeSetUtilities.java
../../classpath/javax/print/attribute/DateTimeSyntax.java
../../classpath/javax/print/attribute/DocAttribute.java
../../classpath/javax/print/attribute/DocAttributeSet.java
../../classpath/javax/print/attribute/EnumSyntax.java
../../classpath/javax/print/attribute/HashAttributeSet.java
../../classpath/javax/print/attribute/HashDocAttributeSet.java
../../classpath/javax/print/attribute/HashPrintJobAttributeSet.java
../../classpath/javax/print/attribute/HashPrintRequestAttributeSet.java
../../classpath/javax/print/attribute/HashPrintServiceAttributeSet.java
../../classpath/javax/print/attribute/IntegerSyntax.java
../../classpath/javax/print/attribute/PrintJobAttribute.java
../../classpath/javax/print/attribute/PrintJobAttributeSet.java
../../classpath/javax/print/attribute/PrintRequestAttribute.java
../../classpath/javax/print/attribute/PrintRequestAttributeSet.java
../../classpath/javax/print/attribute/PrintServiceAttribute.java
../../classpath/javax/print/attribute/PrintServiceAttributeSet.java
../../classpath/javax/print/attribute/ResolutionSyntax.java
../../classpath/javax/print/attribute/SetOfIntegerSyntax.java
../../classpath/javax/print/attribute/Size2DSyntax.java
../../classpath/javax/print/attribute/SupportedValuesAttribute.java
../../classpath/javax/print/attribute/TextSyntax.java
../../classpath/javax/print/attribute/UnmodifiableSetException.java
../../classpath/javax/print/attribute/URISyntax.java
../../classpath/javax/print/attribute/standard/Copies.java
../../classpath/javax/print/attribute/standard/DateTimeAtCompleted.java
../../classpath/javax/print/attribute/standard/DateTimeAtCreation.java
../../classpath/javax/print/attribute/standard/DateTimeAtProcessing.java
../../classpath/javax/print/attribute/standard/DocumentName.java
../../classpath/javax/print/attribute/standard/JobHoldUntil.java
../../classpath/javax/print/attribute/standard/JobImpressions.java
../../classpath/javax/print/attribute/standard/JobImpressionsCompleted.java
../../classpath/javax/print/attribute/standard/JobKOctets.java
../../classpath/javax/print/attribute/standard/JobKOctetsProcessed.java
../../classpath/javax/print/attribute/standard/JobMediaSheets.java
../../classpath/javax/print/attribute/standard/JobMediaSheetsCompleted.java
../../classpath/javax/print/attribute/standard/JobMessageFromOperator.java
../../classpath/javax/print/attribute/standard/JobName.java
../../classpath/javax/print/attribute/standard/JobOriginatingUserName.java
../../classpath/javax/print/attribute/standard/JobPriority.java
../../classpath/javax/print/attribute/standard/JobPrioritySupported.java
../../classpath/javax/print/attribute/standard/NumberOfDocuments.java
../../classpath/javax/print/attribute/standard/NumberOfInterveningJobs.java
../../classpath/javax/print/attribute/standard/NumberUp.java
../../classpath/javax/print/attribute/standard/OutputDeviceAssigned.java
../../classpath/javax/print/attribute/standard/PagesPerMinute.java
../../classpath/javax/print/attribute/standard/PagesPerMinuteColor.java
../../classpath/javax/print/attribute/standard/PrinterInfo.java
../../classpath/javax/print/attribute/standard/PrinterLocation.java
../../classpath/javax/print/attribute/standard/PrinterMakeAndModel.java
../../classpath/javax/print/attribute/standard/PrinterMessageFromOperator.java
../../classpath/javax/print/attribute/standard/PrinterName.java
../../classpath/javax/print/attribute/standard/QueuedJobCount.java
../../classpath/javax/print/attribute/standard/RequestingUserName.java
../../classpath/javax/rmi/BAD_OPERATION.java
../../classpath/javax/rmi/ORB.java
../../classpath/javax/rmi/PortableRemoteObject.java
@ -1704,6 +1800,7 @@ sun/misc/Ref.java
../../classpath/javax/swing/plaf/UIResource.java
../../classpath/javax/swing/plaf/ViewportUI.java
../../classpath/javax/swing/plaf/basic/BasicBorders.java
../../classpath/javax/swing/plaf/basic/BasicButtonListener.java
../../classpath/javax/swing/plaf/basic/BasicButtonUI.java
../../classpath/javax/swing/plaf/basic/BasicCheckBoxUI.java
../../classpath/javax/swing/plaf/basic/BasicGraphicsUtils.java
@ -1714,6 +1811,7 @@ sun/misc/Ref.java
../../classpath/javax/swing/plaf/basic/BasicOptionPaneUI.java
../../classpath/javax/swing/plaf/basic/BasicPanelUI.java
../../classpath/javax/swing/plaf/basic/BasicRadioButtonUI.java
../../classpath/javax/swing/plaf/basic/BasicRootPaneUI.java
../../classpath/javax/swing/plaf/basic/BasicScrollPaneUI.java
../../classpath/javax/swing/plaf/basic/BasicSplitPaneDivider.java
../../classpath/javax/swing/plaf/basic/BasicSplitPaneUI.java

Просмотреть файл

@ -28,7 +28,7 @@
</target>
<target name="classpath.dll" depends="classes">
<exec program="${nant.project.basedir}/../bin/ikvmc.exe" useruntimeengine="true" commandline="-nojni -out:classpath.dll -remap:map.xml -exclude:exclude.lst -target:library -recurse:./*.class -recurse:${Classpath.dir}/*.class -recurse:${Classpath.dir}/*.properties mscorlib.jar System.jar System.Xml.jar -resource:lib/security/classpath.security=classpath.security" />
<exec program="${nant.project.basedir}/../bin/ikvmc.exe" useruntimeengine="true" commandline="-nojni -out:classpath.dll -remap:map.xml -exclude:exclude.lst -target:library -recurse:./*.class -recurse:${Classpath.dir}/*.class -recurse:${Classpath.dir}/*.properties -recurse:${Classpath.dir}/resource/*.properties mscorlib.jar System.jar System.Xml.jar -resource:lib/security/classpath.security=classpath.security" />
<copy file="classpath.dll" tofile="../bin/classpath.dll.new" />
<exec program="peverify" commandline="../bin/classpath.dll.new" />
<copy file="classpath.dll" todir="../bin" />

Просмотреть файл

@ -1,5 +1,5 @@
/*
Copyright (C) 2002 Jeroen Frijters
Copyright (C) 2002, 2003, 2004 Jeroen Frijters
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@ -25,86 +25,223 @@
package gnu.java.net.protocol.ikvmres;
import cli.System.IO.*;
import cli.System.Resources.*;
import cli.System.Reflection.*;
import cli.System.Collections.*;
import java.net.*;
import java.io.*;
import java.io.IOException;
class IkvmresURLConnection extends URLConnection
{
private InputStream inputStream;
private InputStream inputStream;
IkvmresURLConnection(URL url)
{
super(url);
doOutput = false;
}
IkvmresURLConnection(URL url)
{
super(url);
doOutput = false;
}
public void connect() throws IOException
public void connect() throws IOException
{
if(!connected)
{
if(!connected)
String assembly = url.getHost();
String resource = url.getFile();
if(assembly == null || resource == null || !resource.startsWith("/"))
{
throw new IOException("Malformed ikvmres url");
}
resource = resource.substring(1);
Assembly asm = Assembly.Load(assembly);
if(asm == null)
{
throw new IOException("assembly " + assembly + " not found");
}
Stream s = asm.GetManifestResourceStream("ikvm:" + resource);
if(s == null)
{
throw new IOException("resource " + resource + " not found in assembly " + assembly);
}
try
{
ResourceReader r = new ResourceReader(s);
try
{
String assembly = url.getHost();
String resource = url.getFile();
Assembly asm = Assembly.Load(assembly);
if(asm == null)
{
throw new IOException("assembly " + assembly + " not found");
}
FieldInfo fi = asm.GetLoadedModules()[0].GetField(resource);
if(fi == null)
{
throw new IOException("resource " + resource + " not found in assembly " + assembly);
}
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;
IEnumerator e = r.GetEnumerator();
if(!e.MoveNext())
{
throw new IOException("invalid resource " + resource + " found in assembly " + assembly);
}
inputStream = new ByteArrayInputStream(ikvm.lang.ByteArrayHack.cast((cli.System.Byte[])((DictionaryEntry)e.get_Current()).get_Value()));
connected = true;
}
}
public InputStream getInputStream() throws IOException
{
if(!connected)
finally
{
connect();
r.Close();
}
return inputStream;
}
finally
{
s.Close();
}
}
}
public OutputStream getOutputStream() throws IOException
public InputStream getInputStream() throws IOException
{
if(!connected)
{
throw new IOException("resource URLs are read only");
connect();
}
return inputStream;
}
public long getLastModified()
{
return -1;
}
public OutputStream getOutputStream() throws IOException
{
throw new IOException("resource URLs are read only");
}
public int getContentLength()
{
return -1;
}
public long getLastModified()
{
return -1;
}
public int getContentLength()
{
return -1;
}
}
public class Handler extends URLStreamHandler
{
protected URLConnection openConnection(URL url) throws IOException
{
return new IkvmresURLConnection(url);
}
private static final String RFC2396_DIGIT = "0123456789";
private static final String RFC2396_LOWALPHA = "abcdefghijklmnopqrstuvwxyz";
private static final String RFC2396_UPALPHA = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
private static final String RFC2396_ALPHA = RFC2396_LOWALPHA + RFC2396_UPALPHA;
private static final String RFC2396_ALPHANUM = RFC2396_DIGIT + RFC2396_ALPHA;
private static final String RFC2396_MARK = "-_.!~*'()";
private static final String RFC2396_UNRESERVED = RFC2396_ALPHANUM + RFC2396_MARK;
private static final String RFC2396_REG_NAME = RFC2396_UNRESERVED + "$,;:@&=+";
private static final String RFC2396_PCHAR = RFC2396_UNRESERVED + ":@&=+$,";
private static final String RFC2396_SEGMENT = RFC2396_PCHAR + ";";
private static final String RFC2396_PATH_SEGMENTS = RFC2396_SEGMENT + "/";
protected void parseURL(URL url, String url_string, int start, int end)
{
int colon = url_string.indexOf(':', start);
String assembly = url_string.substring(start, colon);
String file = url_string.substring(colon + 1);
setURL(url, "ikvmres", assembly, 0, file, null);
}
protected URLConnection openConnection(URL url) throws IOException
{
return new IkvmresURLConnection(url);
}
protected String toExternalForm(URL url)
protected void parseURL(URL url, String url_string, int start, int end)
{
try
{
return "ikvmres:" + url.getHost() + ":" + url.getFile();
// NOTE originally I wanted to use java.net.URI to handling parsing and constructing of these things,
// but it turns out that URI uses regex and that depends on resource loading...
url_string = url_string.substring(start, end);
if(!url_string.startsWith("//"))
{
throw new gnu.java.net.URLParseError("ikvmres: URLs must start with //");
}
int slash = url_string.indexOf('/', 2);
if(slash == -1)
{
throw new gnu.java.net.URLParseError("ikvmres: URLs must contain path");
}
String assembly = unquote(url_string.substring(2, slash));
String file = unquote(url_string.substring(slash));
setURL(url, "ikvmres", assembly, 0, file, null);
}
catch(URISyntaxException x)
{
throw new gnu.java.net.URLParseError(x.getMessage());
}
}
protected String toExternalForm(URL url)
{
// NOTE originally I wanted to use java.net.URI to handling parsing and constructing of these things,
// but it turns out that URI uses regex and that depends on resource loading...
return "ikvmres://" + quote(url.getHost(), RFC2396_REG_NAME) + quote(url.getFile(), RFC2396_PATH_SEGMENTS);
}
private static String quote (String str, String legalCharacters)
{
StringBuffer sb = new StringBuffer(str.length());
for (int i = 0; i < str.length(); i++)
{
char c = str.charAt(i);
if (legalCharacters.indexOf(c) == -1)
{
String hex = "0123456789ABCDEF";
if (c <= 127)
{
sb.append('%')
.append(hex.charAt(c / 16))
.append(hex.charAt(c % 16));
}
else
{
try
{
// this is far from optimal, but it works
byte[] utf8 = str.substring(i, i + 1).getBytes("utf-8");
for (int j = 0; j < utf8.length; j++)
{
sb.append('%')
.append(hex.charAt((utf8[j] & 0xff) / 16))
.append(hex.charAt((utf8[j] & 0xff) % 16));
}
}
catch (java.io.UnsupportedEncodingException x)
{
throw (Error)new InternalError().initCause(x);
}
}
}
else
{
sb.append(c);
}
}
return sb.toString();
}
private static String unquote (String str)
throws URISyntaxException
{
if (str == null)
return null;
byte[] buf = new byte[str.length()];
int pos = 0;
for (int i = 0; i < str.length(); i++)
{
char c = str.charAt(i);
if (c > 127)
throw new URISyntaxException(str, "Invalid character");
if (c == '%')
{
if (i + 2 >= str.length())
throw new URISyntaxException(str, "Invalid quoted character");
String hex = "0123456789ABCDEF";
int hi = hex.indexOf(str.charAt(++i));
int lo = hex.indexOf(str.charAt(++i));
if (lo < 0 || hi < 0)
throw new URISyntaxException(str, "Invalid quoted character");
buf[pos++] = (byte)(hi * 16 + lo);
}
else
{
buf[pos++] = (byte)c;
}
}
try
{
return new String(buf, 0, pos, "utf-8");
}
catch (java.io.UnsupportedEncodingException x2)
{
throw (Error)new InternalError().initCause(x2);
}
}
}

Просмотреть файл

@ -526,10 +526,11 @@ final class StringHelper
static int hashCode(String s)
{
int h = 0;
int len = s.length();
for(int i = 0; i < len; i++)
// NOTE having the get_Length in the for condition is actually faster than hoisting it,
// the CLR JIT recognizes this pattern and optimizes the array bounds check in get_Chars.
for(int i = 0; i < cli.System.String.get_Length(s); i++)
{
h = h *31 + cli.System.String.get_Chars(s, i);
h = h * 31 + cli.System.String.get_Chars(s, i);
}
return h;
}

Просмотреть файл

@ -129,22 +129,22 @@ final class VMClassLoader
* @param name the resource to find
* @return the URL to the resource
*/
static URL getResource(String name)
static URL getResource(String name)
{
try
{
try
{
Assembly assembly = findResourceAssembly(name);
if(assembly != null)
{
return new URL("ikvmres:" + assembly.get_FullName() + ":" + name);
}
}
catch(java.net.MalformedURLException x)
{
}
return null;
Assembly assembly = findResourceAssembly(name);
if(assembly != null)
{
return new URL("ikvmres", assembly.get_FullName(), 0, "/" + name);
}
}
private static native Assembly findResourceAssembly(String name);
catch(java.net.MalformedURLException x)
{
}
return null;
}
private static native Assembly findResourceAssembly(String name);
/**
* Helper to get a list of resources from the bootstrap class loader.

Просмотреть файл

@ -449,7 +449,8 @@ final class VMRuntime
p.setProperty("user.home", home);
p.setProperty("user.dir", cli.System.Environment.get_CurrentDirectory());
p.setProperty("awt.toolkit", "ikvm.awt.NetToolkit, awt, Version=1.0, Culture=neutral, PublicKeyToken=null");
p.setProperty("gnu.classpath.home.url", "ikvmres:" + cli.System.Reflection.Assembly.GetExecutingAssembly().get_FullName() + ":lib");
// HACK since we cannot use URL here, we manually encode the assembly name
p.setProperty("gnu.classpath.home.url", "ikvmres://" + cli.System.String.Replace(cli.System.Reflection.Assembly.GetExecutingAssembly().get_FullName(), " ", "%20") + "/lib");
}
// HACK we need a way to get the assembly version of ik.vm.net.dll

Просмотреть файл

@ -4,6 +4,10 @@ package java.lang;
// executing code in this class.
final class VMThread
{
private static cli.System.LocalDataStoreSlot localDataStoreSlot = cli.System.Threading.Thread.AllocateDataSlot();
private static cli.System.LocalDataStoreSlot cleanupDataStoreSlot = cli.System.Threading.Thread.AllocateNamedDataSlot("ikvm-thread-hack");
private cli.System.WeakReference nativeThreadReference;
// Note: when this thread dies, this reference is *not* cleared
volatile Thread thread;
private volatile boolean running;
@ -49,11 +53,6 @@ final class VMThread
// VMThread be unstoppable.
running = false;
thread.die();
synchronized(this)
{
// release the threads waiting to join us
notifyAll();
}
}
}
@ -98,11 +97,28 @@ final class VMThread
return 0;
}
private static cli.System.TimeSpan makeTimeSpan(long ms, int ns)
{
// NOTE we assume that ns is already validated to be in the range 0..999999
return new cli.System.TimeSpan(Math.min(ms, Long.MAX_VALUE / 10000) * 10000 + (ns + 99) / 100);
}
synchronized void join(long ms, int ns) throws InterruptedException
{
// We use the VMThread object to wait on, because this is a private
// object, so client code cannot call notify on us.
wait(ms, ns);
cli.System.Threading.Thread nativeThread = (cli.System.Threading.Thread)nativeThreadReference.get_Target();
if(nativeThread != null)
{
// TODO if we're joining a thread that has a CleanupHack object, we should coordinate with the CleanupHack,
// to make sure there is no race between join returning and the thread being removed from the thread group.
if(ms == 0 && ns == 0)
{
nativeThread.Join();
}
else
{
nativeThread.Join(makeTimeSpan(ms, ns));
}
}
}
void stop(Throwable t)
@ -115,10 +131,7 @@ final class VMThread
thread.stillborn = t;
}
private static cli.System.LocalDataStoreSlot localDataStoreSlot = cli.System.Threading.Thread.AllocateDataSlot();
private cli.System.Threading.Thread nativeThread;
/*native*/ void start(long stacksize)
void start(long stacksize)
{
cli.System.Threading.ThreadStart starter = new cli.System.Threading.ThreadStart(
new cli.System.Threading.ThreadStart.Method()
@ -129,19 +142,24 @@ final class VMThread
run();
}
});
nativeThread = new cli.System.Threading.Thread(starter);
cli.System.Threading.Thread nativeThread = new cli.System.Threading.Thread(starter);
nativeThreadReference = new cli.System.WeakReference(nativeThread);
nativeThread.set_Name(thread.name);
nativeThread.set_IsBackground(thread.daemon);
nativeSetPriority(thread.priority);
nativeThread.Start();
}
/*native*/ void interrupt()
void interrupt()
{
nativeThread.Interrupt();
cli.System.Threading.Thread nativeThread = (cli.System.Threading.Thread)nativeThreadReference.get_Target();
if(nativeThread != null)
{
nativeThread.Interrupt();
}
}
/*native*/ boolean isInterrupted()
boolean isInterrupted()
{
// NOTE special case for current thread, because then we can use the .NET interrupted status
if(thread == currentThread())
@ -155,7 +173,11 @@ final class VMThread
catch(InterruptedException x)
{
// because we "consumed" the interrupt, we need to interrupt ourself again
nativeThread.Interrupt();
cli.System.Threading.Thread nativeThread = (cli.System.Threading.Thread)nativeThreadReference.get_Target();
if(nativeThread != null)
{
nativeThread.Interrupt();
}
return true;
}
}
@ -165,41 +187,53 @@ final class VMThread
return false;
}
/*native*/ void suspend()
void suspend()
{
nativeThread.Suspend();
}
/*native*/ void resume()
{
nativeThread.Resume();
}
/*native*/ void nativeSetPriority(int priority)
{
if(priority == Thread.MIN_PRIORITY)
cli.System.Threading.Thread nativeThread = (cli.System.Threading.Thread)nativeThreadReference.get_Target();
if(nativeThread != null)
{
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(cli.System.Threading.ThreadPriority.wrap(cli.System.Threading.ThreadPriority.BelowNormal));
}
else if(priority == Thread.NORM_PRIORITY)
{
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(cli.System.Threading.ThreadPriority.wrap(cli.System.Threading.ThreadPriority.AboveNormal));
}
else if(priority == Thread.MAX_PRIORITY)
{
nativeThread.set_Priority(cli.System.Threading.ThreadPriority.wrap(cli.System.Threading.ThreadPriority.Highest));
nativeThread.Suspend();
}
}
/*native*/ void nativeStop(Throwable t)
void resume()
{
cli.System.Threading.Thread nativeThread = (cli.System.Threading.Thread)nativeThreadReference.get_Target();
if(nativeThread != null)
{
nativeThread.Resume();
}
}
void nativeSetPriority(int priority)
{
cli.System.Threading.Thread nativeThread = (cli.System.Threading.Thread)nativeThreadReference.get_Target();
if(nativeThread != null)
{
if(priority == Thread.MIN_PRIORITY)
{
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(cli.System.Threading.ThreadPriority.wrap(cli.System.Threading.ThreadPriority.BelowNormal));
}
else if(priority == Thread.NORM_PRIORITY)
{
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(cli.System.Threading.ThreadPriority.wrap(cli.System.Threading.ThreadPriority.AboveNormal));
}
else if(priority == Thread.MAX_PRIORITY)
{
nativeThread.set_Priority(cli.System.Threading.ThreadPriority.wrap(cli.System.Threading.ThreadPriority.Highest));
}
}
}
void nativeStop(Throwable t)
{
// NOTE we allow ThreadDeath (and its subclasses) to be thrown on every thread, but any
// other exception is ignored, except if we're throwing it on the current Thread. This
@ -217,21 +251,39 @@ final class VMThread
}
else if(t instanceof ThreadDeath)
{
nativeThread.Abort(t);
cli.System.Threading.Thread nativeThread = (cli.System.Threading.Thread)nativeThreadReference.get_Target();
if(nativeThread != null)
{
nativeThread.Abort(t);
}
}
}
/*native*/ static Thread currentThread()
private static class CleanupHack
{
private Thread thread;
CleanupHack(Thread thread)
{
this.thread = thread;
}
protected void finalize()
{
thread.die();
}
}
static Thread currentThread()
{
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.
// TODO if the thread dies, it needs to be removed from the root ThreadGroup
cli.System.Threading.Thread nativeThread = cli.System.Threading.Thread.get_CurrentThread();
VMThread vmThread = new VMThread(null);
vmThread.nativeThread = nativeThread;
vmThread.nativeThreadReference = new cli.System.WeakReference(nativeThread);
vmThread.running = true;
int priority = Thread.NORM_PRIORITY;
switch(nativeThread.get_Priority().Value)
@ -255,6 +307,7 @@ final class VMThread
javaThread = new Thread(vmThread, nativeThread.get_Name(), priority, nativeThread.get_IsBackground());
vmThread.thread = javaThread;
cli.System.Threading.Thread.SetData(localDataStoreSlot, javaThread);
cli.System.Threading.Thread.SetData(cleanupDataStoreSlot, new CleanupHack(javaThread));
javaThread.group = ThreadGroup.root;
javaThread.group.addThread(javaThread);
InheritableThreadLocal.newChildThread(javaThread);
@ -262,26 +315,17 @@ final class VMThread
return javaThread;
}
static /*native*/ void yield()
static void yield()
{
cli.System.Threading.Thread.Sleep(0);
}
static /*native*/ void sleep(long ms, int ns) throws InterruptedException
static void sleep(long ms, int ns) throws InterruptedException
{
try
{
if(false) throw new cli.System.Threading.ThreadInterruptedException();
// TODO guard against ms and ns overflowing
cli.System.Threading.Thread.Sleep(new cli.System.TimeSpan(ms * 10000 + (ns + 99) / 100));
}
catch(cli.System.Threading.ThreadInterruptedException x)
{
throw new InterruptedException(x.getMessage());
}
cli.System.Threading.Thread.Sleep(makeTimeSpan(ms, ns));
}
static /*native*/ boolean interrupted()
static boolean interrupted()
{
try
{
@ -298,7 +342,7 @@ final class VMThread
}
}
static /*native*/ boolean holdsLock(Object obj)
static boolean holdsLock(Object obj)
{
if(obj == null)
{

Просмотреть файл

@ -82,6 +82,12 @@ public class PlainSocketImpl extends SocketImpl
try
{
if(false) throw new cli.System.Net.Sockets.SocketException();
int timeout = ((Integer)getOption(SO_TIMEOUT)).intValue();
if(timeout != 0 && !socket.Poll(Math.min(timeout, Integer.MAX_VALUE / 1000) * 1000,
cli.System.Net.Sockets.SelectMode.wrap(cli.System.Net.Sockets.SelectMode.SelectRead)))
{
throw new java.io.InterruptedIOException("Accept timed out");
}
cli.System.Net.Sockets.Socket accept = socket.Accept();
((PlainSocketImpl)impl).socket = accept;
IPEndPoint remoteEndPoint = ((IPEndPoint)accept.get_RemoteEndPoint());

Просмотреть файл

@ -204,8 +204,10 @@
<ret />
</body>
</method>
<!-- we have a toString here to make sure that toString shows up as a declared method in reflection -->
<!-- we have a toString here to make sure that it shows up as a declared method in reflection -->
<method name="toString" sig="()Ljava.lang.String;" modifiers="public" />
<!-- we have an equals here to make sure that it shows up as a declared method in reflection -->
<method name="equals" sig="(Ljava.lang.Object;)Z" modifiers="public" />
<method name="valueOf" sig="(Z)Ljava.lang.String;" modifiers="public static">
<redirect class="java.lang.StringHelper" />
</method>
@ -308,6 +310,9 @@
<method name="compareTo" sig="(Ljava.lang.String;)I" modifiers="public">
<redirect class="java.lang.StringHelper" type="static" sig="(Ljava.lang.String;Ljava.lang.String;)I" />
</method>
<method name="compareTo" sig="(Ljava.lang.Object;)I" modifiers="public">
<redirect name="CompareTo" />
</method>
<method name="replace" sig="(CC)Ljava.lang.String;" modifiers="public">
<redirect name="Replace" />
</method>
@ -336,6 +341,64 @@
<method name="concat" sig="(Ljava.lang.String;)Ljava.lang.String;" modifiers="public">
<redirect class="java.lang.StringHelper" type="static" sig="(Ljava.lang.String;Ljava.lang.String;)Ljava.lang.String;" />
</method>
<method name="contentEquals" sig="(Ljava.lang.StringBuffer;)Z" modifiers="public">
<body>
<ldarg_0 />
<ldarg_1 />
<callvirt class="java.lang.StringBuffer" name="toString" sig="()Ljava.lang.String;" />
<callvirt type="System.String, mscorlib" name="Equals" sig="(Ljava.lang.String;)Z" />
<ret />
</body>
</method>
<method name="matches" sig="(Ljava.lang.String;)Z" modifiers="public">
<body>
<ldarg_1 />
<ldarg_0 />
<call class="java.util.regex.Pattern" name="matches" sig="(Ljava.lang.String;Ljava.lang.CharSequence;)Z" />
<ret />
</body>
</method>
<method name="replaceAll" sig="(Ljava.lang.String;Ljava.lang.String;)Ljava.lang.String;" modifiers="public">
<body>
<ldarg_1 />
<call class="java.util.regex.Pattern" name="compile" sig="(Ljava.lang.String;)Ljava.util.regex.Pattern;" />
<ldarg_0 />
<callvirt class="java.util.regex.Pattern" name="matcher" sig="(Ljava.lang.CharSequence;)Ljava.util.regex.Matcher;" />
<ldarg_2 />
<callvirt class="java.util.regex.Matcher" name="replaceAll" sig="(Ljava.lang.String;)Ljava.lang.String;" />
<ret />
</body>
</method>
<method name="replaceFirst" sig="(Ljava.lang.String;Ljava.lang.String;)Ljava.lang.String;" modifiers="public">
<body>
<ldarg_1 />
<call class="java.util.regex.Pattern" name="compile" sig="(Ljava.lang.String;)Ljava.util.regex.Pattern;" />
<ldarg_0 />
<callvirt class="java.util.regex.Pattern" name="matcher" sig="(Ljava.lang.CharSequence;)Ljava.util.regex.Matcher;" />
<ldarg_2 />
<callvirt class="java.util.regex.Matcher" name="replaceFirst" sig="(Ljava.lang.String;)Ljava.lang.String;" />
<ret />
</body>
</method>
<method name="split" sig="(Ljava.lang.String;)[Ljava.lang.String;" modifiers="public">
<body>
<ldarg_0 />
<ldarg_1 />
<ldc_i4_0 />
<callvirt class="java.lang.String" name="split" sig="(Ljava.lang.String;I)[Ljava.lang.String;" />
<ret />
</body>
</method>
<method name="split" sig="(Ljava.lang.String;I)[Ljava.lang.String;" modifiers="public">
<body>
<ldarg_1 />
<call class="java.util.regex.Pattern" name="compile" sig="(Ljava.lang.String;)Ljava.util.regex.Pattern;" />
<ldarg_0 />
<ldarg_2 />
<callvirt class="java.util.regex.Pattern" name="split" sig="(Ljava.lang.CharSequence;I)[Ljava.lang.String;" />
<ret />
</body>
</method>
<method name="copyValueOf" sig="([C)Ljava.lang.String;" modifiers="public static">
<body>
<ldarg_0 />

Просмотреть файл

@ -309,10 +309,6 @@ public class Starter
}
}
java.lang.Class clazz = java.lang.Class.forName(mainClass, true, loader);
if(saveAssembly)
{
java.lang.Runtime.getRuntime().addShutdownHook(new SaveAssemblyShutdownHook(clazz));
}
Method method = FindMainMethod(clazz);
if(method == null)
{
@ -324,6 +320,10 @@ public class Starter
}
else
{
if(saveAssembly)
{
java.lang.Runtime.getRuntime().addShutdownHook(new SaveAssemblyShutdownHook(clazz));
}
try
{
method.invoke(null, new object[] { vmargs });
@ -338,11 +338,16 @@ public class Starter
catch(System.Exception x)
{
java.lang.Thread thread = java.lang.Thread.currentThread();
thread.getThreadGroup().uncaughtException(thread, ExceptionHelper.MapExceptionFast(x));
thread.getThreadGroup().uncaughtException(thread, java.lang.ExceptionHelper.MapExceptionFast(x));
}
finally
{
// TODO the current thread should be removed from its ThreadGroup and signaled
// FXBUG when the main thread ends, it doesn't actually die, it stays around to manage the lifetime
// of the CLR, but in doing so it also keeps alive the thread local storage for this thread and we
// use the TLS as a hack to track when the thread dies (if the object stored in the TLS is finalized,
// we know the thread is dead). So to make that work for the main thread, we explicitly clear the TLS
// slot that contains our hack object.
System.Threading.Thread.SetData(System.Threading.Thread.GetNamedDataSlot("ikvm-thread-hack"), null);
}
return 1;
}

Просмотреть файл

@ -60,6 +60,7 @@ class Compiler
static int Main(string[] args)
{
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
System.Threading.Thread.CurrentThread.Name = "compiler";
Tracer.EnableTraceForDebug();
System.Reflection.Emit.PEFileKinds target = System.Reflection.Emit.PEFileKinds.ConsoleApplication;
@ -170,12 +171,17 @@ class Compiler
string spec = s.Substring(9);
if(Directory.Exists(spec))
{
DirectoryInfo dir = new DirectoryInfo(spec);
// NOTE we're appending a DirectorySeparatorChar to make sure that dir.FullName always
// ends with a separator (multiple separators are automatically collapsed into one).
// This is important because later on we will be using baseDir.FullName to make
// an absolute path relative again.
DirectoryInfo dir = new DirectoryInfo(spec + Path.DirectorySeparatorChar);
Recurse(dir, dir, "*");
}
else
{
DirectoryInfo dir = new DirectoryInfo(Path.GetDirectoryName(spec));
// see comment above about Path.DirectorySeparatorChar
DirectoryInfo dir = new DirectoryInfo(Path.GetDirectoryName(spec) + Path.DirectorySeparatorChar);
Recurse(dir, dir, Path.GetFileName(spec));
}
}
@ -388,7 +394,7 @@ class Compiler
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);
string name = file.Substring(baseDir.FullName.Length);
name = name.Replace('\\', '/');
resources.Add(name, b);
itemsProcessed++;
@ -439,4 +445,18 @@ class Compiler
Console.Error.WriteLine("Warning: could not find exclusion file '{0}'", filename);
}
}
private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
// make sure all the referenced assemblies are visible (they are loaded with LoadFrom, so
// they end up in the LoadFrom context [unless they happen to be available in one of the probe paths])
foreach(Assembly a in AppDomain.CurrentDomain.GetAssemblies())
{
if(a.FullName == args.Name)
{
return a;
}
}
return null;
}
}