зеркало из https://github.com/mono/ikvm-fork.git
*** empty log message ***
This commit is contained in:
Родитель
18aacac574
Коммит
9a08682b9c
|
@ -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)
|
||||
|
|
122
awt/toolkit.cs
122
awt/toolkit.cs
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче