This commit is contained in:
jfrijters 2004-03-20 13:25:08 +00:00
Родитель 9a08682b9c
Коммит f13f93800a
14 изменённых файлов: 716 добавлений и 239 удалений

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

@ -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));
}
}
}
}

62
IK.VM.NET/CoreClasses.cs Normal file
Просмотреть файл

@ -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());
}
}