This commit is contained in:
jfrijters 2003-01-06 13:56:37 +00:00
Родитель eef60b5726
Коммит 98df8c2fbe
9 изменённых файлов: 1512 добавлений и 1256 удалений

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

@ -49,9 +49,10 @@ class ClassFile
{
private ConstantPoolItem[] constantpool;
private Modifiers access_flags;
private string name;
private string supername;
private string[] interfaces;
private ConstantPoolItemClass this_cpi;
private ConstantPoolItemClass super_cpi;
private ConstantPoolItemClass[] interfaces;
private TypeWrapper[] interfaceTypeWrappers;
private Field[] fields;
private Method[] methods;
private Attribute[] attributes;
@ -114,7 +115,7 @@ class ClassFile
int this_class = br.ReadUInt16();
try
{
name = ((ConstantPoolItemClass)constantpool[this_class]).Name;
this_cpi = (ConstantPoolItemClass)constantpool[this_class];
}
catch(Exception)
{
@ -127,7 +128,7 @@ class ClassFile
{
try
{
supername = ((ConstantPoolItemClass)constantpool[super_class]).Name;
super_cpi = (ConstantPoolItemClass)constantpool[super_class];
}
catch(Exception)
{
@ -141,12 +142,12 @@ class ClassFile
throw JavaException.ClassFormatError("{0} (Bad superclass index)", Name);
}
}
if(IsInterface && (super_class == 0 || supername != "java/lang/Object"))
if(IsInterface && (super_class == 0 || super_cpi.Name != "java/lang/Object"))
{
throw JavaException.ClassFormatError("{0} (Interfaces must have java.lang.Object as superclass)", Name);
}
int interfaces_count = br.ReadUInt16();
interfaces = new string[interfaces_count];
interfaces = new ConstantPoolItemClass[interfaces_count];
Hashtable interfaceNames = new Hashtable();
for(int i = 0; i < interfaces_count; i++)
{
@ -160,7 +161,7 @@ class ClassFile
{
throw JavaException.ClassFormatError("{0} (Interface name has bad constant type)", Name);
}
interfaces[i] = ((ConstantPoolItemClass)GetConstantPoolItem(index)).Name;
interfaces[i] = (ConstantPoolItemClass)GetConstantPoolItem(index);
if(interfaceNames.ContainsKey(interfaces[i]))
{
throw JavaException.ClassFormatError("{0} (Repetitive interface name)", Name);
@ -321,6 +322,11 @@ class ClassFile
return ((ConstantPoolItemClass)constantpool[index]).Name;
}
internal TypeWrapper GetConstantPoolClassType(int index, ClassLoaderWrapper classLoader)
{
return ((ConstantPoolItemClass)constantpool[index]).GetClassType(classLoader);
}
private string GetConstantPoolString(int index)
{
return ((ConstantPoolItemString)constantpool[index]).Value;
@ -364,7 +370,7 @@ class ClassFile
{
get
{
return name;
return this_cpi.Name;
}
}
@ -372,6 +378,7 @@ class ClassFile
{
get
{
string name = Name;
int index = name.LastIndexOf('/');
if(index == -1)
{
@ -381,11 +388,16 @@ class ClassFile
}
}
internal TypeWrapper GetSuperTypeWrapper(ClassLoaderWrapper classLoader)
{
return super_cpi.GetClassType(classLoader);
}
internal string SuperClass
{
get
{
return supername;
return super_cpi.Name;
}
}
@ -405,11 +417,31 @@ class ClassFile
}
}
internal TypeWrapper[] GetInterfaceTypeWrappers(ClassLoaderWrapper classLoader)
{
if(interfaceTypeWrappers == null)
{
TypeWrapper[] tw = new TypeWrapper[interfaces.Length];
for(int i = 0; i < tw.Length; i++)
{
tw[i] = interfaces[i].GetClassType(classLoader);
}
interfaceTypeWrappers = tw;
}
return interfaceTypeWrappers;
}
// TODO this is legacy and needs to be removed in the future
internal string[] Interfaces
{
get
{
return interfaces;
string[] s = new string[interfaces.Length];
for(int i = 0; i < s.Length; i++)
{
s[i] = interfaces[i].Name;
}
return s;
}
}
@ -539,12 +571,113 @@ class ClassFile
{
if(typeWrapper == null)
{
typeWrapper = classLoader.LoadClassBySlashedName(name);
typeWrapper = LoadClassHelper(classLoader, name);
}
return typeWrapper;
}
}
private static TypeWrapper LoadClassHelper(ClassLoaderWrapper classLoader, string name)
{
try
{
return classLoader.LoadClassBySlashedName(name);
}
catch(Exception)
{
// TODO consider what to do with this error, may be a command line switch?
// TODO it might not be a good idea to catch .NET system exceptions here
return new UnloadableTypeWrapper(name);
}
}
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 new TypeWrapper[0];
}
ArrayList list = new ArrayList();
for(int i = 1; sig[i] != ')';)
{
list.Add(SigDecoderWrapper(classLoader, ref i, sig));
}
TypeWrapper[] types = new TypeWrapper[list.Count];
list.CopyTo(types);
return types;
}
private static TypeWrapper RetTypeWrapperFromSig(ClassLoaderWrapper classLoader, string sig)
{
int index = sig.IndexOf(')') + 1;
return SigDecoderWrapper(classLoader, ref index, sig);
}
private class ConstantPoolItemDouble : ConstantPoolItem
{
private double d;
@ -628,6 +761,11 @@ class ClassFile
{
return name_and_type.GetRetType(classLoader);
}
internal TypeWrapper GetFieldType(ClassLoaderWrapper classLoader)
{
return name_and_type.GetFieldType(classLoader);
}
}
internal class ConstantPoolItemFieldref : ConstantPoolItemFMI
@ -772,7 +910,7 @@ class ClassFile
{
if(argTypeWrappers == null)
{
argTypeWrappers = classLoader.ArgTypeWrapperListFromSig(descriptor);
argTypeWrappers = ArgTypeWrapperListFromSig(classLoader, descriptor);
}
return argTypeWrappers;
}
@ -781,7 +919,7 @@ class ClassFile
{
if(retTypeWrapper == null)
{
retTypeWrapper = classLoader.RetTypeWrapperFromSig(descriptor);
retTypeWrapper = RetTypeWrapperFromSig(classLoader, descriptor);
}
return retTypeWrapper;
}
@ -790,7 +928,8 @@ class ClassFile
{
if(fieldTypeWrapper == null)
{
fieldTypeWrapper = classLoader.RetTypeWrapperFromSig("()" + descriptor);
// HACK
fieldTypeWrapper = RetTypeWrapperFromSig(classLoader, "()" + descriptor);
}
return fieldTypeWrapper;
}
@ -920,6 +1059,9 @@ class ClassFile
private ushort name_index;
private ushort descriptor_index;
private Attribute[] attributes;
private TypeWrapper[] argTypeWrappers;
private TypeWrapper retTypeWrapper;
private TypeWrapper fieldTypeWrapper;
internal FieldOrMethod(ClassFile classFile, BigEndianBinaryReader br)
{
@ -953,6 +1095,34 @@ class ClassFile
}
}
internal TypeWrapper[] GetArgTypes(ClassLoaderWrapper classLoader)
{
if(argTypeWrappers == null)
{
argTypeWrappers = ArgTypeWrapperListFromSig(classLoader, Signature);
}
return argTypeWrappers;
}
internal TypeWrapper GetRetType(ClassLoaderWrapper classLoader)
{
if(retTypeWrapper == null)
{
retTypeWrapper = RetTypeWrapperFromSig(classLoader, Signature);
}
return retTypeWrapper;
}
internal TypeWrapper GetFieldType(ClassLoaderWrapper classLoader)
{
if(fieldTypeWrapper == null)
{
// HACK
fieldTypeWrapper = RetTypeWrapperFromSig(classLoader, "()" + Signature);
}
return fieldTypeWrapper;
}
internal Modifiers Modifiers
{
get

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

@ -128,9 +128,9 @@ class ClassLoaderWrapper
{
nativeMethods = new Hashtable();
// TODO interfaces have java/lang/Object as the base type (do they really?)
types["java.lang.Cloneable"] = new RemappedTypeWrapper(ModifiersAttribute.GetModifiers(typeof(java.lang.Cloneable)), "java/lang/Cloneable", typeof(java.lang.Cloneable), new TypeWrapper[0], null);
types["java.lang.Cloneable"] = new RemappedTypeWrapper(this, ModifiersAttribute.GetModifiers(typeof(java.lang.Cloneable)), "java/lang/Cloneable", typeof(java.lang.Cloneable), new TypeWrapper[0], null);
typeToTypeWrapper.Add(typeof(java.lang.Cloneable), types["java.lang.Cloneable"]);
types["java.io.Serializable"] = new RemappedTypeWrapper(ModifiersAttribute.GetModifiers(typeof(java.io.Serializable)), "java/io/Serializable", typeof(java.io.Serializable), new TypeWrapper[0], null);
types["java.io.Serializable"] = new RemappedTypeWrapper(this, ModifiersAttribute.GetModifiers(typeof(java.io.Serializable)), "java/io/Serializable", typeof(java.io.Serializable), new TypeWrapper[0], null);
typeToTypeWrapper.Add(typeof(java.io.Serializable), types["java.io.Serializable"]);
MapXml.Root map = null;
using(Stream s = Assembly.GetExecutingAssembly().GetManifestResourceStream("map.xml"))
@ -151,7 +151,7 @@ class ClassLoaderWrapper
string name = c.Name;
Modifiers modifiers = (Modifiers)c.Modifiers;
// TODO specify interfaces
TypeWrapper tw = new RemappedTypeWrapper(modifiers, name.Replace('.', '/'), Type.GetType(c.Type, true), new TypeWrapper[0], baseWrapper);
TypeWrapper tw = new RemappedTypeWrapper(this, modifiers, name.Replace('.', '/'), Type.GetType(c.Type, true), new TypeWrapper[0], baseWrapper);
types.Add(name, tw);
typeToTypeWrapper.Add(tw.Type, tw);
}
@ -365,7 +365,7 @@ class ClassLoaderWrapper
MethodDescriptor mdClone = new MethodDescriptor(GetBootstrapClassLoader(), "clone", "()Ljava/lang/Object;");
Modifiers modifiers = Modifiers.Final | Modifiers.Public;
// TODO copy accessibility from element type
wrapper = new RemappedTypeWrapper(modifiers, name, array, interfaces, GetBootstrapClassLoader().LoadClassByDottedName("java.lang.Object"));
wrapper = new RemappedTypeWrapper(this, modifiers, name, array, interfaces, GetBootstrapClassLoader().LoadClassByDottedName("java.lang.Object"));
MethodInfo clone = typeof(Array).GetMethod("Clone");
MethodWrapper mw = new MethodWrapper(wrapper, mdClone, clone, Modifiers.Public);
mw.EmitCall = CodeEmitter.Create(OpCodes.Callvirt, clone);
@ -415,7 +415,7 @@ class ClassLoaderWrapper
}
else
{
type = new DynamicTypeWrapper(f.Name, f, baseType, this, nativeMethods);
type = new DynamicTypeWrapper(f, this, nativeMethods);
dynamicTypes.Add(f.Name.Replace('/', '.'), type);
}
types.Add(f.Name.Replace('/', '.'), type);
@ -526,19 +526,18 @@ class ClassLoaderWrapper
return moduleBuilder;
}
internal Type ExpressionType(string type)
internal TypeWrapper ExpressionTypeWrapper(string type)
{
// HACK to ease the burden of the compiler, we support the Lret pseudo type here
if(type.StartsWith("Lret;"))
{
return typeof(int);
throw new InvalidOperationException("ExpressionTypeWrapper for Lret; requested");
}
if(type == "Lnull")
{
throw new InvalidOperationException("ExpressionType for Lnull requested");
throw new InvalidOperationException("ExpressionTypeWrapper for Lnull requested");
}
int index = 0;
return SigDecoder(ref index, type);
return SigDecoderWrapper(ref index, type);
}
// NOTE: this will ignore anything following the sig marker (so that it can be used to decode method signatures)
@ -713,66 +712,6 @@ class ClassLoaderWrapper
return types;
}
// subType and baseType are Java class name (e.g. java/lang/Object)
internal bool IsSubType(string subType, string baseType)
{
return LoadClassBySlashedName(subType).IsSubTypeOf(LoadClassBySlashedName(baseType));
}
internal string FindCommonBaseType(string type1, string type2)
{
TypeWrapper t1 = LoadClassBySlashedName(type1);
TypeWrapper t2 = LoadClassBySlashedName(type2);
if(t1 == t2)
{
return type1;
}
if(t1.IsInterface || t2.IsInterface)
{
// TODO I don't know how finding the common base for interfaces is defined, but
// for now I'm just doing the naive thing
// UPDATE according to a paper by Alessandro Coglio & Allen Goldberg titled
// "Type Safety in the JVM: Some Problems in Java 2 SDK 1.2 and Proposed Solutions"
// the common base of two interfaces is java/lang/Object, and there is special
// treatment for java/lang/Object types that allow it to be assigned to any interface
// type, the JVM's typesafety then depends on the invokeinterface instruction to make
// sure that the reference actually implements the interface.
// So strictly speaking, the code below isn't correct, but it works, so for now it stays in.
if(t1.ImplementsInterface(t2))
{
return t2.Name;
}
if(t2.ImplementsInterface(t1))
{
return t1.Name;
}
return "java/lang/Object";
}
Stack st1 = new Stack();
Stack st2 = new Stack();
while(t1 != null)
{
st1.Push(t1);
t1 = t1.BaseTypeWrapper;
}
while(t2 != null)
{
st2.Push(t2);
t2 = t2.BaseTypeWrapper;
}
TypeWrapper type = null;
for(;;)
{
t1 = st1.Count > 0 ? (TypeWrapper)st1.Pop() : null;
t2 = st2.Count > 0 ? (TypeWrapper)st2.Pop() : null;
if(t1 != t2)
{
return type.Name;
}
type = t1;
}
}
internal static ClassLoaderWrapper GetBootstrapClassLoader()
{
if(bootstrapClassLoader == null)
@ -821,7 +760,26 @@ class ClassLoaderWrapper
internal static TypeWrapper GetWrapperFromTypeFast(Type type)
{
Debug.Assert(!(type is TypeBuilder));
return (TypeWrapper)typeToTypeWrapper[type];
TypeWrapper wrapper = (TypeWrapper)typeToTypeWrapper[type];
if(wrapper == null && type.IsArray)
{
// it might be an array of a dynamically compiled Java type
int rank = 1;
Type elem = type.GetElementType();
while(elem.IsArray)
{
rank++;
elem = elem.GetElementType();
}
wrapper = (TypeWrapper)typeToTypeWrapper[elem];
if(wrapper != null)
{
// HACK this is a lame way of creating the array wrapper
wrapper = wrapper.GetClassLoader().LoadClassBySlashedName(new String('[', rank) + "L" + wrapper.Name + ";");
typeToTypeWrapper[type] = wrapper;
}
}
return wrapper;
}
internal static TypeWrapper GetWrapperFromType(Type type)

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

@ -25,7 +25,7 @@
BaseAddress = "285212672"
CheckForOverflowUnderflow = "false"
ConfigurationOverrideFile = ""
DefineConstants = "DEBUG;TRACE;PROFILE"
DefineConstants = "DEBUG;TRACE"
DocumentationFile = ""
DebugSymbols = "true"
FileAlignment = "4096"

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

@ -34,6 +34,22 @@ sealed class MethodDescriptor
private string sig;
private Type[] args;
private Type ret;
private TypeWrapper[] argTypeWrappers;
private TypeWrapper retTypeWrapper;
internal MethodDescriptor(ClassLoaderWrapper classLoader, ClassFile.ConstantPoolItemFMI cpi)
: this(classLoader, cpi.Name, cpi.Signature)
{
argTypeWrappers = cpi.GetArgTypes(classLoader);
retTypeWrapper = cpi.GetRetType(classLoader);
}
internal MethodDescriptor(ClassLoaderWrapper classLoader, ClassFile.Method method)
: this(classLoader, method.Name, method.Signature)
{
argTypeWrappers = method.GetArgTypes(classLoader);
retTypeWrapper = method.GetRetType(classLoader);
}
internal MethodDescriptor(ClassLoaderWrapper classLoader, string name, string sig)
{
@ -76,6 +92,18 @@ sealed class MethodDescriptor
}
}
internal TypeWrapper[] ArgTypeWrappers
{
get
{
if(argTypeWrappers == null)
{
argTypeWrappers = classLoader.ArgTypeWrapperListFromSig(sig);
}
return argTypeWrappers;
}
}
internal Type RetType
{
get
@ -88,6 +116,18 @@ sealed class MethodDescriptor
}
}
internal TypeWrapper RetTypeWrapper
{
get
{
if(retTypeWrapper == null)
{
retTypeWrapper = classLoader.RetTypeWrapperFromSig(sig);
}
return retTypeWrapper;
}
}
public override bool Equals(object o)
{
// TODO instead of comparing the signature strings, we should compare the actual types
@ -196,6 +236,51 @@ abstract class TypeWrapper
this.classLoader = classLoader;
}
public override string ToString()
{
return GetType().Name + "[" + name + "]";
}
// NOTE for non-array types this returns 0
internal int ArrayRank
{
get
{
int i = 0;
while(name[i] == '[')
{
i++;
}
return i;
}
}
internal virtual bool IsPrimitive
{
get
{
return false;
}
}
internal bool IsUnloadable
{
get
{
// NOTE we abuse modifiers to note unloadable classes
return modifiers == Modifiers.Synthetic;
}
}
internal bool IsVerifierType
{
get
{
// NOTE we abuse modifiers to note verifier types
return modifiers == (Modifiers.Final | Modifiers.Interface);
}
}
internal Modifiers Modifiers
{
get
@ -235,6 +320,7 @@ abstract class TypeWrapper
protected abstract FieldWrapper GetFieldImpl(string fieldName);
// TODO this shouldn't just be based on the name, fields can be overloaded on type
public FieldWrapper GetFieldWrapper(string fieldName)
{
FieldWrapper fae = (FieldWrapper)fields[fieldName];
@ -364,6 +450,23 @@ abstract class TypeWrapper
get;
}
internal Type TypeOrUnloadableAsObject
{
get
{
if(IsUnloadable)
{
return typeof(object);
}
// HACK as a convenience to the compiler, we replace return address types with typeof(int)
if(VerifierTypeWrapper.IsRet(this))
{
return typeof(int);
}
return Type;
}
}
public TypeWrapper BaseTypeWrapper
{
get
@ -372,6 +475,43 @@ abstract class TypeWrapper
}
}
internal TypeWrapper ElementTypeWrapper
{
get
{
if(name[0] != '[')
{
throw new InvalidOperationException();
}
// TODO consider caching the element type
switch(name[1])
{
case '[':
return classLoader.LoadClassBySlashedName(name.Substring(1));
case 'L':
return classLoader.LoadClassBySlashedName(name.Substring(2, name.Length - 3));
case 'Z':
return PrimitiveTypeWrapper.BOOLEAN;
case 'B':
return PrimitiveTypeWrapper.BYTE;
case 'S':
return PrimitiveTypeWrapper.SHORT;
case 'C':
return PrimitiveTypeWrapper.CHAR;
case 'I':
return PrimitiveTypeWrapper.INT;
case 'J':
return PrimitiveTypeWrapper.LONG;
case 'F':
return PrimitiveTypeWrapper.FLOAT;
case 'D':
return PrimitiveTypeWrapper.DOUBLE;
default:
throw new InvalidOperationException(name);
}
}
}
public bool ImplementsInterface(TypeWrapper interfaceWrapper)
{
TypeWrapper typeWrapper = this;
@ -415,6 +555,40 @@ abstract class TypeWrapper
return true;
}
internal bool IsAssignableTo(TypeWrapper wrapper)
{
if(this == wrapper)
{
return true;
}
if(wrapper.IsPrimitive)
{
return false;
}
if(this == VerifierTypeWrapper.Null)
{
return true;
}
int rank1 = this.ArrayRank;
int rank2 = wrapper.ArrayRank;
if(rank1 > 0 && rank2 > 0)
{
rank1--;
rank2--;
TypeWrapper elem1 = this.ElementTypeWrapper;
TypeWrapper elem2 = wrapper.ElementTypeWrapper;
while(rank1 != 0 && rank2 != 0)
{
elem1 = elem1.ElementTypeWrapper;
elem2 = elem2.ElementTypeWrapper;
rank1--;
rank2--;
}
return elem1.IsSubTypeOf(elem2);
}
return this.IsSubTypeOf(wrapper);
}
public abstract bool IsInterface
{
get;
@ -608,6 +782,53 @@ abstract class TypeWrapper
}
}
class UnloadableTypeWrapper : TypeWrapper
{
internal UnloadableTypeWrapper(string name)
: base(Modifiers.Synthetic, name, null, null)
{
}
protected override FieldWrapper GetFieldImpl(string fieldName)
{
throw new InvalidOperationException("GetFieldImpl called on UnloadableTypeWrapper");
}
protected override MethodWrapper GetMethodImpl(MethodDescriptor md)
{
throw new InvalidOperationException("GetMethodImpl called on UnloadableTypeWrapper");
}
public override Type Type
{
get
{
throw new InvalidOperationException("get_Type called on UnloadableTypeWrapper");
}
}
public override bool IsInterface
{
get
{
throw new InvalidOperationException("get_IsInterface called on UnloadableTypeWrapper");
}
}
public override TypeWrapper[] Interfaces
{
get
{
throw new InvalidOperationException("get_Interfaces called on UnloadableTypeWrapper");
}
}
public override void Finish()
{
throw new InvalidOperationException("Finish called on UnloadableTypeWrapper");
}
}
class PrimitiveTypeWrapper : TypeWrapper
{
internal static readonly PrimitiveTypeWrapper BYTE = new PrimitiveTypeWrapper(typeof(sbyte));
@ -628,6 +849,14 @@ class PrimitiveTypeWrapper : TypeWrapper
this.type = type;
}
internal override bool IsPrimitive
{
get
{
return true;
}
}
public override Type Type
{
get
@ -673,12 +902,47 @@ class DynamicTypeWrapper : TypeWrapper
private DynamicImpl impl;
private TypeWrapper[] interfaces;
internal DynamicTypeWrapper(string name, ClassFile f, TypeWrapper baseType, ClassLoaderWrapper classLoader, Hashtable nativeMethods)
: base(f.Modifiers, name, baseType, classLoader)
internal DynamicTypeWrapper(ClassFile f, ClassLoaderWrapper classLoader, Hashtable nativeMethods)
: base(f.Modifiers, f.Name, f.GetSuperTypeWrapper(classLoader), classLoader)
{
JavaTypeImpl impl = new JavaTypeImpl(f, this, baseType, nativeMethods);
this.impl = impl;
interfaces = impl.GetInterfaces();
if(BaseTypeWrapper.IsUnloadable)
{
throw JavaException.NoClassDefFoundError(BaseTypeWrapper.Name);
}
// if the base type isn't public, it must be in the same package
if(!BaseTypeWrapper.IsPublic)
{
if(BaseTypeWrapper.GetClassLoader() != classLoader || f.PackageName != BaseTypeWrapper.PackageName)
{
throw JavaException.IllegalAccessError("Class {0} cannot access its superclass {1}", f.Name, BaseTypeWrapper.Name);
}
}
if(BaseTypeWrapper.IsFinal)
{
throw JavaException.VerifyError("Cannot inherit from final class");
}
if(BaseTypeWrapper.IsInterface)
{
throw JavaException.IncompatibleClassChangeError("Class {0} has interface {1} as superclass", f.Name, BaseTypeWrapper.Name);
}
interfaces = f.GetInterfaceTypeWrappers(classLoader);
for(int i = 0; i < interfaces.Length; i++)
{
if(interfaces[i].IsUnloadable)
{
throw JavaException.NoClassDefFoundError(interfaces[i].Name);
}
if(!interfaces[i].IsInterface)
{
throw JavaException.IncompatibleClassChangeError("Implementing class");
}
if(!interfaces[i].IsAccessibleFrom(this))
{
throw JavaException.IllegalAccessError("Class {0} cannot access its superinterface {1}", f.Name, interfaces[i].Name);
}
}
impl = new JavaTypeImpl(f, this, BaseTypeWrapper, interfaces, nativeMethods);
}
protected override FieldWrapper GetFieldImpl(string fieldName)
@ -747,12 +1011,13 @@ class DynamicTypeWrapper : TypeWrapper
private FinishedTypeImpl finishedType;
private Hashtable nativeMethods;
internal JavaTypeImpl(ClassFile f, DynamicTypeWrapper wrapper, TypeWrapper baseWrapper, Hashtable nativeMethods)
internal JavaTypeImpl(ClassFile f, DynamicTypeWrapper wrapper, TypeWrapper baseWrapper, TypeWrapper[] interfaces, Hashtable nativeMethods)
{
// Console.WriteLine("constructing JavaTypeImpl for " + f.Name);
//Console.WriteLine("constructing JavaTypeImpl for " + f.Name);
this.classFile = f;
this.wrapper = wrapper;
this.baseWrapper = baseWrapper;
this.interfaces = interfaces;
this.nativeMethods = nativeMethods;
TypeAttributes typeAttribs = 0;
@ -768,21 +1033,6 @@ class DynamicTypeWrapper : TypeWrapper
{
typeAttribs |= TypeAttributes.Public;
}
interfaces = new TypeWrapper[f.Interfaces.Length];
for(int i = 0; i < f.Interfaces.Length; i++)
{
interfaces[i] = wrapper.GetClassLoader().LoadClassBySlashedName(f.Interfaces[i]);
if(!interfaces[i].IsInterface)
{
throw JavaException.IncompatibleClassChangeError("Implementing class");
}
if(!interfaces[i].IsAccessibleFrom(wrapper))
{
throw JavaException.IllegalAccessError("Class {0} cannot access its superinterface {1}", wrapper.Name, interfaces[i].Name);
}
}
// NOTE we call DefineType after all the interfaces have been resolved, because otherwise
// we end up with a .NET type that cannot be completed
if(f.IsInterface)
{
typeAttribs |= TypeAttributes.Interface | TypeAttributes.Abstract;
@ -799,11 +1049,6 @@ class DynamicTypeWrapper : TypeWrapper
}
}
internal TypeWrapper[] GetInterfaces()
{
return interfaces;
}
public override DynamicImpl Finish()
{
if(baseWrapper != null)
@ -850,7 +1095,7 @@ class DynamicTypeWrapper : TypeWrapper
MethodDescriptor[] methodDescriptors = new MethodDescriptor[classFile.Methods.Length];
for(int i = 0; i < classFile.Methods.Length; i++)
{
methodDescriptors[i] = new MethodDescriptor(wrapper.GetClassLoader(), classFile.Methods[i].Name, classFile.Methods[i].Signature);
methodDescriptors[i] = new MethodDescriptor(wrapper.GetClassLoader(), classFile.Methods[i]);
}
if(methodLookup == null)
{
@ -1149,21 +1394,17 @@ class DynamicTypeWrapper : TypeWrapper
{
FieldBuilder field;
ClassFile.Field fld = classFile.Fields[i];
Type type = null;
try
TypeWrapper typeWrapper = fld.GetFieldType(wrapper.GetClassLoader());
Type type;
if(typeWrapper.IsUnloadable)
{
type = wrapper.GetClassLoader().ExpressionType(fld.Signature);
// TODO the field name should be mangled here, because otherwise it might conflict with another field
// with the same name and a different unloadable type (or java.lang.Object as its type)
type = typeof(object);
}
catch(Exception x)
else
{
if(x.GetType().FullName == "java.lang.ClassNotFoundException")
{
// TODO set fields[i] to a special FieldWrapper that does the appropriate thing (whatever that may be)
fields[i] = new FieldWrapper(this.wrapper, fld.Name, fld.Signature, fld.Modifiers);
Console.Error.WriteLine("Type " + fld.Signature + " of field " + fld.Name + " in class " + classFile.Name + " is unloadable");
return;
}
throw;
type = typeWrapper.Type;
}
FieldAttributes attribs = 0;
MethodAttributes methodAttribs = 0;
@ -1294,6 +1535,11 @@ class DynamicTypeWrapper : TypeWrapper
fields[i] = FieldWrapper.Create(wrapper, field, fld.Signature, fld.Modifiers);
}
}
if(typeWrapper.IsUnloadable)
{
CustomAttributeBuilder attrib = new CustomAttributeBuilder(typeof(UnloadableTypeAttribute).GetConstructor(new Type[] { typeof(string) }), new object[] { typeWrapper.Name });
field.SetCustomAttribute(attrib);
}
// if the Java modifiers cannot be expressed in .NET, we emit the Modifiers attribute to store
// the Java modifiers
if(setModifiers)
@ -1310,7 +1556,7 @@ class DynamicTypeWrapper : TypeWrapper
methodLookup = new Hashtable();
for(int i = 0; i < classFile.Methods.Length; i++)
{
methodLookup[new MethodDescriptor(wrapper.GetClassLoader(), classFile.Methods[i].Name, classFile.Methods[i].Signature)] = i;
methodLookup[new MethodDescriptor(wrapper.GetClassLoader(), classFile.Methods[i])] = i;
}
}
object index = methodLookup[md];
@ -1332,25 +1578,36 @@ class DynamicTypeWrapper : TypeWrapper
{
throw new InvalidOperationException();
}
// TODO things to consider when we support unloadable types on the argument list on return type:
// - later on, the method can be overriden by a class that does have access to the type, so
// this should be detected and an appropriate override stub should be generated
// - overloading might conflict with the generalised argument list (unloadable types appear
// as System.Object). The nicest way to solve this would be to emit a modreq attribute on the parameter,
// but Reflection.Emit doesn't support this, so we'll probably have to use a name mangling scheme
MethodBase method;
ClassFile.Method m = classFile.Methods[index];
Type[] args = null;
Type retType = null;
try
TypeWrapper[] argTypeWrappers = m.GetArgTypes(wrapper.GetClassLoader());
TypeWrapper retTypeWrapper = m.GetRetType(wrapper.GetClassLoader());
Type[] args = new Type[argTypeWrappers.Length];
Type retType;
if(retTypeWrapper.IsUnloadable)
{
args = wrapper.GetClassLoader().ArgTypeListFromSig(m.Signature);
retType = wrapper.GetClassLoader().RetTypeFromSig(m.Signature);
retType = typeof(object);
}
catch(Exception x)
else
{
if(x.GetType().FullName == "java.lang.ClassNotFoundException")
retType = retTypeWrapper.Type;
}
for(int i = 0; i < args.Length; i++)
{
if(argTypeWrappers[i].IsUnloadable)
{
// TODO set methods[i] to a special MethodWrapper that does the appropriate thing (whatever that may be)
methods[index] = new MethodWrapper(this.wrapper, new MethodDescriptor(wrapper.GetClassLoader(), m.Name, m.Signature), null, m.Modifiers);
Console.Error.WriteLine("Type " + x.Message + " of method " + m.Name + m.Signature + " in class " + classFile.Name + " is unloadable");
return;
args[i] = typeof(object);
}
else
{
args[i] = argTypeWrappers[i].Type;
}
throw;
}
MethodAttributes attribs = 0;
if(m.IsAbstract)
@ -1412,7 +1669,7 @@ class DynamicTypeWrapper : TypeWrapper
attribs |= MethodAttributes.Virtual;
}
string name = m.Name;
MethodDescriptor md = new MethodDescriptor(wrapper.GetClassLoader(), name, m.Signature);
MethodDescriptor md = new MethodDescriptor(wrapper.GetClassLoader(), m);
// if a method is virtual, we need to find the method it overrides (if any), for several reasons:
// - if we're overriding a method that has a different name (e.g. some of the virtual methods
// in System.Object [Equals <-> equals]) we need to add an explicit MethodOverride
@ -1506,7 +1763,27 @@ class DynamicTypeWrapper : TypeWrapper
typeBuilder.DefineMethodOverride(mb, (MethodInfo)baseMethod);
}
}
methods[index] = MethodWrapper.Create(wrapper, new MethodDescriptor(wrapper.GetClassLoader(), m.Name, m.Signature), method, method, m.Modifiers);
if(retTypeWrapper.IsUnloadable)
{
CustomAttributeBuilder attrib = new CustomAttributeBuilder(typeof(UnloadableTypeAttribute).GetConstructor(new Type[] { typeof(string) }), new object[] { retTypeWrapper.Name });
((MethodBuilder)method).DefineParameter(0, ParameterAttributes.None, null).SetCustomAttribute(attrib);
}
for(int i = 0; i < argTypeWrappers.Length; i++)
{
if(argTypeWrappers[i].IsUnloadable)
{
CustomAttributeBuilder attrib = new CustomAttributeBuilder(typeof(UnloadableTypeAttribute).GetConstructor(new Type[] { typeof(string) }), new object[] { argTypeWrappers[i].Name });
if(method is MethodBuilder)
{
((MethodBuilder)method).DefineParameter(i + 1, ParameterAttributes.None, null).SetCustomAttribute(attrib);
}
else
{
((ConstructorBuilder)method).DefineParameter(i + 1, ParameterAttributes.None, null).SetCustomAttribute(attrib);
}
}
}
methods[index] = MethodWrapper.Create(wrapper, new MethodDescriptor(wrapper.GetClassLoader(), m), method, method, m.Modifiers);
}
public override Type Type
@ -1568,8 +1845,8 @@ class RemappedTypeWrapper : TypeWrapper
private Type virtualsInterface;
private Type virtualsHelperHack;
public RemappedTypeWrapper(Modifiers modifiers, string name, Type type, TypeWrapper[] interfaces, TypeWrapper baseType)
: base(modifiers, name, baseType, ClassLoaderWrapper.GetBootstrapClassLoader())
public RemappedTypeWrapper(ClassLoaderWrapper classLoader, Modifiers modifiers, string name, Type type, TypeWrapper[] interfaces, TypeWrapper baseType)
: base(modifiers, name, baseType, classLoader)
{
this.type = type;
this.interfaces = interfaces;
@ -1709,9 +1986,8 @@ class RemappedTypeWrapper : TypeWrapper
{
if(method.@override != null)
{
MethodDescriptor redir = new MethodDescriptor(GetClassLoader(), method.@override.Name, sig);
BindingFlags binding = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
overrideMethod = type.GetMethod(redir.Name, binding, null, CallingConventions.Standard, redir.ArgTypes, null);
overrideMethod = type.GetMethod(method.@override.Name, binding, null, CallingConventions.Standard, GetClassLoader().ArgTypeListFromSig(sig), null);
if(overrideMethod == null)
{
throw new InvalidOperationException("Override method not found: " + Name + "." + name + sig);
@ -2908,13 +3184,13 @@ sealed class MethodWrapper
{
get
{
return declaringType.GetClassLoader().RetTypeWrapperFromSig(md.Signature);
return md.RetTypeWrapper;
}
}
internal TypeWrapper[] GetParameters()
{
return declaringType.GetClassLoader().ArgTypeWrapperListFromSig(md.Signature);
return md.ArgTypeWrappers;
}
internal Modifiers Modifiers
@ -3139,7 +3415,16 @@ sealed class FieldWrapper
{
get
{
return declaringType.GetClassLoader().ExpressionType(sig);
return FieldTypeWrapper.Type;
}
}
internal TypeWrapper FieldTypeWrapper
{
get
{
// HACK
return declaringType.GetClassLoader().RetTypeWrapperFromSig("()" + sig);
}
}

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

@ -35,6 +35,25 @@ public class IKVMAssemblyAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.ReturnValue)]
public class UnloadableTypeAttribute : Attribute
{
private string name;
public UnloadableTypeAttribute(string name)
{
this.name = name;
}
public string Name
{
get
{
return name;
}
}
}
[AttributeUsage(AttributeTargets.All)]
public class ModifiersAttribute : Attribute
{

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

@ -1100,7 +1100,25 @@ namespace NativeCode.java
}
// we need to finish the type otherwise all methods will not be in the method map yet
wrapper.Finish();
return wrapper.GetMethods();
// we need to look through the array for unloadable types, because we may not let them
// escape into the 'wild'
MethodWrapper[] methods = wrapper.GetMethods();
for(int i = 0; i < methods.Length; i++)
{
if(methods[i].ReturnType.IsUnloadable)
{
throw JavaException.NoClassDefFoundError(methods[i].ReturnType.Name);
}
TypeWrapper[] args = methods[i].GetParameters();
for(int j = 0; j < args.Length; j++)
{
if(args[j].IsUnloadable)
{
throw JavaException.NoClassDefFoundError(args[j].Name);
}
}
}
return methods;
}
public static object[] GetDeclaredFields(Type type, object cwrapper)
@ -1112,7 +1130,17 @@ namespace NativeCode.java
}
// we need to finish the type otherwise all fields will not be in the field map yet
wrapper.Finish();
return wrapper.GetFields();
// we need to look through the array for unloadable types, because we may not let them
// escape into the 'wild'
FieldWrapper[] fields = wrapper.GetFields();
for(int i = 0; i < fields.Length; i++)
{
if(fields[i].FieldTypeWrapper.IsUnloadable)
{
throw JavaException.NoClassDefFoundError(fields[i].FieldTypeWrapper.Name);
}
}
return fields;
}
public static object[] GetDeclaredClasses(Type type, object cwrapper)

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

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

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

@ -37,7 +37,7 @@ public final class FileDescriptor
{
}
private FileDescriptor(Stream stream)
public FileDescriptor(Stream stream)
{
this.stream = stream;
}