This commit is contained in:
jfrijters 2005-08-05 08:40:54 +00:00
Родитель e94332d37d
Коммит 41f7f8b1e6
7 изменённых файлов: 2007 добавлений и 1790 удалений

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

@ -233,7 +233,6 @@ enum NormalizedByteCode : byte
{
__nop = 0,
__aconst_null = 1,
__iconst = 255,
__lconst_0 = 9,
__lconst_1 = 10,
__fconst_0 = 11,
@ -379,7 +378,13 @@ enum NormalizedByteCode : byte
__multianewarray = 197,
__ifnull = 198,
__ifnonnull = 199,
__static_error = 254 // not a real instruction, this signals an instruction that is compiled as an exception
// This is where the pseudo-bytecodes start
__dynamic_invokeinterface = 250,
__dynamic_invokestatic = 251,
__dynamic_invokevirtual = 252,
__clone_array = 253,
__static_error = 254, // not a real instruction, this signals an instruction that is compiled as an exception
__iconst = 255
}
enum ByteCodeMode : byte
@ -493,8 +498,19 @@ struct ByteCodeMetaData
internal static bool CanThrowException(NormalizedByteCode bc)
{
// special case __iconst, because that's the only normalized opcode that doesn't correspond to a real opcode
return bc != NormalizedByteCode.__iconst && (data[(int)bc].flags & ByteCodeFlags.CannotThrow) == 0;
switch(bc)
{
case NormalizedByteCode.__dynamic_invokeinterface:
case NormalizedByteCode.__dynamic_invokestatic:
case NormalizedByteCode.__dynamic_invokevirtual:
case NormalizedByteCode.__clone_array:
case NormalizedByteCode.__static_error:
return true;
case NormalizedByteCode.__iconst:
return false;
default:
return (data[(int)bc].flags & ByteCodeFlags.CannotThrow) == 0;
}
}
static ByteCodeMetaData()

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

@ -2098,6 +2098,11 @@ namespace IKVM.Internal
}
}
internal void PatchOpCode(NormalizedByteCode bc)
{
this.normopcode = bc;
}
internal void SetTermNop(ushort pc)
{
// TODO what happens if we already have exactly the maximum number of instructions?

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

@ -786,6 +786,7 @@ namespace IKVM.Internal
internal static void FinishAll()
{
JVM.FinishingForDebugSave = true;
while(dynamicTypes.Count > 0)
{
ArrayList l = new ArrayList(dynamicTypes.Values);
@ -793,7 +794,7 @@ namespace IKVM.Internal
{
string name = tw.TypeAsTBD.FullName;
Tracer.Info(Tracer.Runtime, "Finishing {0}", name);
tw.Finish(true);
tw.Finish();
dynamicTypes.Remove(name);
}
}

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

@ -1496,12 +1496,7 @@ namespace IKVM.Internal
get;
}
internal void Finish()
{
Finish(false);
}
internal abstract void Finish(bool forDebugSave);
internal abstract void Finish();
private void ImplementInterfaceMethodStubImpl(MethodWrapper ifmethod, TypeBuilder typeBuilder, DynamicTypeWrapper wrapper)
{
@ -1964,7 +1959,7 @@ namespace IKVM.Internal
}
}
internal override void Finish(bool forDebugSave)
internal override void Finish()
{
throw new InvalidOperationException("Finish called on UnloadableTypeWrapper: " + Name);
}
@ -2059,7 +2054,7 @@ namespace IKVM.Internal
}
}
internal override void Finish(bool forDebugSave)
internal override void Finish()
{
}
@ -2302,14 +2297,14 @@ namespace IKVM.Internal
}
}
internal override void Finish(bool forDebugSave)
internal override void Finish()
{
lock(this)
{
Profiler.Enter("DynamicTypeWrapper.Finish");
try
{
impl = impl.Finish(forDebugSave);
impl = impl.Finish();
}
finally
{
@ -2339,7 +2334,7 @@ namespace IKVM.Internal
internal abstract TypeWrapper[] InnerClasses { get; }
internal abstract TypeWrapper DeclaringTypeWrapper { get; }
internal abstract Modifiers ReflectiveModifiers { get; }
internal abstract DynamicImpl Finish(bool forDebugSave);
internal abstract DynamicImpl Finish();
internal abstract MethodBase LinkMethod(MethodWrapper mw);
internal abstract FieldInfo LinkField(FieldWrapper fw);
}
@ -2352,7 +2347,6 @@ namespace IKVM.Internal
private MethodWrapper[] methods;
private MethodWrapper[] baseMethods;
private FieldWrapper[] fields;
private bool finishingForDebugSave;
private FinishedTypeImpl finishedType;
private readonly DynamicTypeWrapper outerClassWrapper;
private Hashtable memberclashtable;
@ -2843,9 +2837,9 @@ namespace IKVM.Internal
// check the loader constraints
if(mw.ReturnType != baseMethod.ReturnType)
{
if(baseMethod.ReturnType.IsUnloadable || finishingForDebugSave)
if(baseMethod.ReturnType.IsUnloadable || JVM.FinishingForDebugSave)
{
if(!mw.ReturnType.IsUnloadable || (!baseMethod.ReturnType.IsUnloadable && finishingForDebugSave))
if(!mw.ReturnType.IsUnloadable || (!baseMethod.ReturnType.IsUnloadable && JVM.FinishingForDebugSave))
{
unloadableOverrideStub = true;
}
@ -2861,9 +2855,9 @@ namespace IKVM.Internal
{
if(here[i] != there[i])
{
if(there[i].IsUnloadable || finishingForDebugSave)
if(there[i].IsUnloadable || JVM.FinishingForDebugSave)
{
if(!here[i].IsUnloadable || (!there[i].IsUnloadable && finishingForDebugSave))
if(!here[i].IsUnloadable || (!there[i].IsUnloadable && JVM.FinishingForDebugSave))
{
unloadableOverrideStub = true;
}
@ -3034,16 +3028,15 @@ namespace IKVM.Internal
return field;
}
internal override DynamicImpl Finish(bool forDebugSave)
internal override DynamicImpl Finish()
{
this.finishingForDebugSave = forDebugSave;
if(wrapper.BaseTypeWrapper != null)
{
wrapper.BaseTypeWrapper.Finish(forDebugSave);
wrapper.BaseTypeWrapper.Finish();
}
if(outerClassWrapper != null)
{
outerClassWrapper.Finish(forDebugSave);
outerClassWrapper.Finish();
}
// NOTE there is a bug in the CLR (.NET 1.0 & 1.1 [1.2 is not yet available]) that
// causes the AppDomain.TypeResolve event to receive the incorrect type name for nested types.
@ -3057,7 +3050,7 @@ namespace IKVM.Internal
// turned up no other cases of the TypeResolve event firing.
for(int i = 0; i < wrapper.Interfaces.Length; i++)
{
wrapper.Interfaces[i].Finish(forDebugSave);
wrapper.Interfaces[i].Finish();
}
// make sure all classes are loaded, before we start finishing the type. During finishing, we
// may not run any Java code, because that might result in a request to finish the type that we
@ -3868,7 +3861,7 @@ namespace IKVM.Internal
Debug.Assert(baseMethods[index].DeclaringType.IsInterface);
string name = GenerateUniqueMethodName(methods[index].Name, baseMethods[index]);
// TODO if the interface is not public, we probably shouldn't make the Miranda method public
MethodBuilder mb = typeBuilder.DefineMethod(methods[index].Name, MethodAttributes.NewSlot | MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Abstract | MethodAttributes.CheckAccessOnOverride, baseMethods[index].ReturnTypeForDefineMethod, baseMethods[index].GetParametersForDefineMethod());
MethodBuilder mb = typeBuilder.DefineMethod(methods[index].Name, MethodAttributes.NewSlot | MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Abstract | MethodAttributes.CheckAccessOnOverride, methods[index].ReturnTypeForDefineMethod, methods[index].GetParametersForDefineMethod());
AttributeHelper.MirandaMethod(mb);
if(unloadableOverrideStub || name != methods[index].Name)
{
@ -4069,20 +4062,23 @@ namespace IKVM.Internal
needFinalize = false;
}
}
if(unloadableOverrideStub)
{
attribs |= MethodAttributes.NewSlot;
}
if(setNameSig || memberclashtable != null)
{
// TODO we really should make sure that the name we generate doesn't already exist in a
// base class (not in the Java method namespace, but in the CLR method namespace)
name = GenerateUniqueMethodName(name, methods[index]);
}
bool needMethodImpl = baseMce != null && (explicitOverride || baseMce.RealName != name) && !needFinalize;
if(unloadableOverrideStub || needMethodImpl)
{
attribs |= MethodAttributes.NewSlot;
}
mb = typeBuilder.DefineMethod(name, attribs, methods[index].ReturnTypeForDefineMethod, methods[index].GetParametersForDefineMethod());
if(unloadableOverrideStub)
{
GenerateUnloadableOverrideStub(baseMce, mb, methods[index].ReturnTypeForDefineMethod, methods[index].GetParametersForDefineMethod());
}
else if(baseMce != null && (explicitOverride || baseMce.RealName != name) && !needFinalize)
else if(needMethodImpl)
{
// assert that the method we're overriding is in fact virtual and not final!
Debug.Assert(baseMce.GetMethod().IsVirtual && !baseMce.GetMethod().IsFinal);
@ -4286,7 +4282,7 @@ namespace IKVM.Internal
}
}
internal override DynamicImpl Finish(bool forDebugSave)
internal override DynamicImpl Finish()
{
return this;
}
@ -6139,7 +6135,7 @@ namespace IKVM.Internal
}
}
internal override void Finish(bool forDebugSave)
internal override void Finish()
{
}
}
@ -7250,7 +7246,7 @@ namespace IKVM.Internal
EmitHelper.Castclass(ilgen, type);
}
internal override void Finish(bool forDebugSave)
internal override void Finish()
{
// TODO instead of linking here, we should just pre-link in LazyPublishMembers
foreach(MethodWrapper mw in GetMethods())
@ -7278,13 +7274,21 @@ namespace IKVM.Internal
this.reflectiveModifiers = reflectiveModifiers;
}
internal static MethodInfo CloneMethod
{
get
{
if(clone == null)
{
clone = typeof(Array).GetMethod("Clone", BindingFlags.Public | BindingFlags.Instance, null, Type.EmptyTypes, null);
}
return clone;
}
}
protected override void LazyPublishMembers()
{
if(clone == null)
{
clone = typeof(Array).GetMethod("Clone", BindingFlags.Public | BindingFlags.Instance, null, Type.EmptyTypes, null);
}
MethodWrapper mw = new SimpleCallMethodWrapper(this, "clone", "()Ljava.lang.Object;", clone, CoreClasses.java.lang.Object.Wrapper, TypeWrapper.EmptyArray, Modifiers.Public, MemberFlags.HideFromReflection, SimpleOpCode.Callvirt, SimpleOpCode.Callvirt);
MethodWrapper mw = new SimpleCallMethodWrapper(this, "clone", "()Ljava.lang.Object;", CloneMethod, CoreClasses.java.lang.Object.Wrapper, TypeWrapper.EmptyArray, Modifiers.Public, MemberFlags.HideFromReflection, SimpleOpCode.Callvirt, SimpleOpCode.Callvirt);
mw.Link();
SetMethods(new MethodWrapper[] { mw });
SetFields(FieldWrapper.EmptyArray);
@ -7367,7 +7371,7 @@ namespace IKVM.Internal
}
}
internal override void Finish(bool forDebugSave)
internal override void Finish()
{
lock(this)
{

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -800,6 +800,14 @@ class InstructionState
return stack[stackSize - 1];
}
internal void MultiPopAnyType(int count)
{
while(count-- != 0)
{
PopAnyType();
}
}
internal TypeWrapper PopAnyType()
{
if(stackSize == 0)
@ -864,6 +872,11 @@ class InstructionState
return stack[stackSize - 1 - pos];
}
internal TypeWrapper GetStackByIndex(int index)
{
return stack[index];
}
private void PushHelper(TypeWrapper type)
{
if(type.IsWidePrimitive)
@ -962,6 +975,139 @@ class InstructionState
}
}
struct StackState
{
private InstructionState state;
private int sp;
internal StackState(InstructionState state)
{
this.state = state;
sp = state.GetStackHeight();
}
internal TypeWrapper PeekType()
{
if(sp == 0)
{
throw new VerifyError("Unable to pop operand off an empty stack");
}
return state.GetStackByIndex(sp - 1);
}
internal TypeWrapper PopAnyType()
{
if(sp == 0)
{
throw new VerifyError("Unable to pop operand off an empty stack");
}
return state.GetStackByIndex(--sp);
}
internal TypeWrapper PopType(TypeWrapper baseType)
{
if(baseType.IsIntOnStackPrimitive)
{
baseType = PrimitiveTypeWrapper.INT;
}
TypeWrapper type = PopAnyType();
if(VerifierTypeWrapper.IsNew(type) || type == VerifierTypeWrapper.UninitializedThis)
{
throw new VerifyError("Expecting to find object/array on stack");
}
if(type != baseType &&
!((type.IsUnloadable && !baseType.IsPrimitive) || (baseType.IsUnloadable && !type.IsPrimitive) ||
type.IsAssignableTo(baseType)))
{
// HACK because of the way interfaces references works, if baseType
// is an interface or array of interfaces, any reference will be accepted
if(baseType.IsInterfaceOrInterfaceArray && !type.IsPrimitive)
{
return type;
}
throw new VerifyError("Unexpected type " + type.Name + " where " + baseType.Name + " was expected");
}
return type;
}
// NOTE this can *not* be used to pop double or long
internal TypeWrapper PopType()
{
TypeWrapper type = PopAnyType();
if(type.IsWidePrimitive)
{
throw new VerifyError("Attempt to split long or double on the stack");
}
return type;
}
internal void PopInt()
{
if(PopAnyType() != PrimitiveTypeWrapper.INT)
{
throw new VerifyError("Int expected on stack");
}
}
internal void PopFloat()
{
if(PopAnyType() != PrimitiveTypeWrapper.FLOAT)
{
throw new VerifyError("Float expected on stack");
}
}
internal void PopDouble()
{
if(PopAnyType() != PrimitiveTypeWrapper.DOUBLE)
{
throw new VerifyError("Double expected on stack");
}
}
internal void PopLong()
{
if(PopAnyType() != PrimitiveTypeWrapper.LONG)
{
throw new VerifyError("Long expected on stack");
}
}
internal TypeWrapper PopArrayType()
{
TypeWrapper type = PopAnyType();
if(!VerifierTypeWrapper.IsNullOrUnloadable(type) && type.ArrayRank == 0)
{
throw new VerifyError("Array reference expected on stack");
}
return type;
}
// either null or an initialized object reference
internal TypeWrapper PopObjectType()
{
TypeWrapper type = PopAnyType();
if(type.IsPrimitive || VerifierTypeWrapper.IsNew(type) || type == VerifierTypeWrapper.UninitializedThis)
{
throw new VerifyError("Expected object reference on stack");
}
return type;
}
// null or an initialized object reference derived from baseType (or baseType)
internal TypeWrapper PopObjectType(TypeWrapper baseType)
{
TypeWrapper type = PopObjectType();
// HACK because of the way interfaces references works, if baseType
// is an interface or array of interfaces, any reference will be accepted
if(!baseType.IsUnloadable && !baseType.IsInterfaceOrInterfaceArray && !(type.IsUnloadable || type.IsAssignableTo(baseType)))
{
throw new VerifyError("Unexpected type " + type + " where " + baseType + " was expected");
}
return type;
}
}
// this is a container for the special verifier TypeWrappers
class VerifierTypeWrapper : TypeWrapper
{
@ -1071,7 +1217,7 @@ class VerifierTypeWrapper : TypeWrapper
}
}
internal override void Finish(bool forDebugSave)
internal override void Finish()
{
throw new InvalidOperationException("Finish called on " + this);
}
@ -1571,97 +1717,26 @@ class MethodAnalyzer
case NormalizedByteCode.__invokestatic:
{
ClassFile.ConstantPoolItemMI cpi = GetMethodref(instr.Arg1);
if((cpi is ClassFile.ConstantPoolItemInterfaceMethodref) != (instr.NormalizedOpCode == NormalizedByteCode.__invokeinterface))
{
throw new VerifyError("Illegal constant pool index");
}
if(instr.NormalizedOpCode != NormalizedByteCode.__invokespecial && cpi.Name == "<init>")
{
throw new VerifyError("Must call initializers using invokespecial");
}
if(cpi.Name == "<clinit>")
{
throw new VerifyError("Illegal call to internal method");
}
TypeWrapper[] args = cpi.GetArgTypes();
for(int j = args.Length - 1; j >= 0; j--)
{
s.PopType(args[j]);
}
if(instr.NormalizedOpCode == NormalizedByteCode.__invokeinterface)
{
int argcount = args.Length + 1;
for(int j = 0; j < args.Length; j++)
{
if(args[j].IsWidePrimitive)
{
argcount++;
}
}
if(instr.Arg2 != argcount)
{
throw new VerifyError("Inconsistent args size");
}
}
s.MultiPopAnyType(cpi.GetArgTypes().Length);
if(instr.NormalizedOpCode != NormalizedByteCode.__invokestatic)
{
TypeWrapper type = s.PopType();
if(cpi.Name == "<init>")
{
TypeWrapper type = s.PopType();
if((VerifierTypeWrapper.IsNew(type) && ((VerifierTypeWrapper)type).UnderlyingType != cpi.GetClassType()) ||
(type == VerifierTypeWrapper.UninitializedThis && cpi.GetClassType() != wrapper.BaseTypeWrapper && cpi.GetClassType() != wrapper) ||
(!VerifierTypeWrapper.IsNew(type) && type != VerifierTypeWrapper.UninitializedThis))
{
// TODO oddly enough, Java fails verification for the class without
// even running the constructor, so maybe constructors are always
// verified...
// NOTE when a constructor isn't verifiable, the static initializer
// doesn't run either (or so I believe)
throw new VerifyError("Call to wrong initialization method");
}
// after the constructor invocation, the uninitialized reference, is now
// suddenly initialized
// after we've invoked the constructor, the uninitialized references
// are now initialized
if(type == VerifierTypeWrapper.UninitializedThis)
{
s.MarkInitialized(type, wrapper, i);
s.SetUnitializedThis(false);
}
else
else if(VerifierTypeWrapper.IsNew(type))
{
s.MarkInitialized(type, ((VerifierTypeWrapper)type).UnderlyingType, i);
}
}
else
{
if(instr.NormalizedOpCode != NormalizedByteCode.__invokeinterface)
else
{
TypeWrapper refType = s.PopObjectType();
TypeWrapper targetType = cpi.GetClassType();
if(!VerifierTypeWrapper.IsNullOrUnloadable(refType) &&
!targetType.IsUnloadable &&
!refType.IsAssignableTo(targetType))
{
throw new VerifyError("Incompatible object argument for function call");
}
// for invokespecial we also need to make sure we're calling ourself or a base class
if(instr.NormalizedOpCode == NormalizedByteCode.__invokespecial)
{
if(!VerifierTypeWrapper.IsNullOrUnloadable(refType) && !refType.IsSubTypeOf(wrapper))
{
throw new VerifyError("Incompatible target object for invokespecial");
}
if(!targetType.IsUnloadable && !wrapper.IsSubTypeOf(targetType))
{
throw new VerifyError("Invokespecial cannot call subclass methods");
}
}
}
else /* __invokeinterface */
{
// NOTE previously we checked the type here, but it turns out that
// the JVM throws an IncompatibleClassChangeError at runtime instead
// of a VerifyError if this doesn't match
s.PopObjectType();
// This is a VerifyError, but it will be caught by our second pass
}
}
}
@ -2204,22 +2279,10 @@ class MethodAnalyzer
case NormalizedByteCode.__if_acmpne:
case NormalizedByteCode.__ifnull:
case NormalizedByteCode.__ifnonnull:
if(instr.Arg1 < 0)
{
// backward branches cannot have uninitialized objects on
// the stack or in local variables
s.CheckUninitializedObjRefs();
}
state[i + 1] += s;
state[method.PcIndexMap[instr.PC + instr.Arg1]] += s;
break;
case NormalizedByteCode.__goto:
if(instr.Arg1 < 0)
{
// backward branches cannot have uninitialized objects on
// the stack or in local variables
s.CheckUninitializedObjRefs();
}
state[method.PcIndexMap[instr.PC + instr.Arg1]] += s;
break;
case NormalizedByteCode.__jsr:
@ -2300,79 +2363,124 @@ class MethodAnalyzer
{
done = false;
instructions[i].flags |= InstructionFlags.Processed;
StackState stack = new StackState(state[i]);
switch(instructions[i].NormalizedOpCode)
{
case NormalizedByteCode.__invokeinterface:
case NormalizedByteCode.__invokespecial:
case NormalizedByteCode.__invokestatic:
case NormalizedByteCode.__invokevirtual:
VerifyInvoke(wrapper, ref instructions[i], stack);
break;
case NormalizedByteCode.__getfield:
case NormalizedByteCode.__putfield:
case NormalizedByteCode.__getstatic:
case NormalizedByteCode.__putstatic:
VerifyFieldAccess(wrapper, mw, ref instructions[i], stack);
break;
case NormalizedByteCode.__ldc:
if(classFile.GetConstantPoolConstantType(instructions[i].Arg1) == ClassFile.ConstantType.Class)
{
TypeWrapper tw = classFile.GetConstantPoolClassType(instructions[i].Arg1);
if(tw.IsUnloadable && JVM.DisableDynamicBinding)
{
instructions[i].SetHardError(HardError.NoClassDefFoundError, AllocErrorMessage(tw.Name));
}
}
break;
case NormalizedByteCode.__new:
{
ClassFile.ConstantPoolItemMI cpi = GetMethodref(instructions[i].Arg1);
if((cpi is ClassFile.ConstantPoolItemInterfaceMethodref) != (instructions[i].NormalizedOpCode == NormalizedByteCode.__invokeinterface))
TypeWrapper tw = classFile.GetConstantPoolClassType(instructions[i].Arg1);
if(tw.IsUnloadable)
{
throw new VerifyError("Illegal constant pool index");
}
if(instructions[i].NormalizedOpCode != NormalizedByteCode.__invokespecial && cpi.Name == "<init>")
{
throw new VerifyError("Must call initializers using invokespecial");
}
if(cpi.Name == "<clinit>")
{
throw new VerifyError("Illegal call to internal method");
}
NormalizedByteCode invoke = instructions[i].NormalizedOpCode;
TypeWrapper thisType;
if(invoke == NormalizedByteCode.__invokestatic)
{
thisType = null;
}
else
{
thisType = SigTypeToClassName(GetRawStackTypeWrapper(i, cpi.GetArgTypes().Length), cpi.GetClassType(), wrapper);
}
MethodWrapper targetMethod = invoke == NormalizedByteCode.__invokespecial ? cpi.GetMethodForInvokespecial() : cpi.GetMethod();
if(targetMethod != null)
{
string errmsg = CheckLoaderConstraints(cpi, targetMethod);
if(errmsg != null)
if(JVM.DisableDynamicBinding)
{
instructions[i].SetHardError(HardError.LinkageError, AllocErrorMessage(errmsg));
instructions[i].SetHardError(HardError.NoClassDefFoundError, AllocErrorMessage(tw.Name));
}
else if(targetMethod.IsStatic == (invoke == NormalizedByteCode.__invokestatic))
}
else if(!tw.IsAccessibleFrom(wrapper))
{
instructions[i].SetHardError(HardError.IllegalAccessError, AllocErrorMessage("Try to access class " + tw.Name + " from class " + wrapper.Name));
}
else if(tw.IsAbstract)
{
instructions[i].SetHardError(HardError.InstantiationError, AllocErrorMessage(tw.Name));
}
break;
}
case NormalizedByteCode.__multianewarray:
case NormalizedByteCode.__anewarray:
{
TypeWrapper tw = classFile.GetConstantPoolClassType(instructions[i].Arg1);
if(tw.IsUnloadable)
{
if(JVM.DisableDynamicBinding)
{
if(targetMethod.IsAbstract && invoke == NormalizedByteCode.__invokespecial)
{
instructions[i].SetHardError(HardError.AbstractMethodError, AllocErrorMessage(cpi.Class + "." + cpi.Name + cpi.Signature));
}
else if(targetMethod.IsAccessibleFrom(cpi.GetClassType(), wrapper, thisType))
{
break;
}
else
{
// NOTE special case for incorrect invocation of Object.clone(), because this could mean
// we're calling clone() on an array
// (bug in javac, see http://developer.java.sun.com/developer/bugParade/bugs/4329886.html)
if(cpi.GetClassType() == CoreClasses.java.lang.Object.Wrapper && thisType.IsArray && cpi.Name == "clone")
{
// NOTE since thisType is an array, we can be sure that the method is already linked
targetMethod = thisType.GetMethodWrapper(cpi.Name, cpi.Signature, false);
if(targetMethod != null && targetMethod.IsPublic)
{
break;
}
}
instructions[i].SetHardError(HardError.IllegalAccessError, AllocErrorMessage("Try to access method " + targetMethod.DeclaringType.Name + "." + cpi.Name + cpi.Signature + " from class " + wrapper.Name));
}
instructions[i].SetHardError(HardError.NoClassDefFoundError, AllocErrorMessage(tw.Name));
}
else
}
else if(!tw.IsAccessibleFrom(wrapper))
{
instructions[i].SetHardError(HardError.IllegalAccessError, AllocErrorMessage("Try to access class " + tw.Name + " from class " + wrapper.Name));
}
break;
}
case NormalizedByteCode.__checkcast:
case NormalizedByteCode.__instanceof:
{
TypeWrapper tw = classFile.GetConstantPoolClassType(instructions[i].Arg1);
if(tw.IsUnloadable)
{
// If the type is unloadable, we always generate the dynamic code
// (regardless of JVM.DisableDynamicBinding), because at runtime,
// null references should always pass thru without attempting
// to load the type (for Sun compatibility).
}
else if(!tw.IsAccessibleFrom(wrapper))
{
instructions[i].SetHardError(HardError.IllegalAccessError, AllocErrorMessage("Try to access class " + tw.Name + " from class " + wrapper.Name));
}
break;
}
case NormalizedByteCode.__aaload:
{
stack.PopInt();
TypeWrapper tw = stack.PopArrayType();
if(tw == VerifierTypeWrapper.Null)
{
}
else if(tw.IsUnloadable)
{
if(JVM.DisableDynamicBinding)
{
instructions[i].SetHardError(HardError.IncompatibleClassChangeError, AllocErrorMessage("static call to non-static method (or v.v.)"));
instructions[i].SetHardError(HardError.NoClassDefFoundError, AllocErrorMessage(tw.Name));
}
}
else
{
instructions[i].SetHardError(HardError.NoSuchMethodError, AllocErrorMessage(cpi.Class + "." + cpi.Name + cpi.Signature));
tw = tw.ElementTypeWrapper;
if(tw.IsPrimitive)
{
throw new VerifyError("Object array expected");
}
}
break;
}
case NormalizedByteCode.__aastore:
{
stack.PopObjectType();
stack.PopInt();
TypeWrapper tw = stack.PopArrayType();
if(tw.IsUnloadable)
{
if(JVM.DisableDynamicBinding)
{
instructions[i].SetHardError(HardError.NoClassDefFoundError, AllocErrorMessage(tw.Name));
}
}
else
{
// TODO do we need any other tests?
}
break;
}
@ -2392,13 +2500,30 @@ class MethodAnalyzer
{
case NormalizedByteCode.__tableswitch:
case NormalizedByteCode.__lookupswitch:
{
bool hasbackbranch = false;
for(int j = 0; j < instructions[i].SwitchEntryCount; j++)
{
hasbackbranch |= instructions[i].GetSwitchTargetOffset(j) < 0;
instructions[method.PcIndexMap[instructions[i].PC + instructions[i].GetSwitchTargetOffset(j)]].flags |= InstructionFlags.Reachable | InstructionFlags.BranchTarget;
}
hasbackbranch |= instructions[i].DefaultOffset < 0;
instructions[method.PcIndexMap[instructions[i].PC + instructions[i].DefaultOffset]].flags |= InstructionFlags.Reachable | InstructionFlags.BranchTarget;
if(hasbackbranch)
{
// backward branches cannot have uninitialized objects on
// the stack or in local variables
state[i].CheckUninitializedObjRefs();
}
break;
}
case NormalizedByteCode.__goto:
if(instructions[i].Arg1 < 0)
{
// backward branches cannot have uninitialized objects on
// the stack or in local variables
state[i].CheckUninitializedObjRefs();
}
instructions[method.PcIndexMap[instructions[i].PC + instructions[i].Arg1]].flags |= InstructionFlags.Reachable | InstructionFlags.BranchTarget;
break;
case NormalizedByteCode.__ifeq:
@ -2417,10 +2542,17 @@ class MethodAnalyzer
case NormalizedByteCode.__if_acmpne:
case NormalizedByteCode.__ifnull:
case NormalizedByteCode.__ifnonnull:
if(instructions[i].Arg1 < 0)
{
// backward branches cannot have uninitialized objects on
// the stack or in local variables
state[i].CheckUninitializedObjRefs();
}
instructions[method.PcIndexMap[instructions[i].PC + instructions[i].Arg1]].flags |= InstructionFlags.Reachable | InstructionFlags.BranchTarget;
instructions[i + 1].flags |= InstructionFlags.Reachable;
break;
case NormalizedByteCode.__jsr:
// TODO should we check for unitialized objects?
instructions[method.PcIndexMap[instructions[i].PC + instructions[i].Arg1]].flags |= InstructionFlags.Reachable | InstructionFlags.BranchTarget;
didjsr = true;
break;
@ -2585,6 +2717,300 @@ class MethodAnalyzer
this.allLocalVars = (LocalVar[])locals.ToArray(typeof(LocalVar));
}
private void VerifyInvoke(TypeWrapper wrapper, ref ClassFile.Method.Instruction instr, StackState stack)
{
ClassFile.ConstantPoolItemMI cpi = GetMethodref(instr.Arg1);
if((cpi is ClassFile.ConstantPoolItemInterfaceMethodref) != (instr.NormalizedOpCode == NormalizedByteCode.__invokeinterface))
{
throw new VerifyError("Illegal constant pool index");
}
if(instr.NormalizedOpCode != NormalizedByteCode.__invokespecial && cpi.Name == "<init>")
{
throw new VerifyError("Must call initializers using invokespecial");
}
if(cpi.Name == "<clinit>")
{
throw new VerifyError("Illegal call to internal method");
}
NormalizedByteCode invoke = instr.NormalizedOpCode;
TypeWrapper[] args = cpi.GetArgTypes();
for(int j = args.Length - 1; j >= 0; j--)
{
stack.PopType(args[j]);
}
if(invoke == NormalizedByteCode.__invokeinterface)
{
int argcount = args.Length + 1;
for(int j = 0; j < args.Length; j++)
{
if(args[j].IsWidePrimitive)
{
argcount++;
}
}
if(instr.Arg2 != argcount)
{
throw new VerifyError("Inconsistent args size");
}
}
TypeWrapper thisType;
if(invoke == NormalizedByteCode.__invokestatic)
{
thisType = null;
}
else
{
thisType = SigTypeToClassName(stack.PeekType(), cpi.GetClassType(), wrapper);
if(cpi.Name == "<init>")
{
TypeWrapper type = stack.PopType();
if((VerifierTypeWrapper.IsNew(type) && ((VerifierTypeWrapper)type).UnderlyingType != cpi.GetClassType()) ||
(type == VerifierTypeWrapper.UninitializedThis && cpi.GetClassType() != wrapper.BaseTypeWrapper && cpi.GetClassType() != wrapper) ||
(!VerifierTypeWrapper.IsNew(type) && type != VerifierTypeWrapper.UninitializedThis))
{
// TODO oddly enough, Java fails verification for the class without
// even running the constructor, so maybe constructors are always
// verified...
// NOTE when a constructor isn't verifiable, the static initializer
// doesn't run either (or so I believe)
throw new VerifyError("Call to wrong initialization method");
}
}
else
{
if(invoke != NormalizedByteCode.__invokeinterface)
{
TypeWrapper refType = stack.PopObjectType();
TypeWrapper targetType = cpi.GetClassType();
if(!VerifierTypeWrapper.IsNullOrUnloadable(refType) &&
!targetType.IsUnloadable &&
!refType.IsAssignableTo(targetType))
{
throw new VerifyError("Incompatible object argument for function call");
}
// for invokespecial we also need to make sure we're calling ourself or a base class
if(invoke == NormalizedByteCode.__invokespecial)
{
if(!VerifierTypeWrapper.IsNullOrUnloadable(refType) && !refType.IsSubTypeOf(wrapper))
{
throw new VerifyError("Incompatible target object for invokespecial");
}
if(!targetType.IsUnloadable && !wrapper.IsSubTypeOf(targetType))
{
throw new VerifyError("Invokespecial cannot call subclass methods");
}
}
}
else /* __invokeinterface */
{
// NOTE previously we checked the type here, but it turns out that
// the JVM throws an IncompatibleClassChangeError at runtime instead
// of a VerifyError if this doesn't match
stack.PopObjectType();
}
}
}
if(cpi.GetClassType().IsUnloadable || (thisType != null && thisType.IsUnloadable))
{
if(JVM.DisableDynamicBinding)
{
instr.SetHardError(HardError.NoClassDefFoundError, AllocErrorMessage(cpi.GetClassType().Name));
}
else
{
switch(invoke)
{
case NormalizedByteCode.__invokeinterface:
instr.PatchOpCode(NormalizedByteCode.__dynamic_invokeinterface);
break;
case NormalizedByteCode.__invokestatic:
instr.PatchOpCode(NormalizedByteCode.__dynamic_invokestatic);
break;
case NormalizedByteCode.__invokevirtual:
instr.PatchOpCode(NormalizedByteCode.__dynamic_invokevirtual);
break;
case NormalizedByteCode.__invokespecial:
instr.SetHardError(HardError.LinkageError, AllocErrorMessage("Base class no longer loadable"));
break;
default:
throw new InvalidOperationException();
}
}
}
else if(cpi.GetClassType().IsInterface != (invoke == NormalizedByteCode.__invokeinterface))
{
instr.SetHardError(HardError.IncompatibleClassChangeError, AllocErrorMessage("invokeinterface on non-interface"));
}
else
{
MethodWrapper targetMethod = invoke == NormalizedByteCode.__invokespecial ? cpi.GetMethodForInvokespecial() : cpi.GetMethod();
if(targetMethod != null)
{
string errmsg = CheckLoaderConstraints(cpi, targetMethod);
if(errmsg != null)
{
instr.SetHardError(HardError.LinkageError, AllocErrorMessage(errmsg));
}
else if(targetMethod.IsStatic == (invoke == NormalizedByteCode.__invokestatic))
{
if(targetMethod.IsAbstract && invoke == NormalizedByteCode.__invokespecial)
{
instr.SetHardError(HardError.AbstractMethodError, AllocErrorMessage(cpi.Class + "." + cpi.Name + cpi.Signature));
}
else if(targetMethod.IsAccessibleFrom(cpi.GetClassType(), wrapper, thisType))
{
return;
}
else
{
// NOTE special case for incorrect invocation of Object.clone(), because this could mean
// we're calling clone() on an array
// (bug in javac, see http://developer.java.sun.com/developer/bugParade/bugs/4329886.html)
if(cpi.GetClassType() == CoreClasses.java.lang.Object.Wrapper && thisType.IsArray && cpi.Name == "clone")
{
// Patch the instruction, so that the compiler doesn't need to do this test again.
instr.PatchOpCode(NormalizedByteCode.__clone_array);
return;
}
instr.SetHardError(HardError.IllegalAccessError, AllocErrorMessage("Try to access method " + targetMethod.DeclaringType.Name + "." + cpi.Name + cpi.Signature + " from class " + wrapper.Name));
}
}
else
{
instr.SetHardError(HardError.IncompatibleClassChangeError, AllocErrorMessage("static call to non-static method (or v.v.)"));
}
}
else
{
instr.SetHardError(HardError.NoSuchMethodError, AllocErrorMessage(cpi.Class + "." + cpi.Name + cpi.Signature));
}
}
}
private void VerifyFieldAccess(TypeWrapper wrapper, MethodWrapper mw, ref ClassFile.Method.Instruction instr, StackState stack)
{
ClassFile.ConstantPoolItemFieldref cpi = classFile.GetFieldref(instr.Arg1);
bool isStatic;
bool write;
TypeWrapper thisType;
switch(instr.NormalizedOpCode)
{
case NormalizedByteCode.__getfield:
isStatic = false;
write = false;
thisType = SigTypeToClassName(stack.PopObjectType(GetFieldref(instr.Arg1).GetClassType()), cpi.GetClassType(), wrapper);
break;
case NormalizedByteCode.__putfield:
stack.PopType(GetFieldref(instr.Arg1).GetFieldType());
isStatic = false;
write = true;
// putfield is allowed to access the unintialized this
if(stack.PeekType() == VerifierTypeWrapper.UninitializedThis
&& wrapper.IsAssignableTo(GetFieldref(instr.Arg1).GetClassType()))
{
thisType = wrapper;
}
else
{
thisType = SigTypeToClassName(stack.PopObjectType(GetFieldref(instr.Arg1).GetClassType()), cpi.GetClassType(), wrapper);
}
break;
case NormalizedByteCode.__getstatic:
isStatic = true;
write = false;
thisType = null;
break;
case NormalizedByteCode.__putstatic:
// special support for when we're being called from IsSideEffectFreeStaticInitializer
if(mw == null)
{
switch(GetFieldref(instr.Arg1).Signature[0])
{
case 'B':
case 'Z':
case 'C':
case 'S':
case 'I':
stack.PopInt();
break;
case 'F':
stack.PopFloat();
break;
case 'D':
stack.PopDouble();
break;
case 'J':
stack.PopLong();
break;
case 'L':
case '[':
if(stack.PopAnyType() != VerifierTypeWrapper.Null)
{
throw new VerifyError();
}
break;
default:
throw new InvalidOperationException();
}
}
else
{
stack.PopType(GetFieldref(instr.Arg1).GetFieldType());
}
isStatic = true;
write = true;
thisType = null;
break;
default:
throw new InvalidOperationException();
}
if(mw == null)
{
// We're being called from IsSideEffectFreeStaticInitializer,
// no further checks are possible (nor needed).
}
else if(cpi.GetClassType().IsUnloadable)
{
if(JVM.DisableDynamicBinding)
{
instr.SetHardError(HardError.NoClassDefFoundError, AllocErrorMessage(cpi.GetClassType().Name));
return;
}
}
else
{
FieldWrapper field = cpi.GetField();
if(field == null)
{
instr.SetHardError(HardError.NoSuchFieldError, AllocErrorMessage(cpi.Class + "." + cpi.Name));
return;
}
if(cpi.GetFieldType() != field.FieldTypeWrapper && !field.FieldTypeWrapper.IsUnloadable)
{
instr.SetHardError(HardError.LinkageError, AllocErrorMessage("Loader constraints violated: " + field.DeclaringType.Name + "." + field.Name));
return;
}
if(field.IsStatic != isStatic)
{
instr.SetHardError(HardError.IncompatibleClassChangeError, AllocErrorMessage("Static field access to non-static field (or v.v.)"));
return;
}
if(!field.IsAccessibleFrom(cpi.GetClassType(), wrapper, thisType))
{
instr.SetHardError(HardError.IllegalAccessError, AllocErrorMessage("Try to access field " + field.DeclaringType.Name + "." + field.Name + " from class " + wrapper.Name));
return;
}
// are we trying to mutate a final field? (they are read-only from outside of the defining class)
if(write && field.IsFinal
&& ((isStatic ? wrapper != cpi.GetClassType() : wrapper != thisType) || (JVM.StrictFinalFieldSemantics && (isStatic ? (mw != null && mw.Name != "<clinit>") : (mw == null || mw.Name != "<init>")))))
{
instr.SetHardError(HardError.IllegalAccessError, AllocErrorMessage("Field " + field.DeclaringType.Name + "." + field.Name + " is final"));
return;
}
}
}
// TODO this method should have a better name
private TypeWrapper SigTypeToClassName(TypeWrapper type, TypeWrapper nullType, TypeWrapper wrapper)
{

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

@ -291,6 +291,7 @@ namespace IKVM.Internal
private static bool enableReflectionOnMethodsWithUnloadableTypeParameters;
private static ikvm.@internal.LibraryVMInterface lib;
private static bool strictFinalFieldSemantics;
private static bool finishingForDebugSave;
internal static Version SafeGetAssemblyVersion(Assembly asm)
{
@ -454,6 +455,18 @@ namespace IKVM.Internal
}
}
internal static bool FinishingForDebugSave
{
get
{
return finishingForDebugSave;
}
set
{
finishingForDebugSave = value;
}
}
internal static bool CompileInnerClassesAsNestedTypes
{
get
@ -1969,7 +1982,7 @@ namespace IKVM.Internal
}
}
internal override void Finish(bool forDebugSave)
internal override void Finish()
{
}