зеркало из https://github.com/mono/ikvm-fork.git
*** empty log message ***
This commit is contained in:
Родитель
9a08682b9c
Коммит
f13f93800a
|
@ -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
|
||||
|
@ -23,9 +23,11 @@
|
|||
*/
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Diagnostics;
|
||||
|
||||
public class ByteCodeHelper
|
||||
{
|
||||
[DebuggerStepThroughAttribute]
|
||||
public static object multianewarray(RuntimeTypeHandle typeHandle, int[] lengths)
|
||||
{
|
||||
for(int i = 0; i < lengths.Length; i++)
|
||||
|
@ -54,6 +56,7 @@ public class ByteCodeHelper
|
|||
}
|
||||
|
||||
[StackTraceInfo(Hidden = true)]
|
||||
[DebuggerStepThroughAttribute]
|
||||
public static object DynamicMultianewarray(RuntimeTypeHandle type, string clazz, int[] lengths)
|
||||
{
|
||||
TypeWrapper wrapper = LoadTypeWrapper(type, clazz);
|
||||
|
@ -61,6 +64,7 @@ public class ByteCodeHelper
|
|||
}
|
||||
|
||||
[StackTraceInfo(Hidden = true)]
|
||||
[DebuggerStepThroughAttribute]
|
||||
public static object DynamicNewarray(int length, RuntimeTypeHandle type, string clazz)
|
||||
{
|
||||
if(length < 0)
|
||||
|
@ -72,6 +76,7 @@ public class ByteCodeHelper
|
|||
}
|
||||
|
||||
[StackTraceInfo(Hidden = true)]
|
||||
[DebuggerStepThroughAttribute]
|
||||
public static void DynamicAastore(object arrayref, int index, object val, RuntimeTypeHandle type, string clazz)
|
||||
{
|
||||
// TODO do we need to load the type here?
|
||||
|
@ -79,6 +84,7 @@ public class ByteCodeHelper
|
|||
}
|
||||
|
||||
[StackTraceInfo(Hidden = true)]
|
||||
[DebuggerStepThroughAttribute]
|
||||
public static object DynamicAaload(object arrayref, int index, RuntimeTypeHandle type, string clazz)
|
||||
{
|
||||
// TODO do we need to load the type here?
|
||||
|
@ -111,24 +117,28 @@ public class ByteCodeHelper
|
|||
}
|
||||
|
||||
[StackTraceInfo(Hidden = true)]
|
||||
[DebuggerStepThroughAttribute]
|
||||
public static object DynamicGetfield(object obj, string name, string sig, RuntimeTypeHandle type, string clazz)
|
||||
{
|
||||
return GetFieldWrapper(ClassLoaderWrapper.GetWrapperFromType(obj.GetType()), type, clazz, name, sig, false).GetValue(obj);
|
||||
}
|
||||
|
||||
[StackTraceInfo(Hidden = true)]
|
||||
[DebuggerStepThroughAttribute]
|
||||
public static object DynamicGetstatic(string name, string sig, RuntimeTypeHandle type, string clazz)
|
||||
{
|
||||
return GetFieldWrapper(null, type, clazz, name, sig, true).GetValue(null);
|
||||
}
|
||||
|
||||
[StackTraceInfo(Hidden = true)]
|
||||
[DebuggerStepThroughAttribute]
|
||||
public static void DynamicPutfield(object obj, object val, string name, string sig, RuntimeTypeHandle type, string clazz)
|
||||
{
|
||||
GetFieldWrapper(ClassLoaderWrapper.GetWrapperFromType(obj.GetType()), type, clazz, name, sig, false).SetValue(obj, val);
|
||||
}
|
||||
|
||||
[StackTraceInfo(Hidden = true)]
|
||||
[DebuggerStepThroughAttribute]
|
||||
public static void DynamicPutstatic(object val, string name, string sig, RuntimeTypeHandle type, string clazz)
|
||||
{
|
||||
GetFieldWrapper(null, type, clazz, name, sig, true).SetValue(null, val);
|
||||
|
@ -136,6 +146,7 @@ public class ByteCodeHelper
|
|||
|
||||
// the sole purpose of this method is to check whether the clazz can be instantiated (but not to actually do it)
|
||||
[StackTraceInfo(Hidden = true)]
|
||||
[DebuggerStepThroughAttribute]
|
||||
public static void DynamicNewCheckOnly(RuntimeTypeHandle type, string clazz)
|
||||
{
|
||||
TypeWrapper wrapper = LoadTypeWrapper(type, clazz);
|
||||
|
@ -164,12 +175,14 @@ public class ByteCodeHelper
|
|||
}
|
||||
|
||||
[StackTraceInfo(Hidden = true)]
|
||||
[DebuggerStepThroughAttribute]
|
||||
public static object DynamicClassLiteral(RuntimeTypeHandle type, string clazz)
|
||||
{
|
||||
return NativeCode.java.lang.VMClass.getClassFromWrapper(LoadTypeWrapper(type, clazz));
|
||||
}
|
||||
|
||||
[StackTraceInfo(Hidden = true)]
|
||||
[DebuggerStepThroughAttribute]
|
||||
public static object DynamicCast(object obj, RuntimeTypeHandle type, string clazz)
|
||||
{
|
||||
if(!DynamicInstanceOf(obj, type, clazz))
|
||||
|
@ -180,6 +193,7 @@ public class ByteCodeHelper
|
|||
}
|
||||
|
||||
[StackTraceInfo(Hidden = true)]
|
||||
[DebuggerStepThroughAttribute]
|
||||
public static bool DynamicInstanceOf(object obj, RuntimeTypeHandle type, string clazz)
|
||||
{
|
||||
TypeWrapper wrapper = LoadTypeWrapper(type, clazz);
|
||||
|
@ -188,6 +202,7 @@ public class ByteCodeHelper
|
|||
}
|
||||
|
||||
[StackTraceInfo(Hidden = true)]
|
||||
[DebuggerStepThroughAttribute]
|
||||
public static object DynamicInvokeSpecialNew(RuntimeTypeHandle type, string clazz, string name, string sig, object[] args)
|
||||
{
|
||||
TypeWrapper wrapper = LoadTypeWrapper(type, clazz);
|
||||
|
@ -203,6 +218,7 @@ public class ByteCodeHelper
|
|||
}
|
||||
|
||||
[StackTraceInfo(Hidden = true)]
|
||||
[DebuggerStepThroughAttribute]
|
||||
public static object DynamicInvokestatic(RuntimeTypeHandle type, string clazz, string name, string sig, object[] args)
|
||||
{
|
||||
TypeWrapper wrapper = LoadTypeWrapper(type, clazz);
|
||||
|
@ -218,6 +234,7 @@ public class ByteCodeHelper
|
|||
}
|
||||
|
||||
[StackTraceInfo(Hidden = true)]
|
||||
[DebuggerStepThroughAttribute]
|
||||
public static object DynamicInvokevirtual(object obj, RuntimeTypeHandle type, string clazz, string name, string sig, object[] args)
|
||||
{
|
||||
TypeWrapper wrapper = LoadTypeWrapper(type, clazz);
|
||||
|
@ -233,6 +250,7 @@ public class ByteCodeHelper
|
|||
}
|
||||
|
||||
[StackTraceInfo(Hidden = true)]
|
||||
[DebuggerStepThroughAttribute]
|
||||
public static Type DynamicGetTypeAsExceptionType(RuntimeTypeHandle type, string clazz)
|
||||
{
|
||||
TypeWrapper tw = LoadTypeWrapper(type, clazz);
|
||||
|
@ -240,6 +258,7 @@ public class ByteCodeHelper
|
|||
return tw.TypeAsExceptionType;
|
||||
}
|
||||
|
||||
[DebuggerStepThroughAttribute]
|
||||
public static int f2i(float f)
|
||||
{
|
||||
if(f <= int.MinValue)
|
||||
|
@ -257,6 +276,7 @@ public class ByteCodeHelper
|
|||
return (int)f;
|
||||
}
|
||||
|
||||
[DebuggerStepThroughAttribute]
|
||||
public static long f2l(float f)
|
||||
{
|
||||
if(f <= long.MinValue)
|
||||
|
@ -274,6 +294,7 @@ public class ByteCodeHelper
|
|||
return (long)f;
|
||||
}
|
||||
|
||||
[DebuggerStepThroughAttribute]
|
||||
public static int d2i(double d)
|
||||
{
|
||||
if(d <= int.MinValue)
|
||||
|
@ -291,6 +312,7 @@ public class ByteCodeHelper
|
|||
return (int)d;
|
||||
}
|
||||
|
||||
[DebuggerStepThroughAttribute]
|
||||
public static long d2l(double d)
|
||||
{
|
||||
if(d <= long.MinValue)
|
||||
|
|
|
@ -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
|
||||
|
@ -718,6 +718,99 @@ 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 FieldTypeWrapperFromSig(ClassLoaderWrapper classLoader, string sig)
|
||||
{
|
||||
int index = 0;
|
||||
return SigDecoderWrapper(classLoader, ref index, sig);
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -970,7 +1063,7 @@ class ClassFile
|
|||
{
|
||||
if(argTypeWrappers == null)
|
||||
{
|
||||
argTypeWrappers = classLoader.ArgTypeWrapperListFromSig(descriptor);
|
||||
argTypeWrappers = ArgTypeWrapperListFromSig(classLoader, descriptor);
|
||||
}
|
||||
return argTypeWrappers;
|
||||
}
|
||||
|
@ -979,7 +1072,7 @@ class ClassFile
|
|||
{
|
||||
if(retTypeWrapper == null)
|
||||
{
|
||||
retTypeWrapper = classLoader.RetTypeWrapperFromSig(descriptor);
|
||||
retTypeWrapper = RetTypeWrapperFromSig(classLoader, descriptor);
|
||||
}
|
||||
return retTypeWrapper;
|
||||
}
|
||||
|
@ -988,7 +1081,7 @@ class ClassFile
|
|||
{
|
||||
if(fieldTypeWrapper == null)
|
||||
{
|
||||
fieldTypeWrapper = classLoader.FieldTypeWrapperFromSig(descriptor);
|
||||
fieldTypeWrapper = FieldTypeWrapperFromSig(classLoader, descriptor);
|
||||
}
|
||||
return fieldTypeWrapper;
|
||||
}
|
||||
|
@ -1171,7 +1264,7 @@ class ClassFile
|
|||
{
|
||||
if(argTypeWrappers == null)
|
||||
{
|
||||
argTypeWrappers = classLoader.ArgTypeWrapperListFromSig(Signature);
|
||||
argTypeWrappers = ArgTypeWrapperListFromSig(classLoader, Signature);
|
||||
}
|
||||
return argTypeWrappers;
|
||||
}
|
||||
|
@ -1180,7 +1273,7 @@ class ClassFile
|
|||
{
|
||||
if(retTypeWrapper == null)
|
||||
{
|
||||
retTypeWrapper = classLoader.RetTypeWrapperFromSig(Signature);
|
||||
retTypeWrapper = RetTypeWrapperFromSig(classLoader, Signature);
|
||||
}
|
||||
return retTypeWrapper;
|
||||
}
|
||||
|
@ -1189,7 +1282,7 @@ class ClassFile
|
|||
{
|
||||
if(fieldTypeWrapper == null)
|
||||
{
|
||||
fieldTypeWrapper = classLoader.FieldTypeWrapperFromSig(Signature);
|
||||
fieldTypeWrapper = FieldTypeWrapperFromSig(classLoader, Signature);
|
||||
}
|
||||
return fieldTypeWrapper;
|
||||
}
|
||||
|
|
|
@ -639,7 +639,15 @@ class ClassLoaderWrapper
|
|||
}
|
||||
foreach(TypeWrapper t in l)
|
||||
{
|
||||
t.Finish();
|
||||
try
|
||||
{
|
||||
t.Finish();
|
||||
}
|
||||
catch(Exception x)
|
||||
{
|
||||
Console.Error.WriteLine(x);
|
||||
Console.Error.WriteLine(new StackTrace(x, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
Copyright (C) 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
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
Jeroen Frijters
|
||||
jeroen@frijters.net
|
||||
|
||||
*/
|
||||
|
||||
namespace CoreClasses.java.lang
|
||||
{
|
||||
sealed class Object
|
||||
{
|
||||
private Object() {}
|
||||
// NOTE we have a dummy static initializer, to make sure we don't get the beforeFieldInit attribute
|
||||
// (we don't want the classes to be loaded prematurely, because they might not be available then)
|
||||
static Object() {}
|
||||
internal static TypeWrapper Wrapper = ClassLoaderWrapper.LoadClassCritical("java.lang.Object");
|
||||
}
|
||||
|
||||
sealed class String
|
||||
{
|
||||
private String() {}
|
||||
// NOTE we have a dummy static initializer, to make sure we don't get the beforeFieldInit attribute
|
||||
// (we don't want the classes to be loaded prematurely, because they might not be available then)
|
||||
static String() {}
|
||||
internal static TypeWrapper Wrapper = ClassLoaderWrapper.LoadClassCritical("java.lang.String");
|
||||
}
|
||||
|
||||
sealed class Class
|
||||
{
|
||||
private Class() {}
|
||||
// NOTE we have a dummy static initializer, to make sure we don't get the beforeFieldInit attribute
|
||||
// (we don't want the classes to be loaded prematurely, because they might not be available then)
|
||||
static Class() {}
|
||||
internal static TypeWrapper Wrapper = ClassLoaderWrapper.LoadClassCritical("java.lang.Class");
|
||||
}
|
||||
|
||||
sealed class Throwable
|
||||
{
|
||||
private Throwable() {}
|
||||
// NOTE we have a dummy static initializer, to make sure we don't get the beforeFieldInit attribute
|
||||
// (we don't want the classes to be loaded prematurely, because they might not be available then)
|
||||
static Throwable() {}
|
||||
internal static TypeWrapper Wrapper = ClassLoaderWrapper.LoadClassCritical("java.lang.Throwable");
|
||||
}
|
||||
}
|
|
@ -611,7 +611,7 @@ class FieldWrapper : MemberWrapper
|
|||
{
|
||||
// NOTE only pritimives and string can be literals in Java (because the other "primitives" (like uint),
|
||||
// are treated as NonPrimitiveValueTypes)
|
||||
if(field != null && (fieldType.IsPrimitive || fieldType == CoreClasses.java_lang_String) && field.IsLiteral)
|
||||
if(field != null && (fieldType.IsPrimitive || fieldType == CoreClasses.java.lang.String.Wrapper) && field.IsLiteral)
|
||||
{
|
||||
ReflectionOnConstant.IssueWarning(field);
|
||||
object val = field.GetValue(null);
|
||||
|
|
|
@ -229,7 +229,7 @@ sealed class MethodDescriptor
|
|||
else
|
||||
{
|
||||
name = "Ljava.lang.Object;";
|
||||
typeWrapper = CoreClasses.java_lang_Object;
|
||||
typeWrapper = CoreClasses.java.lang.Object.Wrapper;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1245,7 +1245,7 @@ abstract class TypeWrapper
|
|||
return ImplementsInterface(baseType);
|
||||
}
|
||||
// NOTE this isn't just an optimization, it is also required when this is an interface
|
||||
if(baseType == CoreClasses.java_lang_Object)
|
||||
if(baseType == CoreClasses.java.lang.Object.Wrapper)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -3185,18 +3185,15 @@ class DynamicTypeWrapper : TypeWrapper
|
|||
}
|
||||
else
|
||||
{
|
||||
if(fld.IsFinal)
|
||||
bool isWrappedFinal = fld.IsFinal && (fld.IsPublic || fld.IsProtected) && !wrapper.IsInterface;
|
||||
if(isWrappedFinal)
|
||||
{
|
||||
// final doesn't make sense for private fields, so if the field is private we ignore final
|
||||
if(!fld.IsPrivate && !wrapper.IsInterface)
|
||||
{
|
||||
// NOTE blank final fields get converted into a read-only property with a private field backing store
|
||||
// we used to make the field privatescope, but that really serves no purpose (and it hinders serialization,
|
||||
// which uses .NET reflection to get at the field)
|
||||
attribs &= ~FieldAttributes.FieldAccessMask;
|
||||
attribs |= FieldAttributes.Private;
|
||||
setModifiers = true;
|
||||
}
|
||||
// NOTE blank final fields get converted into a read-only property with a private field backing store
|
||||
// we used to make the field privatescope, but that really serves no purpose (and it hinders serialization,
|
||||
// which uses .NET reflection to get at the field)
|
||||
attribs &= ~FieldAttributes.FieldAccessMask;
|
||||
attribs |= FieldAttributes.Private;
|
||||
setModifiers = true;
|
||||
}
|
||||
field = typeBuilder.DefineField(fieldName, type, attribs);
|
||||
if(fld.IsTransient)
|
||||
|
@ -3209,7 +3206,7 @@ class DynamicTypeWrapper : TypeWrapper
|
|||
// TODO the field should be marked as modreq(IsVolatile), but Reflection.Emit doesn't have a way of doing this
|
||||
setModifiers = true;
|
||||
}
|
||||
if(fld.IsFinal && !fld.IsPrivate && !wrapper.IsInterface)
|
||||
if(isWrappedFinal)
|
||||
{
|
||||
methodAttribs |= MethodAttributes.SpecialName;
|
||||
// TODO we should ensure that the getter method name doesn't clash with an existing method
|
||||
|
@ -3518,7 +3515,7 @@ class DynamicTypeWrapper : TypeWrapper
|
|||
needFinalize = true;
|
||||
needDispatch = true;
|
||||
}
|
||||
else if(baseMethod.DeclaringType == CoreClasses.java_lang_Object.TypeAsBaseType)
|
||||
else if(baseMethod.DeclaringType == CoreClasses.java.lang.Object.Wrapper.TypeAsBaseType)
|
||||
{
|
||||
needFinalize = true;
|
||||
needDispatch = true;
|
||||
|
@ -3949,7 +3946,7 @@ class CompiledTypeWrapper : LazyTypeWrapper
|
|||
else if(type.BaseType == null)
|
||||
{
|
||||
// System.Object must appear to be derived from java.lang.Object
|
||||
return CoreClasses.java_lang_Object;
|
||||
return CoreClasses.java.lang.Object.Wrapper;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -3962,7 +3959,7 @@ class CompiledTypeWrapper : LazyTypeWrapper
|
|||
}
|
||||
else
|
||||
{
|
||||
return CoreClasses.java_lang_Object;
|
||||
return CoreClasses.java.lang.Object.Wrapper;
|
||||
}
|
||||
}
|
||||
return ClassLoaderWrapper.GetWrapperFromType(type.BaseType);
|
||||
|
@ -4950,7 +4947,7 @@ class DotNetTypeWrapper : LazyTypeWrapper
|
|||
{
|
||||
Modifiers mods = AttributeHelper.GetModifiers(mb, true);
|
||||
if(md.Name == "Finalize" && md.Signature == "()V" && !mb.IsStatic &&
|
||||
TypeAsBaseType.IsSubclassOf(CoreClasses.java_lang_Object.TypeAsBaseType))
|
||||
TypeAsBaseType.IsSubclassOf(CoreClasses.java.lang.Object.Wrapper.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);
|
||||
|
@ -5109,7 +5106,7 @@ class ArrayTypeWrapper : TypeWrapper
|
|||
private Type type;
|
||||
|
||||
internal ArrayTypeWrapper(Type type, Modifiers modifiers, string name, ClassLoaderWrapper classLoader)
|
||||
: base(modifiers, name, CoreClasses.java_lang_Object, classLoader)
|
||||
: base(modifiers, name, CoreClasses.java.lang.Object.Wrapper, classLoader)
|
||||
{
|
||||
this.type = type;
|
||||
if(mdClone == null)
|
||||
|
|
|
@ -563,7 +563,7 @@ namespace NativeCode.java
|
|||
ar.Add(VMClass.getClassFromType(frame.GetMethod().DeclaringType));
|
||||
}
|
||||
}
|
||||
return ar.ToArray(CoreClasses.java_lang_Class.TypeAsArrayType);
|
||||
return ar.ToArray(CoreClasses.java.lang.Class.Wrapper.TypeAsArrayType);
|
||||
}
|
||||
|
||||
public static object currentClassLoader()
|
||||
|
@ -774,7 +774,7 @@ namespace NativeCode.java
|
|||
public static void setOut(object printStream)
|
||||
{
|
||||
TypeWrapper tw = ClassLoaderWrapper.LoadClassCritical("java.lang.System");
|
||||
FieldWrapper fw = tw.GetFieldWrapper("in", ClassLoaderWrapper.LoadClassCritical("java.io.PrintStream"));
|
||||
FieldWrapper fw = tw.GetFieldWrapper("out", ClassLoaderWrapper.LoadClassCritical("java.io.PrintStream"));
|
||||
fw.SetValue(null, printStream);
|
||||
}
|
||||
|
||||
|
|
|
@ -78,7 +78,6 @@ class Compiler
|
|||
private ILGenerator ilGenerator;
|
||||
private ClassLoaderWrapper classLoader;
|
||||
private MethodAnalyzer ma;
|
||||
private Hashtable locals = new Hashtable();
|
||||
private ClassFile.Method.ExceptionTableEntry[] exceptions;
|
||||
private ISymbolDocumentWriter symboldocument;
|
||||
|
||||
|
@ -88,9 +87,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 = CoreClasses.java_lang_Throwable;
|
||||
java_lang_Object = CoreClasses.java_lang_Object;
|
||||
java_lang_Class = CoreClasses.java_lang_Class;
|
||||
java_lang_Throwable = CoreClasses.java.lang.Throwable.Wrapper;
|
||||
java_lang_Object = CoreClasses.java.lang.Object.Wrapper;
|
||||
java_lang_Class = CoreClasses.java.lang.Class.Wrapper;
|
||||
java_lang_ThreadDeath = ClassLoaderWrapper.LoadClassCritical("java.lang.ThreadDeath");
|
||||
}
|
||||
|
||||
|
@ -105,7 +104,7 @@ class Compiler
|
|||
string sourcefile = m.Method.ClassFile.SourceFileAttribute;
|
||||
if(sourcefile != null)
|
||||
{
|
||||
this.symboldocument = classLoader.ModuleBuilder.DefineDocument(sourcefile, Guid.Empty, Guid.Empty, Guid.Empty);
|
||||
this.symboldocument = classLoader.ModuleBuilder.DefineDocument(sourcefile, SymLanguageType.Java, Guid.Empty, SymDocumentType.Text);
|
||||
}
|
||||
}
|
||||
Profiler.Enter("MethodAnalyzer");
|
||||
|
@ -691,7 +690,13 @@ class Compiler
|
|||
{
|
||||
// HACK this nop is a workaround for a bizarre bug in System.Diagnostics.StackTrace
|
||||
// that causes it to report the incorrect line number sometimes...
|
||||
ilGenerator.Emit(OpCodes.Nop);
|
||||
// BUT, make sure we don't put a nop at the start of the method, because if there
|
||||
// is no line number information on the first instruction, VS.NET refuses to step into
|
||||
// the method.
|
||||
if(instr.PC > 0)
|
||||
{
|
||||
ilGenerator.Emit(OpCodes.Nop);
|
||||
}
|
||||
ilGenerator.MarkSequencePoint(symboldocument, table[j].line_number, 0, table[j].line_number + 1, 0);
|
||||
break;
|
||||
}
|
||||
|
@ -783,10 +788,11 @@ class Compiler
|
|||
}
|
||||
BranchCookie bc = new BranchCookie(ilGenerator, 1, exceptions[j].handler_pc);
|
||||
newExits.Add(bc);
|
||||
Instruction handlerInstr = code[FindPcIndex(exceptions[j].handler_pc)];
|
||||
int handlerIndex = FindPcIndex(exceptions[j].handler_pc);
|
||||
Instruction handlerInstr = code[handlerIndex];
|
||||
bool unusedException = handlerInstr.NormalizedOpCode == NormalizedByteCode.__pop ||
|
||||
(handlerInstr.NormalizedOpCode == NormalizedByteCode.__astore &&
|
||||
!ma.IsAloadUsed(handlerInstr.NormalizedArg1));
|
||||
ma.GetLocalVar(handlerIndex) == null);
|
||||
// special case for catch(Throwable) (and finally), that produces less code and
|
||||
// should be faster
|
||||
if(mapSafe || excType == typeof(Exception))
|
||||
|
@ -1120,7 +1126,6 @@ class Compiler
|
|||
int trivcount = 0;
|
||||
bool nontrivial = false;
|
||||
bool[] stackfix = new bool[ma.GetStackHeight(i) - (argcount + 1)];
|
||||
bool[] localsfix = new bool[m.MaxLocals];
|
||||
for(int j = 0; j < stackfix.Length; j++)
|
||||
{
|
||||
if(ma.GetRawStackTypeWrapper(i, argcount + 1 + j) == type)
|
||||
|
@ -1139,11 +1144,10 @@ class Compiler
|
|||
}
|
||||
}
|
||||
}
|
||||
for(int j = 0; j < localsfix.Length; j++)
|
||||
for(int j = 0; !nontrivial && j < m.MaxLocals; j++)
|
||||
{
|
||||
if(ma.GetLocalTypeWrapper(i, j) == type)
|
||||
{
|
||||
localsfix[j] = true;
|
||||
nontrivial = true;
|
||||
}
|
||||
}
|
||||
|
@ -1165,7 +1169,7 @@ class Compiler
|
|||
// this could be done a little more efficiently, but since in practice this
|
||||
// code never runs (for code compiled from Java source) it doesn't
|
||||
// really matter
|
||||
LocalBuilder newobj = ilGenerator.DeclareLocal(thisType.TypeAsTBD);
|
||||
LocalBuilder newobj = ilGenerator.DeclareLocal(thisType.TypeAsLocalOrStackType);
|
||||
ilGenerator.Emit(OpCodes.Stloc, newobj);
|
||||
LocalBuilder[] tempstack = new LocalBuilder[stackfix.Length];
|
||||
for(int j = 0; j < stackfix.Length; j++)
|
||||
|
@ -1199,12 +1203,18 @@ class Compiler
|
|||
ilGenerator.Emit(OpCodes.Ldloc, tempstack[j]);
|
||||
}
|
||||
}
|
||||
for(int j = 0; j < localsfix.Length; j++)
|
||||
LocalVar[] locals = ma.GetLocalVarsForInvokeSpecial(i);
|
||||
for(int j = 0; j < locals.Length; j++)
|
||||
{
|
||||
if(localsfix[j])
|
||||
if(locals[j] != null)
|
||||
{
|
||||
if(locals[j].builder == null)
|
||||
{
|
||||
// for invokespecial the resulting type can never be null
|
||||
locals[j].builder = ilGenerator.DeclareLocal(locals[j].type.TypeAsLocalOrStackType);
|
||||
}
|
||||
ilGenerator.Emit(OpCodes.Ldloc, newobj);
|
||||
ilGenerator.Emit(OpCodes.Stloc, GetLocal(typeof(object), j));
|
||||
ilGenerator.Emit(OpCodes.Stloc, locals[j].builder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1268,7 +1278,10 @@ class Compiler
|
|||
int stackHeight = ma.GetStackHeight(i);
|
||||
if(instr.NormalizedOpCode == NormalizedByteCode.__return)
|
||||
{
|
||||
ilGenerator.Emit(OpCodes.Leave_S, (byte)0);
|
||||
if(stackHeight != 0)
|
||||
{
|
||||
ilGenerator.Emit(OpCodes.Leave_S, (byte)0);
|
||||
}
|
||||
ilGenerator.Emit(OpCodes.Ret);
|
||||
}
|
||||
else
|
||||
|
@ -1312,17 +1325,8 @@ class Compiler
|
|||
}
|
||||
else
|
||||
{
|
||||
Load(instr, typeof(object));
|
||||
if(instr.NormalizedArg1 >= m.ArgMap.Length)
|
||||
{
|
||||
// HACK since, for now, all locals are of type object, we've got to cast them to the proper type
|
||||
// UPDATE the above is no longer true, we now have at least some idea of the type of the local
|
||||
if(type != ma.GetDeclaredLocalTypeWrapper(instr.NormalizedArg1) && !type.IsUnloadable && !type.IsGhost && !type.IsNonPrimitiveValueType)
|
||||
{
|
||||
ilGenerator.Emit(OpCodes.Castclass, type.TypeAsTBD);
|
||||
}
|
||||
}
|
||||
else
|
||||
LoadLocal(instr);
|
||||
if(instr.NormalizedArg1 < m.ArgMap.Length)
|
||||
{
|
||||
// HACK we're boxing the arguments when they are loaded, this is inconsistent
|
||||
// with the way locals are treated, so we probably should only box the arguments
|
||||
|
@ -1338,7 +1342,7 @@ class Compiler
|
|||
// HACK we use "int" to track the return address of a jsr
|
||||
if(VerifierTypeWrapper.IsRet(type))
|
||||
{
|
||||
Store(instr, typeof(int));
|
||||
StoreLocal(instr);
|
||||
}
|
||||
else if(VerifierTypeWrapper.IsNew(type))
|
||||
{
|
||||
|
@ -1346,7 +1350,7 @@ class Compiler
|
|||
// We do store a null in the local, to prevent it from retaining an unintentional reference
|
||||
// to whatever object reference happens to be there
|
||||
ilGenerator.Emit(OpCodes.Ldnull);
|
||||
Store(instr, typeof(object));
|
||||
StoreLocal(instr);
|
||||
}
|
||||
else if(type == VerifierTypeWrapper.UninitializedThis)
|
||||
{
|
||||
|
@ -1379,33 +1383,33 @@ class Compiler
|
|||
ilGenerator.Emit(OpCodes.Castclass, args[arg].TypeAsParameterType);
|
||||
}
|
||||
}
|
||||
Store(instr, typeof(object));
|
||||
StoreLocal(instr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NormalizedByteCode.__iload:
|
||||
Load(instr, typeof(int));
|
||||
LoadLocal(instr);
|
||||
break;
|
||||
case NormalizedByteCode.__istore:
|
||||
Store(instr, typeof(int));
|
||||
StoreLocal(instr);
|
||||
break;
|
||||
case NormalizedByteCode.__lload:
|
||||
Load(instr, typeof(long));
|
||||
LoadLocal(instr);
|
||||
break;
|
||||
case NormalizedByteCode.__lstore:
|
||||
Store(instr, typeof(long));
|
||||
StoreLocal(instr);
|
||||
break;
|
||||
case NormalizedByteCode.__fload:
|
||||
Load(instr, typeof(float));
|
||||
LoadLocal(instr);
|
||||
break;
|
||||
case NormalizedByteCode.__fstore:
|
||||
Store(instr, typeof(float));
|
||||
StoreLocal(instr);
|
||||
break;
|
||||
case NormalizedByteCode.__dload:
|
||||
Load(instr, typeof(double));
|
||||
LoadLocal(instr);
|
||||
break;
|
||||
case NormalizedByteCode.__dstore:
|
||||
Store(instr, typeof(double));
|
||||
StoreLocal(instr);
|
||||
break;
|
||||
case NormalizedByteCode.__new:
|
||||
{
|
||||
|
@ -2188,10 +2192,10 @@ class Compiler
|
|||
ilGenerator.Emit(OpCodes.Br, GetLabel(labels, instr.PC + instr.DefaultOffset, inuse, rangeBegin, rangeEnd, exits));
|
||||
break;
|
||||
case NormalizedByteCode.__iinc:
|
||||
Load(instr, typeof(int));
|
||||
LoadLocal(instr);
|
||||
ilGenerator.Emit(OpCodes.Ldc_I4, instr.Arg2);
|
||||
ilGenerator.Emit(OpCodes.Add);
|
||||
Store(instr, typeof(int));
|
||||
StoreLocal(instr);
|
||||
break;
|
||||
case NormalizedByteCode.__i2b:
|
||||
ilGenerator.Emit(OpCodes.Conv_I1);
|
||||
|
@ -2253,7 +2257,7 @@ class Compiler
|
|||
int[] callsites = ma.GetCallSites(subid);
|
||||
for(int j = 0; j < callsites.Length - 1; j++)
|
||||
{
|
||||
Load(instr, typeof(int));
|
||||
LoadLocal(instr);
|
||||
ilGenerator.Emit(OpCodes.Ldc_I4, j);
|
||||
ilGenerator.Emit(OpCodes.Beq, GetLabel(labels, m.Instructions[callsites[j] + 1].PC, inuse, rangeBegin, rangeEnd, exits));
|
||||
}
|
||||
|
@ -2747,13 +2751,12 @@ class Compiler
|
|||
return m.PcIndexMap[target];
|
||||
}
|
||||
|
||||
private void Load(ClassFile.Method.Instruction instr, Type type)
|
||||
private void LoadLocal(ClassFile.Method.Instruction instr)
|
||||
{
|
||||
// TODO this check will become more complex, once we support changing the type of an argument 'local'
|
||||
if(instr.NormalizedArg1 >= m.ArgMap.Length)
|
||||
{
|
||||
// OPTIMIZE use short form when possible
|
||||
ilGenerator.Emit(OpCodes.Ldloc, GetLocal(type, instr.NormalizedArg1));
|
||||
ilGenerator.Emit(OpCodes.Ldloc, GetLocal(FindPcIndex(instr.PC)));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2786,12 +2789,21 @@ class Compiler
|
|||
}
|
||||
}
|
||||
|
||||
private void Store(ClassFile.Method.Instruction instr, Type type)
|
||||
private void StoreLocal(ClassFile.Method.Instruction instr)
|
||||
{
|
||||
// TODO this check will become more complex, once we support changing the type of an argument 'local'
|
||||
if(instr.NormalizedArg1 >= m.ArgMap.Length)
|
||||
{
|
||||
ilGenerator.Emit(OpCodes.Stloc, GetLocal(type, instr.NormalizedArg1));
|
||||
LocalBuilder local = GetLocal(FindPcIndex(instr.PC));
|
||||
if(local == null)
|
||||
{
|
||||
// dead store
|
||||
ilGenerator.Emit(OpCodes.Pop);
|
||||
}
|
||||
else
|
||||
{
|
||||
ilGenerator.Emit(OpCodes.Stloc, local);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2807,47 +2819,22 @@ class Compiler
|
|||
}
|
||||
}
|
||||
|
||||
private LocalBuilder GetLocal(Type type, int index)
|
||||
private LocalBuilder GetLocal(int instructionIndex)
|
||||
{
|
||||
string name;
|
||||
if(type.IsValueType)
|
||||
LocalVar v = ma.GetLocalVar(instructionIndex);
|
||||
if(v == null)
|
||||
{
|
||||
name = type.Name + index;
|
||||
return null;
|
||||
}
|
||||
else
|
||||
if(v.builder == null && v.type != VerifierTypeWrapper.Null)
|
||||
{
|
||||
name = "Obj" + index;
|
||||
TypeWrapper t = ma.GetDeclaredLocalTypeWrapper(index);
|
||||
if(t != VerifierTypeWrapper.Null)
|
||||
v.builder = ilGenerator.DeclareLocal(v.type.TypeAsLocalOrStackType);
|
||||
if(JVM.Debug && v.name != null)
|
||||
{
|
||||
type = t.TypeAsLocalOrStackType;
|
||||
v.builder.SetLocalSymInfo(v.name);
|
||||
}
|
||||
}
|
||||
LocalBuilder lb = (LocalBuilder)locals[name];
|
||||
if(lb == null)
|
||||
{
|
||||
lb = ilGenerator.DeclareLocal(type);
|
||||
locals[name] = lb;
|
||||
// the local variable table is disabled, because we need to have
|
||||
// better support for overloaded indexes to make this usefull
|
||||
if(JVM.Debug && false)
|
||||
{
|
||||
// TODO this should be done better
|
||||
ClassFile.Method.LocalVariableTableEntry[] table = m.LocalVariableTableAttribute;
|
||||
if(table != null)
|
||||
{
|
||||
for(int i = 0; i < table.Length; i++)
|
||||
{
|
||||
if(table[i].index == index)
|
||||
{
|
||||
lb.SetLocalSymInfo(table[i].name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return lb;
|
||||
return v.builder;
|
||||
}
|
||||
|
||||
private Label GetLabel(object[] labels, int targetPC, bool[] inuse, int rangeBegin, int rangeEnd, ArrayList exits)
|
||||
|
|
|
@ -665,6 +665,8 @@ namespace MapXml
|
|||
public string Type;
|
||||
[XmlAttribute("modifiers")]
|
||||
public MapModifiers Modifiers;
|
||||
[XmlAttribute("oneway")]
|
||||
public bool OneWay;
|
||||
[XmlElement("constructor")]
|
||||
public Constructor[] Constructors;
|
||||
[XmlElement("method")]
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Collections;
|
||||
using System.Diagnostics;
|
||||
|
||||
class VerifyError : ApplicationException
|
||||
{
|
||||
|
@ -91,15 +92,17 @@ class InstructionState
|
|||
private TypeWrapper[] stack;
|
||||
private int stackSize;
|
||||
private TypeWrapper[] locals;
|
||||
private Hashtable[] localStoreSites;
|
||||
private ArrayList subroutines;
|
||||
private int callsites;
|
||||
internal bool changed = true;
|
||||
|
||||
private InstructionState(TypeWrapper[] stack, int stackSize, TypeWrapper[] locals, ArrayList subroutines, int callsites)
|
||||
private InstructionState(TypeWrapper[] stack, int stackSize, TypeWrapper[] locals, Hashtable[] localStoreSites, ArrayList subroutines, int callsites)
|
||||
{
|
||||
this.stack = stack;
|
||||
this.stackSize = stackSize;
|
||||
this.locals = locals;
|
||||
this.localStoreSites = localStoreSites;
|
||||
this.subroutines = subroutines;
|
||||
this.callsites = callsites;
|
||||
}
|
||||
|
@ -108,11 +111,12 @@ class InstructionState
|
|||
{
|
||||
this.stack = new TypeWrapper[maxStack];
|
||||
this.locals = new TypeWrapper[maxLocals];
|
||||
this.localStoreSites = new Hashtable[maxLocals];
|
||||
}
|
||||
|
||||
internal InstructionState Copy()
|
||||
{
|
||||
return new InstructionState((TypeWrapper[])stack.Clone(), stackSize, (TypeWrapper[])locals.Clone(), CopySubroutines(subroutines), callsites);
|
||||
return new InstructionState((TypeWrapper[])stack.Clone(), stackSize, (TypeWrapper[])locals.Clone(), (Hashtable[])localStoreSites.Clone(), CopySubroutines(subroutines), callsites);
|
||||
}
|
||||
|
||||
internal void CopyTo(InstructionState target)
|
||||
|
@ -120,6 +124,7 @@ class InstructionState
|
|||
stack.CopyTo(target.stack, 0);
|
||||
target.stackSize = stackSize;
|
||||
locals.CopyTo(target.locals, 0);
|
||||
localStoreSites.CopyTo(target.localStoreSites, 0);
|
||||
target.subroutines = CopySubroutines(subroutines);
|
||||
target.callsites = callsites;
|
||||
target.changed = true;
|
||||
|
@ -127,7 +132,7 @@ class InstructionState
|
|||
|
||||
internal InstructionState CopyLocalsAndSubroutines()
|
||||
{
|
||||
return new InstructionState(new TypeWrapper[stack.Length], 0, (TypeWrapper[])locals.Clone(), CopySubroutines(subroutines), callsites);
|
||||
return new InstructionState(new TypeWrapper[stack.Length], 0, (TypeWrapper[])locals.Clone(), (Hashtable[])localStoreSites.Clone(), CopySubroutines(subroutines), callsites);
|
||||
}
|
||||
|
||||
private ArrayList CopySubroutines(ArrayList l)
|
||||
|
@ -207,6 +212,7 @@ class InstructionState
|
|||
if(!locals_modified[i])
|
||||
{
|
||||
s2.locals[i] = s3.locals[i];
|
||||
s2.localStoreSites[i] = s3.localStoreSites[i] != null ? (Hashtable)s3.localStoreSites[i].Clone() : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -231,7 +237,7 @@ class InstructionState
|
|||
}
|
||||
else if(!type.IsPrimitive)
|
||||
{
|
||||
TypeWrapper baseType = s.FindCommonBaseType(type, s2.stack[i]);
|
||||
TypeWrapper baseType = InstructionState.FindCommonBaseType(type, s2.stack[i]);
|
||||
if(baseType == VerifierTypeWrapper.Invalid)
|
||||
{
|
||||
// if we never return from a subroutine, it is legal to merge to subroutine flows
|
||||
|
@ -260,20 +266,30 @@ class InstructionState
|
|||
{
|
||||
TypeWrapper type = s.locals[i];
|
||||
TypeWrapper type2;
|
||||
Hashtable storeSites = s.localStoreSites[i];
|
||||
Hashtable storeSites2;
|
||||
if(locals_modified == null || locals_modified[i])
|
||||
{
|
||||
type2 = s2.locals[i];
|
||||
storeSites2 = s2.localStoreSites[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
type2 = s3.locals[i];
|
||||
storeSites2 = s3.localStoreSites[i];
|
||||
}
|
||||
TypeWrapper baseType = s2.FindCommonBaseType(type, type2);
|
||||
TypeWrapper baseType = InstructionState.FindCommonBaseType(type, type2);
|
||||
if(type != baseType)
|
||||
{
|
||||
s.locals[i] = baseType;
|
||||
s.changed = true;
|
||||
}
|
||||
storeSites = MergeStoreSites(storeSites, storeSites2);
|
||||
if(storeSites != null && (s.localStoreSites[i] == null || storeSites.Count != s.localStoreSites[i].Count))
|
||||
{
|
||||
s.localStoreSites[i] = storeSites;
|
||||
s.changed = true;
|
||||
}
|
||||
}
|
||||
s.MergeSubroutineHelper(s2);
|
||||
if(s3 != null)
|
||||
|
@ -283,6 +299,32 @@ class InstructionState
|
|||
return s;
|
||||
}
|
||||
|
||||
private static Hashtable MergeStoreSites(Hashtable h1, Hashtable h2)
|
||||
{
|
||||
if(h1 == null && h2 == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if(h1 == null)
|
||||
{
|
||||
return (Hashtable)h2.Clone();
|
||||
}
|
||||
if(h2 == null)
|
||||
{
|
||||
return (Hashtable)h1.Clone();
|
||||
}
|
||||
Hashtable h = new Hashtable();
|
||||
foreach(DictionaryEntry de in h1)
|
||||
{
|
||||
h.Add(de.Key, de.Value);
|
||||
}
|
||||
foreach(DictionaryEntry de in h2)
|
||||
{
|
||||
h[de.Key] = de.Value;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
internal void AddCallSite()
|
||||
{
|
||||
callsites++;
|
||||
|
@ -344,7 +386,7 @@ class InstructionState
|
|||
throw new VerifyError("inactive subroutine");
|
||||
}
|
||||
|
||||
internal TypeWrapper FindCommonBaseType(TypeWrapper type1, TypeWrapper type2)
|
||||
internal static TypeWrapper FindCommonBaseType(TypeWrapper type1, TypeWrapper type2)
|
||||
{
|
||||
if(type1 == type2)
|
||||
{
|
||||
|
@ -400,7 +442,7 @@ class InstructionState
|
|||
TypeWrapper baseType = FindCommonBaseTypeHelper(elem1, elem2);
|
||||
if(baseType == VerifierTypeWrapper.Invalid)
|
||||
{
|
||||
baseType = CoreClasses.java_lang_Object;
|
||||
baseType = CoreClasses.java.lang.Object.Wrapper;
|
||||
rank--;
|
||||
if(rank == 0)
|
||||
{
|
||||
|
@ -412,7 +454,7 @@ class InstructionState
|
|||
return FindCommonBaseTypeHelper(type1, type2);
|
||||
}
|
||||
|
||||
private TypeWrapper FindCommonBaseTypeHelper(TypeWrapper t1, TypeWrapper t2)
|
||||
private static TypeWrapper FindCommonBaseTypeHelper(TypeWrapper t1, TypeWrapper t2)
|
||||
{
|
||||
if(t1 == t2)
|
||||
{
|
||||
|
@ -445,12 +487,12 @@ class InstructionState
|
|||
foreach (TypeWrapper baseInterface in t1.Interfaces)
|
||||
{
|
||||
TypeWrapper commonBase = FindCommonBaseTypeHelper(baseInterface, t2);
|
||||
if (commonBase != CoreClasses.java_lang_Object)
|
||||
if (commonBase != CoreClasses.java.lang.Object.Wrapper)
|
||||
{
|
||||
return commonBase;
|
||||
}
|
||||
}
|
||||
return CoreClasses.java_lang_Object;
|
||||
return CoreClasses.java.lang.Object.Wrapper;
|
||||
}
|
||||
Stack st1 = new Stack();
|
||||
Stack st2 = new Stack();
|
||||
|
@ -539,62 +581,80 @@ class InstructionState
|
|||
}
|
||||
}
|
||||
|
||||
internal void GetLocalInt(int index)
|
||||
private void SetLocalStoreSite(int localIndex, int instructionIndex)
|
||||
{
|
||||
if(GetLocalType(index) != PrimitiveTypeWrapper.INT)
|
||||
localStoreSites[localIndex] = new Hashtable();
|
||||
localStoreSites[localIndex].Add(instructionIndex, "");
|
||||
}
|
||||
|
||||
internal void GetLocalInt(int index, ref Hashtable readers)
|
||||
{
|
||||
if(GetLocalType(index, ref readers) != PrimitiveTypeWrapper.INT)
|
||||
{
|
||||
throw new VerifyError("Invalid local type");
|
||||
}
|
||||
}
|
||||
|
||||
internal void SetLocalInt(int index)
|
||||
internal void SetLocalInt(int index, int instructionIndex)
|
||||
{
|
||||
SetLocalStoreSite(index, instructionIndex);
|
||||
SetLocal1(index, PrimitiveTypeWrapper.INT);
|
||||
}
|
||||
|
||||
internal void GetLocalLong(int index)
|
||||
internal void GetLocalLong(int index, ref Hashtable readers)
|
||||
{
|
||||
if(GetLocalType(index) != PrimitiveTypeWrapper.LONG)
|
||||
if(GetLocalType(index, ref readers) != PrimitiveTypeWrapper.LONG)
|
||||
{
|
||||
throw new VerifyError("incorrect local type, not long");
|
||||
}
|
||||
}
|
||||
|
||||
internal void SetLocalLong(int index)
|
||||
internal void SetLocalLong(int index, int instructionIndex)
|
||||
{
|
||||
SetLocalStoreSite(index, instructionIndex);
|
||||
SetLocal2(index, PrimitiveTypeWrapper.LONG);
|
||||
}
|
||||
|
||||
internal void GetLocalFloat(int index)
|
||||
internal void GetLocalFloat(int index, ref Hashtable readers)
|
||||
{
|
||||
if(GetLocalType(index) != PrimitiveTypeWrapper.FLOAT)
|
||||
if(GetLocalType(index, ref readers) != PrimitiveTypeWrapper.FLOAT)
|
||||
{
|
||||
throw new VerifyError("incorrect local type, not float");
|
||||
}
|
||||
}
|
||||
|
||||
internal void SetLocalFloat(int index)
|
||||
internal void SetLocalFloat(int index, int instructionIndex)
|
||||
{
|
||||
SetLocalStoreSite(index, instructionIndex);
|
||||
SetLocal1(index, PrimitiveTypeWrapper.FLOAT);
|
||||
}
|
||||
|
||||
internal void GetLocalDouble(int index)
|
||||
internal void GetLocalDouble(int index, ref Hashtable readers)
|
||||
{
|
||||
if(GetLocalType(index) != PrimitiveTypeWrapper.DOUBLE)
|
||||
if(GetLocalType(index, ref readers) != PrimitiveTypeWrapper.DOUBLE)
|
||||
{
|
||||
throw new VerifyError("incorrect local type, not double");
|
||||
}
|
||||
}
|
||||
|
||||
internal void SetLocalDouble(int index)
|
||||
internal void SetLocalDouble(int index, int instructionIndex)
|
||||
{
|
||||
SetLocalStoreSite(index, instructionIndex);
|
||||
SetLocal2(index, PrimitiveTypeWrapper.DOUBLE);
|
||||
}
|
||||
|
||||
internal TypeWrapper GetLocalType(int index)
|
||||
internal TypeWrapper GetLocalType(int index, ref Hashtable readers)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(readers == null)
|
||||
{
|
||||
readers = new Hashtable();
|
||||
}
|
||||
foreach(int store in localStoreSites[index].Keys)
|
||||
{
|
||||
readers[store] = "";
|
||||
}
|
||||
return locals[index];
|
||||
}
|
||||
catch(IndexOutOfRangeException)
|
||||
|
@ -603,9 +663,17 @@ class InstructionState
|
|||
}
|
||||
}
|
||||
|
||||
internal int GetLocalRet(int index)
|
||||
// this is used by the compiler (indirectly, through MethodAnalyzer.GetLocalTypeWrapper),
|
||||
// we've already verified the code so we know we won't run outside the array boundary,
|
||||
// and we don't need to record the fact that we're reading the local.
|
||||
internal TypeWrapper GetLocalTypeEx(int index)
|
||||
{
|
||||
TypeWrapper type = GetLocalType(index);
|
||||
return locals[index];
|
||||
}
|
||||
|
||||
internal int GetLocalRet(int index, ref Hashtable readers)
|
||||
{
|
||||
TypeWrapper type = GetLocalType(index, ref readers);
|
||||
if(VerifierTypeWrapper.IsRet(type))
|
||||
{
|
||||
return ((VerifierTypeWrapper)type).Index;
|
||||
|
@ -613,8 +681,9 @@ class InstructionState
|
|||
throw new VerifyError("incorrect local type, not ret");
|
||||
}
|
||||
|
||||
internal void SetLocalType(int index, TypeWrapper type)
|
||||
internal void SetLocalType(int index, TypeWrapper type, int instructionIndex)
|
||||
{
|
||||
SetLocalStoreSite(index, instructionIndex);
|
||||
if(type.IsWidePrimitive)
|
||||
{
|
||||
SetLocal2(index, type);
|
||||
|
@ -797,7 +866,7 @@ class InstructionState
|
|||
stack[stackSize++] = type;
|
||||
}
|
||||
|
||||
internal void MarkInitialized(TypeWrapper type, TypeWrapper initType)
|
||||
internal void MarkInitialized(TypeWrapper type, TypeWrapper initType, int instructionIndex)
|
||||
{
|
||||
System.Diagnostics.Debug.Assert(type != null && initType != null);
|
||||
|
||||
|
@ -805,6 +874,7 @@ class InstructionState
|
|||
{
|
||||
if(locals[i] == type)
|
||||
{
|
||||
SetLocalStoreSite(i, instructionIndex);
|
||||
locals[i] = initType;
|
||||
}
|
||||
}
|
||||
|
@ -993,6 +1063,50 @@ class VerifierTypeWrapper : TypeWrapper
|
|||
}
|
||||
}
|
||||
|
||||
class LocalVar : IComparable
|
||||
{
|
||||
internal int local;
|
||||
internal TypeWrapper type;
|
||||
internal System.Reflection.Emit.LocalBuilder builder;
|
||||
// used to emit debugging info, only available if JVM.Debug is true
|
||||
internal string name;
|
||||
internal int start_pc;
|
||||
internal int end_pc;
|
||||
// we have a linked list of LocalVars that are really the same
|
||||
private LocalVar next;
|
||||
|
||||
internal void Link(LocalVar v)
|
||||
{
|
||||
Debug.Assert(v != this);
|
||||
v = v.Tail();
|
||||
v.next = this;
|
||||
next = null;
|
||||
}
|
||||
|
||||
internal LocalVar Tail()
|
||||
{
|
||||
if(next == null)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
return next.Tail();
|
||||
}
|
||||
|
||||
int IComparable.CompareTo(object obj)
|
||||
{
|
||||
LocalVar other = (LocalVar)obj;
|
||||
if(local > other.local)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else if(local < other.local)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return type.SigName.CompareTo(other.type.SigName);
|
||||
}
|
||||
}
|
||||
|
||||
class MethodAnalyzer
|
||||
{
|
||||
private static TypeWrapper ByteArrayType;
|
||||
|
@ -1007,8 +1121,8 @@ class MethodAnalyzer
|
|||
private ClassFile.Method.Code method;
|
||||
private InstructionState[] state;
|
||||
private ArrayList[] callsites;
|
||||
private TypeWrapper[] localTypes;
|
||||
private bool[] aload_used;
|
||||
private LocalVar[] localVars;
|
||||
private LocalVar[][] invokespecialLocalVars;
|
||||
|
||||
static MethodAnalyzer()
|
||||
{
|
||||
|
@ -1028,11 +1142,8 @@ class MethodAnalyzer
|
|||
this.method = method;
|
||||
state = new InstructionState[method.Instructions.Length];
|
||||
callsites = new ArrayList[method.Instructions.Length];
|
||||
localTypes = new TypeWrapper[method.MaxLocals];
|
||||
// HACK aload_used is used to track whether aload is ever used on a particular local (a very lame way of
|
||||
// trying to determine if a local that contains an exception, is ever used)
|
||||
// TODO we really need real liveness analyses for the locals
|
||||
aload_used = new Boolean[method.MaxLocals];
|
||||
|
||||
Hashtable[] localStoreReaders = new Hashtable[method.Instructions.Length];
|
||||
|
||||
// HACK because types have to have identity, the subroutine return address and new types are cached here
|
||||
Hashtable returnAddressTypes = new Hashtable();
|
||||
|
@ -1046,11 +1157,11 @@ class MethodAnalyzer
|
|||
// this reference. If we're a constructor, the this reference is uninitialized.
|
||||
if(method.Method.Name == "<init>")
|
||||
{
|
||||
state[0].SetLocalType(arg++, VerifierTypeWrapper.UninitializedThis);
|
||||
state[0].SetLocalType(arg++, VerifierTypeWrapper.UninitializedThis, -1);
|
||||
}
|
||||
else
|
||||
{
|
||||
state[0].SetLocalType(arg++, wrapper);
|
||||
state[0].SetLocalType(arg++, wrapper, -1);
|
||||
}
|
||||
}
|
||||
// HACK articial scope to make "args" name reusable
|
||||
|
@ -1064,7 +1175,7 @@ class MethodAnalyzer
|
|||
{
|
||||
type = PrimitiveTypeWrapper.INT;
|
||||
}
|
||||
state[0].SetLocalType(arg++, type);
|
||||
state[0].SetLocalType(arg++, type, -1);
|
||||
if(type.IsWidePrimitive)
|
||||
{
|
||||
arg++;
|
||||
|
@ -1101,7 +1212,7 @@ class MethodAnalyzer
|
|||
int catch_type = method.ExceptionTable[j].catch_type;
|
||||
if(catch_type == 0)
|
||||
{
|
||||
ex.PushType(CoreClasses.java_lang_Throwable);
|
||||
ex.PushType(CoreClasses.java.lang.Throwable.Wrapper);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1119,8 +1230,7 @@ class MethodAnalyzer
|
|||
{
|
||||
case NormalizedByteCode.__aload:
|
||||
{
|
||||
aload_used[instr.NormalizedArg1] = true;
|
||||
TypeWrapper type = s.GetLocalType(instr.NormalizedArg1);
|
||||
TypeWrapper type = s.GetLocalType(instr.NormalizedArg1, ref localStoreReaders[i]);
|
||||
if(type == VerifierTypeWrapper.Invalid || type.IsPrimitive)
|
||||
{
|
||||
throw new VerifyError("Object reference expected");
|
||||
|
@ -1136,7 +1246,7 @@ class MethodAnalyzer
|
|||
{
|
||||
throw new VerifyError("Object reference expected");
|
||||
}
|
||||
s.SetLocalType(instr.NormalizedArg1, type);
|
||||
s.SetLocalType(instr.NormalizedArg1, type, i);
|
||||
break;
|
||||
}
|
||||
case NormalizedByteCode.__aconst_null:
|
||||
|
@ -1333,14 +1443,14 @@ class MethodAnalyzer
|
|||
s.PushLong();
|
||||
break;
|
||||
case ClassFile.ConstantType.String:
|
||||
s.PushType(CoreClasses.java_lang_String);
|
||||
s.PushType(CoreClasses.java.lang.String.Wrapper);
|
||||
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);
|
||||
s.PushType(CoreClasses.java.lang.Class.Wrapper);
|
||||
break;
|
||||
default:
|
||||
// NOTE this is not a VerifyError, because it cannot happen (unless we have
|
||||
|
@ -1398,11 +1508,11 @@ class MethodAnalyzer
|
|||
// suddenly initialized
|
||||
if(type == VerifierTypeWrapper.UninitializedThis)
|
||||
{
|
||||
s.MarkInitialized(type, wrapper);
|
||||
s.MarkInitialized(type, wrapper, i);
|
||||
}
|
||||
else
|
||||
{
|
||||
s.MarkInitialized(type, ((VerifierTypeWrapper)type).UnderlyingType);
|
||||
s.MarkInitialized(type, ((VerifierTypeWrapper)type).UnderlyingType, i);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -1443,10 +1553,10 @@ class MethodAnalyzer
|
|||
break;
|
||||
case NormalizedByteCode.__istore:
|
||||
s.PopInt();
|
||||
s.SetLocalInt(instr.NormalizedArg1);
|
||||
s.SetLocalInt(instr.NormalizedArg1, i);
|
||||
break;
|
||||
case NormalizedByteCode.__iload:
|
||||
s.GetLocalInt(instr.NormalizedArg1);
|
||||
s.GetLocalInt(instr.NormalizedArg1, ref localStoreReaders[i]);
|
||||
s.PushInt();
|
||||
break;
|
||||
case NormalizedByteCode.__ineg:
|
||||
|
@ -1782,28 +1892,28 @@ class MethodAnalyzer
|
|||
}
|
||||
break;
|
||||
case NormalizedByteCode.__fload:
|
||||
s.GetLocalFloat(instr.NormalizedArg1);
|
||||
s.GetLocalFloat(instr.NormalizedArg1, ref localStoreReaders[i]);
|
||||
s.PushFloat();
|
||||
break;
|
||||
case NormalizedByteCode.__fstore:
|
||||
s.PopFloat();
|
||||
s.SetLocalFloat(instr.NormalizedArg1);
|
||||
s.SetLocalFloat(instr.NormalizedArg1, i);
|
||||
break;
|
||||
case NormalizedByteCode.__dload:
|
||||
s.GetLocalDouble(instr.NormalizedArg1);
|
||||
s.GetLocalDouble(instr.NormalizedArg1, ref localStoreReaders[i]);
|
||||
s.PushDouble();
|
||||
break;
|
||||
case NormalizedByteCode.__dstore:
|
||||
s.PopDouble();
|
||||
s.SetLocalDouble(instr.NormalizedArg1);
|
||||
s.SetLocalDouble(instr.NormalizedArg1, i);
|
||||
break;
|
||||
case NormalizedByteCode.__lload:
|
||||
s.GetLocalLong(instr.NormalizedArg1);
|
||||
s.GetLocalLong(instr.NormalizedArg1, ref localStoreReaders[i]);
|
||||
s.PushLong();
|
||||
break;
|
||||
case NormalizedByteCode.__lstore:
|
||||
s.PopLong();
|
||||
s.SetLocalLong(instr.NormalizedArg1);
|
||||
s.SetLocalLong(instr.NormalizedArg1, i);
|
||||
break;
|
||||
case NormalizedByteCode.__lconst_0:
|
||||
case NormalizedByteCode.__lconst_1:
|
||||
|
@ -1844,10 +1954,10 @@ class MethodAnalyzer
|
|||
s.PushInt();
|
||||
break;
|
||||
case NormalizedByteCode.__iinc:
|
||||
s.GetLocalInt(instr.Arg1);
|
||||
s.GetLocalInt(instr.Arg1, ref localStoreReaders[i]);
|
||||
break;
|
||||
case NormalizedByteCode.__athrow:
|
||||
s.PopObjectType(CoreClasses.java_lang_Throwable);
|
||||
s.PopObjectType(CoreClasses.java.lang.Throwable.Wrapper);
|
||||
break;
|
||||
case NormalizedByteCode.__lookupswitch:
|
||||
s.PopInt();
|
||||
|
@ -1919,7 +2029,7 @@ class MethodAnalyzer
|
|||
{
|
||||
// TODO if we're returning from a higher level subroutine, invalidate
|
||||
// all the intermediate return addresses
|
||||
int subroutineIndex = s.GetLocalRet(instr.Arg1);
|
||||
int subroutineIndex = s.GetLocalRet(instr.Arg1, ref localStoreReaders[i]);
|
||||
s.CheckSubroutineActive(subroutineIndex);
|
||||
break;
|
||||
}
|
||||
|
@ -2002,7 +2112,7 @@ class MethodAnalyzer
|
|||
// HACK if the ret is processed before all of the jsr instructions to this subroutine
|
||||
// we wouldn't be able to properly merge, so that is why we track the number of callsites
|
||||
// for each subroutine instruction (see Instruction.AddCallSite())
|
||||
int subroutineIndex = s.GetLocalRet(instr.Arg1);
|
||||
int subroutineIndex = s.GetLocalRet(instr.Arg1, ref localStoreReaders[i]);
|
||||
int[] cs = GetCallSites(subroutineIndex);
|
||||
bool[] locals_modified = s.ClearSubroutineId(subroutineIndex);
|
||||
for(int j = 0; j < cs.Length; j++)
|
||||
|
@ -2032,37 +2142,6 @@ class MethodAnalyzer
|
|||
// in an IndexOutOfRangeException
|
||||
throw new VerifyError("Illegal target of jump or branch");
|
||||
}
|
||||
// HACK track the local types (but only for object references)
|
||||
for(int j = 0; j < localTypes.Length ; j++)
|
||||
{
|
||||
TypeWrapper l = s.GetLocalType(j);
|
||||
if(l != VerifierTypeWrapper.Invalid)
|
||||
{
|
||||
if(l == VerifierTypeWrapper.UninitializedThis)
|
||||
{
|
||||
localTypes[j] = wrapper;
|
||||
}
|
||||
else if(VerifierTypeWrapper.IsNew(l))
|
||||
{
|
||||
localTypes[j] = ((VerifierTypeWrapper)l).UnderlyingType;
|
||||
}
|
||||
else if(!VerifierTypeWrapper.IsRet(l) && !l.IsPrimitive)
|
||||
{
|
||||
if(!VerifierTypeWrapper.IsNullOrUnloadable(l) && l.IsNonPrimitiveValueType)
|
||||
{
|
||||
l = CoreClasses.java_lang_Object;
|
||||
}
|
||||
if(localTypes[j] == VerifierTypeWrapper.Invalid)
|
||||
{
|
||||
localTypes[j] = l;
|
||||
}
|
||||
else
|
||||
{
|
||||
localTypes[j] = s.FindCommonBaseType(localTypes[j], l);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(VerifyError x)
|
||||
{
|
||||
|
@ -2093,7 +2172,191 @@ class MethodAnalyzer
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// now that we've done the code flow analysis, we can do a liveness analysis on the local variables
|
||||
Hashtable localByStoreSite = new Hashtable();
|
||||
ArrayList locals = new ArrayList();
|
||||
for(int i = 0; i < localStoreReaders.Length; i++)
|
||||
{
|
||||
if(localStoreReaders[i] != null)
|
||||
{
|
||||
VisitLocalLoads(locals, localByStoreSite, localStoreReaders[i], i);
|
||||
}
|
||||
}
|
||||
Hashtable unique = new Hashtable();
|
||||
for(int i = 0; i < locals.Count; i++)
|
||||
{
|
||||
unique[((LocalVar)locals[i]).Tail()] = "";
|
||||
}
|
||||
locals = new ArrayList(unique.Keys);
|
||||
locals.Sort();
|
||||
Hashtable forwarders = new Hashtable();
|
||||
for(int i = 0; i < locals.Count - 1; i++)
|
||||
{
|
||||
LocalVar v1 = (LocalVar)locals[i];
|
||||
LocalVar v2 = (LocalVar)locals[i + 1];
|
||||
// if the two locals are the same, we merge them (note that the debugging stuff
|
||||
// will always match if debugging is disabled)
|
||||
// NOTE this is a small optimization (and to improve the debugging experience)
|
||||
// it should *not* be required for correctness.
|
||||
if(v1.local == v2.local && v1.type == v2.type &&
|
||||
v1.name == v2.name && v1.start_pc == v2.start_pc && v1.end_pc == v2.end_pc)
|
||||
{
|
||||
forwarders.Add(v2, v1);
|
||||
locals.RemoveAt(i + 1);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
invokespecialLocalVars = new LocalVar[method.Instructions.Length][];
|
||||
localVars = new LocalVar[method.Instructions.Length];
|
||||
for(int i = 0; i < localVars.Length; i++)
|
||||
{
|
||||
LocalVar v = null;
|
||||
if(localStoreReaders[i] != null)
|
||||
{
|
||||
Debug.Assert(IsLoadLocal(method.Instructions[i].NormalizedOpCode));
|
||||
// lame way to look up the local variable for a load
|
||||
// (by indirecting through a corresponding store)
|
||||
foreach(int store in localStoreReaders[i].Keys)
|
||||
{
|
||||
v = (LocalVar)localByStoreSite[store + ":" + method.Instructions[i].NormalizedArg1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(method.Instructions[i].NormalizedOpCode == NormalizedByteCode.__invokespecial)
|
||||
{
|
||||
invokespecialLocalVars[i] = new LocalVar[method.MaxLocals];
|
||||
for(int j = 0; j < invokespecialLocalVars[i].Length; j++)
|
||||
{
|
||||
invokespecialLocalVars[i][j] = (LocalVar)localByStoreSite[i + ":" + j];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
v = (LocalVar)localByStoreSite[i + ":" + method.Instructions[i].NormalizedArg1];
|
||||
}
|
||||
}
|
||||
if(v != null)
|
||||
{
|
||||
LocalVar fwd = (LocalVar)forwarders[v];
|
||||
if(fwd != null)
|
||||
{
|
||||
v = fwd;
|
||||
}
|
||||
localVars[i] = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsLoadLocal(NormalizedByteCode bc)
|
||||
{
|
||||
return bc == NormalizedByteCode.__aload ||
|
||||
bc == NormalizedByteCode.__iload ||
|
||||
bc == NormalizedByteCode.__lload ||
|
||||
bc == NormalizedByteCode.__fload ||
|
||||
bc == NormalizedByteCode.__dload ||
|
||||
bc == NormalizedByteCode.__iinc ||
|
||||
bc == NormalizedByteCode.__ret;
|
||||
}
|
||||
|
||||
private static bool IsStoreLocal(NormalizedByteCode bc)
|
||||
{
|
||||
return bc == NormalizedByteCode.__astore ||
|
||||
bc == NormalizedByteCode.__istore ||
|
||||
bc == NormalizedByteCode.__lstore ||
|
||||
bc == NormalizedByteCode.__fstore ||
|
||||
bc == NormalizedByteCode.__dstore;
|
||||
}
|
||||
|
||||
private void VisitLocalLoads(ArrayList locals, Hashtable localByStoreSite, Hashtable storeSites, int instructionIndex)
|
||||
{
|
||||
Debug.Assert(IsLoadLocal(method.Instructions[instructionIndex].NormalizedOpCode));
|
||||
LocalVar local = null;
|
||||
TypeWrapper type = VerifierTypeWrapper.Null;
|
||||
int localIndex = method.Instructions[instructionIndex].NormalizedArg1;
|
||||
foreach(int store in storeSites.Keys)
|
||||
{
|
||||
if(store == -1)
|
||||
{
|
||||
// it's a method argument, it has no initial store, but the type is simply the parameter type
|
||||
type = InstructionState.FindCommonBaseType(type, state[0].GetLocalTypeEx(localIndex));
|
||||
}
|
||||
else
|
||||
{
|
||||
if(method.Instructions[store].NormalizedOpCode == NormalizedByteCode.__invokespecial)
|
||||
{
|
||||
type = InstructionState.FindCommonBaseType(type, GetLocalTypeWrapper(store + 1, localIndex));
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Assert(IsStoreLocal(method.Instructions[store].NormalizedOpCode));
|
||||
type = InstructionState.FindCommonBaseType(type, GetRawStackTypeWrapper(store, 0));
|
||||
}
|
||||
}
|
||||
// we can't have an invalid type, because that would have failed verification earlier
|
||||
Debug.Assert(type != VerifierTypeWrapper.Invalid);
|
||||
|
||||
LocalVar l = (LocalVar)localByStoreSite[store + ":" + localIndex];
|
||||
|
||||
// If we've already defined a LocalVar and we find another one, then we join them
|
||||
// together.
|
||||
// This happens for the following code fragment:
|
||||
//
|
||||
// int i = -1;
|
||||
// try { i = 0; for(; ; ) System.out.println(i); } catch(Exception x) {}
|
||||
// try { i = 0; for(; ; ) System.out.println(i); } catch(Exception x) {}
|
||||
// System.out.println(i);
|
||||
//
|
||||
if(l != null && local != null && l != local)
|
||||
{
|
||||
Debug.Assert(l.local == local.local);
|
||||
local.Link(l);
|
||||
l = null;
|
||||
}
|
||||
Debug.Assert(local == null || l == null || local == l);
|
||||
if(l != null)
|
||||
{
|
||||
Debug.Assert(l.local == localIndex);
|
||||
local = l;
|
||||
}
|
||||
}
|
||||
if(local == null)
|
||||
{
|
||||
local = new LocalVar();
|
||||
local.local = localIndex;
|
||||
local.type = type;
|
||||
if(JVM.Debug)
|
||||
{
|
||||
ClassFile.Method.LocalVariableTableEntry[] lvt = method.LocalVariableTableAttribute;
|
||||
if(lvt != null)
|
||||
{
|
||||
int pc = method.Instructions[instructionIndex].PC;
|
||||
foreach(ClassFile.Method.LocalVariableTableEntry e in lvt)
|
||||
{
|
||||
if(e.index == localIndex && e.start_pc <= pc && e.start_pc + e.length >= pc)
|
||||
{
|
||||
local.name = e.name;
|
||||
local.start_pc = e.start_pc;
|
||||
local.end_pc = e.start_pc + e.length;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
locals.Add(local);
|
||||
}
|
||||
else
|
||||
{
|
||||
local.type = InstructionState.FindCommonBaseType(local.type, type);
|
||||
Debug.Assert(local.type != VerifierTypeWrapper.Invalid);
|
||||
}
|
||||
foreach(int store in storeSites.Keys)
|
||||
{
|
||||
localByStoreSite[store + ":" + localIndex] = local;
|
||||
}
|
||||
}
|
||||
|
||||
private ClassFile.ConstantPoolItemFMI GetMethodref(int index)
|
||||
|
@ -2216,16 +2479,18 @@ class MethodAnalyzer
|
|||
|
||||
internal TypeWrapper GetLocalTypeWrapper(int index, int local)
|
||||
{
|
||||
return state[index].GetLocalType(local);
|
||||
return state[index].GetLocalTypeEx(local);
|
||||
}
|
||||
|
||||
internal TypeWrapper GetDeclaredLocalTypeWrapper(int local)
|
||||
// NOTE for dead stores, this returns null
|
||||
internal LocalVar GetLocalVar(int instructionIndex)
|
||||
{
|
||||
return localTypes[local];
|
||||
return localVars[instructionIndex];
|
||||
}
|
||||
|
||||
internal bool IsAloadUsed(int local)
|
||||
internal LocalVar[] GetLocalVarsForInvokeSpecial(int instructionIndex)
|
||||
{
|
||||
return aload_used[local];
|
||||
Debug.Assert(method.Instructions[instructionIndex].NormalizedOpCode == NormalizedByteCode.__invokespecial);
|
||||
return invokespecialLocalVars[instructionIndex];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -88,6 +88,14 @@ public class JVM
|
|||
}
|
||||
}
|
||||
|
||||
internal static bool IsUnix
|
||||
{
|
||||
get
|
||||
{
|
||||
return Environment.OSVersion.ToString().IndexOf("Unix") >= 0;
|
||||
}
|
||||
}
|
||||
|
||||
public static IJniProvider JniProvider
|
||||
{
|
||||
get
|
||||
|
@ -103,7 +111,7 @@ public class JVM
|
|||
}
|
||||
else
|
||||
{
|
||||
if(Environment.OSVersion.ToString().IndexOf("Unix") >= 0)
|
||||
if(IsUnix)
|
||||
{
|
||||
Tracer.Info(Tracer.Runtime, "Loading JNI provider: Mono.IKVM.JNI");
|
||||
provider = Assembly.Load("Mono.IKVM.JNI").GetType("JNI", true);
|
||||
|
@ -404,16 +412,19 @@ public class JVM
|
|||
AttributeHelper.SetModifiers(typeBuilder, (Modifiers)c.Modifiers);
|
||||
}
|
||||
|
||||
// FXBUG we would like to emit an attribute with a Type argument here, but that doesn't work because
|
||||
// of a bug in SetCustomAttribute that causes type arguments to be serialized incorrectly (if the type
|
||||
// is in the same assembly). Normally we use AttributeHelper.FreezeDry to get around this, but that doesn't
|
||||
// work in this case (to attribute is emitted at all). So we work around by emitting a string instead
|
||||
ConstructorInfo remappedClassAttribute = typeof(RemappedClassAttribute).GetConstructor(new Type[] { typeof(string), typeof(Type) });
|
||||
classLoader.assemblyBuilder.SetCustomAttribute(new CustomAttributeBuilder(remappedClassAttribute, new object[] { name, equivalencyType }));
|
||||
if(!c.OneWay)
|
||||
{
|
||||
// FXBUG we would like to emit an attribute with a Type argument here, but that doesn't work because
|
||||
// of a bug in SetCustomAttribute that causes type arguments to be serialized incorrectly (if the type
|
||||
// is in the same assembly). Normally we use AttributeHelper.FreezeDry to get around this, but that doesn't
|
||||
// work in this case (to attribute is emitted at all). So we work around by emitting a string instead
|
||||
ConstructorInfo remappedClassAttribute = typeof(RemappedClassAttribute).GetConstructor(new Type[] { typeof(string), typeof(Type) });
|
||||
classLoader.assemblyBuilder.SetCustomAttribute(new CustomAttributeBuilder(remappedClassAttribute, new object[] { name, equivalencyType }));
|
||||
|
||||
ConstructorInfo remappedTypeAttribute = typeof(RemappedTypeAttribute).GetConstructor(new Type[] { typeof(Type) });
|
||||
typeBuilder.SetCustomAttribute(new CustomAttributeBuilder(remappedTypeAttribute, new object[] { equivalencyType }));
|
||||
AttributeHelper.HideFromReflection(typeBuilder);
|
||||
ConstructorInfo remappedTypeAttribute = typeof(RemappedTypeAttribute).GetConstructor(new Type[] { typeof(Type) });
|
||||
typeBuilder.SetCustomAttribute(new CustomAttributeBuilder(remappedTypeAttribute, new object[] { equivalencyType }));
|
||||
AttributeHelper.HideFromReflection(typeBuilder);
|
||||
}
|
||||
|
||||
// HACK because of the above FXBUG that prevents us from making the type both abstract and sealed,
|
||||
// we need to emit a private constructor (otherwise reflection will automatically generate a public
|
||||
|
@ -1432,7 +1443,7 @@ public class JVM
|
|||
{
|
||||
Tracer.Error(Tracer.Runtime, "CRITICAL FAILURE: {0}", message);
|
||||
// NOTE we use reflection to invoke MessageBox.Show, to make sure we run on Mono as well
|
||||
Assembly winForms = Assembly.LoadWithPartialName("System.Windows.Forms");
|
||||
Assembly winForms = IsUnix ? null : Assembly.LoadWithPartialName("System.Windows.Forms");
|
||||
Type messageBox = null;
|
||||
if(winForms != null)
|
||||
{
|
||||
|
|
|
@ -52,6 +52,15 @@ final class VMThread
|
|||
// being called while we're cleaning up. To be safe all code in
|
||||
// VMThread be unstoppable.
|
||||
running = false;
|
||||
cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
// notify Thread that it is dead, this method can safely be called multiple times
|
||||
private synchronized void cleanup()
|
||||
{
|
||||
if(thread.vmThread != null)
|
||||
{
|
||||
thread.die();
|
||||
}
|
||||
}
|
||||
|
@ -63,28 +72,25 @@ final class VMThread
|
|||
thread.vmThread = vmThread;
|
||||
}
|
||||
|
||||
String getName()
|
||||
synchronized String getName()
|
||||
{
|
||||
return thread.name;
|
||||
}
|
||||
|
||||
void setName(String name)
|
||||
synchronized void setName(String name)
|
||||
{
|
||||
thread.name = name;
|
||||
}
|
||||
|
||||
void setPriority(int priority)
|
||||
synchronized void setPriority(int priority)
|
||||
{
|
||||
thread.priority = priority;
|
||||
nativeSetPriority(priority);
|
||||
}
|
||||
|
||||
int getPriority()
|
||||
synchronized int getPriority()
|
||||
{
|
||||
synchronized(thread)
|
||||
{
|
||||
return thread.priority;
|
||||
}
|
||||
return thread.priority;
|
||||
}
|
||||
|
||||
boolean isDaemon()
|
||||
|
@ -103,13 +109,11 @@ final class VMThread
|
|||
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
|
||||
void join(long ms, int ns) throws InterruptedException
|
||||
{
|
||||
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();
|
||||
|
@ -118,12 +122,18 @@ final class VMThread
|
|||
{
|
||||
nativeThread.Join(makeTimeSpan(ms, ns));
|
||||
}
|
||||
// make sure the thread is marked as dead and removed from the thread group, before we
|
||||
// return from a successful join
|
||||
if(!nativeThread.get_IsAlive())
|
||||
{
|
||||
cleanup();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void stop(Throwable t)
|
||||
{
|
||||
// Note: we assume that we own the lock on thread
|
||||
// NOTE we assume that we own the lock on thread
|
||||
// (i.e. that Thread.stop() is synchronized)
|
||||
if(running)
|
||||
nativeStop(t);
|
||||
|
@ -270,7 +280,11 @@ final class VMThread
|
|||
|
||||
protected void finalize()
|
||||
{
|
||||
thread.die();
|
||||
VMThread vmThread = thread.vmThread;
|
||||
if(vmThread != null)
|
||||
{
|
||||
vmThread.cleanup();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -317,23 +331,37 @@ final class VMThread
|
|||
|
||||
static void yield()
|
||||
{
|
||||
cli.System.Threading.Thread.Sleep(0);
|
||||
try
|
||||
{
|
||||
if(false) throw new InterruptedException();
|
||||
cli.System.Threading.Thread.Sleep(0);
|
||||
}
|
||||
catch(InterruptedException x)
|
||||
{
|
||||
// since we "consumed" the interrupt, we have to interrupt ourself again
|
||||
cli.System.Threading.Thread.get_CurrentThread().Interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
static void sleep(long ms, int ns) throws InterruptedException
|
||||
{
|
||||
cli.System.Threading.Thread.Sleep(makeTimeSpan(ms, ns));
|
||||
// NOTE strangely, sleep(0) doesn't trigger a pending interrupt
|
||||
if(ms == 0 && ns == 0)
|
||||
{
|
||||
yield();
|
||||
}
|
||||
else
|
||||
{
|
||||
cli.System.Threading.Thread.Sleep(makeTimeSpan(ms, ns));
|
||||
}
|
||||
}
|
||||
|
||||
static boolean interrupted()
|
||||
{
|
||||
try
|
||||
{
|
||||
synchronized(currentThread())
|
||||
{
|
||||
if(false) throw new InterruptedException();
|
||||
cli.System.Threading.Thread.Sleep(0);
|
||||
}
|
||||
if(false) throw new InterruptedException();
|
||||
cli.System.Threading.Thread.Sleep(0);
|
||||
return false;
|
||||
}
|
||||
catch(InterruptedException x)
|
||||
|
@ -363,7 +391,7 @@ final class VMThread
|
|||
}
|
||||
catch(InterruptedException x1)
|
||||
{
|
||||
// Since we "consumed" the interrupt, we have to interrupt ourself again
|
||||
// since we "consumed" the interrupt, we have to interrupt ourself again
|
||||
cli.System.Threading.Thread.get_CurrentThread().Interrupt();
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -527,8 +527,9 @@
|
|||
<override name="CompareTo" />
|
||||
</method>
|
||||
</class>
|
||||
<!-- TODO support "oneway" attribute (don't associate System.IntPtr with gnu.classpath.RawData -->
|
||||
<class name="gnu.classpath.RawData" type="System.IntPtr, mscorlib" oneway="true">
|
||||
<!-- TODO custom boxing isn't support for non-oneway remapped types, but since this is the only
|
||||
type that has a custom boxing rule, this isn't yet as issue -->
|
||||
<box>
|
||||
<!-- We special case boxing, to "box" IntPtr.Zero as null -->
|
||||
<dup />
|
||||
|
|
|
@ -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
|
||||
|
@ -152,6 +152,7 @@ public class Starter
|
|||
catch(Exception x)
|
||||
{
|
||||
Console.Error.WriteLine(x);
|
||||
Console.Error.WriteLine(new System.Diagnostics.StackTrace(x, true));
|
||||
System.Diagnostics.Debug.Assert(false, x.ToString());
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче