ikvm-fork/runtime/TypeWrapper.cs

7360 строки
222 KiB
C#
Исходник Обычный вид История

2002-12-18 19:00:25 +03:00
/*
2005-02-02 18:11:26 +03:00
Copyright (C) 2002, 2003, 2004, 2005 Jeroen Frijters
2002-12-18 19:00:25 +03:00
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
Jeroen Frijters
jeroen@frijters.net
*/
using System;
using System.Collections;
using System.Reflection;
using System.Reflection.Emit;
using System.Diagnostics;
2005-05-23 12:24:07 +04:00
using System.Security;
using System.Security.Permissions;
2004-09-09 15:17:55 +04:00
using IKVM.Runtime;
using IKVM.Attributes;
2002-12-18 19:00:25 +03:00
2005-06-01 13:49:30 +04:00
using ILGenerator = IKVM.Internal.CountingILGenerator;
2004-10-19 17:43:55 +04:00
2005-06-01 13:49:30 +04:00
namespace IKVM.Internal
2003-05-13 00:00:15 +04:00
{
2005-06-01 13:49:30 +04:00
class EmitHelper
2004-03-08 18:18:47 +03:00
{
2005-06-01 13:49:30 +04:00
private static MethodInfo objectToString = typeof(object).GetMethod("ToString", BindingFlags.Public | BindingFlags.Instance, null, Type.EmptyTypes, null);
private static MethodInfo verboseCastFailure = JVM.SafeGetEnvironmentVariable("IKVM_VERBOSE_CAST") == null ? null : typeof(ByteCodeHelper).GetMethod("VerboseCastFailure");
2004-03-08 18:18:47 +03:00
2005-06-01 13:49:30 +04:00
internal static void Throw(ILGenerator ilgen, string dottedClassName)
{
TypeWrapper exception = ClassLoaderWrapper.GetBootstrapClassLoader().LoadClassByDottedName(dottedClassName);
MethodWrapper mw = exception.GetMethodWrapper("<init>", "()V", false);
mw.Link();
mw.EmitNewobj(ilgen);
ilgen.Emit(OpCodes.Throw);
}
2003-05-30 16:08:59 +04:00
2005-06-01 13:49:30 +04:00
internal static void Throw(ILGenerator ilgen, string dottedClassName, string message)
{
TypeWrapper exception = ClassLoaderWrapper.GetBootstrapClassLoader().LoadClassByDottedName(dottedClassName);
ilgen.Emit(OpCodes.Ldstr, message);
MethodWrapper mw = exception.GetMethodWrapper("<init>", "(Ljava.lang.String;)V", false);
mw.Link();
mw.EmitNewobj(ilgen);
ilgen.Emit(OpCodes.Throw);
}
internal static void RunClassConstructor(ILGenerator ilgen, Type type)
{
// NOTE we're *not* running the .cctor if the class is not a Java class
// NOTE this is a potential versioning problem, if the base class lives in another assembly and doesn't
// have a <clinit> now, a newer version that does have a <clinit> will not have it's <clinit> called by us.
// A possible solution would be to use RuntimeHelpers.RunClassConstructor when "type" is a Java type and
// lives in another assembly as the caller (which we don't know at the moment).
FieldInfo field = type.GetField("__<clinit>", BindingFlags.Static | BindingFlags.NonPublic);
if(field != null)
{
ilgen.Emit(OpCodes.Ldsfld, field);
ilgen.Emit(OpCodes.Pop);
}
}
internal static void NullCheck(ILGenerator ilgen)
{
// I think this is the most efficient way to generate a NullReferenceException if the
// reference is null
ilgen.Emit(OpCodes.Ldvirtftn, objectToString);
2003-11-17 15:01:50 +03:00
ilgen.Emit(OpCodes.Pop);
}
2004-03-08 18:18:47 +03:00
2005-06-01 13:49:30 +04:00
internal static void Castclass(ILGenerator ilgen, Type type)
{
if(verboseCastFailure != null)
{
LocalBuilder lb = ilgen.DeclareLocal(typeof(object));
ilgen.Emit(OpCodes.Stloc, lb);
ilgen.Emit(OpCodes.Ldloc, lb);
ilgen.Emit(OpCodes.Isinst, type);
ilgen.Emit(OpCodes.Dup);
Label ok = ilgen.DefineLabel();
ilgen.Emit(OpCodes.Brtrue_S, ok);
ilgen.Emit(OpCodes.Ldloc, lb);
ilgen.Emit(OpCodes.Brfalse_S, ok); // handle null
ilgen.Emit(OpCodes.Ldtoken, type);
ilgen.Emit(OpCodes.Ldloc, lb);
ilgen.Emit(OpCodes.Call, verboseCastFailure);
ilgen.MarkLabel(ok);
}
else
{
ilgen.Emit(OpCodes.Castclass, type);
}
}
2005-02-11 17:46:58 +03:00
2005-06-01 13:49:30 +04:00
// This is basically the same as Castclass, except that it
// throws an IncompatibleClassChangeError on failure.
internal static void EmitAssertType(ILGenerator ilgen, Type type)
2005-02-11 17:46:58 +03:00
{
LocalBuilder lb = ilgen.DeclareLocal(typeof(object));
ilgen.Emit(OpCodes.Stloc, lb);
ilgen.Emit(OpCodes.Ldloc, lb);
ilgen.Emit(OpCodes.Isinst, type);
ilgen.Emit(OpCodes.Dup);
Label ok = ilgen.DefineLabel();
2005-02-16 14:20:43 +03:00
ilgen.Emit(OpCodes.Brtrue_S, ok);
2005-02-11 17:46:58 +03:00
ilgen.Emit(OpCodes.Ldloc, lb);
2005-02-16 14:20:43 +03:00
ilgen.Emit(OpCodes.Brfalse_S, ok); // handle null
2005-06-01 13:49:30 +04:00
EmitHelper.Throw(ilgen, "java.lang.IncompatibleClassChangeError");
2005-02-11 17:46:58 +03:00
ilgen.MarkLabel(ok);
}
}
2005-02-16 14:20:43 +03:00
2005-06-01 13:49:30 +04:00
class AttributeHelper
2005-02-16 14:20:43 +03:00
{
2005-06-01 13:49:30 +04:00
private static CustomAttributeBuilder ghostInterfaceAttribute;
private static CustomAttributeBuilder hideFromJavaAttribute;
private static CustomAttributeBuilder deprecatedAttribute;
private static CustomAttributeBuilder editorBrowsableNever;
private static ConstructorInfo implementsAttribute;
private static ConstructorInfo throwsAttribute;
private static ConstructorInfo sourceFileAttribute;
private static ConstructorInfo lineNumberTableAttribute;
2003-05-30 16:08:59 +04:00
2005-06-01 13:49:30 +04:00
private static object ParseValue(TypeWrapper tw, string val)
2005-04-27 10:10:01 +04:00
{
2005-06-01 13:49:30 +04:00
if(tw == CoreClasses.java.lang.String.Wrapper)
{
return val;
}
else if(tw.TypeAsTBD.IsEnum)
{
return Enum.Parse(tw.TypeAsTBD, val);
}
else if(tw.TypeAsTBD == typeof(Type))
{
return Type.GetType(val, true);
}
else if(tw == PrimitiveTypeWrapper.BOOLEAN)
{
return bool.Parse(val);
}
else if(tw == PrimitiveTypeWrapper.BYTE)
{
return (byte)sbyte.Parse(val);
}
else if(tw == PrimitiveTypeWrapper.CHAR)
{
return char.Parse(val);
}
else if(tw == PrimitiveTypeWrapper.SHORT)
{
return short.Parse(val);
}
else if(tw == PrimitiveTypeWrapper.INT)
{
return int.Parse(val);
}
else if(tw == PrimitiveTypeWrapper.FLOAT)
{
return float.Parse(val);
}
else if(tw == PrimitiveTypeWrapper.LONG)
{
return long.Parse(val);
}
else if(tw == PrimitiveTypeWrapper.DOUBLE)
{
return double.Parse(val);
}
else
{
throw new NotImplementedException();
}
2005-04-27 10:10:01 +04:00
}
2005-06-01 13:49:30 +04:00
#if! NO_STATIC_COMPILER
private static void SetPropertiesAndFields(Attribute attrib, IKVM.Internal.MapXml.Attribute attr)
2005-04-27 10:10:01 +04:00
{
2005-06-01 13:49:30 +04:00
Type t = attrib.GetType();
if(attr.Properties != null)
{
foreach(IKVM.Internal.MapXml.Param prop in attr.Properties)
{
PropertyInfo pi = t.GetProperty(prop.Name);
pi.SetValue(attrib, ParseValue(ClassFile.FieldTypeWrapperFromSig(ClassLoaderWrapper.GetBootstrapClassLoader(), new Hashtable(), prop.Sig), prop.Value), null);
}
}
if(attr.Fields != null)
{
foreach(IKVM.Internal.MapXml.Param field in attr.Fields)
{
FieldInfo fi = t.GetField(field.Name);
fi.SetValue(attrib, ParseValue(ClassFile.FieldTypeWrapperFromSig(ClassLoaderWrapper.GetBootstrapClassLoader(), new Hashtable(), field.Sig), field.Value));
}
}
2005-04-27 10:10:01 +04:00
}
2005-06-01 13:49:30 +04:00
internal static Attribute InstantiatePseudoCustomAttribute(IKVM.Internal.MapXml.Attribute attr)
2005-04-27 10:10:01 +04:00
{
2005-06-01 13:49:30 +04:00
Type t = Type.GetType(attr.Type, true);
Type[] argTypes;
object[] args;
GetAttributeArgsAndTypes(attr, out argTypes, out args);
ConstructorInfo ci = t.GetConstructor(argTypes);
Attribute attrib = ci.Invoke(args) as Attribute;
SetPropertiesAndFields(attrib, attr);
return attrib;
2005-04-27 10:10:01 +04:00
}
2005-06-01 13:49:30 +04:00
private static bool IsCodeAccessSecurityAttribute(IKVM.Internal.MapXml.Attribute attr, out SecurityAction action, out PermissionSet pset)
2005-04-27 10:10:01 +04:00
{
2005-06-01 13:49:30 +04:00
action = SecurityAction.Deny;
pset = null;
if(attr.Type != null)
{
Type t = Type.GetType(attr.Type, true);
if(typeof(CodeAccessSecurityAttribute).IsAssignableFrom(t))
{
Type[] argTypes;
object[] args;
GetAttributeArgsAndTypes(attr, out argTypes, out args);
ConstructorInfo ci = t.GetConstructor(argTypes);
CodeAccessSecurityAttribute attrib = ci.Invoke(args) as CodeAccessSecurityAttribute;
SetPropertiesAndFields(attrib, attr);
action = attrib.Action;
pset = new PermissionSet(PermissionState.None);
pset.AddPermission(attrib.CreatePermission());
return true;
}
}
return false;
2005-04-27 10:10:01 +04:00
}
2005-06-01 13:49:30 +04:00
internal static void SetCustomAttribute(TypeBuilder tb, IKVM.Internal.MapXml.Attribute attr)
2005-04-27 10:10:01 +04:00
{
2005-06-01 13:49:30 +04:00
SecurityAction action;
PermissionSet pset;
if(IsCodeAccessSecurityAttribute(attr, out action, out pset))
{
tb.AddDeclarativeSecurity(action, pset);
}
else
{
tb.SetCustomAttribute(CreateCustomAttribute(attr));
}
2005-04-27 10:10:01 +04:00
}
2005-06-01 13:49:30 +04:00
internal static void SetCustomAttribute(FieldBuilder fb, IKVM.Internal.MapXml.Attribute attr)
2005-04-27 10:10:01 +04:00
{
2005-06-01 13:49:30 +04:00
fb.SetCustomAttribute(CreateCustomAttribute(attr));
2005-04-27 10:10:01 +04:00
}
2005-06-01 13:49:30 +04:00
internal static void SetCustomAttribute(ParameterBuilder pb, IKVM.Internal.MapXml.Attribute attr)
2005-04-27 10:10:01 +04:00
{
2005-06-01 13:49:30 +04:00
pb.SetCustomAttribute(CreateCustomAttribute(attr));
2005-04-27 10:10:01 +04:00
}
2005-06-01 13:49:30 +04:00
internal static void SetCustomAttribute(MethodBuilder mb, IKVM.Internal.MapXml.Attribute attr)
2005-05-27 16:44:06 +04:00
{
2005-06-01 13:49:30 +04:00
SecurityAction action;
PermissionSet pset;
if(IsCodeAccessSecurityAttribute(attr, out action, out pset))
2005-05-27 16:44:06 +04:00
{
2005-06-01 13:49:30 +04:00
mb.AddDeclarativeSecurity(action, pset);
2005-05-27 16:44:06 +04:00
}
2005-06-01 13:49:30 +04:00
else
2005-05-27 16:44:06 +04:00
{
2005-06-01 13:49:30 +04:00
mb.SetCustomAttribute(CreateCustomAttribute(attr));
2005-05-27 16:44:06 +04:00
}
}
2005-06-01 13:49:30 +04:00
internal static void SetCustomAttribute(ConstructorBuilder cb, IKVM.Internal.MapXml.Attribute attr)
2005-05-23 12:24:07 +04:00
{
2005-06-01 13:49:30 +04:00
SecurityAction action;
PermissionSet pset;
if(IsCodeAccessSecurityAttribute(attr, out action, out pset))
2005-05-23 12:24:07 +04:00
{
2005-06-01 13:49:30 +04:00
cb.AddDeclarativeSecurity(action, pset);
}
else
{
cb.SetCustomAttribute(CreateCustomAttribute(attr));
2005-05-23 12:24:07 +04:00
}
}
2005-06-01 13:49:30 +04:00
internal static void SetCustomAttribute(PropertyBuilder pb, IKVM.Internal.MapXml.Attribute attr)
2005-05-23 12:24:07 +04:00
{
2005-06-01 13:49:30 +04:00
pb.SetCustomAttribute(CreateCustomAttribute(attr));
2005-05-23 12:24:07 +04:00
}
2005-06-01 13:49:30 +04:00
internal static void SetCustomAttribute(AssemblyBuilder ab, IKVM.Internal.MapXml.Attribute attr)
2005-05-23 12:24:07 +04:00
{
2005-06-01 13:49:30 +04:00
ab.SetCustomAttribute(CreateCustomAttribute(attr));
2005-05-23 12:24:07 +04:00
}
2005-06-01 13:49:30 +04:00
private static void GetAttributeArgsAndTypes(IKVM.Internal.MapXml.Attribute attr, out Type[] argTypes, out object[] args)
2005-05-23 12:24:07 +04:00
{
2005-06-01 13:49:30 +04:00
// TODO add error handling
TypeWrapper[] twargs = ClassFile.ArgTypeWrapperListFromSig(ClassLoaderWrapper.GetBootstrapClassLoader(), new Hashtable(), attr.Sig);
argTypes = new Type[twargs.Length];
args = new object[argTypes.Length];
for(int i = 0; i < twargs.Length; i++)
{
argTypes[i] = twargs[i].TypeAsSignatureType;
TypeWrapper tw = twargs[i];
if(tw == CoreClasses.java.lang.Object.Wrapper)
{
tw = ClassFile.FieldTypeWrapperFromSig(ClassLoaderWrapper.GetBootstrapClassLoader(), new Hashtable(), attr.Params[i].Sig);
}
if(tw.IsArray)
{
Array arr = Array.CreateInstance(tw.ElementTypeWrapper.TypeAsArrayType, attr.Params[i].Elements.Length);
for(int j = 0; j < arr.Length; j++)
{
arr.SetValue(ParseValue(tw.ElementTypeWrapper, attr.Params[i].Elements[j].Value), j);
}
args[i] = arr;
}
else
{
args[i] = ParseValue(tw, attr.Params[i].Value);
}
}
2005-05-23 12:24:07 +04:00
}
2005-06-01 13:49:30 +04:00
private static CustomAttributeBuilder CreateCustomAttribute(IKVM.Internal.MapXml.Attribute attr)
2005-04-27 10:10:01 +04:00
{
2005-06-01 13:49:30 +04:00
// TODO add error handling
Type[] argTypes;
object[] args;
GetAttributeArgsAndTypes(attr, out argTypes, out args);
if(attr.Type != null)
2005-04-27 10:10:01 +04:00
{
2005-06-01 13:49:30 +04:00
Type t = Type.GetType(attr.Type, true);
if(typeof(CodeAccessSecurityAttribute).IsAssignableFrom(t))
{
throw new NotImplementedException("CodeAccessSecurityAttribute support not implemented");
}
ConstructorInfo ci = t.GetConstructor(argTypes);
PropertyInfo[] namedProperties;
object[] propertyValues;
if(attr.Properties != null)
{
namedProperties = new PropertyInfo[attr.Properties.Length];
propertyValues = new object[attr.Properties.Length];
for(int i = 0; i < namedProperties.Length; i++)
{
namedProperties[i] = t.GetProperty(attr.Properties[i].Name);
propertyValues[i] = ParseValue(ClassFile.FieldTypeWrapperFromSig(ClassLoaderWrapper.GetBootstrapClassLoader(), new Hashtable(), attr.Properties[i].Sig), attr.Properties[i].Value);
}
}
else
{
namedProperties = new PropertyInfo[0];
propertyValues = new object[0];
}
FieldInfo[] namedFields;
object[] fieldValues;
if(attr.Fields != null)
{
namedFields = new FieldInfo[attr.Fields.Length];
fieldValues = new object[attr.Fields.Length];
for(int i = 0; i < namedFields.Length; i++)
{
namedFields[i] = t.GetField(attr.Fields[i].Name);
fieldValues[i] = ParseValue(ClassFile.FieldTypeWrapperFromSig(ClassLoaderWrapper.GetBootstrapClassLoader(), new Hashtable(), attr.Fields[i].Sig), attr.Fields[i].Value);
}
}
else
{
namedFields = new FieldInfo[0];
fieldValues = new object[0];
}
return new CustomAttributeBuilder(ci, args, namedProperties, propertyValues, namedFields, fieldValues);
2005-04-27 10:10:01 +04:00
}
2005-06-01 13:49:30 +04:00
else
2005-04-27 10:10:01 +04:00
{
2005-06-01 13:49:30 +04:00
if(attr.Properties != null)
{
throw new NotImplementedException("Setting property values on Java attributes is not implemented");
}
TypeWrapper t = ClassLoaderWrapper.LoadClassCritical(attr.Class);
MethodWrapper mw = t.GetMethodWrapper("<init>", attr.Sig, false);
mw.Link();
ConstructorInfo ci = (ConstructorInfo)mw.GetMethod();
FieldInfo[] namedFields;
object[] fieldValues;
if(attr.Fields != null)
{
namedFields = new FieldInfo[attr.Fields.Length];
fieldValues = new object[attr.Fields.Length];
for(int i = 0; i < namedFields.Length; i++)
{
FieldWrapper fw = t.GetFieldWrapper(attr.Fields[i].Name, attr.Fields[i].Sig);
fw.Link();
namedFields[i] = fw.GetField();
fieldValues[i] = ParseValue(ClassFile.FieldTypeWrapperFromSig(ClassLoaderWrapper.GetBootstrapClassLoader(), new Hashtable(), attr.Fields[i].Sig), attr.Fields[i].Value);
}
}
else
2005-04-27 10:10:01 +04:00
{
2005-06-01 13:49:30 +04:00
namedFields = new FieldInfo[0];
fieldValues = new object[0];
2005-04-27 10:10:01 +04:00
}
2005-06-01 13:49:30 +04:00
return new CustomAttributeBuilder(ci, args, namedFields, fieldValues);
2005-04-27 10:10:01 +04:00
}
2005-06-01 13:49:30 +04:00
}
#endif
internal static void SetEditorBrowsableNever(MethodBuilder mb)
{
if(editorBrowsableNever == null)
2005-04-27 10:10:01 +04:00
{
2005-06-01 13:49:30 +04:00
editorBrowsableNever = new CustomAttributeBuilder(typeof(System.ComponentModel.EditorBrowsableAttribute).GetConstructor(new Type[] { typeof(System.ComponentModel.EditorBrowsableState) }), new object[] { System.ComponentModel.EditorBrowsableState.Never });
2005-04-27 10:10:01 +04:00
}
2005-06-01 13:49:30 +04:00
mb.SetCustomAttribute(editorBrowsableNever);
2005-04-27 10:10:01 +04:00
}
2005-05-23 12:24:07 +04:00
2005-06-01 13:49:30 +04:00
internal static void SetEditorBrowsableNever(PropertyBuilder pb)
2005-04-27 10:10:01 +04:00
{
2005-06-01 13:49:30 +04:00
if(editorBrowsableNever == null)
2005-05-23 12:24:07 +04:00
{
2005-06-01 13:49:30 +04:00
editorBrowsableNever = new CustomAttributeBuilder(typeof(System.ComponentModel.EditorBrowsableAttribute).GetConstructor(new Type[] { typeof(System.ComponentModel.EditorBrowsableState) }), new object[] { System.ComponentModel.EditorBrowsableState.Never });
2005-05-23 12:24:07 +04:00
}
2005-06-01 13:49:30 +04:00
pb.SetCustomAttribute(editorBrowsableNever);
}
internal static void SetDeprecatedAttribute(MethodBase mb)
{
if(deprecatedAttribute == null)
2005-04-27 10:10:01 +04:00
{
2005-06-01 13:49:30 +04:00
deprecatedAttribute = new CustomAttributeBuilder(typeof(ObsoleteAttribute).GetConstructor(Type.EmptyTypes), new object[0]);
2005-04-27 10:10:01 +04:00
}
2005-06-01 13:49:30 +04:00
MethodBuilder method = mb as MethodBuilder;
if(method != null)
2005-04-27 10:10:01 +04:00
{
2005-06-01 13:49:30 +04:00
method.SetCustomAttribute(deprecatedAttribute);
2005-04-27 10:10:01 +04:00
}
2005-06-01 13:49:30 +04:00
else
2005-04-27 10:10:01 +04:00
{
2005-06-01 13:49:30 +04:00
((ConstructorBuilder)mb).SetCustomAttribute(deprecatedAttribute);
2005-04-27 10:10:01 +04:00
}
2005-06-01 13:49:30 +04:00
}
internal static void SetDeprecatedAttribute(TypeBuilder tb)
{
if(deprecatedAttribute == null)
2005-04-27 10:10:01 +04:00
{
2005-06-01 13:49:30 +04:00
deprecatedAttribute = new CustomAttributeBuilder(typeof(ObsoleteAttribute).GetConstructor(Type.EmptyTypes), new object[0]);
2005-04-27 10:10:01 +04:00
}
2005-06-01 13:49:30 +04:00
tb.SetCustomAttribute(deprecatedAttribute);
2005-04-27 10:10:01 +04:00
}
2005-06-01 13:49:30 +04:00
internal static void SetDeprecatedAttribute(FieldBuilder fb)
2005-04-27 10:10:01 +04:00
{
2005-06-01 13:49:30 +04:00
if(deprecatedAttribute == null)
2005-04-27 10:10:01 +04:00
{
2005-06-01 13:49:30 +04:00
deprecatedAttribute = new CustomAttributeBuilder(typeof(ObsoleteAttribute).GetConstructor(Type.EmptyTypes), new object[0]);
2005-04-27 10:10:01 +04:00
}
2005-06-01 13:49:30 +04:00
fb.SetCustomAttribute(deprecatedAttribute);
}
internal static void SetThrowsAttribute(MethodBase mb, string[] exceptions)
{
if(exceptions != null && exceptions.Length != 0)
2005-04-27 10:10:01 +04:00
{
2005-06-01 13:49:30 +04:00
if(throwsAttribute == null)
2005-04-27 10:10:01 +04:00
{
2005-06-01 13:49:30 +04:00
throwsAttribute = typeof(ThrowsAttribute).GetConstructor(new Type[] { typeof(string[]) });
}
if(mb is MethodBuilder)
{
MethodBuilder method = (MethodBuilder)mb;
method.SetCustomAttribute(new CustomAttributeBuilder(throwsAttribute, new object[] { exceptions }));
}
else
{
ConstructorBuilder constructor = (ConstructorBuilder)mb;
constructor.SetCustomAttribute(new CustomAttributeBuilder(throwsAttribute, new object[] { exceptions }));
2005-04-27 10:10:01 +04:00
}
}
2004-11-23 20:46:39 +03:00
}
2005-06-01 13:49:30 +04:00
internal static void SetGhostInterface(TypeBuilder typeBuilder)
2004-11-23 20:46:39 +03:00
{
2005-06-01 13:49:30 +04:00
if(ghostInterfaceAttribute == null)
{
ghostInterfaceAttribute = new CustomAttributeBuilder(typeof(GhostInterfaceAttribute).GetConstructor(Type.EmptyTypes), new object[0]);
}
typeBuilder.SetCustomAttribute(ghostInterfaceAttribute);
2004-11-23 20:46:39 +03:00
}
2003-11-17 15:01:50 +03:00
2005-06-01 13:49:30 +04:00
internal static void MirandaMethod(MethodBuilder mb)
2003-11-17 15:01:50 +03:00
{
2005-06-01 13:49:30 +04:00
CustomAttributeBuilder cab = new CustomAttributeBuilder(typeof(MirandaMethodAttribute).GetConstructor(Type.EmptyTypes), new object[0]);
mb.SetCustomAttribute(cab);
2003-11-17 15:01:50 +03:00
}
2005-06-01 13:49:30 +04:00
internal static bool IsMirandaMethod(MethodInfo mi)
2003-11-17 15:01:50 +03:00
{
2005-06-01 13:49:30 +04:00
return mi.IsAbstract && mi.IsDefined(typeof(MirandaMethodAttribute), false);
2003-11-17 15:01:50 +03:00
}
2005-06-01 13:49:30 +04:00
internal static void HideFromJava(TypeBuilder typeBuilder)
2003-11-17 15:01:50 +03:00
{
2005-06-01 13:49:30 +04:00
if(hideFromJavaAttribute == null)
{
hideFromJavaAttribute = new CustomAttributeBuilder(typeof(HideFromJavaAttribute).GetConstructor(Type.EmptyTypes), new object[0]);
}
typeBuilder.SetCustomAttribute(hideFromJavaAttribute);
2003-11-17 15:01:50 +03:00
}
2005-06-01 13:49:30 +04:00
internal static void HideFromJava(ConstructorBuilder cb)
2003-11-17 15:01:50 +03:00
{
2005-06-01 13:49:30 +04:00
if(hideFromJavaAttribute == null)
{
hideFromJavaAttribute = new CustomAttributeBuilder(typeof(HideFromJavaAttribute).GetConstructor(Type.EmptyTypes), new object[0]);
}
cb.SetCustomAttribute(hideFromJavaAttribute);
2003-11-17 15:01:50 +03:00
}
2005-06-01 13:49:30 +04:00
internal static void HideFromJava(MethodBuilder mb)
2003-11-17 15:01:50 +03:00
{
2005-06-01 13:49:30 +04:00
if(hideFromJavaAttribute == null)
{
hideFromJavaAttribute = new CustomAttributeBuilder(typeof(HideFromJavaAttribute).GetConstructor(Type.EmptyTypes), new object[0]);
}
mb.SetCustomAttribute(hideFromJavaAttribute);
2003-11-17 15:01:50 +03:00
}
2005-06-01 13:49:30 +04:00
internal static void HideFromJava(FieldBuilder fb)
2003-11-17 15:01:50 +03:00
{
2005-06-01 13:49:30 +04:00
if(hideFromJavaAttribute == null)
2003-11-17 15:01:50 +03:00
{
2005-06-01 13:49:30 +04:00
hideFromJavaAttribute = new CustomAttributeBuilder(typeof(HideFromJavaAttribute).GetConstructor(Type.EmptyTypes), new object[0]);
2003-11-17 15:01:50 +03:00
}
2005-06-01 13:49:30 +04:00
fb.SetCustomAttribute(hideFromJavaAttribute);
}
internal static bool IsHideFromJava(MemberInfo mi)
{
// NOTE all privatescope fields and methods are "hideFromJava"
// because Java cannot deal with the potential name clashes
FieldInfo fi = mi as FieldInfo;
if(fi != null && (fi.Attributes & FieldAttributes.FieldAccessMask) == FieldAttributes.PrivateScope)
2003-11-17 15:01:50 +03:00
{
2005-06-01 13:49:30 +04:00
return true;
2003-11-17 15:01:50 +03:00
}
2005-06-01 13:49:30 +04:00
MethodBase mb = mi as MethodBase;
if(mb != null && (mb.Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.PrivateScope)
2003-11-17 15:01:50 +03:00
{
2005-06-01 13:49:30 +04:00
return true;
2003-11-17 15:01:50 +03:00
}
2005-06-01 13:49:30 +04:00
return mi.IsDefined(typeof(HideFromJavaAttribute), false);
2003-11-17 15:01:50 +03:00
}
2003-10-17 12:08:31 +04:00
2005-06-01 13:49:30 +04:00
internal static void SetImplementsAttribute(TypeBuilder typeBuilder, TypeWrapper[] ifaceWrappers)
2003-10-17 12:08:31 +04:00
{
2005-06-01 13:49:30 +04:00
if(ifaceWrappers != null && ifaceWrappers.Length != 0)
{
string[] interfaces = new string[ifaceWrappers.Length];
for(int i = 0; i < interfaces.Length; i++)
{
interfaces[i] = ifaceWrappers[i].Name;
}
if(implementsAttribute == null)
{
implementsAttribute = typeof(ImplementsAttribute).GetConstructor(new Type[] { typeof(string[]) });
}
typeBuilder.SetCustomAttribute(new CustomAttributeBuilder(implementsAttribute, new object[] { interfaces }));
}
}
2004-08-17 13:05:21 +04:00
2005-06-01 13:49:30 +04:00
internal static Modifiers GetModifiers(MethodBase mb, bool assemblyIsPrivate)
2003-10-17 12:08:31 +04:00
{
2005-06-01 13:49:30 +04:00
object[] customAttribute = mb.GetCustomAttributes(typeof(ModifiersAttribute), false);
if(customAttribute.Length == 1)
{
return ((ModifiersAttribute)customAttribute[0]).Modifiers;
}
Modifiers modifiers = 0;
if(mb.IsPublic)
{
modifiers |= Modifiers.Public;
}
else if(mb.IsPrivate)
{
modifiers |= Modifiers.Private;
}
else if(mb.IsFamily || mb.IsFamilyOrAssembly)
{
modifiers |= Modifiers.Protected;
}
else if(assemblyIsPrivate)
{
modifiers |= Modifiers.Private;
}
// NOTE Java doesn't support non-virtual methods, but we set the Final modifier for
// non-virtual methods to approximate the semantics
if((mb.IsFinal || (!mb.IsVirtual && ((modifiers & Modifiers.Private) == 0))) && !mb.IsStatic && !mb.IsConstructor)
{
modifiers |= Modifiers.Final;
}
if(mb.IsAbstract)
{
modifiers |= Modifiers.Abstract;
}
else
{
// Some .NET interfaces (like System._AppDomain) have synchronized methods,
// Java doesn't allow synchronized on an abstract methods, so we ignore it for
// abstract methods.
if((mb.GetMethodImplementationFlags() & MethodImplAttributes.Synchronized) != 0)
{
modifiers |= Modifiers.Synchronized;
}
}
if(mb.IsStatic)
{
modifiers |= Modifiers.Static;
}
if((mb.Attributes & MethodAttributes.PinvokeImpl) != 0)
{
modifiers |= Modifiers.Native;
}
return modifiers;
2003-10-17 12:08:31 +04:00
}
2003-05-30 16:08:59 +04:00
2005-06-01 13:49:30 +04:00
internal static Modifiers GetModifiers(FieldInfo fi, bool assemblyIsPrivate)
2003-05-30 16:08:59 +04:00
{
2005-06-01 13:49:30 +04:00
object[] customAttribute = fi.GetCustomAttributes(typeof(ModifiersAttribute), false);
if(customAttribute.Length == 1)
{
return ((ModifiersAttribute)customAttribute[0]).Modifiers;
}
Modifiers modifiers = 0;
if(fi.IsPublic)
{
modifiers |= Modifiers.Public;
}
else if(fi.IsPrivate)
{
modifiers |= Modifiers.Private;
}
else if(fi.IsFamily || fi.IsFamilyOrAssembly)
{
modifiers |= Modifiers.Protected;
}
else if(assemblyIsPrivate)
{
modifiers |= Modifiers.Private;
}
if(fi.IsInitOnly || fi.IsLiteral)
{
modifiers |= Modifiers.Final;
}
if(fi.IsNotSerialized)
{
modifiers |= Modifiers.Transient;
}
if(fi.IsStatic)
{
modifiers |= Modifiers.Static;
}
// TODO reflection doesn't support volatile
return modifiers;
2003-05-30 16:08:59 +04:00
}
2005-06-01 13:49:30 +04:00
internal static void SetModifiers(MethodBuilder mb, Modifiers modifiers)
2003-05-30 16:08:59 +04:00
{
2005-06-01 13:49:30 +04:00
CustomAttributeBuilder customAttributeBuilder = new CustomAttributeBuilder(typeof(ModifiersAttribute).GetConstructor(new Type[] { typeof(Modifiers) }), new object[] { modifiers });
mb.SetCustomAttribute(customAttributeBuilder);
2003-05-30 16:08:59 +04:00
}
2005-06-01 13:49:30 +04:00
internal static void SetModifiers(ConstructorBuilder cb, Modifiers modifiers)
2003-10-17 12:08:31 +04:00
{
2005-06-01 13:49:30 +04:00
CustomAttributeBuilder customAttributeBuilder = new CustomAttributeBuilder(typeof(ModifiersAttribute).GetConstructor(new Type[] { typeof(Modifiers) }), new object[] { modifiers });
cb.SetCustomAttribute(customAttributeBuilder);
2003-10-17 12:08:31 +04:00
}
2005-06-01 13:49:30 +04:00
internal static void SetModifiers(FieldBuilder fb, Modifiers modifiers)
2003-05-30 16:08:59 +04:00
{
2005-06-01 13:49:30 +04:00
CustomAttributeBuilder customAttributeBuilder = new CustomAttributeBuilder(typeof(ModifiersAttribute).GetConstructor(new Type[] { typeof(Modifiers) }), new object[] { modifiers });
fb.SetCustomAttribute(customAttributeBuilder);
2003-05-30 16:08:59 +04:00
}
2005-06-01 13:49:30 +04:00
internal static void SetModifiers(TypeBuilder tb, Modifiers modifiers)
2003-05-30 16:08:59 +04:00
{
2005-06-01 13:49:30 +04:00
CustomAttributeBuilder customAttributeBuilder = new CustomAttributeBuilder(typeof(ModifiersAttribute).GetConstructor(new Type[] { typeof(Modifiers) }), new object[] { modifiers });
tb.SetCustomAttribute(customAttributeBuilder);
2003-05-30 16:08:59 +04:00
}
2005-06-01 13:49:30 +04:00
internal static void SetNameSig(MethodBase mb, string name, string sig)
2003-07-24 11:29:51 +04:00
{
2005-06-01 13:49:30 +04:00
CustomAttributeBuilder customAttributeBuilder = new CustomAttributeBuilder(typeof(NameSigAttribute).GetConstructor(new Type[] { typeof(string), typeof(string) }), new object[] { name, sig });
MethodBuilder method = mb as MethodBuilder;
if(method != null)
2004-05-14 13:31:54 +04:00
{
2005-06-01 13:49:30 +04:00
method.SetCustomAttribute(customAttributeBuilder);
2004-05-14 13:31:54 +04:00
}
2005-06-01 13:49:30 +04:00
else
2004-05-14 13:31:54 +04:00
{
2005-06-01 13:49:30 +04:00
((ConstructorBuilder)mb).SetCustomAttribute(customAttributeBuilder);
2004-05-14 13:31:54 +04:00
}
2003-08-05 18:07:22 +04:00
}
2003-07-24 11:29:51 +04:00
2005-06-01 13:49:30 +04:00
internal static void SetNameSig(FieldBuilder fb, string name, string sig)
2003-12-24 14:51:41 +03:00
{
2005-06-01 13:49:30 +04:00
CustomAttributeBuilder customAttributeBuilder = new CustomAttributeBuilder(typeof(NameSigAttribute).GetConstructor(new Type[] { typeof(string), typeof(string) }), new object[] { name, sig });
fb.SetCustomAttribute(customAttributeBuilder);
2003-12-24 14:51:41 +03:00
}
2005-06-01 13:49:30 +04:00
internal static byte[] FreezeDryType(Type type)
2003-05-30 16:08:59 +04:00
{
2005-06-01 13:49:30 +04:00
System.IO.MemoryStream mem = new System.IO.MemoryStream();
System.IO.BinaryWriter bw = new System.IO.BinaryWriter(mem, System.Text.UTF8Encoding.UTF8);
bw.Write((short)1);
bw.Write(type.FullName);
bw.Write((short)0);
return mem.ToArray();
2003-05-30 16:08:59 +04:00
}
2005-06-01 13:49:30 +04:00
2005-07-07 15:24:08 +04:00
internal static void SetInnerClass(TypeBuilder typeBuilder, string innerClass, Modifiers modifiers)
2003-05-30 16:08:59 +04:00
{
2005-07-07 15:24:08 +04:00
Type[] argTypes = new Type[] { typeof(string), typeof(Modifiers) };
object[] args = new object[] { innerClass, modifiers };
2005-06-01 13:49:30 +04:00
ConstructorInfo ci = typeof(InnerClassAttribute).GetConstructor(argTypes);
CustomAttributeBuilder customAttributeBuilder = new CustomAttributeBuilder(ci, args);
typeBuilder.SetCustomAttribute(customAttributeBuilder);
2003-05-30 16:08:59 +04:00
}
2005-06-01 13:49:30 +04:00
internal static void SetSourceFile(TypeBuilder typeBuilder, string filename)
2003-05-30 16:08:59 +04:00
{
2005-06-01 13:49:30 +04:00
if(sourceFileAttribute == null)
2003-08-21 14:06:34 +04:00
{
2005-06-01 13:49:30 +04:00
sourceFileAttribute = typeof(SourceFileAttribute).GetConstructor(new Type[] { typeof(string) });
2003-08-21 14:06:34 +04:00
}
2005-06-01 13:49:30 +04:00
typeBuilder.SetCustomAttribute(new CustomAttributeBuilder(sourceFileAttribute, new object[] { filename }));
2003-05-30 16:08:59 +04:00
}
2005-06-01 13:49:30 +04:00
internal static void SetLineNumberTable(MethodBase mb, byte[] table)
2003-05-30 16:08:59 +04:00
{
2005-06-01 13:49:30 +04:00
if(lineNumberTableAttribute == null)
{
lineNumberTableAttribute = typeof(LineNumberTableAttribute).GetConstructor(new Type[] { typeof(byte[]) });
}
if(mb is ConstructorBuilder)
{
((ConstructorBuilder)mb).SetCustomAttribute(new CustomAttributeBuilder(lineNumberTableAttribute, new object[] { table }));
}
else
{
((MethodBuilder)mb).SetCustomAttribute(new CustomAttributeBuilder(lineNumberTableAttribute, new object[] { table }));
}
2003-05-30 16:08:59 +04:00
}
}
2005-06-01 13:49:30 +04:00
public abstract class TypeWrapper
2003-05-30 16:08:59 +04:00
{
2005-06-01 13:49:30 +04:00
private readonly ClassLoaderWrapper classLoader;
private readonly string name; // java name (e.g. java.lang.Object)
private readonly Modifiers modifiers;
private MethodWrapper[] methods;
private FieldWrapper[] fields;
private readonly TypeWrapper baseWrapper;
private readonly object classObject;
private bool hasIncompleteInterfaceImplementation;
internal static readonly TypeWrapper[] EmptyArray = new TypeWrapper[0];
internal const Modifiers UnloadableModifiersHack = Modifiers.Final | Modifiers.Interface | Modifiers.Private;
internal const Modifiers VerifierTypeModifiersHack = Modifiers.Final | Modifiers.Interface;
2003-07-31 16:49:29 +04:00
2005-06-01 13:49:30 +04:00
internal TypeWrapper(Modifiers modifiers, string name, TypeWrapper baseWrapper, ClassLoaderWrapper classLoader, object protectionDomain)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
Profiler.Count("TypeWrapper");
// class name should be dotted or null for primitives
Debug.Assert(name == null || name.IndexOf('/') < 0);
2003-08-01 16:12:08 +04:00
2005-06-01 13:49:30 +04:00
this.modifiers = modifiers;
this.name = name;
this.baseWrapper = baseWrapper;
this.classLoader = classLoader;
if(IsUnloadable || IsVerifierType || JVM.IsStaticCompiler)
{
this.classObject = null;
}
else
{
this.classObject = JVM.Library.newClass(this, protectionDomain);
}
2004-10-19 17:43:55 +04:00
}
2005-06-01 13:49:30 +04:00
internal object ClassObject
2004-10-19 17:43:55 +04:00
{
2005-06-01 13:49:30 +04:00
get
{
Debug.Assert(!IsUnloadable && !IsVerifierType);
return classObject;
}
2004-10-19 17:43:55 +04:00
}
2003-05-13 00:00:15 +04:00
2005-06-01 13:49:30 +04:00
public override string ToString()
2004-12-21 17:59:29 +03:00
{
2005-06-01 13:49:30 +04:00
return GetType().Name + "[" + name + "]";
2004-12-21 17:59:29 +03:00
}
2005-06-01 13:49:30 +04:00
// For UnloadableTypeWrapper it tries to load the type through the specified loader
// and if that fails it throw a NoClassDefFoundError (not a java.lang.NoClassDefFoundError),
// for all other types this is a no-op.
internal virtual TypeWrapper EnsureLoadable(ClassLoaderWrapper loader)
2004-12-21 17:59:29 +03:00
{
2005-06-01 13:49:30 +04:00
return this;
2004-12-21 17:59:29 +03:00
}
2005-02-23 15:56:15 +03:00
2005-06-01 13:49:30 +04:00
internal bool HasIncompleteInterfaceImplementation
2003-05-13 00:00:15 +04:00
{
2005-06-01 13:49:30 +04:00
get
{
return hasIncompleteInterfaceImplementation || (baseWrapper != null && baseWrapper.HasIncompleteInterfaceImplementation);
}
set
{
hasIncompleteInterfaceImplementation = value;
}
2003-05-13 00:00:15 +04:00
}
2005-06-01 13:49:30 +04:00
internal virtual bool HasStaticInitializer
2004-09-15 17:35:44 +04:00
{
2005-06-01 13:49:30 +04:00
get
{
return false;
}
2004-09-15 17:35:44 +04:00
}
2005-06-01 13:49:30 +04:00
// a ghost is an interface that appears to be implemented by a .NET type
// (e.g. System.String (aka java.lang.String) appears to implement java.lang.CharSequence,
// so java.lang.CharSequence is a ghost)
internal virtual bool IsGhost
2003-07-31 16:49:29 +04:00
{
2005-06-01 13:49:30 +04:00
get
{
return false;
}
2003-07-31 16:49:29 +04:00
}
2005-06-01 13:49:30 +04:00
// is this an array type of which the ultimate element type is a ghost?
internal bool IsGhostArray
2003-08-12 17:09:31 +04:00
{
2005-06-01 13:49:30 +04:00
get
{
return IsArray && (ElementTypeWrapper.IsGhost || ElementTypeWrapper.IsGhostArray);
}
2003-08-12 17:09:31 +04:00
}
2005-06-01 13:49:30 +04:00
internal virtual FieldInfo GhostRefField
2003-10-17 12:08:31 +04:00
{
2005-06-01 13:49:30 +04:00
get
{
throw new InvalidOperationException();
}
2003-10-17 12:08:31 +04:00
}
2005-06-01 13:49:30 +04:00
internal virtual bool IsRemapped
2004-03-08 18:18:47 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return false;
}
2004-03-08 18:18:47 +03:00
}
2005-06-01 13:49:30 +04:00
internal bool IsArray
2003-03-21 16:41:43 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return name != null && name[0] == '[';
}
2003-03-21 16:41:43 +03:00
}
2005-06-01 13:49:30 +04:00
// NOTE for non-array types this returns 0
internal int ArrayRank
2003-01-06 16:56:37 +03:00
{
2005-06-01 13:49:30 +04:00
get
2003-01-06 16:56:37 +03:00
{
2005-06-01 13:49:30 +04:00
int i = 0;
if(name != null)
2003-06-20 17:46:13 +04:00
{
2005-06-01 13:49:30 +04:00
while(name[i] == '[')
{
i++;
}
2003-06-20 17:46:13 +04:00
}
2005-06-01 13:49:30 +04:00
return i;
2003-01-06 16:56:37 +03:00
}
}
2005-06-01 13:49:30 +04:00
internal bool IsNonPrimitiveValueType
2003-04-14 13:41:58 +04:00
{
2005-06-01 13:49:30 +04:00
get
{
return this != VerifierTypeWrapper.Null && !IsPrimitive && !IsGhost && TypeAsTBD.IsValueType;
}
2003-04-14 13:41:58 +04:00
}
2005-06-01 13:49:30 +04:00
internal bool IsPrimitive
2003-01-06 16:56:37 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return name == null;
}
2003-01-06 16:56:37 +03:00
}
2005-06-01 13:49:30 +04:00
internal bool IsWidePrimitive
2003-11-17 15:01:50 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return this == PrimitiveTypeWrapper.LONG || this == PrimitiveTypeWrapper.DOUBLE;
}
2003-11-17 15:01:50 +03:00
}
2005-06-01 13:49:30 +04:00
internal bool IsIntOnStackPrimitive
2003-11-17 15:01:50 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return name == null &&
(this == PrimitiveTypeWrapper.BOOLEAN ||
this == PrimitiveTypeWrapper.BYTE ||
this == PrimitiveTypeWrapper.CHAR ||
this == PrimitiveTypeWrapper.SHORT ||
this == PrimitiveTypeWrapper.INT);
}
2003-11-17 15:01:50 +03:00
}
2005-06-01 13:49:30 +04:00
internal bool IsUnloadable
2003-01-06 16:56:37 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
// NOTE we abuse modifiers to note unloadable classes
return modifiers == UnloadableModifiersHack;
}
2003-01-06 16:56:37 +03:00
}
2005-06-01 13:49:30 +04:00
internal bool IsVerifierType
2003-01-06 16:56:37 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
// NOTE we abuse modifiers to note verifier types
return modifiers == VerifierTypeModifiersHack;
}
2003-01-06 16:56:37 +03:00
}
2005-06-01 13:49:30 +04:00
internal virtual bool IsMapUnsafeException
2004-03-08 18:18:47 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return false;
}
2004-03-08 18:18:47 +03:00
}
2005-06-01 13:49:30 +04:00
internal Modifiers Modifiers
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return modifiers;
}
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
// since for inner classes, the modifiers returned by Class.getModifiers are different from the actual
// modifiers (as used by the VM access control mechanism), we have this additional property
internal virtual Modifiers ReflectiveModifiers
2003-05-30 16:08:59 +04:00
{
2005-06-01 13:49:30 +04:00
get
{
return modifiers;
}
2003-05-30 16:08:59 +04:00
}
2005-06-01 13:49:30 +04:00
internal bool IsPublic
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return (modifiers & Modifiers.Public) != 0;
}
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal bool IsAbstract
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
// interfaces don't need to marked abstract explicitly (and javac 1.1 didn't do it)
return (modifiers & (Modifiers.Abstract | Modifiers.Interface)) != 0;
}
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal bool IsFinal
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return (modifiers & Modifiers.Final) != 0;
}
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal bool IsInterface
2003-05-30 16:08:59 +04:00
{
2005-06-01 13:49:30 +04:00
get
{
Debug.Assert(!IsUnloadable && !IsVerifierType);
return (modifiers & Modifiers.Interface) != 0;
}
2003-05-30 16:08:59 +04:00
}
2005-06-01 13:49:30 +04:00
// this exists because interfaces and arrays of interfaces are treated specially
// by the verifier, interfaces don't have a common base (other than java.lang.Object)
// so any object reference or object array reference can be used where an interface
// or interface array reference is expected (the compiler will insert the required casts).
internal bool IsInterfaceOrInterfaceArray
2003-08-29 14:14:08 +04:00
{
2005-06-01 13:49:30 +04:00
get
2003-08-29 14:14:08 +04:00
{
2005-06-01 13:49:30 +04:00
TypeWrapper tw = this;
while(tw.IsArray)
{
tw = tw.ElementTypeWrapper;
}
return tw.IsInterface;
2003-08-29 14:14:08 +04:00
}
}
2005-06-01 13:49:30 +04:00
internal virtual ClassLoaderWrapper GetClassLoader()
{
return classLoader;
}
2002-12-18 19:00:25 +03:00
2005-06-01 13:49:30 +04:00
internal FieldWrapper GetFieldWrapper(string fieldName, string fieldSig)
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
lock(this)
{
if(fields == null)
{
LazyPublishMembers();
}
}
foreach(FieldWrapper fw in fields)
{
if(fw.Name == fieldName && fw.Signature == fieldSig)
{
return fw;
}
}
foreach(TypeWrapper iface in this.Interfaces)
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
FieldWrapper fw = iface.GetFieldWrapper(fieldName, fieldSig);
if(fw != null)
{
return fw;
}
2005-01-03 11:26:21 +03:00
}
2005-06-01 13:49:30 +04:00
if(baseWrapper != null)
{
return baseWrapper.GetFieldWrapper(fieldName, fieldSig);
}
return null;
2005-01-03 11:26:21 +03:00
}
2005-06-01 13:49:30 +04:00
protected virtual void LazyPublishMembers()
2005-01-03 11:26:21 +03:00
{
2005-06-01 13:49:30 +04:00
if(methods == null)
{
methods = MethodWrapper.EmptyArray;
}
if(fields == null)
2005-01-03 11:26:21 +03:00
{
2005-06-01 13:49:30 +04:00
fields = FieldWrapper.EmptyArray;
}
2005-01-03 11:26:21 +03:00
}
2005-06-01 13:49:30 +04:00
internal MethodWrapper[] GetMethods()
2005-01-03 11:26:21 +03:00
{
2005-06-01 13:49:30 +04:00
lock(this)
2005-01-03 11:26:21 +03:00
{
2005-06-01 13:49:30 +04:00
if(methods == null)
{
LazyPublishMembers();
}
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
return methods;
2005-01-03 11:26:21 +03:00
}
2005-06-01 13:49:30 +04:00
internal FieldWrapper[] GetFields()
2005-01-03 11:26:21 +03:00
{
2005-06-01 13:49:30 +04:00
lock(this)
{
if(fields == null)
{
LazyPublishMembers();
}
}
return fields;
2005-01-03 11:26:21 +03:00
}
2005-06-01 13:49:30 +04:00
internal MethodWrapper GetMethodWrapper(string name, string sig, bool inherit)
2005-01-03 11:26:21 +03:00
{
2005-06-01 13:49:30 +04:00
lock(this)
{
if(methods == null)
{
LazyPublishMembers();
}
}
foreach(MethodWrapper mw in methods)
{
if(mw.Name == name && mw.Signature == sig)
{
return mw;
}
}
if(inherit && baseWrapper != null)
{
return baseWrapper.GetMethodWrapper(name, sig, inherit);
}
return null;
2005-01-03 11:26:21 +03:00
}
2005-06-01 13:49:30 +04:00
internal void SetMethods(MethodWrapper[] methods)
2005-01-03 11:26:21 +03:00
{
2005-06-01 13:49:30 +04:00
Debug.Assert(methods != null);
this.methods = methods;
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal void SetFields(FieldWrapper[] fields)
2005-01-03 11:26:21 +03:00
{
2005-06-01 13:49:30 +04:00
Debug.Assert(fields != null);
this.fields = fields;
2005-01-03 11:26:21 +03:00
}
2002-12-18 19:00:25 +03:00
2005-06-01 13:49:30 +04:00
internal string Name
2005-01-03 11:26:21 +03:00
{
2005-06-01 13:49:30 +04:00
get
2005-01-03 11:26:21 +03:00
{
2005-06-01 13:49:30 +04:00
return name;
2005-01-03 11:26:21 +03:00
}
}
2002-12-18 19:00:25 +03:00
2005-06-01 13:49:30 +04:00
// the name of the type as it appears in a Java signature string (e.g. "Ljava.lang.Object;" or "I")
internal virtual string SigName
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
get
2005-01-03 11:26:21 +03:00
{
2005-06-01 13:49:30 +04:00
return "L" + this.Name + ";";
2005-01-03 11:26:21 +03:00
}
}
2005-06-01 13:49:30 +04:00
internal abstract Assembly Assembly
2005-01-03 11:26:21 +03:00
{
2005-06-01 13:49:30 +04:00
get;
2005-01-03 11:26:21 +03:00
}
2005-06-01 13:49:30 +04:00
// returns true iff wrapper is allowed to access us
internal bool IsAccessibleFrom(TypeWrapper wrapper)
2005-01-03 11:26:21 +03:00
{
2005-06-01 13:49:30 +04:00
return IsPublic || IsInSamePackageAs(wrapper);
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal bool IsInSamePackageAs(TypeWrapper wrapper)
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
if(GetClassLoader() == wrapper.GetClassLoader() &&
// Both types must also be in the same assembly, otherwise
// the packages are not accessible.
wrapper.Assembly == this.Assembly)
{
int index1 = name.LastIndexOf('.');
int index2 = wrapper.name.LastIndexOf('.');
if(index1 == -1 && index2 == -1)
{
return true;
}
// for array types we need to skip the brackets
int skip1 = 0;
int skip2 = 0;
while(name[skip1] == '[')
{
skip1++;
}
while(wrapper.name[skip2] == '[')
{
skip2++;
}
if(skip1 > 0)
{
// skip over the L that follows the brackets
skip1++;
}
if(skip2 > 0)
{
// skip over the L that follows the brackets
skip2++;
}
if((index1 - skip1) != (index2 - skip2))
{
return false;
}
return String.CompareOrdinal(name, skip1, wrapper.name, skip2, index1 - skip1) == 0;
}
return false;
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal abstract Type TypeAsTBD
2003-08-21 14:06:34 +04:00
{
2005-06-01 13:49:30 +04:00
get;
2003-08-21 14:06:34 +04:00
}
2005-06-01 13:49:30 +04:00
internal virtual TypeBuilder TypeAsBuilder
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
get
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
TypeBuilder typeBuilder = TypeAsTBD as TypeBuilder;
Debug.Assert(typeBuilder != null);
return typeBuilder;
2002-12-18 19:00:25 +03:00
}
}
2005-06-01 13:49:30 +04:00
internal Type TypeAsSignatureType
2003-08-12 17:09:31 +04:00
{
2005-06-01 13:49:30 +04:00
get
{
if(IsUnloadable)
{
return typeof(object);
}
if(IsGhostArray)
{
int rank = ArrayRank;
string type = "System.Object";
for(int i = 0; i < rank; i++)
{
type += "[]";
}
return Type.GetType(type, true);
}
return TypeAsTBD;
}
2003-08-12 17:09:31 +04:00
}
2005-06-01 13:49:30 +04:00
internal virtual Type TypeAsBaseType
2003-10-17 12:08:31 +04:00
{
2005-06-01 13:49:30 +04:00
get
2003-01-06 16:56:37 +03:00
{
2005-06-01 13:49:30 +04:00
return TypeAsTBD;
2003-01-06 16:56:37 +03:00
}
2005-06-01 13:49:30 +04:00
}
internal Type TypeAsLocalOrStackType
{
get
2003-08-12 17:09:31 +04:00
{
2005-06-01 13:49:30 +04:00
// NOTE as a convenience to the compiler, we replace return address types with typeof(int)
if(VerifierTypeWrapper.IsRet(this))
{
return typeof(int);
}
if(IsUnloadable || IsGhost)
{
return typeof(object);
}
if(IsNonPrimitiveValueType)
{
// return either System.ValueType or System.Enum
return TypeAsTBD.BaseType;
}
if(IsGhostArray)
2003-08-12 17:09:31 +04:00
{
2005-06-01 13:49:30 +04:00
int rank = ArrayRank;
string type = "System.Object";
for(int i = 0; i < rank; i++)
{
type += "[]";
}
return Type.GetType(type, true);
2003-08-12 17:09:31 +04:00
}
2005-06-01 13:49:30 +04:00
return TypeAsTBD;
2003-08-12 17:09:31 +04:00
}
2003-09-10 18:58:19 +04:00
}
2005-06-01 13:49:30 +04:00
/** <summary>Use this if the type is used as an array or array element</summary> */
internal Type TypeAsArrayType
2003-09-10 18:58:19 +04:00
{
2005-06-01 13:49:30 +04:00
get
2003-09-10 18:58:19 +04:00
{
2005-06-01 13:49:30 +04:00
if(IsUnloadable || IsGhost)
2003-09-10 18:58:19 +04:00
{
2005-06-01 13:49:30 +04:00
return typeof(object);
2003-09-10 18:58:19 +04:00
}
2005-06-01 13:49:30 +04:00
if(IsGhostArray)
{
int rank = ArrayRank;
string type = "System.Object";
for(int i = 0; i < rank; i++)
{
type += "[]";
}
return Type.GetType(type, true);
}
return TypeAsTBD;
2003-09-10 18:58:19 +04:00
}
}
2005-06-01 13:49:30 +04:00
internal Type TypeAsExceptionType
2003-09-10 18:58:19 +04:00
{
2005-06-01 13:49:30 +04:00
get
2003-10-17 12:08:31 +04:00
{
2005-06-01 13:49:30 +04:00
if(IsUnloadable)
2003-10-17 12:08:31 +04:00
{
2005-06-01 13:49:30 +04:00
return typeof(Exception);
2003-10-17 12:08:31 +04:00
}
2005-06-01 13:49:30 +04:00
return TypeAsTBD;
2003-10-17 12:08:31 +04:00
}
2003-09-10 18:58:19 +04:00
}
2005-06-01 13:49:30 +04:00
internal TypeWrapper BaseTypeWrapper
2003-09-10 18:58:19 +04:00
{
2005-06-01 13:49:30 +04:00
get
2003-09-10 18:58:19 +04:00
{
2005-06-01 13:49:30 +04:00
return baseWrapper;
2003-09-10 18:58:19 +04:00
}
2003-01-06 16:56:37 +03:00
}
2005-06-01 13:49:30 +04:00
internal TypeWrapper ElementTypeWrapper
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
Debug.Assert(!this.IsUnloadable);
Debug.Assert(this == VerifierTypeWrapper.Null || this.IsArray);
if(this == VerifierTypeWrapper.Null)
{
return VerifierTypeWrapper.Null;
}
// TODO consider caching the element type
switch(name[1])
{
case '[':
// NOTE this call to LoadClassByDottedNameFast can never fail and will not trigger a class load
// (because the ultimate element type was already loaded when this type was created)
return classLoader.LoadClassByDottedNameFast(name.Substring(1));
case 'L':
// NOTE this call to LoadClassByDottedNameFast can never fail and will not trigger a class load
// (because the ultimate element type was already loaded when this type was created)
return classLoader.LoadClassByDottedNameFast(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);
}
}
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal TypeWrapper MakeArrayType(int rank)
2003-01-06 16:56:37 +03:00
{
2005-06-01 13:49:30 +04:00
// NOTE this call to LoadClassByDottedNameFast can never fail and will not trigger a class load
return GetClassLoader().LoadClassByDottedNameFast(new String('[', rank) + this.SigName);
}
2003-12-24 14:51:41 +03:00
2005-06-01 13:49:30 +04:00
internal bool ImplementsInterface(TypeWrapper interfaceWrapper)
{
TypeWrapper typeWrapper = this;
while(typeWrapper != null)
2003-06-13 19:13:20 +04:00
{
2005-06-01 13:49:30 +04:00
TypeWrapper[] interfaces = typeWrapper.Interfaces;
for(int i = 0; i < interfaces.Length; i++)
{
if(interfaces[i] == interfaceWrapper)
{
return true;
}
if(interfaces[i].ImplementsInterface(interfaceWrapper))
{
return true;
}
}
typeWrapper = typeWrapper.BaseTypeWrapper;
2003-01-06 16:56:37 +03:00
}
2005-06-01 13:49:30 +04:00
return false;
2003-01-06 16:56:37 +03:00
}
2003-12-24 14:51:41 +03:00
2005-06-01 13:49:30 +04:00
internal bool IsSubTypeOf(TypeWrapper baseType)
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
// make sure IsSubTypeOf isn't used on primitives
Debug.Assert(!this.IsPrimitive);
Debug.Assert(!baseType.IsPrimitive);
// can't be used on Unloadable
Debug.Assert(!this.IsUnloadable);
Debug.Assert(!baseType.IsUnloadable);
if(baseType.IsInterface)
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
if(baseType == this)
2002-12-18 19:00:25 +03:00
{
return true;
}
2005-06-01 13:49:30 +04:00
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.Wrapper)
{
return true;
}
TypeWrapper subType = this;
while(subType != baseType)
{
subType = subType.BaseTypeWrapper;
if(subType == null)
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
return false;
2002-12-18 19:00:25 +03:00
}
}
2005-06-01 13:49:30 +04:00
return true;
2002-12-18 19:00:25 +03:00
}
2003-01-07 17:53:17 +03:00
2005-06-01 13:49:30 +04:00
internal bool IsAssignableTo(TypeWrapper wrapper)
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
if(this == wrapper)
2002-12-18 19:00:25 +03:00
{
return true;
}
2005-06-01 13:49:30 +04:00
if(this.IsPrimitive || wrapper.IsPrimitive)
2002-12-18 19:00:25 +03:00
{
return false;
}
2005-06-01 13:49:30 +04:00
if(this == VerifierTypeWrapper.Null)
{
return true;
}
if(wrapper.IsInterface)
{
return ImplementsInterface(wrapper);
}
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.IsNonPrimitiveValueType && elem1.IsSubTypeOf(elem2);
}
return this.IsSubTypeOf(wrapper);
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal abstract TypeWrapper[] Interfaces
2003-01-06 16:56:37 +03:00
{
2005-06-01 13:49:30 +04:00
get;
2003-01-06 16:56:37 +03:00
}
2005-06-01 13:49:30 +04:00
// NOTE this property can only be called for finished types!
internal abstract TypeWrapper[] InnerClasses
2003-01-06 16:56:37 +03:00
{
2005-06-01 13:49:30 +04:00
get;
2003-01-06 16:56:37 +03:00
}
2005-06-01 13:49:30 +04:00
// NOTE this property can only be called for finished types!
internal abstract TypeWrapper DeclaringTypeWrapper
2004-02-02 12:46:13 +03:00
{
2005-06-01 13:49:30 +04:00
get;
2004-02-02 12:46:13 +03:00
}
2005-06-01 13:49:30 +04:00
internal void Finish()
2003-01-06 16:56:37 +03:00
{
2005-06-01 13:49:30 +04:00
Finish(false);
2003-01-06 16:56:37 +03:00
}
2003-02-18 12:30:34 +03:00
2005-06-01 13:49:30 +04:00
internal abstract void Finish(bool forDebugSave);
2004-08-17 13:05:21 +04:00
2005-06-01 13:49:30 +04:00
private void ImplementInterfaceMethodStubImpl(MethodWrapper ifmethod, TypeBuilder typeBuilder, DynamicTypeWrapper wrapper)
2003-06-10 17:28:47 +04:00
{
2005-06-01 13:49:30 +04:00
// we're mangling the name to prevent subclasses from accidentally overriding this method and to
// prevent clashes with overloaded method stubs that are erased to the same signature (e.g. unloadable types and ghost arrays)
string mangledName = this.Name + "/" + ifmethod.Name + ifmethod.Signature;
MethodWrapper mce = null;
TypeWrapper lookup = wrapper;
while(lookup != null)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
mce = lookup.GetMethodWrapper(ifmethod.Name, ifmethod.Signature, true);
if(mce == null || !mce.IsStatic)
{
break;
}
lookup = mce.DeclaringType.BaseTypeWrapper;
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
if(mce != null)
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
if(mce.IsMirandaMethod && mce.DeclaringType == wrapper)
{
// Miranda methods already have a methodimpl (if needed) to implement the correct interface method
}
else if(!mce.IsPublic)
{
// NOTE according to the ECMA spec it isn't legal for a privatescope method to be virtual, but this works and
// it makes sense, so I hope the spec is wrong
// UPDATE unfortunately, according to Serge Lidin the spec is correct, and it is not allowed to have virtual privatescope
// methods. Sigh! So I have to use private methods and mangle the name
MethodBuilder mb = typeBuilder.DefineMethod(mangledName, MethodAttributes.NewSlot | MethodAttributes.Private | MethodAttributes.Virtual | MethodAttributes.Final, ifmethod.ReturnTypeForDefineMethod, ifmethod.GetParametersForDefineMethod());
AttributeHelper.HideFromJava(mb);
EmitHelper.Throw(mb.GetILGenerator(), "java.lang.IllegalAccessError", wrapper.Name + "." + ifmethod.Name + ifmethod.Signature);
typeBuilder.DefineMethodOverride(mb, (MethodInfo)ifmethod.GetMethod());
wrapper.HasIncompleteInterfaceImplementation = true;
}
else if(mce.GetMethod() == null || mce.RealName != ifmethod.RealName)
{
MethodBuilder mb = typeBuilder.DefineMethod(mangledName, MethodAttributes.NewSlot | MethodAttributes.Private | MethodAttributes.Virtual | MethodAttributes.Final, ifmethod.ReturnTypeForDefineMethod, ifmethod.GetParametersForDefineMethod());
AttributeHelper.HideFromJava(mb);
ILGenerator ilGenerator = mb.GetILGenerator();
ilGenerator.Emit(OpCodes.Ldarg_0);
int argc = mce.GetParameters().Length;
for(int n = 0; n < argc; n++)
{
ilGenerator.Emit(OpCodes.Ldarg_S, (byte)(n + 1));
}
mce.EmitCallvirt(ilGenerator);
ilGenerator.Emit(OpCodes.Ret);
typeBuilder.DefineMethodOverride(mb, (MethodInfo)ifmethod.GetMethod());
}
else if(mce.DeclaringType.TypeAsTBD.Assembly != typeBuilder.Assembly)
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
// NOTE methods inherited from base classes in a different assembly do *not* automatically implement
// interface methods, so we have to generate a stub here that doesn't do anything but call the base
// implementation
MethodBuilder mb = typeBuilder.DefineMethod(mangledName, MethodAttributes.NewSlot | MethodAttributes.Private | MethodAttributes.Virtual | MethodAttributes.Final, ifmethod.ReturnTypeForDefineMethod, ifmethod.GetParametersForDefineMethod());
typeBuilder.DefineMethodOverride(mb, (MethodInfo)ifmethod.GetMethod());
AttributeHelper.HideFromJava(mb);
ILGenerator ilGenerator = mb.GetILGenerator();
ilGenerator.Emit(OpCodes.Ldarg_0);
int argc = mce.GetParameters().Length;
for(int n = 0; n < argc; n++)
{
ilGenerator.Emit(OpCodes.Ldarg_S, (byte)(n + 1));
}
mce.EmitCallvirt(ilGenerator);
ilGenerator.Emit(OpCodes.Ret);
2002-12-18 19:00:25 +03:00
}
}
2005-06-01 13:49:30 +04:00
else
2002-12-29 19:27:00 +03:00
{
2005-06-01 13:49:30 +04:00
if(!wrapper.IsAbstract)
2002-12-29 19:27:00 +03:00
{
2005-06-01 13:49:30 +04:00
// the type doesn't implement the interface method and isn't abstract either. The JVM allows this, but the CLR doesn't,
// so we have to create a stub method that throws an AbstractMethodError
MethodBuilder mb = typeBuilder.DefineMethod(mangledName, MethodAttributes.NewSlot | MethodAttributes.Private | MethodAttributes.Virtual | MethodAttributes.Final, ifmethod.ReturnTypeForDefineMethod, ifmethod.GetParametersForDefineMethod());
AttributeHelper.HideFromJava(mb);
EmitHelper.Throw(mb.GetILGenerator(), "java.lang.AbstractMethodError", wrapper.Name + "." + ifmethod.Name + ifmethod.Signature);
typeBuilder.DefineMethodOverride(mb, (MethodInfo)ifmethod.GetMethod());
wrapper.HasIncompleteInterfaceImplementation = true;
2002-12-29 19:27:00 +03:00
}
}
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal void ImplementInterfaceMethodStubs(TypeBuilder typeBuilder, DynamicTypeWrapper wrapper, Hashtable doneSet)
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
Debug.Assert(this.IsInterface);
// make sure we don't do the same method twice
if(doneSet.ContainsKey(this))
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
return;
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
doneSet.Add(this, this);
foreach(MethodWrapper method in GetMethods())
{
if(!method.IsStatic)
{
ImplementInterfaceMethodStubImpl(method, typeBuilder, wrapper);
}
}
TypeWrapper[] interfaces = Interfaces;
for(int i = 0; i < interfaces.Length; i++)
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
interfaces[i].ImplementInterfaceMethodStubs(typeBuilder, wrapper, doneSet);
2002-12-18 19:00:25 +03:00
}
}
2005-06-01 13:49:30 +04:00
[Conditional("DEBUG")]
internal static void AssertFinished(Type type)
2003-02-22 15:28:12 +03:00
{
2005-06-01 13:49:30 +04:00
if(type != null)
2003-02-22 15:28:12 +03:00
{
2005-06-01 13:49:30 +04:00
while(type.IsArray)
{
type = type.GetElementType();
}
Debug.Assert(!(type is TypeBuilder));
2003-02-22 15:28:12 +03:00
}
}
2003-12-20 01:19:18 +03:00
2005-06-01 13:49:30 +04:00
internal void RunClassInit()
2005-02-02 18:11:26 +03:00
{
2005-06-01 13:49:30 +04:00
System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(TypeAsTBD.TypeHandle);
2005-02-02 18:11:26 +03:00
}
2005-06-01 13:49:30 +04:00
internal void EmitUnbox(ILGenerator ilgen)
2005-02-02 18:11:26 +03:00
{
2005-06-01 13:49:30 +04:00
Debug.Assert(this.IsNonPrimitiveValueType);
Type type = this.TypeAsTBD;
// NOTE if the reference is null, we treat it as a default instance of the value type.
ilgen.Emit(OpCodes.Dup);
Label label1 = ilgen.DefineLabel();
ilgen.Emit(OpCodes.Brtrue_S, label1);
ilgen.Emit(OpCodes.Pop);
ilgen.Emit(OpCodes.Ldloc, ilgen.DeclareLocal(type));
Label label2 = ilgen.DefineLabel();
ilgen.Emit(OpCodes.Br_S, label2);
ilgen.MarkLabel(label1);
ilgen.Emit(OpCodes.Unbox, type);
ilgen.Emit(OpCodes.Ldobj, type);
ilgen.MarkLabel(label2);
2005-02-02 18:11:26 +03:00
}
2005-06-01 13:49:30 +04:00
internal void EmitBox(ILGenerator ilgen)
2005-02-02 18:11:26 +03:00
{
2005-06-01 13:49:30 +04:00
Debug.Assert(this.IsNonPrimitiveValueType);
ilgen.Emit(OpCodes.Box, this.TypeAsTBD);
2005-02-02 18:11:26 +03:00
}
2005-06-01 13:49:30 +04:00
internal void EmitConvSignatureTypeToStackType(ILGenerator ilgen)
2003-12-20 01:19:18 +03:00
{
2005-06-01 13:49:30 +04:00
if(IsUnloadable)
2003-12-20 01:19:18 +03:00
{
}
2005-06-01 13:49:30 +04:00
else if(this == PrimitiveTypeWrapper.BYTE)
2004-03-08 18:18:47 +03:00
{
2005-06-01 13:49:30 +04:00
ilgen.Emit(OpCodes.Conv_I1);
2004-03-08 18:18:47 +03:00
}
else if(IsNonPrimitiveValueType)
{
2005-06-01 13:49:30 +04:00
EmitBox(ilgen);
}
else if(IsGhost)
{
LocalBuilder local = ilgen.DeclareLocal(TypeAsSignatureType);
ilgen.Emit(OpCodes.Stloc, local);
ilgen.Emit(OpCodes.Ldloca, local);
ilgen.Emit(OpCodes.Ldfld, GhostRefField);
2004-03-08 18:18:47 +03:00
}
2003-12-20 01:19:18 +03:00
}
2005-06-01 13:49:30 +04:00
// NOTE sourceType is optional and only used for interfaces,
// it is *not* used to automatically downcast
internal void EmitConvStackTypeToSignatureType(ILGenerator ilgen, TypeWrapper sourceType)
2004-01-11 16:14:42 +03:00
{
2005-06-01 13:49:30 +04:00
if(!IsUnloadable)
2004-01-11 16:14:42 +03:00
{
2005-06-01 13:49:30 +04:00
if(IsGhost)
{
LocalBuilder local1 = ilgen.DeclareLocal(TypeAsLocalOrStackType);
ilgen.Emit(OpCodes.Stloc, local1);
LocalBuilder local2 = ilgen.DeclareLocal(TypeAsSignatureType);
ilgen.Emit(OpCodes.Ldloca, local2);
ilgen.Emit(OpCodes.Ldloc, local1);
ilgen.Emit(OpCodes.Stfld, GhostRefField);
ilgen.Emit(OpCodes.Ldloca, local2);
ilgen.Emit(OpCodes.Ldobj, TypeAsSignatureType);
}
// because of the way interface merging works, any reference is valid
// for any interface reference
else if(IsInterfaceOrInterfaceArray && (sourceType == null || sourceType.IsUnloadable || !sourceType.IsAssignableTo(this)))
{
EmitHelper.EmitAssertType(ilgen, TypeAsTBD);
Profiler.Count("InterfaceDownCast");
}
else if(IsNonPrimitiveValueType)
{
EmitUnbox(ilgen);
}
2004-01-11 16:14:42 +03:00
}
}
2005-06-01 13:49:30 +04:00
internal virtual void EmitCheckcast(TypeWrapper context, ILGenerator ilgen)
2004-01-11 16:14:42 +03:00
{
2005-06-01 13:49:30 +04:00
if(IsGhost)
{
ilgen.Emit(OpCodes.Dup);
// TODO make sure we get the right "Cast" method and cache it
// NOTE for dynamic ghosts we don't end up here because DynamicTypeWrapper overrides this method,
// so we're safe to call GetMethod on TypeAsTBD (because it has to be a compiled type, if we're here)
ilgen.Emit(OpCodes.Call, TypeAsTBD.GetMethod("Cast"));
ilgen.Emit(OpCodes.Pop);
}
else if(IsGhostArray)
{
ilgen.Emit(OpCodes.Dup);
// TODO make sure we get the right "CastArray" method and cache it
// NOTE for dynamic ghosts we don't end up here because DynamicTypeWrapper overrides this method,
// so we're safe to call GetMethod on TypeAsTBD (because it has to be a compiled type, if we're here)
TypeWrapper tw = this;
int rank = 0;
while(tw.IsArray)
{
rank++;
tw = tw.ElementTypeWrapper;
}
ilgen.Emit(OpCodes.Ldc_I4, rank);
ilgen.Emit(OpCodes.Call, tw.TypeAsTBD.GetMethod("CastArray"));
}
else
{
EmitHelper.Castclass(ilgen, TypeAsTBD);
}
2004-01-11 16:14:42 +03:00
}
2005-06-01 13:49:30 +04:00
internal virtual void EmitInstanceOf(TypeWrapper context, ILGenerator ilgen)
2004-01-11 16:14:42 +03:00
{
2005-06-01 13:49:30 +04:00
if(IsGhost)
{
// TODO make sure we get the right "IsInstance" method and cache it
// NOTE for dynamic ghosts we don't end up here because DynamicTypeWrapper overrides this method,
// so we're safe to call GetMethod on TypeAsTBD (because it has to be a compiled type, if we're here)
ilgen.Emit(OpCodes.Call, TypeAsTBD.GetMethod("IsInstance"));
}
else if(IsGhostArray)
{
// TODO make sure we get the right "IsInstanceArray" method and cache it
// NOTE for dynamic ghosts we don't end up here because DynamicTypeWrapper overrides this method,
// so we're safe to call GetMethod on TypeAsTBD (because it has to be a compiled type, if we're here)
ilgen.Emit(OpCodes.Call, TypeAsTBD.GetMethod("IsInstanceArray"));
}
else
{
ilgen.Emit(OpCodes.Isinst, TypeAsTBD);
ilgen.Emit(OpCodes.Ldnull);
ilgen.Emit(OpCodes.Cgt_Un);
}
2004-01-11 16:14:42 +03:00
}
2005-06-01 13:49:30 +04:00
internal static string GetSigNameFromType(Type type)
2004-01-11 16:14:42 +03:00
{
2005-06-01 13:49:30 +04:00
TypeWrapper wrapper = ClassLoaderWrapper.GetWrapperFromTypeFast(type);
2004-01-11 16:14:42 +03:00
2005-06-01 13:49:30 +04:00
if(wrapper != null)
{
return wrapper.SigName;
}
2004-01-11 16:14:42 +03:00
2005-06-01 13:49:30 +04:00
if(type.IsArray)
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
while(type.IsArray)
{
sb.Append('[');
type = type.GetElementType();
}
return sb.Append(GetSigNameFromType(type)).ToString();
}
2004-01-11 16:14:42 +03:00
2005-06-01 13:49:30 +04:00
string s = TypeWrapper.GetNameFromType(type);
if(s[0] != '[')
2004-01-11 16:14:42 +03:00
{
2005-06-01 13:49:30 +04:00
s = "L" + s + ";";
2004-01-11 16:14:42 +03:00
}
2005-06-01 13:49:30 +04:00
return s;
2004-01-11 16:14:42 +03:00
}
2005-06-01 13:49:30 +04:00
// NOTE returns null for primitive types
internal static string GetNameFromType(Type type)
2004-01-11 16:14:42 +03:00
{
2005-06-01 13:49:30 +04:00
TypeWrapper.AssertFinished(type);
2004-01-11 16:14:42 +03:00
2005-06-01 13:49:30 +04:00
if(type.IsArray)
{
return GetSigNameFromType(type);
}
2004-01-11 16:14:42 +03:00
2005-06-01 13:49:30 +04:00
// first we check if a wrapper exists, because if it does we must use the name from the wrapper to
// make sure that remapped types return the proper name
TypeWrapper wrapper = ClassLoaderWrapper.GetWrapperFromTypeFast(type);
if(wrapper != null)
{
return wrapper.Name;
}
2004-01-11 16:14:42 +03:00
2005-06-01 13:49:30 +04:00
if(type.Module.IsDefined(typeof(JavaModuleAttribute), false))
{
return CompiledTypeWrapper.GetName(type);
}
else
{
return DotNetTypeWrapper.GetName(type);
}
2004-01-11 16:14:42 +03:00
}
2005-06-01 13:49:30 +04:00
// NOTE don't call this method, call MethodWrapper.Link instead
internal virtual MethodBase LinkMethod(MethodWrapper mw)
2004-01-11 16:14:42 +03:00
{
2005-06-01 13:49:30 +04:00
return mw.GetMethod();
2004-01-11 16:14:42 +03:00
}
2005-06-01 13:49:30 +04:00
// NOTE don't call this method, call FieldWrapper.Link instead
internal virtual FieldInfo LinkField(FieldWrapper fw)
2004-01-11 16:14:42 +03:00
{
2005-06-01 13:49:30 +04:00
return fw.GetField();
2004-01-11 16:14:42 +03:00
}
}
2004-08-17 13:05:21 +04:00
2005-06-01 13:49:30 +04:00
class UnloadableTypeWrapper : TypeWrapper
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
private static Hashtable warningHashtable;
2002-12-18 19:00:25 +03:00
2005-06-01 13:49:30 +04:00
internal UnloadableTypeWrapper(string name)
: base(TypeWrapper.UnloadableModifiersHack, name, null, null, null)
{
if(JVM.IsStaticCompiler && name != "<verifier>")
{
if(warningHashtable == null)
{
warningHashtable = new Hashtable();
}
if(name.StartsWith("["))
{
int skip = 1;
while(name[skip++] == '[');
name = name.Substring(skip, name.Length - skip - 1);
}
if(!warningHashtable.ContainsKey(name))
{
warningHashtable.Add(name, name);
Console.Error.WriteLine("Warning: class \"{0}\" not found", name);
}
}
}
2005-02-23 15:56:15 +03:00
2005-06-01 13:49:30 +04:00
internal override TypeWrapper EnsureLoadable(ClassLoaderWrapper loader)
2005-02-23 15:56:15 +03:00
{
2005-06-01 13:49:30 +04:00
TypeWrapper tw = null;
try
2005-02-23 15:56:15 +03:00
{
2005-06-01 13:49:30 +04:00
tw = loader.LoadClassByDottedNameFast(this.Name);
2005-02-23 15:56:15 +03:00
}
2005-06-01 13:49:30 +04:00
catch
2005-05-23 12:24:07 +04:00
{
}
2005-06-01 13:49:30 +04:00
if(tw == null)
2005-02-23 15:56:15 +03:00
{
2005-06-01 13:49:30 +04:00
throw new NoClassDefFoundError(this.Name);
2005-02-23 15:56:15 +03:00
}
2005-06-01 13:49:30 +04:00
return tw;
2005-02-23 15:56:15 +03:00
}
2005-06-01 13:49:30 +04:00
internal override Assembly Assembly
2005-02-23 15:56:15 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return null;
}
2005-02-23 15:56:15 +03:00
}
2005-06-01 13:49:30 +04:00
internal override string SigName
2005-02-23 15:56:15 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
string name = Name;
if(name.StartsWith("["))
{
return name;
}
return "L" + name + ";";
}
2005-02-23 15:56:15 +03:00
}
2005-06-01 13:49:30 +04:00
protected override void LazyPublishMembers()
2005-02-23 15:56:15 +03:00
{
2005-06-01 13:49:30 +04:00
throw new InvalidOperationException("LazyPublishMembers called on UnloadableTypeWrapper: " + Name);
2005-02-23 15:56:15 +03:00
}
2003-01-06 16:56:37 +03:00
2005-06-01 13:49:30 +04:00
internal override Type TypeAsTBD
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
get
{
throw new InvalidOperationException("get_Type called on UnloadableTypeWrapper: " + Name);
}
}
2004-08-17 13:05:21 +04:00
2005-06-01 13:49:30 +04:00
internal override TypeWrapper[] Interfaces
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
get
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
throw new InvalidOperationException("get_Interfaces called on UnloadableTypeWrapper: " + Name);
2004-08-17 13:05:21 +04:00
}
}
2005-06-01 13:49:30 +04:00
internal override TypeWrapper[] InnerClasses
{
get
{
throw new InvalidOperationException("get_InnerClasses called on UnloadableTypeWrapper: " + Name);
}
}
2003-01-06 16:56:37 +03:00
2005-06-01 13:49:30 +04:00
internal override TypeWrapper DeclaringTypeWrapper
2003-01-06 16:56:37 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
throw new InvalidOperationException("get_DeclaringTypeWrapper called on UnloadableTypeWrapper: " + Name);
}
}
2003-01-06 16:56:37 +03:00
2005-06-01 13:49:30 +04:00
internal override void Finish(bool forDebugSave)
2003-01-06 16:56:37 +03:00
{
2005-06-01 13:49:30 +04:00
throw new InvalidOperationException("Finish called on UnloadableTypeWrapper: " + Name);
2003-01-06 16:56:37 +03:00
}
2005-06-01 13:49:30 +04:00
internal override void EmitCheckcast(TypeWrapper context, ILGenerator ilgen)
2003-02-18 12:30:34 +03:00
{
2005-06-01 13:49:30 +04:00
ilgen.Emit(OpCodes.Ldtoken, context.TypeAsTBD);
ilgen.Emit(OpCodes.Ldstr, Name);
ilgen.Emit(OpCodes.Call, typeof(ByteCodeHelper).GetMethod("DynamicCast"));
2003-02-18 12:30:34 +03:00
}
2005-06-01 13:49:30 +04:00
internal override void EmitInstanceOf(TypeWrapper context, ILGenerator ilgen)
2003-02-18 12:30:34 +03:00
{
2005-06-01 13:49:30 +04:00
ilgen.Emit(OpCodes.Ldtoken, context.TypeAsTBD);
ilgen.Emit(OpCodes.Ldstr, Name);
ilgen.Emit(OpCodes.Call, typeof(ByteCodeHelper).GetMethod("DynamicInstanceOf"));
2003-02-18 12:30:34 +03:00
}
}
2005-06-01 13:49:30 +04:00
class PrimitiveTypeWrapper : TypeWrapper
2003-01-06 16:56:37 +03:00
{
2005-06-01 13:49:30 +04:00
internal static readonly PrimitiveTypeWrapper BYTE = new PrimitiveTypeWrapper(typeof(byte), "B");
internal static readonly PrimitiveTypeWrapper CHAR = new PrimitiveTypeWrapper(typeof(char), "C");
internal static readonly PrimitiveTypeWrapper DOUBLE = new PrimitiveTypeWrapper(typeof(double), "D");
internal static readonly PrimitiveTypeWrapper FLOAT = new PrimitiveTypeWrapper(typeof(float), "F");
internal static readonly PrimitiveTypeWrapper INT = new PrimitiveTypeWrapper(typeof(int), "I");
internal static readonly PrimitiveTypeWrapper LONG = new PrimitiveTypeWrapper(typeof(long), "J");
internal static readonly PrimitiveTypeWrapper SHORT = new PrimitiveTypeWrapper(typeof(short), "S");
internal static readonly PrimitiveTypeWrapper BOOLEAN = new PrimitiveTypeWrapper(typeof(bool), "Z");
internal static readonly PrimitiveTypeWrapper VOID = new PrimitiveTypeWrapper(typeof(void), "V");
2004-01-11 16:14:42 +03:00
2005-06-01 13:49:30 +04:00
private readonly Type type;
private readonly string sigName;
2004-01-11 16:14:42 +03:00
2005-06-01 13:49:30 +04:00
private PrimitiveTypeWrapper(Type type, string sigName)
: base(Modifiers.Public | Modifiers.Abstract | Modifiers.Final, null, null, null, null)
{
this.type = type;
this.sigName = sigName;
}
2003-01-06 16:56:37 +03:00
2005-06-01 13:49:30 +04:00
internal override Assembly Assembly
{
get
{
return null;
}
}
2003-08-21 14:06:34 +04:00
2005-06-01 13:49:30 +04:00
internal override string SigName
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
get
{
return sigName;
}
2004-08-17 13:05:21 +04:00
}
2005-06-01 13:49:30 +04:00
internal override ClassLoaderWrapper GetClassLoader()
2003-08-21 14:06:34 +04:00
{
2005-06-01 13:49:30 +04:00
return ClassLoaderWrapper.GetBootstrapClassLoader();
2003-08-21 14:06:34 +04:00
}
2002-12-18 19:00:25 +03:00
2005-06-01 13:49:30 +04:00
internal override Type TypeAsTBD
{
get
{
return type;
}
}
2003-04-14 13:41:58 +04:00
2005-06-01 13:49:30 +04:00
internal override TypeWrapper[] Interfaces
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return TypeWrapper.EmptyArray;
}
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal override TypeWrapper[] InnerClasses
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return TypeWrapper.EmptyArray;
}
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal override TypeWrapper DeclaringTypeWrapper
2003-02-18 12:30:34 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return null;
}
2003-02-18 12:30:34 +03:00
}
2005-06-01 13:49:30 +04:00
internal override void Finish(bool forDebugSave)
2003-02-18 12:30:34 +03:00
{
}
2005-06-01 13:49:30 +04:00
public override string ToString()
{
return "PrimitiveTypeWrapper[" + sigName + "]";
}
2002-12-18 19:00:25 +03:00
}
2005-02-02 18:11:26 +03:00
2005-06-01 13:49:30 +04:00
class BakedTypeCleanupHack
2005-02-02 18:11:26 +03:00
{
2005-06-01 13:49:30 +04:00
private static readonly FieldInfo m_methodBuilder = typeof(ConstructorBuilder).GetField("m_methodBuilder", BindingFlags.Instance | BindingFlags.NonPublic);
private static readonly FieldInfo[] methodBuilderFields = GetFieldList(typeof(MethodBuilder), new string[]
2005-01-03 11:26:21 +03:00
{
"m_ilGenerator",
"m_ubBody",
"m_RVAFixups",
"mm_mdMethodFixups",
"m_localSignature",
"m_localSymInfo",
"m_exceptions",
"m_parameterTypes",
"m_retParam",
"m_returnType",
"m_signature"
});
2005-06-01 13:49:30 +04:00
private static readonly FieldInfo[] fieldBuilderFields = GetFieldList(typeof(FieldBuilder), new string[]
2005-01-03 11:26:21 +03:00
{
"m_data",
"m_fieldType",
2005-06-01 13:49:30 +04:00
});
2005-01-03 11:26:21 +03:00
2005-06-01 13:49:30 +04:00
private static bool IsSupportedVersion
2005-01-05 15:11:50 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return Environment.Version.Major == 1 && Environment.Version.Minor == 1 && Environment.Version.Build == 4322;
}
2005-01-05 15:11:50 +03:00
}
2005-06-01 13:49:30 +04:00
private static FieldInfo[] GetFieldList(Type type, string[] list)
2005-01-03 11:26:21 +03:00
{
2005-06-01 13:49:30 +04:00
if(JVM.IsStaticCompiler || ClassLoaderWrapper.IsSaveDebugImage || !IsSupportedVersion)
2005-01-03 11:26:21 +03:00
{
2005-06-01 13:49:30 +04:00
// if we're going to be saving the image, we cannot bash the MethodBuilder fields,
// because the data is required to generated the PE file.
2005-01-03 11:26:21 +03:00
return null;
}
2005-06-01 13:49:30 +04:00
if(!SecurityManager.IsGranted(new SecurityPermission(SecurityPermissionFlag.Assertion)) ||
!SecurityManager.IsGranted(new ReflectionPermission(ReflectionPermissionFlag.MemberAccess)))
{
return null;
}
FieldInfo[] fields = new FieldInfo[list.Length];
for(int i = 0; i < list.Length; i++)
{
fields[i] = type.GetField(list[i], BindingFlags.Instance | BindingFlags.NonPublic);
if(fields[i] == null)
{
return null;
}
}
return fields;
2005-01-03 11:26:21 +03:00
}
2005-06-01 13:49:30 +04:00
internal static void Process(DynamicTypeWrapper wrapper)
2005-01-03 11:26:21 +03:00
{
2005-06-01 13:49:30 +04:00
if(m_methodBuilder != null && methodBuilderFields != null && fieldBuilderFields != null)
2005-01-03 11:26:21 +03:00
{
2005-06-01 13:49:30 +04:00
foreach(MethodWrapper mw in wrapper.GetMethods())
2005-01-03 11:26:21 +03:00
{
2005-06-01 13:49:30 +04:00
MethodBuilder mb = mw.GetMethod() as MethodBuilder;
if(mb == null)
2005-01-03 11:26:21 +03:00
{
2005-06-01 13:49:30 +04:00
ConstructorBuilder cb = mw.GetMethod() as ConstructorBuilder;
if(cb != null)
{
new ReflectionPermission(ReflectionPermissionFlag.MemberAccess).Assert();
mb = (MethodBuilder)m_methodBuilder.GetValue(cb);
CodeAccessPermission.RevertAssert();
}
2005-01-03 11:26:21 +03:00
}
2005-06-01 13:49:30 +04:00
if(mb != null)
2005-01-03 11:26:21 +03:00
{
2005-06-01 13:49:30 +04:00
new ReflectionPermission(ReflectionPermissionFlag.MemberAccess).Assert();
foreach(FieldInfo fi in methodBuilderFields)
{
fi.SetValue(mb, null);
}
CodeAccessPermission.RevertAssert();
2005-01-03 11:26:21 +03:00
}
}
2005-06-01 13:49:30 +04:00
foreach(FieldWrapper fw in wrapper.GetFields())
2005-01-03 11:26:21 +03:00
{
2005-06-01 13:49:30 +04:00
FieldBuilder fb = fw.GetField() as FieldBuilder;
if(fb != null)
2005-01-03 11:26:21 +03:00
{
2005-06-01 13:49:30 +04:00
new ReflectionPermission(ReflectionPermissionFlag.MemberAccess).Assert();
foreach(FieldInfo fi in fieldBuilderFields)
{
fi.SetValue(fb, null);
}
CodeAccessPermission.RevertAssert();
2005-01-03 11:26:21 +03:00
}
}
}
}
}
2002-12-18 19:00:25 +03:00
2005-06-01 13:49:30 +04:00
class DynamicTypeWrapper : TypeWrapper
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
private volatile DynamicImpl impl;
private TypeWrapper[] interfaces;
private bool hasStaticInitializer;
2004-08-17 13:05:21 +04:00
2005-06-01 13:49:30 +04:00
private static TypeWrapper LoadTypeWrapper(ClassLoaderWrapper classLoader, string name)
2003-01-06 16:56:37 +03:00
{
2005-06-01 13:49:30 +04:00
TypeWrapper tw = classLoader.LoadClassByDottedNameFast(name);
if(tw == null)
2003-06-10 17:28:47 +04:00
{
2005-06-01 13:49:30 +04:00
throw new NoClassDefFoundError(name);
2003-06-10 17:28:47 +04:00
}
2005-06-01 13:49:30 +04:00
return tw;
}
internal DynamicTypeWrapper(ClassFile f, ClassLoaderWrapper classLoader, object protectionDomain)
: base(f.Modifiers, f.Name, f.IsInterface ? null : LoadTypeWrapper(classLoader, f.SuperClass), classLoader, protectionDomain)
{
Profiler.Count("DynamicTypeWrapper");
if(BaseTypeWrapper != null)
2004-10-04 23:30:53 +04:00
{
2005-06-01 13:49:30 +04:00
if(!BaseTypeWrapper.IsAccessibleFrom(this))
{
throw new IllegalAccessError("Class " + f.Name + " cannot access its superclass " + BaseTypeWrapper.Name);
}
if(BaseTypeWrapper.IsFinal)
{
throw new VerifyError("Cannot inherit from final class");
}
if(BaseTypeWrapper.IsInterface)
{
throw new IncompatibleClassChangeError("Class " + f.Name + " has interface " + BaseTypeWrapper.Name + " as superclass");
}
if(!f.IsFinal)
{
if(BaseTypeWrapper.TypeAsTBD == typeof(ValueType) || BaseTypeWrapper.TypeAsTBD == typeof(Enum))
{
throw new VerifyError("Value types must be final");
}
if(BaseTypeWrapper.TypeAsTBD == typeof(MulticastDelegate))
{
throw new VerifyError("Delegates must be final");
}
}
if(BaseTypeWrapper.TypeAsTBD == typeof(Delegate))
{
throw new VerifyError(BaseTypeWrapper.Name + " cannot be used as a base class");
}
// NOTE defining value types, enums and delegates is not supported in IKVM v1
2004-10-04 23:30:53 +04:00
if(BaseTypeWrapper.TypeAsTBD == typeof(ValueType) || BaseTypeWrapper.TypeAsTBD == typeof(Enum))
{
2005-06-01 13:49:30 +04:00
throw new VerifyError("Defining value types in Java is not implemented in IKVM v1");
2004-10-04 23:30:53 +04:00
}
if(BaseTypeWrapper.TypeAsTBD == typeof(MulticastDelegate))
{
2005-06-01 13:49:30 +04:00
throw new VerifyError("Defining delegates in Java is not implemented in IKVM v1");
2004-10-04 23:30:53 +04:00
}
}
2005-06-01 13:49:30 +04:00
ClassFile.ConstantPoolItemClass[] interfaces = f.Interfaces;
this.interfaces = new TypeWrapper[interfaces.Length];
for(int i = 0; i < interfaces.Length; i++)
2004-10-04 23:30:53 +04:00
{
2005-06-01 13:49:30 +04:00
TypeWrapper iface = LoadTypeWrapper(classLoader, interfaces[i].Name);
if(!iface.IsAccessibleFrom(this))
{
throw new IllegalAccessError("Class " + f.Name + " cannot access its superinterface " + iface.Name);
}
if(!iface.IsInterface)
{
throw new IncompatibleClassChangeError("Implementing class");
}
this.interfaces[i] = iface;
2004-10-04 23:30:53 +04:00
}
2005-06-01 13:49:30 +04:00
impl = new JavaTypeImpl(f, this);
2003-01-06 16:56:37 +03:00
}
2004-08-17 13:05:21 +04:00
2005-06-01 13:49:30 +04:00
internal override bool HasStaticInitializer
2003-01-06 16:56:37 +03:00
{
2005-06-01 13:49:30 +04:00
get
2003-01-06 16:56:37 +03:00
{
2005-06-01 13:49:30 +04:00
return hasStaticInitializer;
2003-01-06 16:56:37 +03:00
}
2004-09-15 17:35:44 +04:00
}
2005-06-01 13:49:30 +04:00
internal override Assembly Assembly
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
get
{
return GetClassLoader().ModuleBuilder.Assembly;
}
2004-08-17 13:05:21 +04:00
}
2005-06-01 13:49:30 +04:00
internal override Modifiers ReflectiveModifiers
2003-05-30 16:08:59 +04:00
{
2005-06-01 13:49:30 +04:00
get
{
return impl.ReflectiveModifiers;
}
2003-05-30 16:08:59 +04:00
}
2002-12-18 19:00:25 +03:00
2005-06-01 13:49:30 +04:00
internal override TypeWrapper[] Interfaces
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return interfaces;
}
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal override TypeWrapper[] InnerClasses
2003-02-18 12:30:34 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return impl.InnerClasses;
}
2003-02-18 12:30:34 +03:00
}
2005-06-01 13:49:30 +04:00
internal override TypeWrapper DeclaringTypeWrapper
2003-02-18 12:30:34 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return impl.DeclaringTypeWrapper;
}
2003-02-18 12:30:34 +03:00
}
2005-06-01 13:49:30 +04:00
internal override Type TypeAsTBD
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return impl.Type;
}
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal override void Finish(bool forDebugSave)
2003-01-02 16:46:16 +03:00
{
2005-06-01 13:49:30 +04:00
lock(this)
2003-05-30 16:08:59 +04:00
{
2005-06-01 13:49:30 +04:00
Profiler.Enter("DynamicTypeWrapper.Finish");
try
{
impl = impl.Finish(forDebugSave);
// call Finish again to get the verify error for doomed types
impl.Finish(forDebugSave);
}
finally
{
Profiler.Leave("DynamicTypeWrapper.Finish");
}
2003-05-30 16:08:59 +04:00
}
2005-06-01 13:49:30 +04:00
}
// NOTE can only be used if the type hasn't been finished yet!
internal FieldInfo ClassObjectField
{
get
2003-05-30 16:08:59 +04:00
{
2005-06-01 13:49:30 +04:00
return ((JavaTypeImpl)impl).ClassObjectField;
2003-05-30 16:08:59 +04:00
}
2003-01-02 16:46:16 +03:00
}
2002-12-18 19:00:25 +03:00
2005-06-01 13:49:30 +04:00
// NOTE can only be used if the type hasn't been finished yet!
protected string GenerateUniqueMethodName(string basename, MethodWrapper mw)
2004-03-08 18:18:47 +03:00
{
2005-06-01 13:49:30 +04:00
return ((JavaTypeImpl)impl).GenerateUniqueMethodName(basename, mw);
2004-03-08 18:18:47 +03:00
}
2004-09-17 13:32:06 +04:00
2005-06-01 13:49:30 +04:00
private abstract class DynamicImpl
{
internal abstract Type Type { get; }
internal abstract TypeWrapper[] InnerClasses { get; }
internal abstract TypeWrapper DeclaringTypeWrapper { get; }
internal abstract Modifiers ReflectiveModifiers { get; }
internal abstract DynamicImpl Finish(bool forDebugSave);
internal abstract MethodBase LinkMethod(MethodWrapper mw);
internal abstract FieldInfo LinkField(FieldWrapper fw);
}
2002-12-18 19:00:25 +03:00
2005-06-01 13:49:30 +04:00
private class JavaTypeImpl : DynamicImpl
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
private readonly ClassFile classFile;
private readonly DynamicTypeWrapper wrapper;
private readonly TypeBuilder typeBuilder;
private MethodWrapper[] methods;
private MethodWrapper[] baseMethods;
private FieldWrapper[] fields;
private bool finishingForDebugSave;
private FinishedTypeImpl finishedType;
private readonly TypeWrapper outerClassWrapper;
private Hashtable memberclashtable;
private Hashtable classCache = new Hashtable();
private FieldInfo classObjectField;
2002-12-18 19:00:25 +03:00
2005-06-01 13:49:30 +04:00
internal JavaTypeImpl(ClassFile f, DynamicTypeWrapper wrapper)
2003-02-20 17:18:38 +03:00
{
2005-06-01 13:49:30 +04:00
Tracer.Info(Tracer.Compiler, "constructing JavaTypeImpl for " + f.Name);
this.classFile = f;
this.wrapper = wrapper;
// process all methods
bool hasclinit = wrapper.BaseTypeWrapper == null ? false : wrapper.BaseTypeWrapper.HasStaticInitializer;
methods = new MethodWrapper[classFile.Methods.Length];
baseMethods = new MethodWrapper[classFile.Methods.Length];
for(int i = 0; i < methods.Length; i++)
2004-09-15 17:35:44 +04:00
{
2005-06-01 13:49:30 +04:00
ClassFile.Method m = classFile.Methods[i];
if(m.IsClassInitializer)
2004-09-15 17:35:44 +04:00
{
2005-06-01 13:49:30 +04:00
if(JVM.IsStaticCompiler)
{
if(!IsSideEffectFreeStaticInitializer(m))
{
hasclinit = true;
}
}
else
2004-09-15 17:35:44 +04:00
{
hasclinit = true;
}
}
2005-06-01 13:49:30 +04:00
if(wrapper.IsGhost)
{
methods[i] = new MethodWrapper.GhostMethodWrapper(wrapper, m.Name, m.Signature, null, null, null, m.Modifiers, MemberFlags.None);
}
else if(m.Name == "<init>")
{
methods[i] = new SmartConstructorMethodWrapper(wrapper, m.Name, m.Signature, null, null, m.Modifiers, MemberFlags.None);
}
2004-09-15 17:35:44 +04:00
else
{
2005-06-01 13:49:30 +04:00
bool explicitOverride = false;
if(!classFile.IsInterface && !m.IsStatic && !m.IsPrivate)
{
baseMethods[i] = FindBaseMethod(m.Name, m.Signature, out explicitOverride);
}
methods[i] = new SmartCallMethodWrapper(wrapper, m.Name, m.Signature, null, null, null, m.Modifiers, explicitOverride ? MemberFlags.ExplicitOverride : MemberFlags.None, SimpleOpCode.Call, SimpleOpCode.Callvirt);
2004-09-15 17:35:44 +04:00
}
}
2005-06-01 13:49:30 +04:00
wrapper.hasStaticInitializer = hasclinit;
if(wrapper.IsAbstract && !wrapper.IsInterface)
2003-02-20 17:18:38 +03:00
{
2005-06-01 13:49:30 +04:00
ArrayList methodsArray = new ArrayList(methods);
ArrayList baseMethodsArray = new ArrayList(baseMethods);
AddMirandaMethods(methodsArray, baseMethodsArray, wrapper);
this.methods = (MethodWrapper[])methodsArray.ToArray(typeof(MethodWrapper));
this.baseMethods = (MethodWrapper[])baseMethodsArray.ToArray(typeof(MethodWrapper));
2003-02-20 17:18:38 +03:00
}
2005-06-01 13:49:30 +04:00
wrapper.SetMethods(methods);
fields = new FieldWrapper[classFile.Fields.Length];
for(int i = 0; i < fields.Length; i++)
2003-02-20 17:18:38 +03:00
{
2005-06-01 13:49:30 +04:00
ClassFile.Field fld = classFile.Fields[i];
if(fld.IsStatic && fld.IsFinal && fld.ConstantValue != null)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
fields[i] = new ConstantFieldWrapper(wrapper, null, fld.Name, fld.Signature, fld.Modifiers, null, fld.ConstantValue);
}
2005-07-07 17:10:09 +04:00
else if(fld.IsFinal && (JVM.IsStaticCompiler && (fld.IsPublic || fld.IsProtected))
&& !wrapper.IsInterface && (!JVM.StrictFinalFieldSemantics || wrapper.Name == "java.lang.System"))
2005-06-01 13:49:30 +04:00
{
fields[i] = new GetterFieldWrapper(wrapper, null, null, fld.Name, fld.Signature, fld.Modifiers, null);
}
else
{
fields[i] = FieldWrapper.Create(wrapper, null, null, fld.Name, fld.Signature, fld.Modifiers);
2004-08-17 13:05:21 +04:00
}
2005-01-03 11:26:21 +03:00
}
2005-06-01 13:49:30 +04:00
wrapper.SetFields(fields);
2004-08-17 13:05:21 +04:00
2005-06-01 13:49:30 +04:00
// from now on we shouldn't be throwing any exceptions (to be precise, after we've
// called ModuleBuilder.DefineType)
try
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
TypeAttributes typeAttribs = 0;
if(f.IsAbstract)
2003-10-17 12:08:31 +04:00
{
2005-06-01 13:49:30 +04:00
typeAttribs |= TypeAttributes.Abstract;
}
if(f.IsFinal)
{
typeAttribs |= TypeAttributes.Sealed;
}
if(!hasclinit)
{
typeAttribs |= TypeAttributes.BeforeFieldInit;
}
TypeBuilder outer = null;
// only if requested, we compile inner classes as nested types, because it has a higher cost
// and doesn't buy us anything, unless we're compiling a library that could be used from C# (e.g.)
if(JVM.CompileInnerClassesAsNestedTypes)
{
if(f.OuterClass != null)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
if(!CheckInnerOuterNames(f.Name, f.OuterClass.Name))
{
Tracer.Warning(Tracer.Compiler, "Incorrect InnerClasses attribute on {0}", f.Name);
}
else
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
outerClassWrapper = wrapper.GetClassLoader().LoadClassByDottedName(f.OuterClass.Name);
if(outerClassWrapper is DynamicTypeWrapper)
{
outer = outerClassWrapper.TypeAsBuilder;
}
2004-08-17 13:05:21 +04:00
}
}
2003-10-17 12:08:31 +04:00
}
2005-06-01 13:49:30 +04:00
if(f.IsPublic)
2003-10-17 12:08:31 +04:00
{
2005-06-01 13:49:30 +04:00
if(outer != null)
{
typeAttribs |= TypeAttributes.NestedPublic;
}
else
{
typeAttribs |= TypeAttributes.Public;
}
2003-10-17 12:08:31 +04:00
}
2005-06-01 13:49:30 +04:00
else if(outer != null)
2003-10-17 12:08:31 +04:00
{
2005-06-01 13:49:30 +04:00
typeAttribs |= TypeAttributes.NestedAssembly;
2003-10-17 12:08:31 +04:00
}
2005-06-01 13:49:30 +04:00
if(f.IsInterface)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
typeAttribs |= TypeAttributes.Interface | TypeAttributes.Abstract;
if(outer != null)
{
if(wrapper.IsGhost)
{
// TODO this is low priority, since the current Java class library doesn't define any ghost interfaces
// as inner classes
throw new NotImplementedException();
}
// LAMESPEC the CLI spec says interfaces cannot contain nested types (Part.II, 9.6), but that rule isn't enforced
// (and broken by J# as well), so we'll just ignore it too.
typeBuilder = outer.DefineNestedType(GetInnerClassName(outerClassWrapper.Name, f.Name), typeAttribs);
}
else
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
typeBuilder = wrapper.DefineType(typeAttribs);
2004-08-17 13:05:21 +04:00
}
}
else
{
2005-06-01 13:49:30 +04:00
typeAttribs |= TypeAttributes.Class;
if(outer != null)
{
// LAMESPEC the CLI spec says interfaces cannot contain nested types (Part.II, 9.6), but that rule isn't enforced
// (and broken by J# as well), so we'll just ignore it too.
typeBuilder = outer.DefineNestedType(GetInnerClassName(outerClassWrapper.Name, f.Name), typeAttribs, wrapper.BaseTypeWrapper.TypeAsBaseType);
}
else
{
typeBuilder = wrapper.GetClassLoader().ModuleBuilder.DefineType(wrapper.GetClassLoader().MangleTypeName(f.Name), typeAttribs, wrapper.BaseTypeWrapper.TypeAsBaseType);
}
2004-08-17 13:05:21 +04:00
}
2005-06-01 13:49:30 +04:00
TypeWrapper[] interfaces = wrapper.Interfaces;
for(int i = 0; i < interfaces.Length; i++)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
// NOTE we're using TypeAsBaseType for the interfaces!
typeBuilder.AddInterfaceImplementation(interfaces[i].TypeAsBaseType);
2004-08-17 13:05:21 +04:00
}
2005-06-01 13:49:30 +04:00
AttributeHelper.SetImplementsAttribute(typeBuilder, interfaces);
if(JVM.IsStaticCompiler && classFile.DeprecatedAttribute)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
AttributeHelper.SetDeprecatedAttribute(typeBuilder);
}
2005-07-07 15:24:08 +04:00
if(!JVM.NoStackTraceInfo)
2005-06-01 13:49:30 +04:00
{
2005-07-07 15:24:08 +04:00
if(f.SourceFileAttribute != null)
{
if(f.SourceFileAttribute != typeBuilder.Name + ".java")
{
AttributeHelper.SetSourceFile(typeBuilder, f.SourceFileAttribute);
}
}
else
{
AttributeHelper.SetSourceFile(typeBuilder, null);
}
2004-08-17 13:05:21 +04:00
}
}
2005-06-01 13:49:30 +04:00
catch(Exception x)
2004-10-19 17:43:55 +04:00
{
2005-06-01 13:49:30 +04:00
if(typeBuilder != null)
{
JVM.CriticalFailure("Exception during critical part of JavaTypeImpl construction", x);
}
throw;
2004-10-19 17:43:55 +04:00
}
2002-12-29 19:27:00 +03:00
}
2005-06-01 13:49:30 +04:00
private bool IsSideEffectFreeStaticInitializer(ClassFile.Method m)
2002-12-29 19:27:00 +03:00
{
2005-06-01 13:49:30 +04:00
if(m.ExceptionTable.Length != 0)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
return false;
2004-08-17 13:05:21 +04:00
}
2005-06-01 13:49:30 +04:00
for(int i = 0; i < m.Instructions.Length; i++)
2004-09-15 17:35:44 +04:00
{
2005-06-01 13:49:30 +04:00
ByteCode bc = m.Instructions[i].OpCode;
if(bc == ByteCode.__getstatic || bc == ByteCode.__putstatic)
{
ClassFile.ConstantPoolItemFieldref fld = classFile.GetFieldref(m.Instructions[i].Arg1);
if(fld.Class != classFile.Name)
{
return false;
}
// don't allow getstatic to load non-primitive fields, because that would
// cause the verifier to try to load the type
if(bc == ByteCode.__getstatic && "L[".IndexOf(fld.Signature[0]) != -1)
{
return false;
}
}
else if(bc == ByteCode.__areturn ||
bc == ByteCode.__ireturn ||
bc == ByteCode.__lreturn ||
bc == ByteCode.__freturn ||
bc == ByteCode.__dreturn)
2004-09-15 17:35:44 +04:00
{
return false;
}
2005-06-01 13:49:30 +04:00
else if(ByteCodeMetaData.CanThrowException(bc))
2004-09-15 17:35:44 +04:00
{
return false;
}
}
2005-06-01 13:49:30 +04:00
// the method needs to be verifiable to be side effect free, since we already analysed it,
// we know that the verifier won't try to load any types (which isn't allowed at this time)
try
2004-09-15 17:35:44 +04:00
{
2005-06-01 13:49:30 +04:00
new MethodAnalyzer(wrapper, null, classFile, m, null);
return true;
2004-09-15 17:35:44 +04:00
}
2005-06-01 13:49:30 +04:00
catch(VerifyError)
2004-09-15 17:35:44 +04:00
{
return false;
}
}
2005-06-01 13:49:30 +04:00
private MethodWrapper GetMethodWrapperDuringCtor(TypeWrapper lookup, ArrayList methods, string name, string sig)
2005-01-03 11:26:21 +03:00
{
2005-06-01 13:49:30 +04:00
if(lookup == wrapper)
2005-01-03 11:26:21 +03:00
{
2005-06-01 13:49:30 +04:00
foreach(MethodWrapper mw in methods)
2005-01-03 11:26:21 +03:00
{
2005-06-01 13:49:30 +04:00
if(mw.Name == name && mw.Signature == sig)
{
return mw;
}
}
if(lookup.BaseTypeWrapper == null)
{
return null;
}
else
{
return lookup.BaseTypeWrapper.GetMethodWrapper(name, sig, true);
2005-01-03 11:26:21 +03:00
}
}
else
{
2005-06-01 13:49:30 +04:00
return lookup.GetMethodWrapper(name, sig, true);
2005-01-03 11:26:21 +03:00
}
}
2005-06-01 13:49:30 +04:00
private void AddMirandaMethods(ArrayList methods, ArrayList baseMethods, TypeWrapper tw)
2003-11-17 15:01:50 +03:00
{
2005-06-01 13:49:30 +04:00
foreach(TypeWrapper iface in tw.Interfaces)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
AddMirandaMethods(methods, baseMethods, iface);
foreach(MethodWrapper ifmethod in iface.GetMethods())
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
// skip <clinit>
if(!ifmethod.IsStatic)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
TypeWrapper lookup = wrapper;
while(lookup != null)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
MethodWrapper mw = GetMethodWrapperDuringCtor(lookup, methods, ifmethod.Name, ifmethod.Signature);
if(mw == null)
{
mw = new SmartCallMethodWrapper(wrapper, ifmethod.Name, ifmethod.Signature, null, null, null, Modifiers.Public | Modifiers.Abstract, MemberFlags.HideFromReflection | MemberFlags.MirandaMethod, SimpleOpCode.Call, SimpleOpCode.Callvirt);
methods.Add(mw);
baseMethods.Add(ifmethod);
break;
}
if(!mw.IsStatic)
{
break;
}
lookup = mw.DeclaringType.BaseTypeWrapper;
2004-08-17 13:05:21 +04:00
}
}
}
}
2003-11-17 15:01:50 +03:00
}
2003-02-20 17:18:38 +03:00
2005-06-01 13:49:30 +04:00
private static bool CheckInnerOuterNames(string inner, string outer)
{
// do some sanity checks on the inner/outer class names
return inner.Length > outer.Length + 1 && inner[outer.Length] == '$' && inner.IndexOf('$', outer.Length + 1) == -1;
}
2002-12-18 19:00:25 +03:00
2005-06-01 13:49:30 +04:00
private static string GetInnerClassName(string outer, string inner)
2003-11-17 15:01:50 +03:00
{
2005-06-01 13:49:30 +04:00
Debug.Assert(CheckInnerOuterNames(inner, outer));
return inner.Substring(outer.Length + 1);
2003-11-17 15:01:50 +03:00
}
2005-06-01 13:49:30 +04:00
private static bool IsCompatibleArgList(TypeWrapper[] caller, TypeWrapper[] callee)
2003-12-20 01:19:18 +03:00
{
2005-06-01 13:49:30 +04:00
if(caller.Length == callee.Length)
2003-12-20 01:19:18 +03:00
{
2005-06-01 13:49:30 +04:00
for(int i = 0; i < caller.Length; i++)
2003-12-20 01:19:18 +03:00
{
2005-06-01 13:49:30 +04:00
if(!caller[i].IsAssignableTo(callee[i]))
2003-12-20 01:19:18 +03:00
{
2005-06-01 13:49:30 +04:00
return false;
2003-12-20 01:19:18 +03:00
}
}
2005-06-01 13:49:30 +04:00
return true;
2003-12-20 01:19:18 +03:00
}
2005-06-01 13:49:30 +04:00
return false;
2003-12-20 01:19:18 +03:00
}
2005-06-01 13:49:30 +04:00
private void EmitConstantValueInitialization(ILGenerator ilGenerator)
2004-09-17 13:32:06 +04:00
{
2005-06-01 13:49:30 +04:00
ClassFile.Field[] fields = classFile.Fields;
for(int i = 0; i < fields.Length; i++)
2004-09-17 13:32:06 +04:00
{
2005-06-01 13:49:30 +04:00
ClassFile.Field f = fields[i];
if(f.IsStatic && !f.IsFinal)
2004-09-17 13:32:06 +04:00
{
2005-06-01 13:49:30 +04:00
object constant = f.ConstantValue;
if(constant != null)
{
if(constant is int)
{
ilGenerator.Emit(OpCodes.Ldc_I4, (int)constant);
}
else if(constant is long)
{
ilGenerator.Emit(OpCodes.Ldc_I8, (long)constant);
}
else if(constant is double)
{
ilGenerator.Emit(OpCodes.Ldc_R8, (double)constant);
}
else if(constant is float)
{
ilGenerator.Emit(OpCodes.Ldc_R4, (float)constant);
}
else if(constant is string)
{
ilGenerator.Emit(OpCodes.Ldstr, (string)constant);
}
else
{
throw new InvalidOperationException();
}
this.fields[i].EmitSet(ilGenerator);
}
2004-09-17 13:32:06 +04:00
}
}
}
2005-06-01 13:49:30 +04:00
internal FieldInfo ClassObjectField
2005-01-03 11:26:21 +03:00
{
2005-06-01 13:49:30 +04:00
get
2005-01-03 11:26:21 +03:00
{
2005-06-01 13:49:30 +04:00
lock(this)
{
if(classObjectField == null)
{
classObjectField = typeBuilder.DefineField("__<classObject>", typeof(object), FieldAttributes.Private | FieldAttributes.Static);
AttributeHelper.HideFromJava((FieldBuilder)classObjectField);
}
return classObjectField;
}
2005-01-03 11:26:21 +03:00
}
}
2005-06-01 13:49:30 +04:00
private int GetMethodIndex(MethodWrapper mw)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
for(int i = 0; i < methods.Length; i++)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
if(methods[i] == mw)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
return i;
2004-08-17 13:05:21 +04:00
}
}
2005-06-01 13:49:30 +04:00
throw new InvalidOperationException();
}
internal override MethodBase LinkMethod(MethodWrapper mw)
{
Debug.Assert(mw != null);
bool unloadableOverrideStub = false;
int index = GetMethodIndex(mw);
MethodWrapper baseMethod = baseMethods[index];
if(baseMethod != null)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
baseMethod.Link();
// check the loader constraints
if(mw.ReturnType != baseMethod.ReturnType)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
if(baseMethod.ReturnType.IsUnloadable || finishingForDebugSave)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
if(!mw.ReturnType.IsUnloadable || (!baseMethod.ReturnType.IsUnloadable && finishingForDebugSave))
2004-08-17 13:05:21 +04:00
{
unloadableOverrideStub = true;
}
}
else
{
throw new LinkageError("Loader constraints violated");
}
}
2005-06-01 13:49:30 +04:00
TypeWrapper[] here = mw.GetParameters();
TypeWrapper[] there = baseMethod.GetParameters();
for(int i = 0; i < here.Length; i++)
{
if(here[i] != there[i])
{
if(there[i].IsUnloadable || finishingForDebugSave)
{
if(!here[i].IsUnloadable || (!there[i].IsUnloadable && finishingForDebugSave))
{
unloadableOverrideStub = true;
}
}
else
{
throw new LinkageError("Loader constraints violated");
}
}
}
2004-08-17 13:05:21 +04:00
}
2005-06-01 13:49:30 +04:00
Debug.Assert(mw.GetMethod() == null);
MethodBase mb = GenerateMethod(index, unloadableOverrideStub);
if((mw.Modifiers & (Modifiers.Synchronized | Modifiers.Static)) == Modifiers.Synchronized)
{
// note that constructors cannot be synchronized in Java
MethodBuilder mbld = (MethodBuilder)mb;
mbld.SetImplementationFlags(mbld.GetMethodImplementationFlags() | MethodImplAttributes.Synchronized);
}
return mb;
2004-08-17 13:05:21 +04:00
}
2005-06-01 13:49:30 +04:00
private int GetFieldIndex(FieldWrapper fw)
2005-01-03 11:26:21 +03:00
{
2005-06-01 13:49:30 +04:00
for(int i = 0; i < fields.Length; i++)
2005-01-03 11:26:21 +03:00
{
2005-06-01 13:49:30 +04:00
if(fields[i] == fw)
{
return i;
}
2005-01-03 11:26:21 +03:00
}
2005-06-01 13:49:30 +04:00
throw new InvalidOperationException();
2005-01-03 11:26:21 +03:00
}
2005-06-01 13:49:30 +04:00
internal override FieldInfo LinkField(FieldWrapper fw)
2005-01-03 11:26:21 +03:00
{
2005-06-01 13:49:30 +04:00
Debug.Assert(fw != null);
FieldBuilder field;
ClassFile.Field fld = classFile.Fields[GetFieldIndex(fw)];
string fieldName = fld.Name;
TypeWrapper typeWrapper = fw.FieldTypeWrapper;
Type type = typeWrapper.TypeAsSignatureType;
bool setNameSig = typeWrapper.IsUnloadable || typeWrapper.IsGhostArray;
if(setNameSig)
2005-01-03 11:26:21 +03:00
{
2005-06-01 13:49:30 +04:00
// TODO use clashtable
// the field name is mangled here, because otherwise it can (theoretically)
// conflict with another unloadable or object or ghost array field
// (fields can be overloaded on type)
fieldName += "/" + typeWrapper.Name;
}
FieldAttributes attribs = 0;
MethodAttributes methodAttribs = 0;
bool setModifiers = false;
if(fld.IsPrivate)
{
attribs |= FieldAttributes.Private;
2005-01-03 11:26:21 +03:00
}
2005-06-01 13:49:30 +04:00
else if(fld.IsProtected)
2005-01-03 11:26:21 +03:00
{
2005-06-01 13:49:30 +04:00
attribs |= FieldAttributes.FamORAssem;
methodAttribs |= MethodAttributes.FamORAssem;
2005-01-03 11:26:21 +03:00
}
2005-06-01 13:49:30 +04:00
else if(fld.IsPublic)
2005-01-03 11:26:21 +03:00
{
2005-06-01 13:49:30 +04:00
attribs |= FieldAttributes.Public;
methodAttribs |= MethodAttributes.Public;
2005-01-03 11:26:21 +03:00
}
2005-06-01 13:49:30 +04:00
else
{
attribs |= FieldAttributes.Assembly;
methodAttribs |= MethodAttributes.Assembly;
}
if(fld.IsStatic)
2005-01-03 11:26:21 +03:00
{
2005-06-01 13:49:30 +04:00
attribs |= FieldAttributes.Static;
methodAttribs |= MethodAttributes.Static;
2005-01-03 11:26:21 +03:00
}
2005-06-01 13:49:30 +04:00
// NOTE "constant" static finals are converted into literals
// TODO it would be possible for Java code to change the value of a non-blank static final, but I don't
// know if we want to support this (since the Java JITs don't really support it either)
object constantValue = fld.ConstantValue;
if(fld.IsStatic && fld.IsFinal && constantValue != null)
2005-01-03 11:26:21 +03:00
{
2005-06-01 13:49:30 +04:00
Profiler.Count("Static Final Constant");
attribs |= FieldAttributes.Literal;
field = typeBuilder.DefineField(fieldName, type, attribs);
field.SetConstant(constantValue);
2005-01-03 11:26:21 +03:00
}
2005-06-01 13:49:30 +04:00
else
2005-01-03 11:26:21 +03:00
{
2005-07-07 17:10:09 +04:00
bool isWrappedFinal = fw is GetterFieldWrapper;
if(fld.IsFinal)
2005-01-03 11:26:21 +03:00
{
2005-07-07 17:10:09 +04:00
if(isWrappedFinal)
2005-06-01 13:49:30 +04:00
{
// NOTE public/protected 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;
}
2005-07-07 17:10:09 +04:00
else if(wrapper.IsInterface || JVM.StrictFinalFieldSemantics)
{
attribs |= FieldAttributes.InitOnly;
}
else
{
setModifiers = true;
}
2005-06-01 13:49:30 +04:00
}
field = typeBuilder.DefineField(fieldName, type, attribs);
if(fld.IsTransient)
{
CustomAttributeBuilder transientAttrib = new CustomAttributeBuilder(typeof(NonSerializedAttribute).GetConstructor(Type.EmptyTypes), new object[0]);
field.SetCustomAttribute(transientAttrib);
}
if(fld.IsVolatile)
{
// TODO the field should be marked as modreq(IsVolatile), but Reflection.Emit doesn't have a way of doing this
setModifiers = true;
}
// Instance fields can also have a ConstantValue attribute (and are inlined by the compiler),
// and ikvmstub has to export them, so we have to add a custom attribute.
if(constantValue != null)
{
CustomAttributeBuilder constantValueAttrib = new CustomAttributeBuilder(typeof(ConstantValueAttribute).GetConstructor(new Type[] { constantValue.GetType() }), new object[] { constantValue });
field.SetCustomAttribute(constantValueAttrib);
}
if(isWrappedFinal)
{
methodAttribs |= MethodAttributes.SpecialName;
// TODO we should ensure that the getter method name doesn't clash with an existing method
MethodBuilder getter = typeBuilder.DefineMethod("get_" + fld.Name, methodAttribs, CallingConventions.Standard, type, Type.EmptyTypes);
AttributeHelper.HideFromJava(getter);
ILGenerator ilgen = getter.GetILGenerator();
if(fld.IsStatic)
{
ilgen.Emit(OpCodes.Ldsfld, field);
}
else
{
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Ldfld, field);
}
ilgen.Emit(OpCodes.Ret);
PropertyBuilder pb = typeBuilder.DefineProperty(fld.Name, PropertyAttributes.None, type, Type.EmptyTypes);
pb.SetGetMethod(getter);
((GetterFieldWrapper)fw).SetGetter(getter);
2005-01-03 11:26:21 +03:00
}
}
2005-06-01 13:49:30 +04:00
// if the Java modifiers cannot be expressed in .NET, we emit the Modifiers attribute to store
// the Java modifiers
if(setModifiers)
{
AttributeHelper.SetModifiers(field, fld.Modifiers);
}
if(setNameSig)
{
AttributeHelper.SetNameSig(field, fld.Name, fld.Signature);
}
if(JVM.IsStaticCompiler && fld.DeprecatedAttribute)
{
AttributeHelper.SetDeprecatedAttribute(field);
}
return field;
2005-01-03 11:26:21 +03:00
}
2004-08-17 13:05:21 +04:00
2005-06-01 13:49:30 +04:00
internal override DynamicImpl Finish(bool forDebugSave)
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
this.finishingForDebugSave = forDebugSave;
// NOTE if a finish is triggered during static compilation phase 1, it cannot be handled properly,
// so we bail out.
// (this should only happen during compilation of classpath.dll and is most likely caused by a bug somewhere)
if(JVM.IsStaticCompilerPhase1)
2003-02-18 12:30:34 +03:00
{
2005-06-01 13:49:30 +04:00
JVM.CriticalFailure("Finish triggered during phase 1 of compilation.", null);
return null;
2003-02-18 12:30:34 +03:00
}
2005-06-01 13:49:30 +04:00
if(wrapper.BaseTypeWrapper != null)
{
wrapper.BaseTypeWrapper.Finish(forDebugSave);
}
if(outerClassWrapper != null)
{
outerClassWrapper.Finish(forDebugSave);
}
// 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.
// The Name in the ResolveEventArgs contains only the nested type name, not the full type name,
// for example, if the type being resolved is "MyOuterType+MyInnerType", then the event only
// receives "MyInnerType" as the name. Since we only compile inner classes as nested types
// when we're statically compiling, we can only run into this bug when we're statically compiling.
// NOTE To work around this bug, we have to make sure that all types that are going to be
// required in finished form, are finished explicitly here. It isn't clear what other types are
// required to be finished. I instrumented a static compilation of classpath.dll and this
// turned up no other cases of the TypeResolve event firing.
for(int i = 0; i < wrapper.Interfaces.Length; i++)
{
wrapper.Interfaces[i].Finish(forDebugSave);
}
// 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
// are in the process of finishing, and this would be a problem.
classFile.Link(wrapper, classCache);
for(int i = 0; i < fields.Length; i++)
{
fields[i].Link();
}
for(int i = 0; i < methods.Length; i++)
{
methods[i].Link();
}
// it is possible that the loading of the referenced classes triggered a finish of us,
// if that happens, we just return
if(finishedType != null)
{
return finishedType;
}
Profiler.Enter("JavaTypeImpl.Finish.Core");
try
2003-10-17 12:08:31 +04:00
{
2005-06-01 13:49:30 +04:00
TypeWrapper declaringTypeWrapper = null;
TypeWrapper[] innerClassesTypeWrappers = TypeWrapper.EmptyArray;
// if we're an inner class, we need to attach an InnerClass attribute
ClassFile.InnerClass[] innerclasses = classFile.InnerClasses;
if(innerclasses != null)
2003-10-17 12:08:31 +04:00
{
2005-06-01 13:49:30 +04:00
// TODO consider not pre-computing innerClassesTypeWrappers and declaringTypeWrapper here
ArrayList wrappers = new ArrayList();
for(int i = 0; i < innerclasses.Length; i++)
2003-10-17 12:08:31 +04:00
{
2005-06-01 13:49:30 +04:00
if(innerclasses[i].innerClass != 0 && innerclasses[i].outerClass != 0)
2003-10-17 12:08:31 +04:00
{
2005-06-01 13:49:30 +04:00
if(classFile.GetConstantPoolClassType(innerclasses[i].outerClass) == wrapper)
{
wrappers.Add(classFile.GetConstantPoolClassType(innerclasses[i].innerClass));
}
if(classFile.GetConstantPoolClassType(innerclasses[i].innerClass) == wrapper)
{
declaringTypeWrapper = classFile.GetConstantPoolClassType(innerclasses[i].outerClass);
2005-07-07 15:24:08 +04:00
string inner = classFile.GetConstantPoolClass(innerclasses[i].innerClass);
if(inner == classFile.Name && inner == declaringTypeWrapper.Name + "$" + typeBuilder.Name)
{
inner = null;
}
AttributeHelper.SetInnerClass(typeBuilder, inner, innerclasses[i].accessFlags);
2005-06-01 13:49:30 +04:00
}
2003-10-17 12:08:31 +04:00
}
}
2005-06-01 13:49:30 +04:00
innerClassesTypeWrappers = (TypeWrapper[])wrappers.ToArray(typeof(TypeWrapper));
2003-10-17 12:08:31 +04:00
}
2005-06-01 13:49:30 +04:00
wrapper.FinishGhost(typeBuilder, methods);
// if we're not abstract make sure we don't inherit any abstract methods
if(!wrapper.IsAbstract)
2003-10-17 12:08:31 +04:00
{
2005-06-01 13:49:30 +04:00
TypeWrapper parent = wrapper.BaseTypeWrapper;
// if parent is not abstract, the .NET implementation will never have abstract methods (only
// stubs that throw AbstractMethodError)
// NOTE interfaces are supposed to be abstract, but the VM doesn't enforce this, so
// we have to check for a null parent (interfaces have no parent).
while(parent != null && parent.IsAbstract)
2003-10-17 12:08:31 +04:00
{
2005-06-01 13:49:30 +04:00
foreach(MethodWrapper mw in parent.GetMethods())
{
MethodInfo mi = mw.GetMethod() as MethodInfo;
if(mi != null && mi.IsAbstract && wrapper.GetMethodWrapper(mw.Name, mw.Signature, true).IsAbstract)
{
// NOTE in Sun's JRE 1.4.1 this method cannot be overridden by subclasses,
// but I think this is a bug, so we'll support it anyway.
MethodBuilder mb = typeBuilder.DefineMethod(mi.Name, mi.Attributes & ~(MethodAttributes.Abstract|MethodAttributes.NewSlot), CallingConventions.Standard, mw.ReturnTypeForDefineMethod, mw.GetParametersForDefineMethod());
AttributeHelper.HideFromJava(mb);
EmitHelper.Throw(mb.GetILGenerator(), "java.lang.AbstractMethodError", wrapper.Name + "." + mw.Name + mw.Signature);
}
}
parent = parent.BaseTypeWrapper;
2003-01-02 18:44:17 +03:00
}
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
string verifyError = null;
bool basehasclinit = wrapper.BaseTypeWrapper != null && wrapper.BaseTypeWrapper.HasStaticInitializer;
bool hasclinit = false;
for(int i = 0; i < classFile.Methods.Length; i++)
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
ClassFile.Method m = classFile.Methods[i];
MethodBase mb = methods[i].GetMethod();
if(mb is ConstructorBuilder)
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
ILGenerator ilGenerator = ((ConstructorBuilder)mb).GetILGenerator();
Tracer.EmitMethodTrace(ilGenerator, classFile.Name + "." + m.Name + m.Signature);
if(basehasclinit && m.IsClassInitializer && !classFile.IsInterface)
2003-01-02 18:44:17 +03:00
{
2005-06-01 13:49:30 +04:00
hasclinit = true;
// before we call the base class initializer, we need to set the non-final static ConstantValue fields
EmitConstantValueInitialization(ilGenerator);
EmitHelper.RunClassConstructor(ilGenerator, Type.BaseType);
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
Compiler.Compile(wrapper, methods[i], classFile, m, ilGenerator, ref verifyError);
2004-08-17 13:05:21 +04:00
}
2005-06-01 13:49:30 +04:00
else
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
if(m.IsAbstract)
2005-05-27 16:44:06 +04:00
{
2005-06-01 13:49:30 +04:00
// NOTE in the JVM it is apparently legal for a non-abstract class to have abstract methods, but
// the CLR doens't allow this, so we have to emit a method that throws an AbstractMethodError
if(!classFile.IsAbstract)
{
ILGenerator ilGenerator = ((MethodBuilder)mb).GetILGenerator();
Tracer.EmitMethodTrace(ilGenerator, classFile.Name + "." + m.Name + m.Signature);
EmitHelper.Throw(ilGenerator, "java.lang.AbstractMethodError", classFile.Name + "." + m.Name + m.Signature);
}
2005-05-27 16:44:06 +04:00
}
2005-06-01 13:49:30 +04:00
else if(m.IsNative)
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
if((mb.Attributes & MethodAttributes.PinvokeImpl) != 0)
2003-11-17 15:01:50 +03:00
{
2005-05-30 19:30:13 +04:00
continue;
2003-11-17 15:01:50 +03:00
}
2005-06-01 13:49:30 +04:00
Profiler.Enter("JavaTypeImpl.Finish.Native");
try
2003-11-17 15:01:50 +03:00
{
2005-06-01 13:49:30 +04:00
ILGenerator ilGenerator = ((MethodBuilder)mb).GetILGenerator();
Tracer.EmitMethodTrace(ilGenerator, classFile.Name + "." + m.Name + m.Signature);
// do we have a native implementation in map.xml?
if(wrapper.EmitMapXmlMethodBody(ilGenerator, classFile, m))
2003-11-17 15:01:50 +03:00
{
2005-06-01 13:49:30 +04:00
continue;
2003-11-17 15:01:50 +03:00
}
2005-06-01 13:49:30 +04:00
// see if there exists a IKVM.NativeCode class for this type
Type nativeCodeType = Type.GetType("IKVM.NativeCode." + classFile.Name.Replace('$', '+'));
MethodInfo nativeMethod = null;
TypeWrapper[] args = methods[i].GetParameters();
if(nativeCodeType != null)
2003-11-17 15:01:50 +03:00
{
2005-06-01 13:49:30 +04:00
TypeWrapper[] nargs = args;
if(!m.IsStatic)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
nargs = new TypeWrapper[args.Length + 1];
args.CopyTo(nargs, 1);
nargs[0] = this.wrapper;
2004-08-17 13:05:21 +04:00
}
2005-06-01 13:49:30 +04:00
MethodInfo[] nativeCodeTypeMethods = nativeCodeType.GetMethods(BindingFlags.Static | BindingFlags.Public);
foreach(MethodInfo method in nativeCodeTypeMethods)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
ParameterInfo[] param = method.GetParameters();
TypeWrapper[] match = new TypeWrapper[param.Length];
for(int j = 0; j < param.Length; j++)
{
match[j] = ClassLoaderWrapper.GetWrapperFromType(param[j].ParameterType);
}
if(m.Name == method.Name && IsCompatibleArgList(nargs, match))
{
// TODO instead of taking the first matching method, we should find the best one
nativeMethod = method;
break;
}
2004-08-17 13:05:21 +04:00
}
2003-11-17 15:01:50 +03:00
}
2005-06-01 13:49:30 +04:00
if(nativeMethod != null)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
int add = 0;
if(!m.IsStatic)
{
ilGenerator.Emit(OpCodes.Ldarg_0);
add = 1;
}
for(int j = 0; j < args.Length; j++)
{
ilGenerator.Emit(OpCodes.Ldarg_S, (byte)(j + add));
}
ilGenerator.Emit(OpCodes.Call, nativeMethod);
TypeWrapper retTypeWrapper = methods[i].ReturnType;
if(!retTypeWrapper.TypeAsTBD.Equals(nativeMethod.ReturnType) && !retTypeWrapper.IsGhost)
{
ilGenerator.Emit(OpCodes.Castclass, retTypeWrapper.TypeAsTBD);
}
ilGenerator.Emit(OpCodes.Ret);
2004-08-17 13:05:21 +04:00
}
else
{
2005-06-01 13:49:30 +04:00
if(JVM.NoJniStubs)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
// since NoJniStubs can only be set when we're statically compiling, it is safe to use the "compiler" trace switch
Tracer.Warning(Tracer.Compiler, "Native method not implemented: {0}.{1}.{2}", classFile.Name, m.Name, m.Signature);
EmitHelper.Throw(ilGenerator, "java.lang.UnsatisfiedLinkError", "Native method not implemented (compiled with -nojni): " + classFile.Name + "." + m.Name + m.Signature);
2004-08-17 13:05:21 +04:00
}
else
{
2005-06-01 13:49:30 +04:00
if(ClassLoaderWrapper.IsSaveDebugImage)
{
JniProxyBuilder.Generate(ilGenerator, wrapper, methods[i], typeBuilder, classFile, m, args);
}
else
{
JniBuilder.Generate(ilGenerator, wrapper, methods[i], typeBuilder, classFile, m, args, false);
}
2004-08-17 13:05:21 +04:00
}
}
2003-01-02 18:44:17 +03:00
}
2005-06-01 13:49:30 +04:00
finally
{
Profiler.Leave("JavaTypeImpl.Finish.Native");
}
2003-01-02 18:44:17 +03:00
}
2005-06-01 13:49:30 +04:00
else
2005-03-01 11:24:54 +03:00
{
2005-06-01 13:49:30 +04:00
MethodBuilder mbld = (MethodBuilder)mb;
ILGenerator ilGenerator = mbld.GetILGenerator();
Tracer.EmitMethodTrace(ilGenerator, classFile.Name + "." + m.Name + m.Signature);
if(wrapper.EmitMapXmlMethodBody(ilGenerator, classFile, m))
{
continue;
}
bool nonleaf = false;
Compiler.Compile(wrapper, methods[i], classFile, m, ilGenerator, ref verifyError, ref nonleaf);
if(nonleaf)
{
mbld.SetImplementationFlags(mbld.GetMethodImplementationFlags() | MethodImplAttributes.NoInlining);
}
2005-03-01 11:24:54 +03:00
}
2002-12-27 12:01:16 +03:00
}
2003-01-02 18:44:17 +03:00
}
2005-06-01 13:49:30 +04:00
// NOTE non-final fields aren't allowed in interfaces so we don't have to initialize constant fields
if(!classFile.IsInterface)
2003-05-30 16:08:59 +04:00
{
2005-06-01 13:49:30 +04:00
// if we don't have a <clinit> we may need to inject one
if(!hasclinit)
2003-12-20 01:19:18 +03:00
{
2005-06-01 13:49:30 +04:00
bool hasconstantfields = false;
if(!basehasclinit)
2003-12-20 01:19:18 +03:00
{
2005-06-01 13:49:30 +04:00
foreach(ClassFile.Field f in classFile.Fields)
2003-12-20 01:19:18 +03:00
{
2005-06-01 13:49:30 +04:00
if(f.IsStatic && !f.IsFinal && f.ConstantValue != null)
{
hasconstantfields = true;
break;
}
2003-12-20 01:19:18 +03:00
}
}
2005-06-01 13:49:30 +04:00
if(basehasclinit || hasconstantfields)
2003-12-20 01:19:18 +03:00
{
2005-06-01 13:49:30 +04:00
ConstructorBuilder cb = DefineClassInitializer();
AttributeHelper.HideFromJava(cb);
ILGenerator ilGenerator = cb.GetILGenerator();
EmitConstantValueInitialization(ilGenerator);
if(basehasclinit)
{
EmitHelper.RunClassConstructor(ilGenerator, Type.BaseType);
}
ilGenerator.Emit(OpCodes.Ret);
2003-12-20 01:19:18 +03:00
}
}
2003-05-30 16:08:59 +04:00
2005-06-01 13:49:30 +04:00
// here we loop thru all the interfaces to explicitly implement any methods that we inherit from
// base types that may have a different name from the name in the interface
// (e.g. interface that has an equals() method that should override System.Object.Equals())
// also deals with interface methods that aren't implemented (generate a stub that throws AbstractMethodError)
// and with methods that aren't public (generate a stub that throws IllegalAccessError)
Hashtable doneSet = new Hashtable();
TypeWrapper[] interfaces = wrapper.Interfaces;
for(int i = 0; i < interfaces.Length; i++)
2003-10-17 12:08:31 +04:00
{
2005-06-01 13:49:30 +04:00
// if we implement a ghost interface, add an implicit conversion to the ghost reference value type
// TODO do this for indirectly implemented interfaces (interfaces implemented by interfaces) as well
if(interfaces[i].IsGhost)
{
MethodBuilder mb = typeBuilder.DefineMethod("op_Implicit", MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.SpecialName, interfaces[i].TypeAsSignatureType, new Type[] { wrapper.TypeAsSignatureType });
AttributeHelper.HideFromJava(mb);
ILGenerator ilgen = mb.GetILGenerator();
LocalBuilder local = ilgen.DeclareLocal(interfaces[i].TypeAsSignatureType);
ilgen.Emit(OpCodes.Ldloca, local);
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Stfld, interfaces[i].GhostRefField);
ilgen.Emit(OpCodes.Ldloca, local);
ilgen.Emit(OpCodes.Ldobj, interfaces[i].TypeAsSignatureType);
ilgen.Emit(OpCodes.Ret);
}
interfaces[i].ImplementInterfaceMethodStubs(typeBuilder, wrapper, doneSet);
2003-10-17 12:08:31 +04:00
}
2005-06-01 13:49:30 +04:00
// if any of our base classes has an incomplete interface implementation we need to look through all
// the base class interfaces to see if we've got an implementation now
TypeWrapper baseTypeWrapper = wrapper.BaseTypeWrapper;
while(baseTypeWrapper.HasIncompleteInterfaceImplementation)
2003-05-13 00:00:15 +04:00
{
2005-06-01 13:49:30 +04:00
for(int i = 0; i < baseTypeWrapper.Interfaces.Length; i++)
{
baseTypeWrapper.Interfaces[i].ImplementInterfaceMethodStubs(typeBuilder, wrapper, doneSet);
}
baseTypeWrapper = baseTypeWrapper.BaseTypeWrapper;
2003-05-13 00:00:15 +04:00
}
2005-06-01 13:49:30 +04:00
foreach(MethodWrapper mw in methods)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
if(mw.Name != "<init>" && !mw.IsStatic && !mw.IsPrivate)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
if(wrapper.BaseTypeWrapper != null && wrapper.BaseTypeWrapper.HasIncompleteInterfaceImplementation)
{
Hashtable hashtable = null;
TypeWrapper tw = wrapper.BaseTypeWrapper;
while(tw.HasIncompleteInterfaceImplementation)
{
foreach(TypeWrapper iface in tw.Interfaces)
{
AddMethodOverride(mw, (MethodBuilder)mw.GetMethod(), iface, mw.Name, mw.Signature, ref hashtable, false);
}
tw = tw.BaseTypeWrapper;
}
}
if(true)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
Hashtable hashtable = null;
foreach(TypeWrapper iface in wrapper.Interfaces)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
AddMethodOverride(mw, (MethodBuilder)mw.GetMethod(), iface, mw.Name, mw.Signature, ref hashtable, true);
2004-08-17 13:05:21 +04:00
}
}
}
2005-06-01 13:49:30 +04:00
}
}
// If we're an interface that has public/protected fields, we create an inner class
// to expose these fields to C# (which stubbornly refuses to see fields in interfaces).
TypeBuilder tbFields = null;
if(JVM.IsStaticCompiler && classFile.IsInterface && !wrapper.IsGhost && classFile.Fields.Length > 0)
{
// TODO handle name clash
tbFields = typeBuilder.DefineNestedType("__Fields", TypeAttributes.Class | TypeAttributes.NestedPublic | TypeAttributes.Sealed);
tbFields.DefineDefaultConstructor(MethodAttributes.Private);
AttributeHelper.HideFromJava(tbFields);
ILGenerator ilgenClinit = null;
foreach(ClassFile.Field f in classFile.Fields)
{
TypeWrapper typeWrapper = ClassFile.FieldTypeWrapperFromSig(wrapper.GetClassLoader(), classCache, f.Signature);
if(f.ConstantValue != null)
{
FieldAttributes attribs = FieldAttributes.Public | FieldAttributes.Static | FieldAttributes.Literal;
FieldBuilder fb = tbFields.DefineField(f.Name, typeWrapper.TypeAsSignatureType, attribs);
fb.SetConstant(f.ConstantValue);
}
else
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
FieldAttributes attribs = FieldAttributes.Public | FieldAttributes.Static | FieldAttributes.InitOnly;
FieldBuilder fb = tbFields.DefineField(f.Name, typeWrapper.TypeAsSignatureType, attribs);
if(ilgenClinit == null)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
ilgenClinit = tbFields.DefineTypeInitializer().GetILGenerator();
2004-08-17 13:05:21 +04:00
}
2005-06-01 13:49:30 +04:00
wrapper.GetFieldWrapper(f.Name, f.Signature).EmitGet(ilgenClinit);
ilgenClinit.Emit(OpCodes.Stsfld, fb);
2004-08-17 13:05:21 +04:00
}
}
2005-06-01 13:49:30 +04:00
if(ilgenClinit != null)
{
ilgenClinit.Emit(OpCodes.Ret);
}
2004-08-17 13:05:21 +04:00
}
2002-12-18 19:00:25 +03:00
2005-06-01 13:49:30 +04:00
// See if there is any additional metadata
wrapper.EmitMapXmlMetadata(typeBuilder, classFile, fields, methods);
Type type;
Profiler.Enter("TypeBuilder.CreateType");
try
2005-01-03 11:26:21 +03:00
{
2005-06-01 13:49:30 +04:00
type = typeBuilder.CreateType();
if(tbFields != null)
2005-01-03 11:26:21 +03:00
{
2005-06-01 13:49:30 +04:00
tbFields.CreateType();
2005-01-03 11:26:21 +03:00
}
2005-06-01 13:49:30 +04:00
BakedTypeCleanupHack.Process(wrapper);
2005-01-03 11:26:21 +03:00
}
2005-06-01 13:49:30 +04:00
finally
2005-01-03 11:26:21 +03:00
{
2005-06-01 13:49:30 +04:00
Profiler.Leave("TypeBuilder.CreateType");
2005-01-03 11:26:21 +03:00
}
2005-06-01 13:49:30 +04:00
ClassLoaderWrapper.SetWrapperForType(type, wrapper);
if(verifyError != null)
2005-01-03 11:26:21 +03:00
{
2005-06-01 13:49:30 +04:00
return new DoomedTypeImpl(verifyError);
}
else
{
wrapper.FinishGhostStep2();
finishedType = new FinishedTypeImpl(type, innerClassesTypeWrappers, declaringTypeWrapper, this.ReflectiveModifiers);
return finishedType;
2005-01-03 11:26:21 +03:00
}
2002-12-29 19:27:00 +03:00
}
2005-06-01 13:49:30 +04:00
catch(Exception x)
2004-12-21 13:26:51 +03:00
{
2005-06-01 13:49:30 +04:00
JVM.CriticalFailure("Exception during finishing of: " + wrapper.Name, x);
return null;
2004-12-21 13:26:51 +03:00
}
2005-06-01 13:49:30 +04:00
finally
2004-12-21 13:26:51 +03:00
{
2005-06-01 13:49:30 +04:00
Profiler.Leave("JavaTypeImpl.Finish.Core");
2004-12-21 13:26:51 +03:00
}
2002-12-18 19:00:25 +03:00
}
2003-12-24 14:51:41 +03:00
2005-06-01 13:49:30 +04:00
internal class JniProxyBuilder
2004-09-05 13:37:58 +04:00
{
2005-06-01 13:49:30 +04:00
private static ModuleBuilder mod;
private static int count;
2004-09-05 13:37:58 +04:00
2005-06-01 13:49:30 +04:00
static JniProxyBuilder()
2003-08-13 19:00:41 +04:00
{
2005-06-01 13:49:30 +04:00
mod = ((AssemblyBuilder)ClassLoaderWrapper.GetBootstrapClassLoader().ModuleBuilder.Assembly).DefineDynamicModule("jniproxy.dll", "jniproxy.dll");
2003-08-13 19:00:41 +04:00
}
2003-05-30 16:08:59 +04:00
2005-06-01 13:49:30 +04:00
internal static void Generate(ILGenerator ilGenerator, DynamicTypeWrapper wrapper, MethodWrapper mw, TypeBuilder typeBuilder, ClassFile classFile, ClassFile.Method m, TypeWrapper[] args)
2004-09-05 13:37:58 +04:00
{
2005-06-01 13:49:30 +04:00
TypeBuilder tb = mod.DefineType("class" + (count++), TypeAttributes.Public | TypeAttributes.Class);
int instance = m.IsStatic ? 0 : 1;
Type[] argTypes = new Type[args.Length + instance + 1];
if(instance != 0)
{
argTypes[0] = wrapper.TypeAsSignatureType;
}
for(int i = 0; i < args.Length; i++)
{
argTypes[i + instance] = args[i].TypeAsSignatureType;
}
argTypes[argTypes.Length - 1] = typeof(RuntimeMethodHandle);
MethodBuilder mb = tb.DefineMethod("method", MethodAttributes.Public | MethodAttributes.Static, mw.ReturnType.TypeAsSignatureType, argTypes);
JniBuilder.Generate(mb.GetILGenerator(), wrapper, mw, tb, classFile, m, args, true);
for(int i = 0; i < argTypes.Length - 1; i++)
{
ilGenerator.Emit(OpCodes.Ldarg, (short)i);
}
2004-09-05 13:37:58 +04:00
ilGenerator.Emit(OpCodes.Ldtoken, (MethodInfo)mw.GetMethod());
2005-06-01 13:49:30 +04:00
ilGenerator.Emit(OpCodes.Call, mb);
ilGenerator.Emit(OpCodes.Ret);
Type type = tb.CreateType();
// HACK since we're creating a type in the dynamic assembly, we must also register its wrapper,
// because the ClassLoaderWrapper assumes that all dynamic types are in its hashtable,
// but note that this only registers it for reverse lookup (from Type -> TypeWrapper), this
// is necessary to make stack walking work.
ClassLoaderWrapper.SetWrapperForType(type, CompiledTypeWrapper.newInstance(type.FullName, type));
}
}
private class JniBuilder
{
private static readonly Type localRefStructType = typeof(IKVM.Runtime.JNI.Frame);
private static readonly MethodInfo jniFuncPtrMethod = localRefStructType.GetMethod("GetFuncPtr");
private static readonly MethodInfo enterLocalRefStruct = localRefStructType.GetMethod("Enter");
private static readonly MethodInfo leaveLocalRefStruct = localRefStructType.GetMethod("Leave");
private static readonly MethodInfo makeLocalRef = localRefStructType.GetMethod("MakeLocalRef");
private static readonly MethodInfo unwrapLocalRef = localRefStructType.GetMethod("UnwrapLocalRef");
private static readonly MethodInfo getClassFromTypeHandle = typeof(ByteCodeHelper).GetMethod("GetClassFromTypeHandle");
private static readonly MethodInfo writeLine = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(object) }, null);
private static readonly MethodInfo monitorEnter = typeof(System.Threading.Monitor).GetMethod("Enter", new Type[] { typeof(object) });
private static readonly MethodInfo monitorExit = typeof(System.Threading.Monitor).GetMethod("Exit", new Type[] { typeof(object) });
internal static void Generate(ILGenerator ilGenerator, DynamicTypeWrapper wrapper, MethodWrapper mw, TypeBuilder typeBuilder, ClassFile classFile, ClassFile.Method m, TypeWrapper[] args, bool thruProxy)
{
LocalBuilder syncObject = null;
FieldInfo classObjectField;
if(thruProxy)
{
classObjectField = typeBuilder.DefineField("__<classObject>", typeof(object), FieldAttributes.Static | FieldAttributes.Private);
}
else
{
classObjectField = wrapper.ClassObjectField;
}
if(m.IsSynchronized && m.IsStatic)
{
ilGenerator.Emit(OpCodes.Ldsfld, classObjectField);
Label label = ilGenerator.DefineLabel();
ilGenerator.Emit(OpCodes.Brtrue_S, label);
ilGenerator.Emit(OpCodes.Ldtoken, wrapper.TypeAsTBD);
ilGenerator.Emit(OpCodes.Call, getClassFromTypeHandle);
ilGenerator.Emit(OpCodes.Stsfld, classObjectField);
ilGenerator.MarkLabel(label);
ilGenerator.Emit(OpCodes.Ldsfld, classObjectField);
ilGenerator.Emit(OpCodes.Dup);
syncObject = ilGenerator.DeclareLocal(typeof(object));
ilGenerator.Emit(OpCodes.Stloc, syncObject);
ilGenerator.Emit(OpCodes.Call, monitorEnter);
ilGenerator.BeginExceptionBlock();
}
string sig = m.Signature.Replace('.', '/');
FieldBuilder methodPtr = typeBuilder.DefineField(JNI.METHOD_PTR_FIELD_PREFIX + m.Name + sig, typeof(IntPtr), FieldAttributes.Static | FieldAttributes.PrivateScope);
LocalBuilder localRefStruct = ilGenerator.DeclareLocal(localRefStructType);
2003-05-30 16:08:59 +04:00
ilGenerator.Emit(OpCodes.Ldloca, localRefStruct);
2005-06-01 13:49:30 +04:00
ilGenerator.Emit(OpCodes.Initobj, localRefStructType);
ilGenerator.Emit(OpCodes.Ldsfld, methodPtr);
Label oklabel = ilGenerator.DefineLabel();
ilGenerator.Emit(OpCodes.Brtrue, oklabel);
if(thruProxy)
{
ilGenerator.Emit(OpCodes.Ldarg_S, (byte)(args.Length + (mw.IsStatic ? 0 : 1)));
}
else
{
ilGenerator.Emit(OpCodes.Ldtoken, (MethodInfo)mw.GetMethod());
}
ilGenerator.Emit(OpCodes.Ldstr, classFile.Name.Replace('.', '/'));
ilGenerator.Emit(OpCodes.Ldstr, m.Name);
ilGenerator.Emit(OpCodes.Ldstr, sig);
ilGenerator.Emit(OpCodes.Call, jniFuncPtrMethod);
ilGenerator.Emit(OpCodes.Stsfld, methodPtr);
ilGenerator.MarkLabel(oklabel);
2003-05-30 16:08:59 +04:00
ilGenerator.Emit(OpCodes.Ldloca, localRefStruct);
2005-06-01 13:49:30 +04:00
if(thruProxy)
{
ilGenerator.Emit(OpCodes.Ldarg_S, (byte)(args.Length + (mw.IsStatic ? 0 : 1)));
}
else
{
ilGenerator.Emit(OpCodes.Ldtoken, (MethodInfo)mw.GetMethod());
}
ilGenerator.Emit(OpCodes.Call, enterLocalRefStruct);
LocalBuilder jnienv = ilGenerator.DeclareLocal(typeof(IntPtr));
ilGenerator.Emit(OpCodes.Stloc, jnienv);
2005-06-03 10:41:48 +04:00
ilGenerator.BeginExceptionBlock();
2005-06-01 13:49:30 +04:00
TypeWrapper retTypeWrapper = mw.ReturnType;
if(!retTypeWrapper.IsUnloadable && !retTypeWrapper.IsPrimitive)
{
// this one is for use after we return from "calli"
ilGenerator.Emit(OpCodes.Ldloca, localRefStruct);
}
ilGenerator.Emit(OpCodes.Ldloc, jnienv);
Type[] modargs = new Type[args.Length + 2];
modargs[0] = typeof(IntPtr);
modargs[1] = typeof(IntPtr);
for(int i = 0; i < args.Length; i++)
{
modargs[i + 2] = args[i].TypeAsSignatureType;
}
int add = 0;
if(!m.IsStatic)
{
ilGenerator.Emit(OpCodes.Ldloca, localRefStruct);
ilGenerator.Emit(OpCodes.Ldarg_0);
ilGenerator.Emit(OpCodes.Call, makeLocalRef);
add = 1;
}
else
{
ilGenerator.Emit(OpCodes.Ldloca, localRefStruct);
2004-09-17 13:32:06 +04:00
2005-06-01 13:49:30 +04:00
ilGenerator.Emit(OpCodes.Ldsfld, classObjectField);
Label label = ilGenerator.DefineLabel();
ilGenerator.Emit(OpCodes.Brtrue_S, label);
ilGenerator.Emit(OpCodes.Ldtoken, wrapper.TypeAsTBD);
ilGenerator.Emit(OpCodes.Call, getClassFromTypeHandle);
ilGenerator.Emit(OpCodes.Stsfld, classObjectField);
ilGenerator.MarkLabel(label);
ilGenerator.Emit(OpCodes.Ldsfld, classObjectField);
2004-09-17 13:32:06 +04:00
2005-06-01 13:49:30 +04:00
ilGenerator.Emit(OpCodes.Call, makeLocalRef);
}
for(int j = 0; j < args.Length; j++)
2003-05-30 16:08:59 +04:00
{
2005-06-01 13:49:30 +04:00
if(args[j].IsUnloadable || !args[j].IsPrimitive)
2005-02-02 18:11:26 +03:00
{
2005-06-01 13:49:30 +04:00
ilGenerator.Emit(OpCodes.Ldloca, localRefStruct);
if(!args[j].IsUnloadable && args[j].IsNonPrimitiveValueType)
{
ilGenerator.Emit(OpCodes.Ldarg_S, (byte)(j + add));
args[j].EmitBox(ilGenerator);
}
else if(!args[j].IsUnloadable && args[j].IsGhost)
{
ilGenerator.Emit(OpCodes.Ldarga_S, (byte)(j + add));
ilGenerator.Emit(OpCodes.Ldfld, args[j].GhostRefField);
}
else
{
ilGenerator.Emit(OpCodes.Ldarg_S, (byte)(j + add));
}
ilGenerator.Emit(OpCodes.Call, makeLocalRef);
modargs[j + 2] = typeof(IntPtr);
2005-02-02 18:11:26 +03:00
}
else
{
ilGenerator.Emit(OpCodes.Ldarg_S, (byte)(j + add));
}
2005-06-01 13:49:30 +04:00
}
ilGenerator.Emit(OpCodes.Ldsfld, methodPtr);
Type realRetType;
if(retTypeWrapper == PrimitiveTypeWrapper.BOOLEAN)
{
realRetType = typeof(byte);
}
else if(retTypeWrapper.IsPrimitive)
{
realRetType = retTypeWrapper.TypeAsSignatureType;
2003-05-30 16:08:59 +04:00
}
else
{
2005-06-01 13:49:30 +04:00
realRetType = typeof(IntPtr);
2003-05-30 16:08:59 +04:00
}
2005-06-01 13:49:30 +04:00
ilGenerator.EmitCalli(OpCodes.Calli, System.Runtime.InteropServices.CallingConvention.StdCall, realRetType, modargs);
LocalBuilder retValue = null;
if(retTypeWrapper != PrimitiveTypeWrapper.VOID)
2003-05-30 16:08:59 +04:00
{
2005-06-01 13:49:30 +04:00
if(!retTypeWrapper.IsUnloadable && !retTypeWrapper.IsPrimitive)
2005-02-02 18:11:26 +03:00
{
2005-06-01 13:49:30 +04:00
ilGenerator.Emit(OpCodes.Call, unwrapLocalRef);
if(retTypeWrapper.IsNonPrimitiveValueType)
{
retTypeWrapper.EmitUnbox(ilGenerator);
}
else if(retTypeWrapper.IsGhost)
{
LocalBuilder ghost = ilGenerator.DeclareLocal(retTypeWrapper.TypeAsSignatureType);
LocalBuilder obj = ilGenerator.DeclareLocal(typeof(object));
ilGenerator.Emit(OpCodes.Stloc, obj);
ilGenerator.Emit(OpCodes.Ldloca, ghost);
ilGenerator.Emit(OpCodes.Ldloc, obj);
ilGenerator.Emit(OpCodes.Stfld, retTypeWrapper.GhostRefField);
ilGenerator.Emit(OpCodes.Ldloc, ghost);
}
else
{
ilGenerator.Emit(OpCodes.Castclass, retTypeWrapper.TypeAsTBD);
}
2003-08-01 16:12:08 +04:00
}
2005-06-01 13:49:30 +04:00
retValue = ilGenerator.DeclareLocal(retTypeWrapper.TypeAsSignatureType);
ilGenerator.Emit(OpCodes.Stloc, retValue);
2003-05-30 16:08:59 +04:00
}
2005-06-01 13:49:30 +04:00
ilGenerator.BeginCatchBlock(typeof(object));
ilGenerator.EmitWriteLine("*** exception in native code ***");
ilGenerator.Emit(OpCodes.Call, writeLine);
ilGenerator.Emit(OpCodes.Rethrow);
2004-09-27 14:17:34 +04:00
ilGenerator.BeginFinallyBlock();
2005-06-01 13:49:30 +04:00
ilGenerator.Emit(OpCodes.Ldloca, localRefStruct);
ilGenerator.Emit(OpCodes.Call, leaveLocalRefStruct);
2004-09-27 14:17:34 +04:00
ilGenerator.EndExceptionBlock();
2005-06-01 13:49:30 +04:00
if(m.IsSynchronized && m.IsStatic)
{
ilGenerator.BeginFinallyBlock();
ilGenerator.Emit(OpCodes.Ldloc, syncObject);
ilGenerator.Emit(OpCodes.Call, monitorExit);
ilGenerator.EndExceptionBlock();
}
if(retTypeWrapper != PrimitiveTypeWrapper.VOID)
{
ilGenerator.Emit(OpCodes.Ldloc, retValue);
}
ilGenerator.Emit(OpCodes.Ret);
2004-09-27 14:17:34 +04:00
}
2003-05-30 16:08:59 +04:00
}
2002-12-18 19:00:25 +03:00
2005-06-01 13:49:30 +04:00
internal override TypeWrapper[] InnerClasses
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
throw new InvalidOperationException("InnerClasses is only available for finished types");
}
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal override TypeWrapper DeclaringTypeWrapper
2003-02-18 12:30:34 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
throw new InvalidOperationException("DeclaringTypeWrapper is only available for finished types");
}
2003-02-18 12:30:34 +03:00
}
2005-06-01 13:49:30 +04:00
internal override Modifiers ReflectiveModifiers
2003-02-18 12:30:34 +03:00
{
2005-06-01 13:49:30 +04:00
get
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
ClassFile.InnerClass[] innerclasses = classFile.InnerClasses;
if(innerclasses != null)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
for(int i = 0; i < innerclasses.Length; i++)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
if(innerclasses[i].innerClass != 0)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
if(classFile.GetConstantPoolClass(innerclasses[i].innerClass) == wrapper.Name)
{
return innerclasses[i].accessFlags;
}
2004-08-17 13:05:21 +04:00
}
}
}
2005-06-01 13:49:30 +04:00
return classFile.Modifiers;
2004-08-17 13:05:21 +04:00
}
2003-02-18 12:30:34 +03:00
}
2005-06-01 13:49:30 +04:00
private void UpdateClashTable()
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
lock(this)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
if(memberclashtable == null)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
memberclashtable = new Hashtable();
for(int i = 0; i < methods.Length; i++)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
// TODO at the moment we don't support constructor signature clash resolving, so we better
// not put them in the clash table
if(methods[i].IsLinked && methods[i].Name != "<init>")
{
string key = GenerateClashKey("method", methods[i].RealName, methods[i].ReturnTypeForDefineMethod, methods[i].GetParametersForDefineMethod());
memberclashtable.Add(key, key);
}
2004-08-17 13:05:21 +04:00
}
}
}
}
2005-06-01 13:49:30 +04:00
private static string GenerateClashKey(string type, string name, Type retOrFieldType, Type[] args)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
System.Text.StringBuilder sb = new System.Text.StringBuilder(type);
sb.Append(':').Append(name).Append(':').Append(retOrFieldType.FullName);
if(args != null)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
foreach(Type t in args)
{
sb.Append(':').Append(t.FullName);
}
2004-08-17 13:05:21 +04:00
}
2005-06-01 13:49:30 +04:00
return sb.ToString();
2004-08-17 13:05:21 +04:00
}
2005-06-01 13:49:30 +04:00
private ConstructorBuilder DefineClassInitializer()
2002-12-29 19:27:00 +03:00
{
2005-06-01 13:49:30 +04:00
if(!classFile.IsFinal && !classFile.IsInterface && wrapper.HasStaticInitializer)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
// We create a field that the derived classes can access in their .cctor to trigger our .cctor
// (previously we used RuntimeHelpers.RunClassConstructor, but that is slow and requires additional privileges)
FieldBuilder field = typeBuilder.DefineField("__<clinit>", typeof(int), FieldAttributes.SpecialName | FieldAttributes.Family | FieldAttributes.Static);
AttributeHelper.HideFromJava(field);
2004-08-17 13:05:21 +04:00
}
2005-06-01 13:49:30 +04:00
if(typeBuilder.IsInterface)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
// LAMESPEC the ECMA spec says (part. I, sect. 8.5.3.2) that all interface members must be public, so we make
// the class constructor public
return typeBuilder.DefineConstructor(MethodAttributes.Static | MethodAttributes.Public, CallingConventions.Standard, Type.EmptyTypes);
2004-08-17 13:05:21 +04:00
}
2005-06-01 13:49:30 +04:00
// NOTE we don't need to record the modifiers here, because they aren't visible from Java reflection
return typeBuilder.DefineTypeInitializer();
2004-08-17 13:05:21 +04:00
}
2005-06-01 13:49:30 +04:00
// this finds the method that md is going to be overriding
private MethodWrapper FindBaseMethod(string name, string sig, out bool explicitOverride)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
Debug.Assert(!classFile.IsInterface);
Debug.Assert(name != "<init>");
2004-08-17 13:05:21 +04:00
2005-06-01 13:49:30 +04:00
explicitOverride = false;
TypeWrapper tw = wrapper.BaseTypeWrapper;
while(tw != null)
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
// TODO we need to handle static methods (duh!)
MethodWrapper baseMethod = tw.GetMethodWrapper(name, sig, true);
if(baseMethod == null)
2003-05-30 16:08:59 +04:00
{
2005-06-01 13:49:30 +04:00
return null;
2003-05-30 16:08:59 +04:00
}
2005-06-01 13:49:30 +04:00
// here are the complex rules for determining whether this method overrides the method we found
// RULE 1: final methods may not be overridden
if(baseMethod.IsFinal && !baseMethod.IsPrivate)
2003-05-30 16:08:59 +04:00
{
2005-06-28 11:12:28 +04:00
throw new VerifyError("final method " + baseMethod.Name + baseMethod.Signature + " in " + baseMethod.DeclaringType.Name + " is overriden in " + wrapper.Name);
2003-05-30 16:08:59 +04:00
}
2005-06-01 13:49:30 +04:00
// RULE 2: public & protected methods can be overridden (package methods are handled by RULE 4)
// (by public, protected & *package* methods [even if they are in a different package])
if(baseMethod.IsPublic || baseMethod.IsProtected)
2005-05-31 12:57:24 +04:00
{
2005-06-01 13:49:30 +04:00
// if we already encountered a package method, we cannot override the base method of
// that package method
if(explicitOverride)
{
explicitOverride = false;
return null;
}
return baseMethod;
2005-05-31 12:57:24 +04:00
}
2005-06-01 13:49:30 +04:00
// RULE 3: private methods are ignored
if(!baseMethod.IsPrivate)
2005-05-31 12:57:24 +04:00
{
2005-06-01 13:49:30 +04:00
// RULE 4: package methods can only be overridden in the same package
if(baseMethod.DeclaringType.IsInSamePackageAs(wrapper))
{
return baseMethod;
}
// since we encountered a method with the same name/signature that we aren't overriding,
// we need to specify an explicit override
// NOTE we only do this if baseMethod isn't private, because if it is, Reflection.Emit
// will complain about the explicit MethodOverride (possibly a bug)
explicitOverride = true;
2005-05-31 12:57:24 +04:00
}
2005-06-01 13:49:30 +04:00
tw = baseMethod.DeclaringType.BaseTypeWrapper;
2005-05-31 12:57:24 +04:00
}
2005-06-01 13:49:30 +04:00
return null;
}
internal string GenerateUniqueMethodName(string basename, MethodWrapper mw)
{
string name = basename;
string key = GenerateClashKey("method", name, mw.ReturnTypeForDefineMethod, mw.GetParametersForDefineMethod());
UpdateClashTable();
lock(memberclashtable.SyncRoot)
2003-05-30 16:08:59 +04:00
{
2005-06-01 13:49:30 +04:00
for(int clashcount = 0; memberclashtable.ContainsKey(key); clashcount++)
{
name = basename + "_" + clashcount;
key = GenerateClashKey("method", name, mw.ReturnTypeForDefineMethod, mw.GetParametersForDefineMethod());
}
memberclashtable.Add(key, key);
2003-05-30 16:08:59 +04:00
}
2005-06-01 13:49:30 +04:00
return name;
}
private MethodBase GenerateMethod(int index, bool unloadableOverrideStub)
{
methods[index].AssertLinked();
Profiler.Enter("JavaTypeImpl.GenerateMethod");
try
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
if(index >= classFile.Methods.Length)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
// We're a Miranda method
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());
AttributeHelper.MirandaMethod(mb);
if(unloadableOverrideStub || name != methods[index].Name)
{
// instead of creating an override stub, we created the Miranda method with the proper signature and
// decorate it with a NameSigAttribute that contains the real signature
AttributeHelper.SetNameSig(mb, methods[index].Name, methods[index].Signature);
}
// if we changed the name or if the interface method name is remapped, we need to add an explicit methodoverride.
if(name != baseMethods[index].RealName)
{
typeBuilder.DefineMethodOverride(mb, (MethodInfo)baseMethods[index].GetMethod());
}
return mb;
2004-08-17 13:05:21 +04:00
}
2005-06-01 13:49:30 +04:00
ClassFile.Method m = classFile.Methods[index];
MethodBase method;
bool setNameSig = methods[index].ReturnType.IsUnloadable || methods[index].ReturnType.IsGhostArray;
foreach(TypeWrapper tw in methods[index].GetParameters())
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
setNameSig |= tw.IsUnloadable || tw.IsGhostArray;
}
bool setModifiers = false;
MethodAttributes attribs = 0;
if(m.IsNative)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
if(wrapper.IsPInvokeMethod(m))
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
// this doesn't appear to be necessary, but we use the flag in Finish to know
// that we shouldn't emit a method body
attribs |= MethodAttributes.PinvokeImpl;
2004-08-17 13:05:21 +04:00
}
else
{
setModifiers = true;
}
}
2005-06-01 13:49:30 +04:00
if(m.IsPrivate)
{
attribs |= MethodAttributes.Private;
}
else if(m.IsProtected)
{
attribs |= MethodAttributes.FamORAssem;
}
else if(m.IsPublic)
{
attribs |= MethodAttributes.Public;
}
else
{
attribs |= MethodAttributes.Assembly;
}
if(m.Name == "<init>")
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
if(setNameSig)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
// TODO we might have to mangle the signature to make it unique
2004-08-17 13:05:21 +04:00
}
2005-06-01 13:49:30 +04:00
// strictfp is the only modifier that a constructor can have
if(m.IsStrictfp)
2004-08-17 13:05:21 +04:00
{
setModifiers = true;
}
2005-06-01 13:49:30 +04:00
method = typeBuilder.DefineConstructor(attribs, CallingConventions.Standard, methods[index].GetParametersForDefineMethod());
((ConstructorBuilder)method).SetImplementationFlags(MethodImplAttributes.NoInlining);
wrapper.AddParameterNames(classFile, m, method);
2004-08-17 13:05:21 +04:00
}
2005-06-01 13:49:30 +04:00
else if(m.IsClassInitializer)
2003-05-30 16:08:59 +04:00
{
2005-06-01 13:49:30 +04:00
method = DefineClassInitializer();
2003-05-30 16:08:59 +04:00
}
2005-06-01 13:49:30 +04:00
else
2003-05-30 16:08:59 +04:00
{
2005-06-01 13:49:30 +04:00
if(m.IsAbstract)
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
// only if the classfile is abstract, we make the CLR method abstract, otherwise,
// we have to generate a method that throws an AbstractMethodError (because the JVM
// allows abstract methods in non-abstract classes)
if(classFile.IsAbstract)
{
attribs |= MethodAttributes.Abstract;
}
else
{
setModifiers = true;
}
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
if(m.IsFinal)
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
if(!m.IsStatic && !m.IsPrivate)
{
attribs |= MethodAttributes.Final;
}
else
2002-12-18 19:00:25 +03:00
{
2003-05-30 16:08:59 +04:00
setModifiers = true;
2002-12-18 19:00:25 +03:00
}
}
2005-06-01 13:49:30 +04:00
if(m.IsStatic)
{
attribs |= MethodAttributes.Static;
}
else if(!m.IsPrivate)
{
attribs |= MethodAttributes.Virtual | MethodAttributes.CheckAccessOnOverride;
}
string name = m.Name;
// 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
// - if one of the base classes has a similar method that is private (or package) that we aren't
// overriding, we need to specify an explicit MethodOverride
MethodWrapper baseMce = baseMethods[index];
bool explicitOverride = methods[index].IsExplicitOverride;
if((attribs & MethodAttributes.Virtual) != 0 && !classFile.IsInterface)
2004-03-16 20:10:09 +03:00
{
2005-06-01 13:49:30 +04:00
// make sure the base method is already defined
Debug.Assert(baseMce == null || baseMce.GetMethod() != null);
if(baseMce == null || baseMce.DeclaringType.IsInterface)
2004-03-16 20:10:09 +03:00
{
2005-06-01 13:49:30 +04:00
// we need to set NewSlot here, to prevent accidentally overriding methods
// (for example, if a Java class has a method "boolean Equals(object)", we don't want that method
// to override System.Object.Equals)
2004-03-16 20:10:09 +03:00
attribs |= MethodAttributes.NewSlot;
}
2005-06-01 13:49:30 +04:00
else
2004-03-16 20:10:09 +03:00
{
2005-06-01 13:49:30 +04:00
// if we have a method overriding a more accessible method (the JVM allows this), we need to make the
// method more accessible, because otherwise the CLR will complain that we're reducing access
MethodBase baseMethod = baseMce.GetMethod();
if((baseMethod.IsPublic && !m.IsPublic) ||
(baseMethod.IsFamily && !m.IsPublic && !m.IsProtected) ||
(!m.IsPublic && !m.IsProtected && !baseMce.DeclaringType.IsInSamePackageAs(wrapper)))
{
attribs &= ~MethodAttributes.MemberAccessMask;
attribs |= baseMethod.IsPublic ? MethodAttributes.Public : MethodAttributes.FamORAssem;
setModifiers = true;
}
2004-03-16 20:10:09 +03:00
}
2005-06-01 13:49:30 +04:00
}
MethodBuilder mb = wrapper.DefineGhostMethod(name, attribs, methods[index]);
if(mb == null)
{
bool needFinalize = false;
bool needDispatch = false;
if(baseMce != null && m.Name == "finalize" && m.Signature == "()V")
2004-03-16 20:10:09 +03:00
{
2005-06-01 13:49:30 +04:00
if(baseMce.RealName == "Finalize")
2004-12-02 11:43:05 +03:00
{
2005-06-01 13:49:30 +04:00
// We're overriding Finalize (that was renamed to finalize by DotNetTypeWrapper)
// in a non-Java base class.
attribs |= MethodAttributes.NewSlot;
needFinalize = true;
2004-12-02 11:43:05 +03:00
needDispatch = true;
}
2005-06-01 13:49:30 +04:00
else if(baseMce.DeclaringType == CoreClasses.java.lang.Object.Wrapper)
2004-12-02 11:43:05 +03:00
{
2005-06-01 13:49:30 +04:00
// This type is the first type in the hierarchy to introduce a finalize method
// (other than the one in java.lang.Object obviously), so we need to override
// the real Finalize method and emit a dispatch call to our finalize method.
2004-12-02 11:43:05 +03:00
needFinalize = true;
needDispatch = true;
}
2005-06-01 13:49:30 +04:00
else if(m.IsFinal)
{
// One of our base classes already has a finalize method, so we already are
// hooked into the real Finalize, but we need to override it again, to make it
// final (so that non-Java types cannot override it either).
needFinalize = true;
needDispatch = false;
// If the base class finalize was optimized away, we need a dispatch call after all.
Type baseFinalizeType = typeBuilder.BaseType.GetMethod("Finalize", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, null, Type.EmptyTypes, null).DeclaringType;
if(baseFinalizeType == typeof(object))
{
needDispatch = true;
}
}
else
{
// One of our base classes already has a finalize method, but it may have been an empty
// method so that the hookup to the real Finalize was optimized away, we need to check
// for that.
Type baseFinalizeType = typeBuilder.BaseType.GetMethod("Finalize", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, null, Type.EmptyTypes, null).DeclaringType;
if(baseFinalizeType == typeof(object))
{
needFinalize = true;
needDispatch = true;
}
}
if(needFinalize &&
!m.IsAbstract && !m.IsNative &&
(!m.IsFinal || classFile.IsFinal) &&
m.Instructions.Length > 0 &&
m.Instructions[0].NormalizedOpCode == NormalizedByteCode.__return)
{
// we've got an empty finalize method, so we don't need to override the real finalizer
// (not having a finalizer makes a huge perf difference)
needFinalize = false;
}
2004-12-02 11:43:05 +03:00
}
2005-06-01 13:49:30 +04:00
if(unloadableOverrideStub)
2004-12-02 11:43:05 +03:00
{
2005-06-01 13:49:30 +04:00
attribs |= MethodAttributes.NewSlot;
2004-03-16 20:10:09 +03:00
}
2005-06-01 13:49:30 +04:00
if(setNameSig || memberclashtable != null)
2004-03-16 20:10:09 +03:00
{
2005-06-01 13:49:30 +04:00
name = GenerateUniqueMethodName(name, methods[index]);
2004-03-16 20:10:09 +03:00
}
2005-06-01 13:49:30 +04:00
mb = typeBuilder.DefineMethod(name, attribs, methods[index].ReturnTypeForDefineMethod, methods[index].GetParametersForDefineMethod());
if(unloadableOverrideStub)
2004-03-16 20:10:09 +03:00
{
2005-06-01 13:49:30 +04:00
GenerateUnloadableOverrideStub(baseMce, mb, methods[index].ReturnTypeForDefineMethod, methods[index].GetParametersForDefineMethod());
2004-03-16 20:10:09 +03:00
}
2005-06-01 13:49:30 +04:00
else if(baseMce != null && (explicitOverride || baseMce.RealName != name) && !needFinalize)
2004-03-16 20:10:09 +03:00
{
2005-06-01 13:49:30 +04:00
// assert that the method we're overriding is in fact virtual and not final!
Debug.Assert(baseMce.GetMethod().IsVirtual && !baseMce.GetMethod().IsFinal);
typeBuilder.DefineMethodOverride(mb, (MethodInfo)baseMce.GetMethod());
2004-03-16 20:10:09 +03:00
}
2005-06-01 13:49:30 +04:00
// if we're overriding java.lang.Object.finalize we need to emit a stub to override System.Object.Finalize,
// or if we're subclassing a non-Java class that has a Finalize method, we need a new Finalize override
if(needFinalize)
{
MethodInfo baseFinalize = typeBuilder.BaseType.GetMethod("Finalize", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, null, Type.EmptyTypes, null);
MethodAttributes attr = MethodAttributes.Virtual;
// make sure we don't reduce accessibility
attr |= baseFinalize.IsPublic ? MethodAttributes.Public : MethodAttributes.Family;
if(m.IsFinal)
{
attr |= MethodAttributes.Final;
}
// TODO if the Java class also defines a Finalize() method, we need to name the stub differently
// (and make it effectively appear hidden by the class's Finalize method)
MethodBuilder finalize = typeBuilder.DefineMethod("Finalize", attr, CallingConventions.Standard, typeof(void), Type.EmptyTypes);
AttributeHelper.HideFromJava(finalize);
ILGenerator ilgen = finalize.GetILGenerator();
ilgen.Emit(OpCodes.Call, typeof(ByteCodeHelper).GetMethod("SkipFinalizer"));
Label skip = ilgen.DefineLabel();
ilgen.Emit(OpCodes.Brtrue_S, skip);
if(needDispatch)
{
ilgen.BeginExceptionBlock();
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Callvirt, mb);
ilgen.BeginCatchBlock(typeof(object));
ilgen.EndExceptionBlock();
}
else
{
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Call, baseFinalize);
}
ilgen.MarkLabel(skip);
ilgen.Emit(OpCodes.Ret);
}
}
wrapper.AddParameterNames(classFile, m, mb);
if((JVM.IsStaticCompiler || ClassLoaderWrapper.IsSaveDebugImage) && setModifiers)
{
AttributeHelper.SetModifiers(mb, m.Modifiers);
2004-03-08 18:18:47 +03:00
}
2005-06-01 13:49:30 +04:00
method = mb;
2003-07-31 16:49:29 +04:00
}
2005-06-01 13:49:30 +04:00
string[] exceptions = m.ExceptionsAttribute;
methods[index].SetDeclaredExceptions(exceptions);
if(JVM.IsStaticCompiler || ClassLoaderWrapper.IsSaveDebugImage)
2005-05-24 19:18:27 +04:00
{
2005-06-01 13:49:30 +04:00
AttributeHelper.SetThrowsAttribute(method, exceptions);
if(m.DeprecatedAttribute)
{
AttributeHelper.SetDeprecatedAttribute(method);
}
if(setNameSig)
{
AttributeHelper.SetNameSig(method, m.Name, m.Signature);
}
2003-04-26 16:13:02 +04:00
}
2005-06-01 13:49:30 +04:00
return method;
2003-05-10 19:34:49 +04:00
}
2005-06-01 13:49:30 +04:00
finally
2003-11-17 15:01:50 +03:00
{
2005-06-01 13:49:30 +04:00
Profiler.Leave("JavaTypeImpl.GenerateMethod");
2003-11-17 15:01:50 +03:00
}
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
private void GenerateUnloadableOverrideStub(MethodWrapper baseMethod, MethodInfo target, Type targetRet, Type[] targetArgs)
2005-05-27 16:44:06 +04:00
{
2005-06-01 13:49:30 +04:00
Type stubret = baseMethod.ReturnTypeForDefineMethod;
Type[] stubargs = baseMethod.GetParametersForDefineMethod();
string name = GenerateUniqueMethodName(baseMethod.RealName + "/unloadablestub", baseMethod);
MethodBuilder overrideStub = typeBuilder.DefineMethod(name, MethodAttributes.Private | MethodAttributes.Virtual | MethodAttributes.NewSlot | MethodAttributes.Final, stubret, stubargs);
AttributeHelper.HideFromJava(overrideStub);
typeBuilder.DefineMethodOverride(overrideStub, (MethodInfo)baseMethod.GetMethod());
ILGenerator ilgen = overrideStub.GetILGenerator();
ilgen.Emit(OpCodes.Ldarg_0);
for(int i = 0; i < targetArgs.Length; i++)
2005-05-27 16:44:06 +04:00
{
2005-06-01 13:49:30 +04:00
ilgen.Emit(OpCodes.Ldarg_S, (byte)(i + 1));
if(targetArgs[i] != stubargs[i])
{
ilgen.Emit(OpCodes.Castclass, targetArgs[i]);
}
2005-05-27 16:44:06 +04:00
}
2005-06-01 13:49:30 +04:00
ilgen.Emit(OpCodes.Callvirt, target);
if(targetRet != stubret)
{
ilgen.Emit(OpCodes.Castclass, stubret);
}
ilgen.Emit(OpCodes.Ret);
2005-05-27 16:44:06 +04:00
}
2005-06-01 13:49:30 +04:00
private static bool CheckRequireOverrideStub(MethodWrapper mw1, MethodWrapper mw2)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
// TODO this is too late to generate LinkageErrors so we need to figure this out earlier
if(mw1.ReturnType != mw2.ReturnType && !(mw1.ReturnType.IsUnloadable && mw2.ReturnType.IsUnloadable))
2004-08-17 13:05:21 +04:00
{
return true;
2003-06-18 12:48:00 +04:00
}
2005-06-01 13:49:30 +04:00
TypeWrapper[] args1 = mw1.GetParameters();
TypeWrapper[] args2 = mw2.GetParameters();
for(int i = 0; i < args1.Length; i++)
{
if(args1[i] != args2[i] && !(args1[i].IsUnloadable && args2[i].IsUnloadable))
{
return true;
}
}
return false;
2003-06-18 12:48:00 +04:00
}
2005-06-01 13:49:30 +04:00
private void AddMethodOverride(MethodWrapper method, MethodBuilder mb, TypeWrapper iface, string name, string sig, ref Hashtable hashtable, bool unloadableOnly)
2003-05-10 19:34:49 +04:00
{
2005-06-01 13:49:30 +04:00
if(hashtable != null && hashtable.ContainsKey(iface))
2003-05-10 19:34:49 +04:00
{
2005-06-01 13:49:30 +04:00
return;
2003-05-10 19:34:49 +04:00
}
2005-06-01 13:49:30 +04:00
MethodWrapper mw = iface.GetMethodWrapper(name, sig, false);
if(mw != null)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
if(hashtable == null)
{
hashtable = new Hashtable();
}
hashtable.Add(iface, iface);
if(CheckRequireOverrideStub(method, mw))
{
GenerateUnloadableOverrideStub(mw, mb, method.ReturnTypeForDefineMethod, method.GetParametersForDefineMethod());
}
else if(!unloadableOnly)
{
typeBuilder.DefineMethodOverride(mb, (MethodInfo)mw.GetMethod());
}
2004-08-17 13:05:21 +04:00
}
2005-06-01 13:49:30 +04:00
foreach(TypeWrapper iface2 in iface.Interfaces)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
AddMethodOverride(method, mb, iface2, name, sig, ref hashtable, unloadableOnly);
2004-08-17 13:05:21 +04:00
}
2003-05-10 19:34:49 +04:00
}
2005-06-01 13:49:30 +04:00
internal override Type Type
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return typeBuilder;
}
2002-12-18 19:00:25 +03:00
}
}
2004-12-21 13:26:51 +03:00
2005-06-01 13:49:30 +04:00
private class DoomedTypeImpl : DynamicImpl
2004-12-21 13:26:51 +03:00
{
2005-06-01 13:49:30 +04:00
private string message;
2004-12-21 13:26:51 +03:00
2005-06-01 13:49:30 +04:00
internal DoomedTypeImpl(string message)
2004-12-21 13:26:51 +03:00
{
2005-06-01 13:49:30 +04:00
this.message = message;
2004-12-21 13:26:51 +03:00
}
2005-06-01 13:49:30 +04:00
internal override TypeWrapper DeclaringTypeWrapper
2004-12-21 13:26:51 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return null;
}
2004-12-21 13:26:51 +03:00
}
2005-06-01 13:49:30 +04:00
internal override DynamicImpl Finish(bool forDebugSave)
2004-12-21 13:26:51 +03:00
{
2005-06-01 13:49:30 +04:00
if(!forDebugSave)
{
throw new VerifyError(message);
}
return this;
2004-12-21 13:26:51 +03:00
}
2005-06-01 13:49:30 +04:00
internal override TypeWrapper[] InnerClasses
{
get
{
return null;
}
}
2004-12-21 13:26:51 +03:00
2005-06-01 13:49:30 +04:00
internal override FieldInfo LinkField(FieldWrapper fw)
2004-12-21 13:26:51 +03:00
{
2005-06-01 13:49:30 +04:00
return null;
2004-12-21 13:26:51 +03:00
}
2005-06-01 13:49:30 +04:00
internal override MethodBase LinkMethod(MethodWrapper mw)
2004-12-21 13:26:51 +03:00
{
return null;
}
2002-12-18 19:00:25 +03:00
2005-06-01 13:49:30 +04:00
internal override Modifiers ReflectiveModifiers
{
get
{
return (Modifiers)0;
}
}
2002-12-18 19:00:25 +03:00
2005-06-01 13:49:30 +04:00
internal override Type Type
{
get
{
return null;
}
}
2003-02-18 12:30:34 +03:00
}
2005-06-01 13:49:30 +04:00
private class FinishedTypeImpl : DynamicImpl
2003-02-18 12:30:34 +03:00
{
2005-06-01 13:49:30 +04:00
private Type type;
private TypeWrapper[] innerclasses;
private TypeWrapper declaringTypeWrapper;
private Modifiers reflectiveModifiers;
internal FinishedTypeImpl(Type type, TypeWrapper[] innerclasses, TypeWrapper declaringTypeWrapper, Modifiers reflectiveModifiers)
2003-02-18 12:30:34 +03:00
{
2005-06-01 13:49:30 +04:00
this.type = type;
this.innerclasses = innerclasses;
this.declaringTypeWrapper = declaringTypeWrapper;
this.reflectiveModifiers = reflectiveModifiers;
2003-02-18 12:30:34 +03:00
}
2005-06-01 13:49:30 +04:00
internal override TypeWrapper[] InnerClasses
2003-02-18 12:30:34 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
// TODO compute the innerclasses lazily (and fix JavaTypeImpl to not always compute them)
return innerclasses;
}
2003-02-18 12:30:34 +03:00
}
2002-12-18 19:00:25 +03:00
2005-06-01 13:49:30 +04:00
internal override TypeWrapper DeclaringTypeWrapper
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
// TODO compute lazily (and fix JavaTypeImpl to not always compute it)
return declaringTypeWrapper;
}
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal override Modifiers ReflectiveModifiers
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return reflectiveModifiers;
}
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal override Type Type
{
get
{
return type;
}
}
2004-08-17 13:05:21 +04:00
2005-06-01 13:49:30 +04:00
internal override DynamicImpl Finish(bool forDebugSave)
{
return this;
}
2004-08-17 13:05:21 +04:00
2005-06-01 13:49:30 +04:00
internal override MethodBase LinkMethod(MethodWrapper mw)
{
// we should never be called, because all methods on a finished type are already linked
Debug.Assert(false);
return mw.GetMethod();
}
2004-01-18 01:46:43 +03:00
2005-06-01 13:49:30 +04:00
internal override FieldInfo LinkField(FieldWrapper fw)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
// we should never be called, because all fields on a finished type are already linked
Debug.Assert(false);
return fw.GetField();
2005-05-30 19:30:13 +04:00
}
2005-06-01 13:49:30 +04:00
}
protected static ParameterBuilder[] AddParameterNames(MethodBase mb, ClassFile.Method m, string[] parameterNames)
{
ClassFile.Method.LocalVariableTableEntry[] localVars = m.LocalVariableTableAttribute;
if(localVars != null)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
int bias = 1;
if(m.IsStatic)
{
bias = 0;
}
ParameterBuilder[] parameterBuilders = new ParameterBuilder[m.ArgMap.Length - bias];
for(int i = bias; i < m.ArgMap.Length; i++)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
if(m.ArgMap[i] != -1)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
for(int j = 0; j < localVars.Length; j++)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
if(localVars[j].index == i && parameterBuilders[i - bias] == null)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
string name = localVars[j].name;
if(parameterNames != null && parameterNames[i - bias] != null)
{
name = parameterNames[i - bias];
}
ParameterBuilder pb;
if(mb is MethodBuilder)
{
pb = ((MethodBuilder)mb).DefineParameter(m.ArgMap[i] + 1 - bias, ParameterAttributes.None, name);
}
else
{
pb = ((ConstructorBuilder)mb).DefineParameter(m.ArgMap[i], ParameterAttributes.None, name);
}
parameterBuilders[i - bias] = pb;
break;
2005-05-30 19:30:13 +04:00
}
}
}
}
2005-06-01 13:49:30 +04:00
return parameterBuilders;
}
else
{
return AddParameterNames(mb, m.Signature, parameterNames);
2005-05-30 19:30:13 +04:00
}
2004-01-18 01:46:43 +03:00
}
2005-06-01 13:49:30 +04:00
protected static ParameterBuilder[] AddParameterNames(MethodBase mb, string sig, string[] parameterNames)
2004-03-08 18:18:47 +03:00
{
2005-06-01 13:49:30 +04:00
ArrayList names = new ArrayList();
for(int i = 1; sig[i] != ')'; i++)
2005-05-30 19:30:13 +04:00
{
if(sig[i] == 'L')
{
i++;
int end = sig.IndexOf(';', i);
2005-06-01 13:49:30 +04:00
names.Add(GetParameterName(sig.Substring(i, end - i)));
2005-05-30 19:30:13 +04:00
i = end;
}
2005-06-01 13:49:30 +04:00
else if(sig[i] == '[')
{
while(sig[++i] == '[');
if(sig[i] == 'L')
{
i++;
int end = sig.IndexOf(';', i);
names.Add(GetParameterName(sig.Substring(i, end - i)) + "arr");
i = end;
}
else
{
switch(sig[i])
{
case 'B':
case 'Z':
names.Add("barr");
break;
case 'C':
names.Add("charr");
break;
case 'S':
names.Add("sarr");
break;
case 'I':
names.Add("iarr");
break;
case 'J':
names.Add("larr");
break;
case 'F':
names.Add("farr");
break;
case 'D':
names.Add("darr");
break;
}
}
}
2005-05-30 19:30:13 +04:00
else
{
switch(sig[i])
{
case 'B':
case 'Z':
2005-06-01 13:49:30 +04:00
names.Add("b");
2005-05-30 19:30:13 +04:00
break;
case 'C':
2005-06-01 13:49:30 +04:00
names.Add("ch");
2005-05-30 19:30:13 +04:00
break;
case 'S':
2005-06-01 13:49:30 +04:00
names.Add("s");
2005-05-30 19:30:13 +04:00
break;
case 'I':
2005-06-01 13:49:30 +04:00
names.Add("i");
2005-05-30 19:30:13 +04:00
break;
case 'J':
2005-06-01 13:49:30 +04:00
names.Add("l");
2005-05-30 19:30:13 +04:00
break;
case 'F':
2005-06-01 13:49:30 +04:00
names.Add("f");
2005-05-30 19:30:13 +04:00
break;
case 'D':
2005-06-01 13:49:30 +04:00
names.Add("d");
2005-05-30 19:30:13 +04:00
break;
}
}
}
2005-06-01 13:49:30 +04:00
ParameterBuilder[] parameterBuilders = new ParameterBuilder[names.Count];
Hashtable clashes = new Hashtable();
for(int i = 0; i < names.Count; i++)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
string name = (string)names[i];
if(parameterNames != null && parameterNames[i] != null)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
name = parameterNames[i];
}
ParameterBuilder pb;
if(names.IndexOf(name, i + 1) >= 0 || clashes.ContainsKey(name))
{
int clash = 1;
if(clashes.ContainsKey(name))
{
clash = (int)clashes[name] + 1;
}
clashes[name] = clash;
name += clash;
2005-05-30 19:30:13 +04:00
}
2005-06-01 13:49:30 +04:00
if(mb is MethodBuilder)
{
pb = ((MethodBuilder)mb).DefineParameter(i + 1, ParameterAttributes.None, name);
}
else
{
pb = ((ConstructorBuilder)mb).DefineParameter(i + 1, ParameterAttributes.None, name);
}
parameterBuilders[i] = pb;
2005-05-30 19:30:13 +04:00
}
2005-06-01 13:49:30 +04:00
return parameterBuilders;
2004-03-08 18:18:47 +03:00
}
2005-06-01 13:49:30 +04:00
private static string GetParameterName(string type)
2004-01-18 01:46:43 +03:00
{
2005-06-01 13:49:30 +04:00
if(type == "java.lang.String")
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
return "str";
2005-05-30 19:30:13 +04:00
}
2005-06-01 13:49:30 +04:00
else if(type == "java.lang.Object")
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
return "obj";
2005-05-30 19:30:13 +04:00
}
else
{
2005-06-01 13:49:30 +04:00
System.Text.StringBuilder sb = new System.Text.StringBuilder();
for(int i = type.LastIndexOf('.') + 1; i < type.Length; i++)
{
if(char.IsUpper(type, i))
{
sb.Append(char.ToLower(type[i]));
}
}
return sb.ToString();
2005-05-30 19:30:13 +04:00
}
}
2005-06-01 13:49:30 +04:00
protected virtual void AddParameterNames(ClassFile classFile, ClassFile.Method m, MethodBase method)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
if((JVM.IsStaticCompiler && classFile.IsPublic && (m.IsPublic || m.IsProtected)) || JVM.Debug || ClassLoaderWrapper.IsSaveDebugImage)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
AddParameterNames(method, m, null);
2005-05-30 19:30:13 +04:00
}
}
2005-06-01 13:49:30 +04:00
protected virtual bool EmitMapXmlMethodBody(ILGenerator ilgen, ClassFile f, ClassFile.Method m)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
return false;
2005-05-30 19:30:13 +04:00
}
2005-06-01 13:49:30 +04:00
protected virtual bool IsPInvokeMethod(ClassFile.Method m)
{
return false;
}
2005-05-30 19:30:13 +04:00
2005-06-01 13:49:30 +04:00
protected virtual void EmitMapXmlMetadata(TypeBuilder typeBuilder, ClassFile classFile, FieldWrapper[] fields, MethodWrapper[] methods)
{
}
2005-05-30 19:30:13 +04:00
2005-06-01 13:49:30 +04:00
protected virtual MethodBuilder DefineGhostMethod(string name, MethodAttributes attribs, MethodWrapper mw)
{
return null;
}
2005-05-30 19:30:13 +04:00
2005-06-01 13:49:30 +04:00
protected virtual void FinishGhost(TypeBuilder typeBuilder, MethodWrapper[] methods)
{
}
2005-05-30 19:30:13 +04:00
2005-06-01 13:49:30 +04:00
protected virtual void FinishGhostStep2()
{
}
2005-05-30 19:30:13 +04:00
2005-06-01 13:49:30 +04:00
protected virtual TypeBuilder DefineType(TypeAttributes typeAttribs)
{
return GetClassLoader().ModuleBuilder.DefineType(GetClassLoader().MangleTypeName(Name), typeAttribs);
}
2005-05-30 19:30:13 +04:00
2005-06-01 13:49:30 +04:00
internal override MethodBase LinkMethod(MethodWrapper mw)
{
mw.AssertLinked();
return impl.LinkMethod(mw);
}
2004-08-17 13:05:21 +04:00
2005-06-01 13:49:30 +04:00
internal override FieldInfo LinkField(FieldWrapper fw)
{
fw.AssertLinked();
return impl.LinkField(fw);
}
2004-08-17 13:05:21 +04:00
}
2002-12-18 19:00:25 +03:00
2005-05-30 19:30:13 +04:00
#if !NO_STATIC_COMPILER
2005-06-01 13:49:30 +04:00
class AotTypeWrapper : DynamicTypeWrapper
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
private FieldInfo ghostRefField;
private MethodBuilder ghostIsInstanceMethod;
private MethodBuilder ghostIsInstanceArrayMethod;
private MethodBuilder ghostCastMethod;
private MethodBuilder ghostCastArrayMethod;
private TypeBuilder typeBuilderGhostInterface;
private static Hashtable ghosts;
private static TypeWrapper[] mappedExceptions;
private static bool[] mappedExceptionsAllSubClasses;
private static Hashtable mapxml;
2005-05-30 19:30:13 +04:00
2005-06-01 13:49:30 +04:00
internal AotTypeWrapper(ClassFile f, ClassLoaderWrapper loader)
: base(f, loader, null)
{
}
2005-05-30 19:30:13 +04:00
2005-06-01 13:49:30 +04:00
internal static void SetupGhosts(IKVM.Internal.MapXml.Root map)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
ghosts = new Hashtable();
// find the ghost interfaces
foreach(IKVM.Internal.MapXml.Class c in map.assembly.Classes)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
if(c.Shadows != null && c.Interfaces != null)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
// NOTE we don't support interfaces that inherit from other interfaces
// (actually, if they are explicitly listed it would probably work)
TypeWrapper typeWrapper = ClassLoaderWrapper.GetBootstrapClassLoader().GetLoadedClass(c.Name);
foreach(IKVM.Internal.MapXml.Interface iface in c.Interfaces)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
TypeWrapper ifaceWrapper = ClassLoaderWrapper.GetBootstrapClassLoader().GetLoadedClass(iface.Name);
if(ifaceWrapper == null || !ifaceWrapper.TypeAsTBD.IsAssignableFrom(typeWrapper.TypeAsTBD))
{
AddGhost(iface.Name, typeWrapper);
}
2005-05-30 19:30:13 +04:00
}
}
}
2005-06-01 13:49:30 +04:00
// we manually add the array ghost interfaces
TypeWrapper array = ClassLoaderWrapper.GetWrapperFromType(typeof(Array));
AddGhost("java.io.Serializable", array);
AddGhost("java.lang.Cloneable", array);
2005-05-30 19:30:13 +04:00
}
2005-06-01 13:49:30 +04:00
private static void AddGhost(string interfaceName, TypeWrapper implementer)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
ArrayList list = (ArrayList)ghosts[interfaceName];
if(list == null)
{
list = new ArrayList();
ghosts[interfaceName] = list;
}
list.Add(implementer);
2005-05-30 19:30:13 +04:00
}
2005-06-01 13:49:30 +04:00
internal override bool IsGhost
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
get
{
return ghosts != null && IsInterface && ghosts.ContainsKey(Name);
}
2005-05-30 19:30:13 +04:00
}
2005-06-01 13:49:30 +04:00
private class ExceptionMapEmitter : CodeEmitter
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
private IKVM.Internal.MapXml.ExceptionMapping[] map;
2005-05-30 19:30:13 +04:00
2005-06-01 13:49:30 +04:00
internal ExceptionMapEmitter(IKVM.Internal.MapXml.ExceptionMapping[] map)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
this.map = map;
}
internal override void Emit(ILGenerator ilgen)
{
MethodWrapper mwSuppressFillInStackTrace = CoreClasses.java.lang.Throwable.Wrapper.GetMethodWrapper("__<suppressFillInStackTrace>", "()V", false);
mwSuppressFillInStackTrace.Link();
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Callvirt, typeof(Object).GetMethod("GetType"));
MethodInfo GetTypeFromHandle = typeof(Type).GetMethod("GetTypeFromHandle");
for(int i = 0; i < map.Length; i++)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
ilgen.Emit(OpCodes.Dup);
ilgen.Emit(OpCodes.Ldtoken, Type.GetType(map[i].src));
ilgen.Emit(OpCodes.Call, GetTypeFromHandle);
ilgen.Emit(OpCodes.Ceq);
Label label = ilgen.DefineLabel();
ilgen.Emit(OpCodes.Brfalse_S, label);
ilgen.Emit(OpCodes.Pop);
if(map[i].code != null)
{
ilgen.Emit(OpCodes.Ldarg_0);
// TODO we should manually walk the instruction list and add a suppressFillInStackTrace call
// before each newobj that instantiates an exception
map[i].code.Emit(ilgen);
ilgen.Emit(OpCodes.Ret);
}
else
{
TypeWrapper tw = ClassLoaderWrapper.GetBootstrapClassLoader().LoadClassByDottedName(map[i].dst);
MethodWrapper mw = tw.GetMethodWrapper("<init>", "()V", false);
mw.Link();
mwSuppressFillInStackTrace.EmitCall(ilgen);
mw.EmitNewobj(ilgen);
ilgen.Emit(OpCodes.Ret);
}
ilgen.MarkLabel(label);
2005-05-30 19:30:13 +04:00
}
2005-06-01 13:49:30 +04:00
ilgen.Emit(OpCodes.Pop);
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Ret);
2005-05-30 19:30:13 +04:00
}
}
2005-06-01 13:49:30 +04:00
internal static void LoadMapXml(IKVM.Internal.MapXml.Root map)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
mapxml = new Hashtable();
// HACK we've got a hardcoded location for the exception mapping method that is generated from the xml mapping
mapxml["java.lang.ExceptionHelper.MapExceptionImpl(Ljava.lang.Throwable;)Ljava.lang.Throwable;"] = new ExceptionMapEmitter(map.exceptionMappings);
foreach(IKVM.Internal.MapXml.Class c in map.assembly.Classes)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
// HACK if it is not a remapped type, we assume it is a container for native methods
if(c.Shadows == null)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
string className = c.Name;
mapxml.Add(className, c);
if(c.Methods != null)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
foreach(IKVM.Internal.MapXml.Method method in c.Methods)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
if(method.body != null)
{
string methodName = method.Name;
string methodSig = method.Sig;
mapxml.Add(className + "." + methodName + methodSig, method.body);
}
2005-05-30 19:30:13 +04:00
}
}
}
}
}
2005-06-01 13:49:30 +04:00
internal override bool IsMapUnsafeException
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
get
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
if(mappedExceptions != null)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
for(int i = 0; i < mappedExceptions.Length; i++)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
if(mappedExceptions[i].IsSubTypeOf(this) ||
(mappedExceptionsAllSubClasses[i] && this.IsSubTypeOf(mappedExceptions[i])))
{
return true;
}
2005-05-30 19:30:13 +04:00
}
}
2005-06-01 13:49:30 +04:00
return false;
2005-05-30 19:30:13 +04:00
}
}
2005-06-01 13:49:30 +04:00
internal static void LoadMappedExceptions(IKVM.Internal.MapXml.Root map)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
if(map.exceptionMappings != null)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
mappedExceptionsAllSubClasses = new bool[map.exceptionMappings.Length];
mappedExceptions = new TypeWrapper[map.exceptionMappings.Length];
for(int i = 0; i < mappedExceptions.Length; i++)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
string dst = map.exceptionMappings[i].dst;
if(dst[0] == '*')
{
mappedExceptionsAllSubClasses[i] = true;
dst = dst.Substring(1);
}
mappedExceptions[i] = ClassLoaderWrapper.GetBootstrapClassLoader().LoadClassByDottedName(dst);
2005-05-30 19:30:13 +04:00
}
}
}
2005-06-01 13:49:30 +04:00
private static TypeWrapper[] GetGhostImplementers(TypeWrapper wrapper)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
ArrayList list = (ArrayList)ghosts[wrapper.Name];
if(list == null)
{
return TypeWrapper.EmptyArray;
}
return (TypeWrapper[])list.ToArray(typeof(TypeWrapper));
2005-05-30 19:30:13 +04:00
}
2005-06-01 13:49:30 +04:00
internal override Type TypeAsBaseType
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
get
{
return typeBuilderGhostInterface != null ? typeBuilderGhostInterface : base.TypeAsBaseType;
}
2005-05-30 19:30:13 +04:00
}
2005-06-01 13:49:30 +04:00
private static IKVM.Internal.MapXml.Param[] GetXmlMapParameters(string classname, string method, string sig)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
if(mapxml != null)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
IKVM.Internal.MapXml.Class clazz = (IKVM.Internal.MapXml.Class)mapxml[classname];
if(clazz != null)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
if(method == "<init>" && clazz.Constructors != null)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
for(int i = 0; i < clazz.Constructors.Length; i++)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
if(clazz.Constructors[i].Sig == sig)
{
return clazz.Constructors[i].Params;
}
2005-05-30 19:30:13 +04:00
}
}
2005-06-01 13:49:30 +04:00
else if(clazz.Methods != null)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
for(int i = 0; i < clazz.Methods.Length; i++)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
if(clazz.Methods[i].Name == method && clazz.Methods[i].Sig == sig)
{
return clazz.Methods[i].Params;
}
2005-05-30 19:30:13 +04:00
}
}
}
}
2005-06-01 13:49:30 +04:00
return null;
2005-05-30 19:30:13 +04:00
}
2005-06-01 13:49:30 +04:00
protected override void AddParameterNames(ClassFile classFile, ClassFile.Method m, MethodBase method)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
IKVM.Internal.MapXml.Param[] parameters = GetXmlMapParameters(classFile.Name, m.Name, m.Signature);
if((JVM.IsStaticCompiler && classFile.IsPublic && (m.IsPublic || m.IsProtected)) || parameters != null || JVM.Debug || ClassLoaderWrapper.IsSaveDebugImage)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
string[] parameterNames = null;
if(parameters != null)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
parameterNames = new string[parameters.Length];
for(int i = 0; i < parameters.Length; i++)
{
parameterNames[i] = parameters[i].Name;
}
2005-05-30 19:30:13 +04:00
}
2005-06-01 13:49:30 +04:00
ParameterBuilder[] pbs = AddParameterNames(method, m, parameterNames);
if(parameters != null)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
for(int i = 0; i < pbs.Length; i++)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
if(parameters[i].Attributes != null)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
foreach(IKVM.Internal.MapXml.Attribute attr in parameters[i].Attributes)
{
AttributeHelper.SetCustomAttribute(pbs[i], attr);
}
2005-05-30 19:30:13 +04:00
}
}
}
}
}
2005-06-01 13:49:30 +04:00
private void AddParameterNames(MethodBuilder method, MethodWrapper mw)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
IKVM.Internal.MapXml.Param[] parameters = GetXmlMapParameters(Name, mw.Name, mw.Signature);
if((JVM.IsStaticCompiler && mw.DeclaringType.IsPublic && (mw.IsPublic || mw.IsProtected)) || parameters != null || JVM.Debug || ClassLoaderWrapper.IsSaveDebugImage)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
string[] parameterNames = null;
if(parameters != null)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
parameterNames = new string[parameters.Length];
for(int i = 0; i < parameters.Length; i++)
{
parameterNames[i] = parameters[i].Name;
}
2005-05-30 19:30:13 +04:00
}
2005-06-01 13:49:30 +04:00
ParameterBuilder[] pbs = AddParameterNames(method, mw.Signature, parameterNames);
if(parameters != null)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
for(int i = 0; i < pbs.Length; i++)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
if(parameters[i].Attributes != null)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
foreach(IKVM.Internal.MapXml.Attribute attr in parameters[i].Attributes)
{
AttributeHelper.SetCustomAttribute(pbs[i], attr);
}
2005-05-30 19:30:13 +04:00
}
}
}
}
}
2005-06-01 13:49:30 +04:00
protected override bool EmitMapXmlMethodBody(CountingILGenerator ilgen, ClassFile f, ClassFile.Method m)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
if(mapxml != null)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
CodeEmitter opcodes = (CodeEmitter)mapxml[f.Name + "." + m.Name + m.Signature];
if(opcodes != null)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
opcodes.Emit(ilgen);
return true;
2005-05-30 19:30:13 +04:00
}
}
2005-06-01 13:49:30 +04:00
return false;
2005-05-30 19:30:13 +04:00
}
2005-06-01 13:49:30 +04:00
private void PublishAttributes(TypeBuilder typeBuilder, IKVM.Internal.MapXml.Class clazz)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
foreach(IKVM.Internal.MapXml.Attribute attr in clazz.Attributes)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
AttributeHelper.SetCustomAttribute(typeBuilder, attr);
2005-05-30 19:30:13 +04:00
}
}
2005-06-01 13:49:30 +04:00
private static bool CheckPropertyArgs(Type[] args1, Type[] args2)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
if(args1.Length == args2.Length)
{
for(int i = 0; i < args1.Length; i++)
{
if(args1[i] != args2[i])
{
return false;
}
}
return true;
}
return false;
2005-05-30 19:30:13 +04:00
}
2005-06-01 13:49:30 +04:00
private static MethodAttributes GetPropertyMethodAttributes(MethodWrapper mw, bool final)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
MethodAttributes attribs = (MethodAttributes)0;
if(mw.IsStatic)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
attribs |= MethodAttributes.Static;
2005-05-30 19:30:13 +04:00
}
2005-06-01 13:49:30 +04:00
else
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
// NOTE in order for IntelliSense to consider the property a "real" property,
// the getter and setter methods need to have substantially the same method attributes,
// so we may need to look at our peer to determine whether we should be final
// or not (and vice versa).
attribs |= MethodAttributes.Virtual | MethodAttributes.NewSlot | MethodAttributes.CheckAccessOnOverride;
if(final)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
attribs |= MethodAttributes.Final;
2005-05-30 19:30:13 +04:00
}
}
2005-06-01 13:49:30 +04:00
// TODO what happens if accessibility doesn't match our peer?
if(mw.IsPublic)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
attribs |= MethodAttributes.Public;
2005-05-30 19:30:13 +04:00
}
2005-06-01 13:49:30 +04:00
else if(mw.IsProtected)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
attribs |= MethodAttributes.FamORAssem;
}
else if(mw.IsPrivate)
{
attribs |= MethodAttributes.Private;
2005-05-30 19:30:13 +04:00
}
2005-06-01 13:49:30 +04:00
else
{
attribs |= MethodAttributes.Assembly;
}
return attribs;
}
private void PublishProperties(TypeBuilder typeBuilder, IKVM.Internal.MapXml.Class clazz)
{
Hashtable classCache = new Hashtable();
foreach(IKVM.Internal.MapXml.Property prop in clazz.Properties)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
TypeWrapper typeWrapper = ClassFile.RetTypeWrapperFromSig(GetClassLoader(), classCache, prop.Sig);
TypeWrapper[] propargs = ClassFile.ArgTypeWrapperListFromSig(GetClassLoader(), classCache, prop.Sig);
Type[] indexer = new Type[propargs.Length];
for(int i = 0; i < propargs.Length; i++)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
indexer[i] = propargs[i].TypeAsSignatureType;
2005-05-30 19:30:13 +04:00
}
2005-06-01 13:49:30 +04:00
PropertyBuilder propbuilder = typeBuilder.DefineProperty(prop.Name, PropertyAttributes.None, typeWrapper.TypeAsSignatureType, indexer);
if(prop.Attributes != null)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
foreach(IKVM.Internal.MapXml.Attribute attr in prop.Attributes)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
AttributeHelper.SetCustomAttribute(propbuilder, attr);
}
}
MethodWrapper getter = null;
MethodWrapper setter = null;
if(prop.getter != null)
{
getter = GetMethodWrapper(prop.getter.Name, prop.getter.Sig, true);
if(getter == null)
{
Console.Error.WriteLine("Warning: getter not found for {0}::{1}", clazz.Name, prop.Name);
}
}
if(prop.setter != null)
{
setter = GetMethodWrapper(prop.setter.Name, prop.setter.Sig, true);
if(setter == null)
{
Console.Error.WriteLine("Warning: setter not found for {0}::{1}", clazz.Name, prop.Name);
}
}
bool final = (getter != null && getter.IsFinal) || (setter != null && setter.IsFinal);
if(getter != null)
{
MethodWrapper mw = getter;
if(!CheckPropertyArgs(mw.GetParametersForDefineMethod(), indexer) || mw.ReturnType != typeWrapper)
{
Console.Error.WriteLine("Warning: ignoring invalid property getter for {0}::{1}", clazz.Name, prop.Name);
}
else
{
MethodBuilder mb = mw.GetMethod() as MethodBuilder;
if(mb == null || mb.DeclaringType != typeBuilder || (!mb.IsFinal && final))
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
mb = typeBuilder.DefineMethod(GenerateUniqueMethodName("get_" + prop.Name, mw), GetPropertyMethodAttributes(mw, final), typeWrapper.TypeAsSignatureType, indexer);
AttributeHelper.HideFromJava(mb);
ILGenerator ilgen = new CountingILGenerator(mb.GetILGenerator());
if(mw.IsStatic)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
for(int i = 0; i < indexer.Length; i++)
{
ilgen.Emit(OpCodes.Ldarg, i);
}
mw.EmitCall(ilgen);
2005-05-30 19:30:13 +04:00
}
2005-06-01 13:49:30 +04:00
else
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
ilgen.Emit(OpCodes.Ldarg_0);
for(int i = 0; i < indexer.Length; i++)
{
ilgen.Emit(OpCodes.Ldarg, i + 1);
}
mw.EmitCallvirt(ilgen);
2005-05-30 19:30:13 +04:00
}
2005-06-01 13:49:30 +04:00
ilgen.Emit(OpCodes.Ret);
2005-05-30 19:30:13 +04:00
}
2005-06-01 13:49:30 +04:00
propbuilder.SetGetMethod(mb);
2005-05-30 19:30:13 +04:00
}
}
2005-06-01 13:49:30 +04:00
if(setter != null)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
MethodWrapper mw = setter;
Type[] args = new Type[indexer.Length + 1];
indexer.CopyTo(args, 0);
args[args.Length - 1] = typeWrapper.TypeAsSignatureType;
if(!CheckPropertyArgs(args, mw.GetParametersForDefineMethod()))
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
Console.Error.WriteLine("Warning: ignoring invalid property setter for {0}::{1}", clazz.Name, prop.Name);
}
else
{
MethodBuilder mb = mw.GetMethod() as MethodBuilder;
if(mb == null || mb.DeclaringType != typeBuilder || (!mb.IsFinal && final))
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
mb = typeBuilder.DefineMethod(GenerateUniqueMethodName("set_" + prop.Name, mw), GetPropertyMethodAttributes(mw, final), mw.ReturnTypeForDefineMethod, args);
AttributeHelper.HideFromJava(mb);
ILGenerator ilgen = new CountingILGenerator(mb.GetILGenerator());
if(mw.IsStatic)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
for(int i = 0; i <= indexer.Length; i++)
{
ilgen.Emit(OpCodes.Ldarg, i);
}
mw.EmitCall(ilgen);
2005-05-30 19:30:13 +04:00
}
2005-06-01 13:49:30 +04:00
else
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
ilgen.Emit(OpCodes.Ldarg_0);
for(int i = 0; i <= indexer.Length; i++)
{
ilgen.Emit(OpCodes.Ldarg, i + 1);
}
mw.EmitCallvirt(ilgen);
2005-05-30 19:30:13 +04:00
}
2005-06-01 13:49:30 +04:00
ilgen.Emit(OpCodes.Ret);
2005-05-30 19:30:13 +04:00
}
2005-06-01 13:49:30 +04:00
propbuilder.SetSetMethod(mb);
2005-05-30 19:30:13 +04:00
}
}
}
}
2005-06-01 13:49:30 +04:00
protected override bool IsPInvokeMethod(ClassFile.Method m)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
if(mapxml != null)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
IKVM.Internal.MapXml.Class clazz = (IKVM.Internal.MapXml.Class)mapxml[Name];
if(clazz != null && clazz.Methods != null)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
foreach(IKVM.Internal.MapXml.Method method in clazz.Methods)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
if(method.Name == m.Name && method.Sig == m.Signature)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
if(method.Attributes != null)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
foreach(IKVM.Internal.MapXml.Attribute attr in method.Attributes)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
if(Type.GetType(attr.Type) == typeof(System.Runtime.InteropServices.DllImportAttribute))
{
return true;
}
2005-05-30 19:30:13 +04:00
}
}
2005-06-01 13:49:30 +04:00
break;
2005-05-30 19:30:13 +04:00
}
}
}
}
2005-06-01 13:49:30 +04:00
return base.IsPInvokeMethod(m);
2005-05-30 19:30:13 +04:00
}
2005-06-01 13:49:30 +04:00
protected override void EmitMapXmlMetadata(TypeBuilder typeBuilder, ClassFile classFile, FieldWrapper[] fields, MethodWrapper[] methods)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
if(mapxml != null)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
IKVM.Internal.MapXml.Class clazz = (IKVM.Internal.MapXml.Class)mapxml[classFile.Name];
if(clazz != null)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
if(clazz.Attributes != null)
{
PublishAttributes(typeBuilder, clazz);
}
if(clazz.Properties != null)
{
PublishProperties(typeBuilder, clazz);
}
if(clazz.Fields != null)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
foreach(IKVM.Internal.MapXml.Field field in clazz.Fields)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
if(field.Attributes != null)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
foreach(FieldWrapper fw in fields)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
if(fw.Name == field.Name && fw.Signature == field.Sig)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
FieldBuilder fb = fw.GetField() as FieldBuilder;
if(fb != null)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
foreach(IKVM.Internal.MapXml.Attribute attr in field.Attributes)
{
AttributeHelper.SetCustomAttribute(fb, attr);
}
2005-05-30 19:30:13 +04:00
}
}
}
}
}
}
2005-06-01 13:49:30 +04:00
if(clazz.Constructors != null)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
foreach(IKVM.Internal.MapXml.Constructor constructor in clazz.Constructors)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
if(constructor.Attributes != null)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
foreach(MethodWrapper mw in methods)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
if(mw.Name == "<init>" && mw.Signature == constructor.Sig)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
ConstructorBuilder mb = mw.GetMethod() as ConstructorBuilder;
if(mb != null)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
foreach(IKVM.Internal.MapXml.Attribute attr in constructor.Attributes)
{
AttributeHelper.SetCustomAttribute(mb, attr);
}
2005-05-30 19:30:13 +04:00
}
}
}
}
}
}
2005-06-01 13:49:30 +04:00
if(clazz.Methods != null)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
foreach(IKVM.Internal.MapXml.Method method in clazz.Methods)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
if(method.Attributes != null)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
foreach(MethodWrapper mw in methods)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
if(mw.Name == method.Name && mw.Signature == method.Sig)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
MethodBuilder mb = mw.GetMethod() as MethodBuilder;
if(mb != null)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
foreach(IKVM.Internal.MapXml.Attribute attr in method.Attributes)
{
AttributeHelper.SetCustomAttribute(mb, attr);
}
2005-05-30 19:30:13 +04:00
}
}
}
}
}
}
}
}
}
2005-06-01 13:49:30 +04:00
protected override MethodBuilder DefineGhostMethod(string name, MethodAttributes attribs, MethodWrapper mw)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
if(typeBuilderGhostInterface != null)
{
return typeBuilderGhostInterface.DefineMethod(name, attribs, mw.ReturnTypeForDefineMethod, mw.GetParametersForDefineMethod());
}
else
{
return base.DefineGhostMethod(name, attribs, mw);
}
2005-05-30 19:30:13 +04:00
}
2005-06-01 13:49:30 +04:00
protected override void FinishGhost(TypeBuilder typeBuilder, MethodWrapper[] methods)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
if(typeBuilderGhostInterface != null)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
// TODO consider adding methods from base interface and java.lang.Object as well
for(int i = 0; i < methods.Length; i++)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
// skip <clinit>
if(!methods[i].IsStatic)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
TypeWrapper[] args = methods[i].GetParameters();
MethodBuilder stub = typeBuilder.DefineMethod(methods[i].Name, MethodAttributes.Public, methods[i].ReturnTypeForDefineMethod, methods[i].GetParametersForDefineMethod());
AddParameterNames(stub, methods[i]);
AttributeHelper.SetModifiers(stub, methods[i].Modifiers);
ILGenerator ilgen = stub.GetILGenerator();
Label end = ilgen.DefineLabel();
TypeWrapper[] implementers = GetGhostImplementers(this);
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Ldfld, ghostRefField);
2005-05-30 19:30:13 +04:00
ilgen.Emit(OpCodes.Dup);
2005-06-01 13:49:30 +04:00
ilgen.Emit(OpCodes.Isinst, typeBuilderGhostInterface);
Label label = ilgen.DefineLabel();
2005-05-30 19:30:13 +04:00
ilgen.Emit(OpCodes.Brfalse_S, label);
2005-06-01 13:49:30 +04:00
ilgen.Emit(OpCodes.Castclass, typeBuilderGhostInterface);
2005-05-30 19:30:13 +04:00
for(int k = 0; k < args.Length; k++)
{
ilgen.Emit(OpCodes.Ldarg_S, (byte)(k + 1));
}
2005-06-01 13:49:30 +04:00
ilgen.Emit(OpCodes.Callvirt, (MethodInfo)methods[i].GetMethod());
2005-05-30 19:30:13 +04:00
ilgen.Emit(OpCodes.Br, end);
ilgen.MarkLabel(label);
2005-06-01 13:49:30 +04:00
for(int j = 0; j < implementers.Length; j++)
{
ilgen.Emit(OpCodes.Dup);
ilgen.Emit(OpCodes.Isinst, implementers[j].TypeAsTBD);
label = ilgen.DefineLabel();
ilgen.Emit(OpCodes.Brfalse_S, label);
ilgen.Emit(OpCodes.Castclass, implementers[j].TypeAsTBD);
for(int k = 0; k < args.Length; k++)
{
ilgen.Emit(OpCodes.Ldarg_S, (byte)(k + 1));
}
MethodWrapper mw = implementers[j].GetMethodWrapper(methods[i].Name, methods[i].Signature, true);
mw.EmitCallvirt(ilgen);
ilgen.Emit(OpCodes.Br, end);
ilgen.MarkLabel(label);
}
// we need to do a null check (null fails all the isinst checks)
EmitHelper.NullCheck(ilgen);
EmitHelper.Throw(ilgen, "java.lang.IncompatibleClassChangeError", Name);
ilgen.MarkLabel(end);
ilgen.Emit(OpCodes.Ret);
2005-05-30 19:30:13 +04:00
}
}
2005-06-01 13:49:30 +04:00
// HACK create a scope to enable reuse of "implementers" name
if(true)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
MethodBuilder mb;
ILGenerator ilgen;
LocalBuilder local;
// add implicit conversions for all the ghost implementers
TypeWrapper[] implementers = GetGhostImplementers(this);
for(int i = 0; i < implementers.Length; i++)
{
mb = typeBuilder.DefineMethod("op_Implicit", MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.SpecialName, TypeAsSignatureType, new Type[] { implementers[i].TypeAsSignatureType });
AttributeHelper.HideFromJava(mb);
ilgen = mb.GetILGenerator();
local = ilgen.DeclareLocal(TypeAsSignatureType);
ilgen.Emit(OpCodes.Ldloca, local);
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Stfld, ghostRefField);
ilgen.Emit(OpCodes.Ldloca, local);
ilgen.Emit(OpCodes.Ldobj, TypeAsSignatureType);
ilgen.Emit(OpCodes.Ret);
}
// Implement the "IsInstance" method
mb = ghostIsInstanceMethod;
2005-05-30 19:30:13 +04:00
AttributeHelper.HideFromJava(mb);
ilgen = mb.GetILGenerator();
2005-06-01 13:49:30 +04:00
Label end = ilgen.DefineLabel();
for(int i = 0; i < implementers.Length; i++)
{
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Isinst, implementers[i].TypeAsTBD);
Label label = ilgen.DefineLabel();
ilgen.Emit(OpCodes.Brfalse_S, label);
ilgen.Emit(OpCodes.Ldc_I4_1);
ilgen.Emit(OpCodes.Br, end);
ilgen.MarkLabel(label);
}
2005-05-30 19:30:13 +04:00
ilgen.Emit(OpCodes.Ldarg_0);
2005-06-01 13:49:30 +04:00
ilgen.Emit(OpCodes.Isinst, typeBuilderGhostInterface);
ilgen.Emit(OpCodes.Ldnull);
ilgen.Emit(OpCodes.Cgt_Un);
ilgen.MarkLabel(end);
2005-05-30 19:30:13 +04:00
ilgen.Emit(OpCodes.Ret);
2005-06-01 13:49:30 +04:00
// Implement the "IsInstanceArray" method
mb = ghostIsInstanceArrayMethod;
AttributeHelper.HideFromJava(mb);
ilgen = mb.GetILGenerator();
LocalBuilder localType = ilgen.DeclareLocal(typeof(Type));
2005-05-30 19:30:13 +04:00
ilgen.Emit(OpCodes.Ldarg_0);
2005-06-01 13:49:30 +04:00
Label skip = ilgen.DefineLabel();
ilgen.Emit(OpCodes.Brtrue_S, skip);
ilgen.Emit(OpCodes.Ldc_I4_0);
ilgen.Emit(OpCodes.Ret);
ilgen.MarkLabel(skip);
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Call, typeof(object).GetMethod("GetType"));
ilgen.Emit(OpCodes.Stloc, localType);
skip = ilgen.DefineLabel();
ilgen.Emit(OpCodes.Br_S, skip);
Label iter = ilgen.DefineLabel();
ilgen.MarkLabel(iter);
ilgen.Emit(OpCodes.Ldarg_1);
2005-05-30 19:30:13 +04:00
ilgen.Emit(OpCodes.Ldc_I4_1);
2005-06-01 13:49:30 +04:00
ilgen.Emit(OpCodes.Sub);
ilgen.Emit(OpCodes.Starg_S, (byte)1);
ilgen.Emit(OpCodes.Ldloc, localType);
ilgen.Emit(OpCodes.Callvirt, typeof(Type).GetMethod("GetElementType"));
ilgen.Emit(OpCodes.Stloc, localType);
ilgen.MarkLabel(skip);
ilgen.Emit(OpCodes.Ldloc, localType);
ilgen.Emit(OpCodes.Callvirt, typeof(Type).GetMethod("get_IsArray"));
ilgen.Emit(OpCodes.Brtrue_S, iter);
ilgen.Emit(OpCodes.Ldarg_1);
skip = ilgen.DefineLabel();
ilgen.Emit(OpCodes.Brfalse_S, skip);
ilgen.Emit(OpCodes.Ldc_I4_0);
ilgen.Emit(OpCodes.Ret);
ilgen.MarkLabel(skip);
for(int i = 0; i < implementers.Length; i++)
{
ilgen.Emit(OpCodes.Ldtoken, implementers[i].TypeAsTBD);
ilgen.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle"));
ilgen.Emit(OpCodes.Ldloc, localType);
ilgen.Emit(OpCodes.Callvirt, typeof(Type).GetMethod("IsAssignableFrom"));
Label label = ilgen.DefineLabel();
ilgen.Emit(OpCodes.Brfalse_S, label);
ilgen.Emit(OpCodes.Ldc_I4_1);
ilgen.Emit(OpCodes.Ret);
ilgen.MarkLabel(label);
}
ilgen.Emit(OpCodes.Ldtoken, typeBuilderGhostInterface);
2005-05-30 19:30:13 +04:00
ilgen.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle"));
ilgen.Emit(OpCodes.Ldloc, localType);
ilgen.Emit(OpCodes.Callvirt, typeof(Type).GetMethod("IsAssignableFrom"));
ilgen.Emit(OpCodes.Ret);
2005-06-01 13:49:30 +04:00
// Implement the "Cast" method
mb = ghostCastMethod;
AttributeHelper.HideFromJava(mb);
ilgen = mb.GetILGenerator();
end = ilgen.DefineLabel();
for(int i = 0; i < implementers.Length; i++)
{
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Isinst, implementers[i].TypeAsTBD);
ilgen.Emit(OpCodes.Brtrue, end);
}
2005-05-30 19:30:13 +04:00
ilgen.Emit(OpCodes.Ldarg_0);
2005-06-01 13:49:30 +04:00
ilgen.Emit(OpCodes.Castclass, typeBuilderGhostInterface);
ilgen.Emit(OpCodes.Pop);
ilgen.MarkLabel(end);
local = ilgen.DeclareLocal(TypeAsSignatureType);
ilgen.Emit(OpCodes.Ldloca, local);
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Stfld, ghostRefField);
ilgen.Emit(OpCodes.Ldloca, local);
ilgen.Emit(OpCodes.Ldobj, TypeAsSignatureType);
ilgen.Emit(OpCodes.Ret);
// Add "ToObject" methods
mb = typeBuilder.DefineMethod("ToObject", MethodAttributes.Public, typeof(object), Type.EmptyTypes);
AttributeHelper.HideFromJava(mb);
ilgen = mb.GetILGenerator();
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Ldfld, ghostRefField);
ilgen.Emit(OpCodes.Ret);
2005-05-30 19:30:13 +04:00
2005-06-01 13:49:30 +04:00
// Implement the "CastArray" method
// NOTE unlike "Cast" this doesn't return anything, it just throws a ClassCastException if the
// cast is unsuccessful. Also, because of the complexity of this test, we call IsInstanceArray
// instead of reimplementing the check here.
mb = ghostCastArrayMethod;
AttributeHelper.HideFromJava(mb);
ilgen = mb.GetILGenerator();
end = ilgen.DefineLabel();
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Brfalse_S, end);
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Ldarg_1);
ilgen.Emit(OpCodes.Call, ghostIsInstanceArrayMethod);
ilgen.Emit(OpCodes.Brtrue_S, end);
EmitHelper.Throw(ilgen, "java.lang.ClassCastException");
ilgen.MarkLabel(end);
ilgen.Emit(OpCodes.Ret);
}
2005-05-30 19:30:13 +04:00
}
}
2005-06-01 13:49:30 +04:00
protected override void FinishGhostStep2()
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
if(typeBuilderGhostInterface != null)
{
typeBuilderGhostInterface.CreateType();
}
2005-05-30 19:30:13 +04:00
}
2005-06-01 13:49:30 +04:00
protected override TypeBuilder DefineType(TypeAttributes typeAttribs)
2005-05-30 19:30:13 +04:00
{
2005-06-01 13:49:30 +04:00
if(IsGhost)
{
typeAttribs &= ~(TypeAttributes.Interface | TypeAttributes.Abstract);
typeAttribs |= TypeAttributes.Class | TypeAttributes.Sealed;
TypeBuilder typeBuilder = GetClassLoader().ModuleBuilder.DefineType(GetClassLoader().MangleTypeName(Name), typeAttribs, typeof(ValueType));
AttributeHelper.SetGhostInterface(typeBuilder);
AttributeHelper.SetModifiers(typeBuilder, Modifiers);
ghostRefField = typeBuilder.DefineField("__<ref>", typeof(object), FieldAttributes.Public | FieldAttributes.SpecialName);
AttributeHelper.HideFromJava((FieldBuilder)ghostRefField);
typeBuilderGhostInterface = typeBuilder.DefineNestedType("__Interface", TypeAttributes.Interface | TypeAttributes.Abstract | TypeAttributes.NestedPublic);
AttributeHelper.HideFromJava(typeBuilderGhostInterface);
ghostIsInstanceMethod = typeBuilder.DefineMethod("IsInstance", MethodAttributes.Public | MethodAttributes.Static, typeof(bool), new Type[] { typeof(object) });
ghostIsInstanceMethod.DefineParameter(1, ParameterAttributes.None, "obj");
ghostIsInstanceArrayMethod = typeBuilder.DefineMethod("IsInstanceArray", MethodAttributes.Public | MethodAttributes.Static, typeof(bool), new Type[] { typeof(object), typeof(int) });
ghostIsInstanceArrayMethod.DefineParameter(1, ParameterAttributes.None, "obj");
ghostIsInstanceArrayMethod.DefineParameter(2, ParameterAttributes.None, "rank");
ghostCastMethod = typeBuilder.DefineMethod("Cast", MethodAttributes.Public | MethodAttributes.Static, typeBuilder, new Type[] { typeof(object) });
ghostCastMethod.DefineParameter(1, ParameterAttributes.None, "obj");
ghostCastArrayMethod = typeBuilder.DefineMethod("CastArray", MethodAttributes.Public | MethodAttributes.Static, typeof(void), new Type[] { typeof(object), typeof(int) });
ghostCastArrayMethod.DefineParameter(1, ParameterAttributes.None, "obj");
ghostCastArrayMethod.DefineParameter(2, ParameterAttributes.None, "rank");
return typeBuilder;
}
else
{
return base.DefineType(typeAttribs);
}
2005-05-30 19:30:13 +04:00
}
2005-03-23 12:33:18 +03:00
2005-06-01 13:49:30 +04:00
internal override FieldInfo GhostRefField
2005-03-23 12:33:18 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return ghostRefField;
}
2005-03-23 12:33:18 +03:00
}
2005-06-01 13:49:30 +04:00
internal override void EmitCheckcast(TypeWrapper context, ILGenerator ilgen)
2005-03-23 12:33:18 +03:00
{
2005-06-01 13:49:30 +04:00
if(IsGhost)
{
ilgen.Emit(OpCodes.Dup);
ilgen.Emit(OpCodes.Call, ghostCastMethod);
ilgen.Emit(OpCodes.Pop);
}
else if(IsGhostArray)
{
ilgen.Emit(OpCodes.Dup);
ilgen.Emit(OpCodes.Call, ghostCastArrayMethod);
}
else
{
base.EmitCheckcast(context, ilgen);
}
2005-03-23 12:33:18 +03:00
}
2005-06-01 13:49:30 +04:00
internal override void EmitInstanceOf(TypeWrapper context, ILGenerator ilgen)
2005-03-23 12:33:18 +03:00
{
2005-06-01 13:49:30 +04:00
if(IsGhost)
{
ilgen.Emit(OpCodes.Call, ghostIsInstanceMethod);
}
else if(IsGhostArray)
{
ilgen.Emit(OpCodes.Call, ghostIsInstanceArrayMethod);
}
else
{
base.EmitInstanceOf(context, ilgen);
}
2005-03-23 12:33:18 +03:00
}
}
2005-06-01 13:49:30 +04:00
#endif
2005-03-23 12:33:18 +03:00
2005-06-01 13:49:30 +04:00
class CompiledTypeWrapper : TypeWrapper
2005-03-23 12:33:18 +03:00
{
2005-06-01 13:49:30 +04:00
private readonly Type type;
private TypeWrapper[] interfaces;
private TypeWrapper[] innerclasses;
2005-03-23 12:33:18 +03:00
2005-06-01 13:49:30 +04:00
internal static CompiledTypeWrapper newInstance(string name, Type type)
2005-03-23 12:33:18 +03:00
{
2005-06-01 13:49:30 +04:00
// TODO since ghost and remapped types can only exist in the core library assembly, we probably
// should be able to remove the Type.IsDefined() tests in most cases
if(type.IsValueType && type.IsDefined(typeof(GhostInterfaceAttribute), false))
2005-03-23 12:33:18 +03:00
{
2005-06-01 13:49:30 +04:00
return new CompiledGhostTypeWrapper(name, type);
}
else if(type.IsDefined(typeof(RemappedTypeAttribute), false))
{
return new CompiledRemappedTypeWrapper(name, type);
}
else
{
return new CompiledTypeWrapper(name, type);
2005-03-23 12:33:18 +03:00
}
}
2005-06-01 13:49:30 +04:00
private sealed class CompiledRemappedTypeWrapper : CompiledTypeWrapper
2005-03-23 12:33:18 +03:00
{
2005-06-01 13:49:30 +04:00
private readonly Type remappedType;
internal CompiledRemappedTypeWrapper(string name, Type type)
: base(name, type)
2005-03-23 12:33:18 +03:00
{
2005-06-01 13:49:30 +04:00
object[] attribs = type.GetCustomAttributes(typeof(RemappedTypeAttribute), false);
if(attribs.Length != 1)
{
throw new InvalidOperationException();
}
remappedType = ((RemappedTypeAttribute)attribs[0]).Type;
2005-03-23 12:33:18 +03:00
}
2005-06-01 13:49:30 +04:00
internal override Type TypeAsTBD
2005-03-23 12:33:18 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return remappedType;
}
2005-03-23 12:33:18 +03:00
}
2005-06-01 13:49:30 +04:00
internal override bool IsRemapped
2005-03-23 12:33:18 +03:00
{
2005-06-01 13:49:30 +04:00
get
2005-03-23 12:33:18 +03:00
{
2005-06-01 13:49:30 +04:00
return true;
}
}
protected override void LazyPublishMembers()
{
ArrayList methods = new ArrayList();
ArrayList fields = new ArrayList();
MemberInfo[] members = type.GetMembers(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance);
foreach(MemberInfo m in members)
{
if(!AttributeHelper.IsHideFromJava(m))
2005-03-23 12:33:18 +03:00
{
2005-06-01 13:49:30 +04:00
MethodBase method = m as MethodBase;
if(method != null &&
(remappedType.IsSealed || !m.Name.StartsWith("instancehelper_")) &&
(!remappedType.IsSealed || method.IsStatic))
2005-03-23 12:33:18 +03:00
{
2005-06-01 13:49:30 +04:00
methods.Add(CreateRemappedMethodWrapper(method));
}
else
{
FieldInfo field = m as FieldInfo;
if(field != null)
{
fields.Add(CreateFieldWrapper(field));
}
2005-03-23 12:33:18 +03:00
}
}
}
2005-06-01 13:49:30 +04:00
// if we're a remapped interface, we need to get the methods from the real interface
if(remappedType.IsInterface)
2005-03-23 12:33:18 +03:00
{
2005-06-01 13:49:30 +04:00
Type nestedHelper = type.GetNestedType("__Helper", BindingFlags.Public | BindingFlags.Static);
foreach(RemappedInterfaceMethodAttribute m in type.GetCustomAttributes(typeof(RemappedInterfaceMethodAttribute), false))
2005-03-23 12:33:18 +03:00
{
2005-06-01 13:49:30 +04:00
MethodInfo method = remappedType.GetMethod(m.MappedTo);
MethodInfo mbHelper = method;
Modifiers modifiers = AttributeHelper.GetModifiers(method, false);
string name;
string sig;
TypeWrapper retType;
TypeWrapper[] paramTypes;
GetNameSigFromMethodBase(method, out name, out sig, out retType, out paramTypes);
if(nestedHelper != null)
2005-03-23 12:33:18 +03:00
{
2005-06-01 13:49:30 +04:00
mbHelper = nestedHelper.GetMethod(m.Name);
if(mbHelper == null)
{
mbHelper = method;
}
2005-03-23 12:33:18 +03:00
}
2005-06-01 13:49:30 +04:00
methods.Add(new CompiledRemappedMethodWrapper(this, m.Name, sig, method, retType, paramTypes, modifiers, false, mbHelper, null));
2005-03-23 12:33:18 +03:00
}
}
2005-06-01 13:49:30 +04:00
SetMethods((MethodWrapper[])methods.ToArray(typeof(MethodWrapper)));
SetFields((FieldWrapper[])fields.ToArray(typeof(FieldWrapper)));
2005-03-23 12:33:18 +03:00
}
2005-06-01 13:49:30 +04:00
private MethodWrapper CreateRemappedMethodWrapper(MethodBase mb)
2005-03-23 12:33:18 +03:00
{
2005-06-01 13:49:30 +04:00
Modifiers modifiers = AttributeHelper.GetModifiers(mb, false);
string name;
string sig;
TypeWrapper retType;
TypeWrapper[] paramTypes;
GetNameSigFromMethodBase(mb, out name, out sig, out retType, out paramTypes);
MethodInfo mbHelper = mb as MethodInfo;
MethodInfo mbNonvirtualHelper = null;
if(!mb.IsStatic && !mb.IsConstructor)
{
ParameterInfo[] parameters = mb.GetParameters();
Type[] argTypes = new Type[parameters.Length + 1];
argTypes[0] = remappedType;
for(int i = 0; i < parameters.Length; i++)
{
argTypes[i + 1] = parameters[i].ParameterType;
}
MethodInfo helper = type.GetMethod("instancehelper_" + mb.Name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static, null, argTypes, null);
if(helper != null)
{
mbHelper = helper;
}
mbNonvirtualHelper = type.GetMethod("nonvirtualhelper/" + mb.Name, BindingFlags.NonPublic | BindingFlags.Static, null, argTypes, null);
2005-03-23 12:33:18 +03:00
}
2005-06-01 13:49:30 +04:00
return new CompiledRemappedMethodWrapper(this, name, sig, mb, retType, paramTypes, modifiers, false, mbHelper, mbNonvirtualHelper);
2005-03-23 12:33:18 +03:00
}
}
2005-06-01 13:49:30 +04:00
private sealed class CompiledGhostTypeWrapper : CompiledTypeWrapper
2005-03-23 12:33:18 +03:00
{
2005-06-01 13:49:30 +04:00
private FieldInfo ghostRefField;
private Type typeAsBaseType;
2005-03-23 12:33:18 +03:00
2005-06-01 13:49:30 +04:00
internal CompiledGhostTypeWrapper(string name, Type type)
: base(name, type)
{
}
internal override Type TypeAsBaseType
2005-03-23 12:33:18 +03:00
{
2005-06-01 13:49:30 +04:00
get
2005-03-23 12:33:18 +03:00
{
2005-06-01 13:49:30 +04:00
if(typeAsBaseType == null)
{
typeAsBaseType = type.GetNestedType("__Interface");
}
return typeAsBaseType;
2005-03-23 12:33:18 +03:00
}
}
2005-06-01 13:49:30 +04:00
internal override FieldInfo GhostRefField
2005-03-23 12:33:18 +03:00
{
2005-06-01 13:49:30 +04:00
get
2005-03-23 12:33:18 +03:00
{
2005-06-01 13:49:30 +04:00
if(ghostRefField == null)
{
ghostRefField = type.GetField("__<ref>");
}
return ghostRefField;
2005-03-23 12:33:18 +03:00
}
}
2005-06-01 13:49:30 +04:00
internal override bool IsGhost
2005-03-23 12:33:18 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return true;
}
2005-03-23 12:33:18 +03:00
}
}
2004-01-11 16:14:42 +03:00
2005-06-01 13:49:30 +04:00
internal static string GetName(Type type)
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
Debug.Assert(type.Module.IsDefined(typeof(JavaModuleAttribute), false));
2002-12-18 19:00:25 +03:00
2005-06-01 13:49:30 +04:00
// look for our custom attribute, that contains the real name of the type (for inner classes)
Object[] attribs = type.GetCustomAttributes(typeof(InnerClassAttribute), false);
if(attribs.Length == 1)
{
2005-07-07 15:24:08 +04:00
string name = ((InnerClassAttribute)attribs[0]).InnerClassName;
if(name != null)
{
return name;
}
return GetName(type.DeclaringType) + "$" + type.Name;
2005-06-01 13:49:30 +04:00
}
return type.FullName;
2003-08-13 19:00:41 +04:00
}
2005-06-01 13:49:30 +04:00
// TODO consider resolving the baseType lazily
private static TypeWrapper GetBaseTypeWrapper(Type type)
2003-08-13 19:00:41 +04:00
{
2005-06-01 13:49:30 +04:00
if(type.IsInterface || type.IsDefined(typeof(GhostInterfaceAttribute), false))
2004-03-08 18:18:47 +03:00
{
2005-06-01 13:49:30 +04:00
return null;
}
else if(type.BaseType == null)
{
// System.Object must appear to be derived from java.lang.Object
return CoreClasses.java.lang.Object.Wrapper;
}
else
{
object[] attribs = type.GetCustomAttributes(typeof(RemappedTypeAttribute), false);
if(attribs.Length == 1)
2004-03-08 18:18:47 +03:00
{
2005-06-01 13:49:30 +04:00
if(((RemappedTypeAttribute)attribs[0]).Type == typeof(object))
{
return null;
}
else
{
return CoreClasses.java.lang.Object.Wrapper;
}
2004-03-08 18:18:47 +03:00
}
2005-06-01 13:49:30 +04:00
return ClassLoaderWrapper.GetWrapperFromType(type.BaseType);
2004-03-08 18:18:47 +03:00
}
2003-08-13 19:00:41 +04:00
}
2002-12-18 19:00:25 +03:00
2005-06-01 13:49:30 +04:00
private static ClassLoaderWrapper GetClassLoader(Type type)
2003-05-30 16:08:59 +04:00
{
2005-06-01 13:49:30 +04:00
return ClassLoaderWrapper.IsCoreAssemblyType(type) ? ClassLoaderWrapper.GetBootstrapClassLoader() : ClassLoaderWrapper.GetSystemClassLoader();
2003-05-30 16:08:59 +04:00
}
2003-10-22 20:34:22 +04:00
2005-06-01 13:49:30 +04:00
private CompiledTypeWrapper(string name, Type type)
: base(GetModifiers(type), name, GetBaseTypeWrapper(type), GetClassLoader(type), null)
2003-05-30 16:08:59 +04:00
{
2005-06-01 13:49:30 +04:00
Debug.Assert(!(type is TypeBuilder));
Debug.Assert(!type.IsArray);
this.type = type;
2003-05-30 16:08:59 +04:00
}
2005-06-01 13:49:30 +04:00
private static Modifiers GetModifiers(Type type)
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
object[] customAttribute = type.GetCustomAttributes(typeof(ModifiersAttribute), false);
if(customAttribute.Length == 1)
{
return ((ModifiersAttribute)customAttribute[0]).Modifiers;
}
// only returns public, protected, private, final, static, abstract and interface (as per
// the documentation of Class.getModifiers())
Modifiers modifiers = 0;
if(type.IsPublic)
{
modifiers |= Modifiers.Public;
}
// TODO do we really need to look for nested attributes? I think all inner classes will have the ModifiersAttribute.
else if(type.IsNestedPublic)
{
modifiers |= Modifiers.Public | Modifiers.Static;
}
else if(type.IsNestedPrivate)
{
modifiers |= Modifiers.Private | Modifiers.Static;
}
else if(type.IsNestedFamily || type.IsNestedFamORAssem)
{
modifiers |= Modifiers.Protected | Modifiers.Static;
}
else if(type.IsNestedAssembly || type.IsNestedFamANDAssem)
{
modifiers |= Modifiers.Static;
}
if(type.IsSealed)
{
modifiers |= Modifiers.Final;
}
if(type.IsAbstract)
{
modifiers |= Modifiers.Abstract;
}
if(type.IsInterface)
{
modifiers |= Modifiers.Interface;
}
return modifiers;
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
internal override bool HasStaticInitializer
2004-09-15 17:35:44 +04:00
{
2005-06-01 13:49:30 +04:00
get
{
return type.GetField("__<clinit>", BindingFlags.NonPublic | BindingFlags.Static) != null;
}
2004-09-15 17:35:44 +04:00
}
2005-06-01 13:49:30 +04:00
internal override Assembly Assembly
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
get
{
return type.Assembly;
}
2004-08-17 13:05:21 +04:00
}
2005-06-01 13:49:30 +04:00
internal override TypeWrapper[] Interfaces
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
get
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
if(interfaces == null)
2004-05-14 13:31:54 +04:00
{
2005-06-01 13:49:30 +04:00
// NOTE instead of getting the interfaces list from Type, we use a custom
// attribute to list the implemented interfaces, because Java reflection only
// reports the interfaces *directly* implemented by the type, not the inherited
// interfaces. This is significant for serialVersionUID calculation (for example).
object[] attribs = type.GetCustomAttributes(typeof(ImplementsAttribute), false);
if(attribs.Length == 1)
{
string[] interfaceNames = ((ImplementsAttribute)attribs[0]).Interfaces;
TypeWrapper[] interfaceWrappers = new TypeWrapper[interfaceNames.Length];
for(int i = 0; i < interfaceWrappers.Length; i++)
{
interfaceWrappers[i] = GetClassLoader().LoadClassByDottedName(interfaceNames[i]);
}
this.interfaces = interfaceWrappers;
}
else
2004-05-14 13:31:54 +04:00
{
2005-06-01 13:49:30 +04:00
interfaces = TypeWrapper.EmptyArray;
2004-05-14 13:31:54 +04:00
}
2002-12-18 19:00:25 +03:00
}
2005-06-01 13:49:30 +04:00
return interfaces;
2002-12-18 19:00:25 +03:00
}
}
2005-06-01 13:49:30 +04:00
internal override TypeWrapper[] InnerClasses
2003-02-18 12:30:34 +03:00
{
2005-06-01 13:49:30 +04:00
get
2003-02-18 12:30:34 +03:00
{
2005-06-01 13:49:30 +04:00
// TODO why are we caching this?
if(innerclasses == null)
2003-02-20 17:18:38 +03:00
{
2005-06-01 13:49:30 +04:00
Type[] nestedTypes = type.GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly);
ArrayList wrappers = new ArrayList();
for(int i = 0; i < nestedTypes.Length; i++)
2003-10-17 12:08:31 +04:00
{
2005-06-01 13:49:30 +04:00
if(!AttributeHelper.IsHideFromJava(nestedTypes[i]))
{
wrappers.Add(ClassLoaderWrapper.GetWrapperFromType(nestedTypes[i]));
}
2003-10-17 12:08:31 +04:00
}
2005-06-01 13:49:30 +04:00
innerclasses = (TypeWrapper[])wrappers.ToArray(typeof(TypeWrapper));
2003-02-20 17:18:38 +03:00
}
2005-06-01 13:49:30 +04:00
return innerclasses;
2003-02-18 12:30:34 +03:00
}
}
2005-06-01 13:49:30 +04:00
internal override TypeWrapper DeclaringTypeWrapper
2003-02-18 12:30:34 +03:00
{
2005-06-01 13:49:30 +04:00
get
2003-02-20 17:18:38 +03:00
{
2005-06-01 13:49:30 +04:00
Type declaringType = type.DeclaringType;
if(declaringType != null)
{
return ClassLoaderWrapper.GetWrapperFromType(declaringType);
}
return null;
2003-02-20 17:18:38 +03:00
}
2003-02-18 12:30:34 +03:00
}
2005-06-01 13:49:30 +04:00
internal override Modifiers ReflectiveModifiers
2003-05-30 16:08:59 +04:00
{
2005-06-01 13:49:30 +04:00
get
2003-05-30 16:08:59 +04:00
{
2005-06-01 13:49:30 +04:00
object[] customAttribute = type.GetCustomAttributes(typeof(InnerClassAttribute), false);
if(customAttribute.Length == 1)
{
return ((InnerClassAttribute)customAttribute[0]).Modifiers;
}
return Modifiers;
2004-08-17 13:05:21 +04:00
}
}
2005-06-01 13:49:30 +04:00
internal override Type TypeAsBaseType
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
get
{
return type;
}
2004-08-17 13:05:21 +04:00
}
2005-06-01 13:49:30 +04:00
private void SigTypePatchUp(string sigtype, ref TypeWrapper type)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
if(sigtype != type.SigName)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
// if type is an array, we know that it is a ghost array, because arrays of unloadable are compiled
// as object (not as arrays of object)
if(type.IsArray)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
type = GetClassLoader().FieldTypeWrapperFromSig(sigtype);
}
else
{
if(sigtype[0] == 'L')
{
sigtype = sigtype.Substring(1, sigtype.Length - 2);
}
type = new UnloadableTypeWrapper(sigtype);
2004-08-17 13:05:21 +04:00
}
2003-05-30 16:08:59 +04:00
}
}
2005-06-01 13:49:30 +04:00
private static void ParseSig(string sig, out string[] sigparam, out string sigret)
2003-10-17 12:08:31 +04:00
{
2005-06-01 13:49:30 +04:00
ArrayList list = new ArrayList();
int pos = 1;
for(;;)
2003-10-17 12:08:31 +04:00
{
2005-06-01 13:49:30 +04:00
switch(sig[pos])
2003-10-17 12:08:31 +04:00
{
2005-06-01 13:49:30 +04:00
case 'L':
2004-08-17 13:05:21 +04:00
{
int end = sig.IndexOf(';', pos) + 1;
list.Add(sig.Substring(pos, end - pos));
pos = end;
2005-06-01 13:49:30 +04:00
break;
2004-08-17 13:05:21 +04:00
}
2005-06-01 13:49:30 +04:00
case '[':
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
int skip = 1;
while(sig[pos + skip] == '[') skip++;
if(sig[pos + skip] == 'L')
{
int end = sig.IndexOf(';', pos) + 1;
list.Add(sig.Substring(pos, end - pos));
pos = end;
}
else
{
skip++;
list.Add(sig.Substring(pos, skip));
pos += skip;
}
break;
2004-08-17 13:05:21 +04:00
}
2005-06-01 13:49:30 +04:00
case ')':
sigparam = (string[])list.ToArray(typeof(string));
sigret = sig.Substring(pos + 1);
return;
default:
list.Add(sig.Substring(pos, 1));
pos++;
break;
2003-10-17 12:08:31 +04:00
}
}
}
2005-06-01 13:49:30 +04:00
private void GetNameSigFromMethodBase(MethodBase method, out string name, out string sig, out TypeWrapper retType, out TypeWrapper[] paramTypes)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
retType = method is ConstructorInfo ? PrimitiveTypeWrapper.VOID : ClassLoaderWrapper.GetWrapperFromType(((MethodInfo)method).ReturnType);
ParameterInfo[] parameters = method.GetParameters();
paramTypes = new TypeWrapper[parameters.Length];
for(int i = 0; i < parameters.Length; i++)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
paramTypes[i] = ClassLoaderWrapper.GetWrapperFromType(parameters[i].ParameterType);
2004-08-17 13:05:21 +04:00
}
2005-06-01 13:49:30 +04:00
if(method.IsDefined(typeof(NameSigAttribute), false))
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
NameSigAttribute attr = (NameSigAttribute)method.GetCustomAttributes(typeof(NameSigAttribute), false)[0];
name = attr.Name;
sig = attr.Sig;
string[] sigparams;
string sigret;
ParseSig(sig, out sigparams, out sigret);
// HACK newhelper methods have a return type, but it should be void
if(name == "<init>")
{
retType = PrimitiveTypeWrapper.VOID;
}
SigTypePatchUp(sigret, ref retType);
// if we have a remapped method, the paramTypes array contains an additional entry for "this" so we have
// to remove that
if(paramTypes.Length == sigparams.Length + 1)
{
TypeWrapper[] temp = paramTypes;
paramTypes = new TypeWrapper[sigparams.Length];
Array.Copy(temp, 1, paramTypes, 0, paramTypes.Length);
}
Debug.Assert(sigparams.Length == paramTypes.Length);
for(int i = 0; i < sigparams.Length; i++)
{
SigTypePatchUp(sigparams[i], ref paramTypes[i]);
}
2004-08-17 13:05:21 +04:00
}
else
{
2005-06-01 13:49:30 +04:00
if(method is ConstructorInfo)
{
name = method.IsStatic ? "<clinit>" : "<init>";
}
else
{
name = method.Name;
}
System.Text.StringBuilder sb = new System.Text.StringBuilder("(");
foreach(TypeWrapper tw in paramTypes)
{
sb.Append(tw.SigName);
}
sb.Append(")");
sb.Append(retType.SigName);
sig = sb.ToString();
2004-08-17 13:05:21 +04:00
}
2003-10-17 12:08:31 +04:00
}
2005-06-01 13:49:30 +04:00
protected override void LazyPublishMembers()
2004-03-08 18:18:47 +03:00
{
2005-06-01 13:49:30 +04:00
ArrayList methods = new ArrayList();
ArrayList fields = new ArrayList();
MemberInfo[] members = type.GetMembers(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance);
foreach(MemberInfo m in members)
2004-03-08 18:18:47 +03:00
{
2005-06-01 13:49:30 +04:00
if(!AttributeHelper.IsHideFromJava(m))
2005-03-23 12:33:18 +03:00
{
2005-06-01 13:49:30 +04:00
MethodBase method = m as MethodBase;
if(method != null)
2004-07-10 11:19:42 +04:00
{
2005-06-01 13:49:30 +04:00
string name;
string sig;
TypeWrapper retType;
TypeWrapper[] paramTypes;
GetNameSigFromMethodBase(method, out name, out sig, out retType, out paramTypes);
MethodInfo mi = method as MethodInfo;
bool miranda = mi != null ? AttributeHelper.IsMirandaMethod(mi) : false;
MemberFlags flags = miranda ? MemberFlags.MirandaMethod | MemberFlags.HideFromReflection : MemberFlags.None;
methods.Add(MethodWrapper.Create(this, name, sig, method, retType, paramTypes, AttributeHelper.GetModifiers(method, false), flags));
}
else
{
FieldInfo field = m as FieldInfo;
if(field != null)
{
fields.Add(CreateFieldWrapper(field));
}
2004-07-10 11:19:42 +04:00
}
2004-03-08 18:18:47 +03:00
}
}
2005-06-01 13:49:30 +04:00
SetMethods((MethodWrapper[])methods.ToArray(typeof(MethodWrapper)));
SetFields((FieldWrapper[])fields.ToArray(typeof(FieldWrapper)));
2004-03-08 18:18:47 +03:00
}
2004-06-14 14:36:38 +04:00
2005-06-01 13:49:30 +04:00
private class CompiledRemappedMethodWrapper : SmartMethodWrapper
2004-06-14 14:36:38 +04:00
{
2005-06-01 13:49:30 +04:00
private MethodInfo mbHelper;
private MethodInfo mbNonvirtualHelper;
2004-06-14 14:36:38 +04:00
2005-06-01 13:49:30 +04:00
internal CompiledRemappedMethodWrapper(TypeWrapper declaringType, string name, string sig, MethodBase method, TypeWrapper returnType, TypeWrapper[] parameterTypes, Modifiers modifiers, bool hideFromReflection, MethodInfo mbHelper, MethodInfo mbNonvirtualHelper)
: base(declaringType, name, sig, method, returnType, parameterTypes, modifiers, hideFromReflection ? MemberFlags.HideFromReflection : MemberFlags.None)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
this.mbHelper = mbHelper;
this.mbNonvirtualHelper = mbNonvirtualHelper;
2004-08-17 13:05:21 +04:00
}
2005-06-01 13:49:30 +04:00
protected override void CallImpl(ILGenerator ilgen)
2004-06-14 14:36:38 +04:00
{
2005-06-01 13:49:30 +04:00
MethodBase mb = GetMethod();
MethodInfo mi = mb as MethodInfo;
if(mi != null)
{
ilgen.Emit(OpCodes.Call, mi);
}
else
{
ilgen.Emit(OpCodes.Call, (ConstructorInfo)mb);
}
2004-06-14 14:36:38 +04:00
}
2005-06-01 13:49:30 +04:00
protected override void CallvirtImpl(ILGenerator ilgen)
2004-06-14 14:36:38 +04:00
{
2005-06-01 13:49:30 +04:00
Debug.Assert(!mbHelper.IsStatic || mbHelper.Name.StartsWith("instancehelper_") || mbHelper.DeclaringType.Name == "__Helper");
ilgen.Emit(mbHelper.IsStatic ? OpCodes.Call : OpCodes.Callvirt, mbHelper);
2004-06-14 14:36:38 +04:00
}
2004-08-17 13:05:21 +04:00
2005-06-01 13:49:30 +04:00
protected override void NewobjImpl(ILGenerator ilgen)
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
MethodBase mb = GetMethod();
MethodInfo mi = mb as MethodInfo;
if(mi != null)
2003-09-10 18:58:19 +04:00
{
2005-06-01 13:49:30 +04:00
Debug.Assert(mi.Name == "newhelper");
ilgen.Emit(OpCodes.Call, mi);
2003-07-02 18:50:35 +04:00
}
2005-06-01 13:49:30 +04:00
else
2003-07-02 18:50:35 +04:00
{
2005-06-01 13:49:30 +04:00
ilgen.Emit(OpCodes.Newobj, (ConstructorInfo)mb);
2003-07-02 18:50:35 +04:00
}
2005-06-01 13:49:30 +04:00
}
[HideFromJava]
internal override object Invoke(object obj, object[] args, bool nonVirtual)
{
MethodBase mb;
if(nonVirtual)
2004-03-08 18:18:47 +03:00
{
2005-06-01 13:49:30 +04:00
if(DeclaringType.TypeAsBaseType.IsInstanceOfType(obj))
{
mb = GetMethod();
}
else if(mbNonvirtualHelper != null)
{
mb = mbNonvirtualHelper;
}
else if(mbHelper != null)
{
mb = mbHelper;
}
else
{
// we can end up here if someone calls a constructor with nonVirtual set (which is pointless, but legal)
mb = GetMethod();
}
2004-03-08 18:18:47 +03:00
}
else
{
2005-06-01 13:49:30 +04:00
mb = mbHelper != null ? mbHelper : GetMethod();
2004-03-08 18:18:47 +03:00
}
2005-06-01 13:49:30 +04:00
return InvokeImpl(mb, obj, args, nonVirtual);
2004-03-08 18:18:47 +03:00
}
2004-10-04 23:30:53 +04:00
}
2004-01-28 14:28:16 +03:00
2005-06-01 13:49:30 +04:00
private FieldWrapper CreateFieldWrapper(FieldInfo field)
2002-12-18 19:00:25 +03:00
{
2005-06-01 13:49:30 +04:00
Modifiers modifiers = AttributeHelper.GetModifiers(field, false);
string name = field.Name;
TypeWrapper type = ClassLoaderWrapper.GetWrapperFromType(field.FieldType);
if(field.IsDefined(typeof(NameSigAttribute), false))
{
NameSigAttribute attr = (NameSigAttribute)field.GetCustomAttributes(typeof(NameSigAttribute), false)[0];
name = attr.Name;
SigTypePatchUp(attr.Sig, ref type);
}
2002-12-18 19:00:25 +03:00
2005-06-01 13:49:30 +04:00
// If the backing field is private, but the modifiers aren't, we've got a final field that
// has a property accessor method.
if(field.IsPrivate && ((modifiers & Modifiers.Private) == 0))
{
BindingFlags bindingFlags = BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Public;
bindingFlags |= field.IsStatic ? BindingFlags.Static : BindingFlags.Instance;
PropertyInfo prop = field.DeclaringType.GetProperty(field.Name, bindingFlags, null, field.FieldType, Type.EmptyTypes, null);
MethodInfo getter = prop.GetGetMethod(true);
return new GetterFieldWrapper(this, type, field, name, type.SigName, modifiers, getter);
}
else if(field.IsLiteral)
{
return new ConstantFieldWrapper(this, type, name, type.SigName, modifiers, field, null);
}
else
{
return FieldWrapper.Create(this, type, field, name, type.SigName, modifiers);
}
2004-03-08 18:18:47 +03:00
}
2005-06-01 13:49:30 +04:00
internal override Type TypeAsTBD
2004-03-08 18:18:47 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return type;
}
2002-12-18 19:00:25 +03:00
}
2004-10-04 23:30:53 +04:00
2005-06-01 13:49:30 +04:00
internal override bool IsMapUnsafeException
2003-02-22 15:28:12 +03:00
{
2005-06-01 13:49:30 +04:00
get
2004-07-10 11:19:42 +04:00
{
2005-06-01 13:49:30 +04:00
return type.IsDefined(typeof(ExceptionIsUnsafeForMappingAttribute), false);
2004-07-10 11:19:42 +04:00
}
2003-02-22 15:28:12 +03:00
}
2003-10-22 20:34:22 +04:00
2005-06-01 13:49:30 +04:00
internal override void Finish(bool forDebugSave)
2003-10-22 20:34:22 +04:00
{
}
2003-08-21 14:06:34 +04:00
}
2005-06-01 13:49:30 +04:00
sealed class Whidbey
2003-08-21 14:06:34 +04:00
{
2005-06-01 13:49:30 +04:00
private static readonly object[] noargs = new object[0];
private static readonly MethodInfo get_IsGenericTypeDefinition = typeof(Type).GetMethod("get_IsGenericTypeDefinition");
private static readonly MethodInfo get_IsGenericMethodDefinition = typeof(MethodBase).GetMethod("get_IsGenericMethodDefinition");
2003-08-21 14:06:34 +04:00
2005-06-01 13:49:30 +04:00
internal static bool IsGenericTypeDefinition(Type type)
2003-10-17 12:08:31 +04:00
{
2005-06-01 13:49:30 +04:00
return get_IsGenericTypeDefinition != null && (bool)get_IsGenericTypeDefinition.Invoke(type, noargs);
2003-10-17 12:08:31 +04:00
}
2005-06-01 13:49:30 +04:00
internal static bool IsGenericMethodDefinition(MethodBase mb)
2004-04-23 18:21:43 +04:00
{
2005-06-01 13:49:30 +04:00
return get_IsGenericMethodDefinition != null && (bool)get_IsGenericMethodDefinition.Invoke(mb, noargs);
2004-04-23 18:21:43 +04:00
}
2003-08-21 14:06:34 +04:00
}
2005-06-01 13:49:30 +04:00
sealed class DotNetTypeWrapper : TypeWrapper
2003-08-21 14:06:34 +04:00
{
2005-06-01 13:49:30 +04:00
private const string NamePrefix = "cli.";
private const string DelegateInterfaceSuffix = "$Method";
private readonly Type type;
private TypeWrapper[] innerClasses;
private TypeWrapper outerClass;
private TypeWrapper[] interfaces;
private static Modifiers GetModifiers(Type type)
2003-10-17 12:08:31 +04:00
{
2005-06-01 13:49:30 +04:00
Modifiers modifiers = 0;
if(type.IsPublic)
2005-05-23 12:24:07 +04:00
{
2005-06-01 13:49:30 +04:00
modifiers |= Modifiers.Public;
2003-08-21 14:06:34 +04:00
}
2005-06-01 13:49:30 +04:00
else if(type.IsNestedPublic)
2003-08-21 14:06:34 +04:00
{
2005-06-01 13:49:30 +04:00
modifiers |= Modifiers.Static;
if(IsVisible(type))
2003-08-21 14:06:34 +04:00
{
2005-06-01 13:49:30 +04:00
modifiers |= Modifiers.Public;
2003-08-21 14:06:34 +04:00
}
}
2005-06-01 13:49:30 +04:00
else if(type.IsNestedPrivate)
2003-08-21 14:06:34 +04:00
{
2005-06-01 13:49:30 +04:00
modifiers |= Modifiers.Private | Modifiers.Static;
2003-08-21 14:06:34 +04:00
}
2005-06-01 13:49:30 +04:00
else if(type.IsNestedFamily || type.IsNestedFamORAssem)
2004-04-23 18:21:43 +04:00
{
2005-06-01 13:49:30 +04:00
modifiers |= Modifiers.Protected | Modifiers.Static;
}
else if(type.IsNestedAssembly || type.IsNestedFamANDAssem)
{
modifiers |= Modifiers.Static;
2004-04-23 18:21:43 +04:00
}
2003-08-26 15:24:17 +04:00
2005-06-01 13:49:30 +04:00
if(type.IsSealed)
{
modifiers |= Modifiers.Final;
}
else if(type.IsAbstract) // we can't be abstract if we're final
{
modifiers |= Modifiers.Abstract;
}
if(type.IsInterface)
{
modifiers |= Modifiers.Interface;
}
return modifiers;
2003-08-26 15:24:17 +04:00
}
2005-06-01 13:49:30 +04:00
// NOTE when this is called on a remapped type, the "warped" underlying type name is returned.
// E.g. GetName(typeof(object)) returns "cli.System.Object".
internal static string GetName(Type type)
2003-08-26 15:24:17 +04:00
{
2005-06-01 13:49:30 +04:00
Debug.Assert(!type.IsArray && !type.Module.IsDefined(typeof(JavaModuleAttribute), false));
2003-08-26 15:24:17 +04:00
2005-06-01 13:49:30 +04:00
if(type.IsDefined(typeof(NoPackagePrefixAttribute), false) || type.Assembly.IsDefined(typeof(NoPackagePrefixAttribute), false))
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
// TODO figure out if this is even required
return type.FullName.Replace('+', '$');
2004-08-17 13:05:21 +04:00
}
2005-06-01 13:49:30 +04:00
return MangleTypeName(type.FullName);
2004-08-17 13:05:21 +04:00
}
2005-06-01 13:49:30 +04:00
private static string MangleTypeName(string name)
2004-08-17 13:05:21 +04:00
{
2005-06-22 17:02:03 +04:00
System.Text.StringBuilder sb = new System.Text.StringBuilder(NamePrefix, NamePrefix.Length + name.Length);
int quoteMode = 0;
2005-06-27 13:06:57 +04:00
bool escape = false;
2005-06-22 17:02:03 +04:00
for(int i = 0; i < name.Length; i++)
{
char c = name[i];
2005-06-27 13:06:57 +04:00
if(c == '[' && !escape)
2005-06-22 17:02:03 +04:00
{
quoteMode++;
}
2005-06-27 13:06:57 +04:00
if(c == ']' && !escape)
2005-06-22 17:02:03 +04:00
{
quoteMode--;
}
2005-06-27 13:06:57 +04:00
if(c == '+' && !escape && (sb.Length == 0 || sb[sb.Length - 1] != '$'))
2005-06-22 17:02:03 +04:00
{
sb.Append('$');
}
2005-06-27 13:06:57 +04:00
else if("_0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".IndexOf(c) != -1
2005-06-22 17:02:03 +04:00
|| (c == '.' && quoteMode == 0))
{
sb.Append(c);
}
else
{
2005-06-27 13:06:57 +04:00
sb.Append("$$");
2005-06-22 17:02:03 +04:00
sb.Append(string.Format("{0:X4}", (int)c));
}
2005-06-27 13:06:57 +04:00
if(c == '\\')
{
escape = !escape;
}
else
{
escape = false;
}
2005-06-22 17:02:03 +04:00
}
return sb.ToString();
2004-08-17 13:05:21 +04:00
}
2005-06-22 17:02:03 +04:00
// NOTE if the name is not a valid mangled type name, no demangling is done and the
// original string is returned
2005-06-01 13:49:30 +04:00
private static string DemangleTypeName(string name)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
Debug.Assert(name.StartsWith(NamePrefix));
2005-06-22 17:02:03 +04:00
System.Text.StringBuilder sb = new System.Text.StringBuilder(name.Length - NamePrefix.Length);
int end = name.Length;
bool hasDelegateSuffix = name.EndsWith(DelegateInterfaceSuffix);
if(hasDelegateSuffix)
2005-06-01 13:49:30 +04:00
{
2005-06-22 17:02:03 +04:00
end -= DelegateInterfaceSuffix.Length;
}
// TODO we should enforce canonical form
for(int i = NamePrefix.Length; i < end; i++)
{
char c = name[i];
if(c == '$')
{
2005-06-27 13:06:57 +04:00
if(i + 1 < end && name[i + 1] != '$')
2005-06-22 17:02:03 +04:00
{
2005-06-27 13:06:57 +04:00
sb.Append('+');
2005-06-22 17:02:03 +04:00
}
2005-06-27 13:06:57 +04:00
else
2005-06-22 17:02:03 +04:00
{
2005-06-27 13:06:57 +04:00
i++;
if(i + 5 > end)
{
return name;
}
int digit0 = "0123456789ABCDEF".IndexOf(name[++i]);
int digit1 = "0123456789ABCDEF".IndexOf(name[++i]);
int digit2 = "0123456789ABCDEF".IndexOf(name[++i]);
int digit3 = "0123456789ABCDEF".IndexOf(name[++i]);
if(digit0 == -1 || digit1 == -1 || digit2 == -1 || digit3 == -1)
{
return name;
}
sb.Append((char)((digit0 << 12) + (digit1 << 8) + (digit2 << 4) + digit3));
2005-06-22 17:02:03 +04:00
}
}
else
{
sb.Append(c);
}
}
if(hasDelegateSuffix)
{
sb.Append(DelegateInterfaceSuffix);
2005-06-01 13:49:30 +04:00
}
2005-06-22 17:02:03 +04:00
return sb.ToString();
2004-08-17 13:05:21 +04:00
}
2005-06-01 13:49:30 +04:00
// this method returns a new TypeWrapper instance for each invocation (doesn't prevent duplicates)
// the caller is responsible for making sure that only one TypeWrapper with the specified name escapes
// out into the world
internal static TypeWrapper CreateDotNetTypeWrapper(string name)
2004-08-17 13:05:21 +04:00
{
2005-06-22 18:24:16 +04:00
string origname = name;
2005-06-01 13:49:30 +04:00
bool prefixed = name.StartsWith(NamePrefix);
if(prefixed)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
name = DemangleTypeName(name);
2004-08-17 13:05:21 +04:00
}
2005-06-01 13:49:30 +04:00
Type type = LoadTypeFromLoadedAssemblies(name);
if(type != null)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
// SECURITY we never expose types from IKVM.Runtime, because doing so would lead to a security hole,
// since the reflection implementation lives inside this assembly, all internal members would
// be accessible through Java reflection.
if(type.Assembly == typeof(DotNetTypeWrapper).Assembly)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
return null;
2004-08-17 13:05:21 +04:00
}
2005-06-01 13:49:30 +04:00
if(Whidbey.IsGenericTypeDefinition(type))
2003-08-26 15:24:17 +04:00
{
2005-06-01 13:49:30 +04:00
return null;
}
if(prefixed || type.IsDefined(typeof(NoPackagePrefixAttribute), false) || type.Assembly.IsDefined(typeof(NoPackagePrefixAttribute), false))
{
return new DotNetTypeWrapper(type);
2003-08-26 15:24:17 +04:00
}
}
2005-06-01 13:49:30 +04:00
if(name.EndsWith(DelegateInterfaceSuffix))
2003-08-26 15:24:17 +04:00
{
2005-06-01 13:49:30 +04:00
Type delegateType = LoadTypeFromLoadedAssemblies(name.Substring(0, name.Length - DelegateInterfaceSuffix.Length));
if(delegateType != null && IsDelegate(delegateType))
2003-08-26 15:24:17 +04:00
{
2005-06-01 13:49:30 +04:00
MethodInfo invoke = delegateType.GetMethod("Invoke");
ParameterInfo[] parameters = invoke.GetParameters();
Type[] args = new Type[parameters.Length];
for(int i = 0; i < args.Length; i++)
2003-08-26 15:24:17 +04:00
{
2005-06-01 13:49:30 +04:00
// we know there aren't any unsupported parameter types, because IsDelegate() returned true
args[i] = parameters[i].ParameterType;
2003-08-26 15:24:17 +04:00
}
2005-06-01 13:49:30 +04:00
ModuleBuilder moduleBuilder = ClassLoaderWrapper.GetBootstrapClassLoader().ModuleBuilder;
2005-06-22 18:24:16 +04:00
TypeBuilder typeBuilder = moduleBuilder.DefineType(origname, TypeAttributes.Public | TypeAttributes.Interface | TypeAttributes.Abstract);
2005-07-07 15:24:08 +04:00
AttributeHelper.SetInnerClass(typeBuilder, origname, Modifiers.Public | Modifiers.Interface | Modifiers.Static | Modifiers.Abstract);
2005-06-01 13:49:30 +04:00
typeBuilder.DefineMethod("Invoke", MethodAttributes.Public | MethodAttributes.Abstract | MethodAttributes.Virtual, CallingConventions.Standard, invoke.ReturnType, args);
2005-06-22 18:24:16 +04:00
return CompiledTypeWrapper.newInstance(origname, typeBuilder.CreateType());
2003-08-26 15:24:17 +04:00
}
}
2005-06-01 13:49:30 +04:00
return null;
2004-06-25 13:38:07 +04:00
}
2005-06-01 13:49:30 +04:00
private static Type LoadTypeFromLoadedAssemblies(string name)
2004-06-25 13:38:07 +04:00
{
2005-06-01 13:49:30 +04:00
foreach(Assembly a in AppDomain.CurrentDomain.GetAssemblies())
{
// HACK we also look inside Java assemblies, because precompiled delegate interfaces might have ended up there
if(!(a is AssemblyBuilder))
{
Type t = a.GetType(name);
if(t != null)
{
return t;
}
// HACK we might be looking for an inner classes
// (if we remove the mangling of NoPackagePrefix types from GetName, we don't need this anymore)
t = a.GetType(name.Replace('$', '+'));
if(t != null)
{
return t;
}
}
}
return null;
2004-06-25 13:38:07 +04:00
}
2005-06-01 13:49:30 +04:00
internal static TypeWrapper GetWrapperFromDotNetType(Type type)
2004-10-04 23:30:53 +04:00
{
2005-06-01 13:49:30 +04:00
// TODO there should be a better way
return ClassLoaderWrapper.GetBootstrapClassLoader().LoadClassByDottedName(DotNetTypeWrapper.GetName(type));
2004-10-04 23:30:53 +04:00
}
2005-06-01 13:49:30 +04:00
private static TypeWrapper GetBaseTypeWrapper(Type type)
2004-10-04 23:30:53 +04:00
{
2005-06-01 13:49:30 +04:00
if(type.IsInterface)
2004-12-21 13:26:51 +03:00
{
2005-06-01 13:49:30 +04:00
return null;
2004-12-21 13:26:51 +03:00
}
2005-06-01 13:49:30 +04:00
else if(ClassLoaderWrapper.IsRemappedType(type))
2004-12-21 13:26:51 +03:00
{
2005-06-01 13:49:30 +04:00
// Remapped types extend their alter ego
// (e.g. cli.System.Object must appear to be derived from java.lang.Object)
// except when they're sealed, of course.
if(type.IsSealed)
{
return CoreClasses.java.lang.Object.Wrapper;
}
return ClassLoaderWrapper.GetWrapperFromType(type);
2004-12-21 13:26:51 +03:00
}
2005-06-01 13:49:30 +04:00
else if(ClassLoaderWrapper.IsRemappedType(type.BaseType))
2004-12-21 13:26:51 +03:00
{
2005-06-01 13:49:30 +04:00
return GetWrapperFromDotNetType(type.BaseType);
2004-12-21 13:26:51 +03:00
}
2005-06-01 13:49:30 +04:00
else
2004-12-21 13:26:51 +03:00
{
2005-06-01 13:49:30 +04:00
return ClassLoaderWrapper.GetWrapperFromType(type.BaseType);
2004-12-21 13:26:51 +03:00
}
2004-10-04 23:30:53 +04:00
}
2005-06-01 13:49:30 +04:00
internal DotNetTypeWrapper(Type type)
: base(GetModifiers(type), GetName(type), GetBaseTypeWrapper(type), null, null)
2004-06-25 13:38:07 +04:00
{
2005-06-01 13:49:30 +04:00
Debug.Assert(!(type.IsByRef), type.FullName);
Debug.Assert(!(type.IsPointer), type.FullName);
Debug.Assert(!(type.IsArray), type.FullName);
Debug.Assert(!(type is TypeBuilder), type.FullName);
Debug.Assert(!(type.Module.IsDefined(typeof(JavaModuleAttribute), false)));
this.type = type;
2004-06-25 13:38:07 +04:00
}
2005-06-01 13:49:30 +04:00
internal override ClassLoaderWrapper GetClassLoader()
2004-06-25 13:38:07 +04:00
{
2005-06-01 13:49:30 +04:00
return ClassLoaderWrapper.GetSystemClassLoader();
2004-06-25 13:38:07 +04:00
}
2005-06-01 13:49:30 +04:00
private class DelegateMethodWrapper : MethodWrapper
2004-06-25 13:38:07 +04:00
{
2005-06-01 13:49:30 +04:00
private ConstructorInfo delegateConstructor;
private MethodInfo method;
internal DelegateMethodWrapper(TypeWrapper declaringType, Type delegateType, TypeWrapper iface)
: base(declaringType, "<init>", "(" + iface.SigName + ")V", null, PrimitiveTypeWrapper.VOID, new TypeWrapper[] { iface }, Modifiers.Public, MemberFlags.None)
2004-12-21 13:26:51 +03:00
{
2005-06-01 13:49:30 +04:00
this.delegateConstructor = delegateType.GetConstructor(new Type[] { typeof(object), typeof(IntPtr) });
this.method = iface.TypeAsTBD.GetMethod("Invoke");
2004-12-21 13:26:51 +03:00
}
2005-06-01 13:49:30 +04:00
internal override void EmitNewobj(ILGenerator ilgen)
2004-12-21 13:26:51 +03:00
{
2005-06-01 13:49:30 +04:00
ilgen.Emit(OpCodes.Dup);
ilgen.Emit(OpCodes.Ldvirtftn, method);
ilgen.Emit(OpCodes.Newobj, delegateConstructor);
2004-12-21 13:26:51 +03:00
}
2005-06-01 13:49:30 +04:00
[HideFromJava]
internal override object Invoke(object obj, object[] args, bool nonVirtual)
2004-12-21 13:26:51 +03:00
{
2005-06-01 13:49:30 +04:00
// TODO map exceptions
return Delegate.CreateDelegate(DeclaringType.TypeAsTBD, args[0], "Invoke");
2004-12-21 13:26:51 +03:00
}
2005-06-01 13:49:30 +04:00
}
private class ByRefMethodWrapper : SmartMethodWrapper
{
private bool[] byrefs;
private Type[] args;
internal ByRefMethodWrapper(Type[] args, bool[] byrefs, TypeWrapper declaringType, string name, string sig, MethodBase method, TypeWrapper returnType, TypeWrapper[] parameterTypes, Modifiers modifiers, bool hideFromReflection)
: base(declaringType, name, sig, method, returnType, parameterTypes, modifiers, hideFromReflection ? MemberFlags.HideFromReflection : MemberFlags.None)
2004-12-21 13:26:51 +03:00
{
2005-06-01 13:49:30 +04:00
this.args = args;
this.byrefs = byrefs;
2004-12-21 13:26:51 +03:00
}
2005-06-01 13:49:30 +04:00
protected override void CallImpl(ILGenerator ilgen)
2004-06-25 13:38:07 +04:00
{
2005-06-01 13:49:30 +04:00
MethodBase mb = GetMethod();
MethodInfo mi = mb as MethodInfo;
if(mi != null)
{
ilgen.Emit(OpCodes.Call, mi);
}
else
{
ilgen.Emit(OpCodes.Call, (ConstructorInfo)mb);
}
2004-06-25 13:38:07 +04:00
}
2005-06-01 13:49:30 +04:00
protected override void CallvirtImpl(ILGenerator ilgen)
2004-12-21 13:26:51 +03:00
{
2005-06-01 13:49:30 +04:00
ilgen.Emit(OpCodes.Callvirt, (MethodInfo)GetMethod());
2004-12-21 13:26:51 +03:00
}
2005-06-01 13:49:30 +04:00
protected override void NewobjImpl(ILGenerator ilgen)
2004-06-25 13:38:07 +04:00
{
2005-06-01 13:49:30 +04:00
ilgen.Emit(OpCodes.Newobj, (ConstructorInfo)GetMethod());
2004-06-25 13:38:07 +04:00
}
2004-12-21 13:26:51 +03:00
2005-06-01 13:49:30 +04:00
protected override void PreEmit(ILGenerator ilgen)
{
LocalBuilder[] locals = new LocalBuilder[args.Length];
for(int i = args.Length - 1; i >= 0; i--)
{
Type type = args[i];
if(type.IsByRef)
{
type = type.Assembly.GetType(type.GetElementType().FullName + "[]", true);
}
locals[i] = ilgen.DeclareLocal(type);
ilgen.Emit(OpCodes.Stloc, locals[i]);
}
for(int i = 0; i < args.Length; i++)
{
ilgen.Emit(OpCodes.Ldloc, locals[i]);
if(args[i].IsByRef)
{
ilgen.Emit(OpCodes.Ldc_I4_0);
ilgen.Emit(OpCodes.Ldelema, args[i].GetElementType());
}
}
base.PreEmit(ilgen);
}
2004-06-25 13:38:07 +04:00
2005-06-01 13:49:30 +04:00
[HideFromJava]
internal override object Invoke(object obj, object[] args, bool nonVirtual)
{
object[] newargs = (object[])args.Clone();
for(int i = 0; i < newargs.Length; i++)
{
if(byrefs[i])
{
newargs[i] = ((Array)args[i]).GetValue(0);
}
}
try
{
return base.Invoke(obj, newargs, nonVirtual);
}
finally
{
for(int i = 0; i < newargs.Length; i++)
{
if(byrefs[i])
{
((Array)args[i]).SetValue(newargs[i], 0);
}
}
}
}
2004-08-17 13:05:21 +04:00
}
2005-06-01 13:49:30 +04:00
internal static bool IsVisible(Type type)
2004-10-19 17:43:55 +04:00
{
2005-06-01 13:49:30 +04:00
return type.IsPublic || (type.IsNestedPublic && IsVisible(type.DeclaringType));
2004-10-19 17:43:55 +04:00
}
2005-06-01 13:49:30 +04:00
private class EnumWrapMethodWrapper : MethodWrapper
2004-10-19 17:43:55 +04:00
{
2005-06-01 13:49:30 +04:00
internal EnumWrapMethodWrapper(DotNetTypeWrapper tw, TypeWrapper fieldType)
: base(tw, "wrap", "(" + fieldType.SigName + ")" + tw.SigName, null, tw, new TypeWrapper[] { fieldType }, Modifiers.Static | Modifiers.Public, MemberFlags.None)
{
}
2004-10-19 17:43:55 +04:00
2005-06-01 13:49:30 +04:00
internal override void EmitCall(ILGenerator ilgen)
{
// We don't actually need to do anything here!
// The compiler will insert a boxing operation after calling us and that will
// result in our argument being boxed (since that's still sitting on the stack).
}
[HideFromJava]
internal override object Invoke(object obj, object[] args, bool nonVirtual)
2004-10-19 17:43:55 +04:00
{
2005-06-01 13:49:30 +04:00
return Enum.ToObject(DeclaringType.TypeAsTBD, ((IConvertible)args[0]).ToInt64(null));
2004-10-19 17:43:55 +04:00
}
}
2005-06-01 13:49:30 +04:00
internal class EnumValueFieldWrapper : FieldWrapper
2003-08-21 14:06:34 +04:00
{
2005-06-01 13:49:30 +04:00
// NOTE if the reference on the stack is null, we *want* the NullReferenceException, so we don't use TypeWrapper.EmitUnbox
internal EnumValueFieldWrapper(DotNetTypeWrapper tw, TypeWrapper fieldType)
: base(tw, fieldType, "Value", fieldType.SigName, Modifiers.Public | Modifiers.Final, null)
2004-12-21 13:26:51 +03:00
{
}
2005-06-01 13:49:30 +04:00
protected override void EmitGetImpl(ILGenerator ilgen)
2004-12-21 13:26:51 +03:00
{
2005-06-01 13:49:30 +04:00
DotNetTypeWrapper tw = (DotNetTypeWrapper)this.DeclaringType;
ilgen.Emit(OpCodes.Unbox, tw.type);
// FXBUG the .NET 1.1 verifier doesn't understand that ldobj on an enum that has an underlying type
// of byte or short that the resulting type on the stack is an int32, so we have to
// to it the hard way. Note that this is fixed in Whidbey.
Type underlyingType = Enum.GetUnderlyingType(tw.type);
if(underlyingType == typeof(sbyte) || underlyingType == typeof(byte))
{
ilgen.Emit(OpCodes.Ldind_I1);
}
else if(underlyingType == typeof(short) || underlyingType == typeof(ushort))
{
ilgen.Emit(OpCodes.Ldind_I2);
}
else if(underlyingType == typeof(int) || underlyingType == typeof(uint))
{
ilgen.Emit(OpCodes.Ldind_I4);
}
else if(underlyingType == typeof(long) || underlyingType == typeof(ulong))
{
ilgen.Emit(OpCodes.Ldind_I8);
}
2004-12-21 13:26:51 +03:00
}
2005-06-01 13:49:30 +04:00
protected override void EmitSetImpl(ILGenerator ilgen)
2004-12-21 13:26:51 +03:00
{
2005-06-01 13:49:30 +04:00
throw new InvalidOperationException();
2004-12-21 13:26:51 +03:00
}
2005-06-01 13:49:30 +04:00
internal override void SetValue(object obj, object val)
2004-12-21 13:26:51 +03:00
{
2005-06-01 13:49:30 +04:00
// NOTE even though the field is final, JNI reflection can still be used to set its value!
// NOTE the CLI spec says that an enum has exactly one instance field, so we take advantage of that fact.
FieldInfo f = DeclaringType.TypeAsTBD.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)[0];
f.SetValue(obj, val);
2004-12-21 13:26:51 +03:00
}
2005-06-01 13:49:30 +04:00
// this method takes a boxed Enum and returns its value as a boxed primitive
// of the subset of Java primitives (i.e. byte, short, int, long)
internal static object GetEnumPrimitiveValue(object obj)
2003-08-21 14:06:34 +04:00
{
2005-06-01 13:49:30 +04:00
Type underlyingType = Enum.GetUnderlyingType(obj.GetType());
if(underlyingType == typeof(sbyte) || underlyingType == typeof(byte))
2003-08-21 14:06:34 +04:00
{
2005-06-01 13:49:30 +04:00
return unchecked((byte)((IConvertible)obj).ToInt32(null));
2003-08-21 14:06:34 +04:00
}
2005-06-01 13:49:30 +04:00
else if(underlyingType == typeof(short) || underlyingType == typeof(ushort))
{
return unchecked((short)((IConvertible)obj).ToInt32(null));
}
else if(underlyingType == typeof(int))
{
return ((IConvertible)obj).ToInt32(null);
}
else if(underlyingType == typeof(uint))
{
return unchecked((int)((IConvertible)obj).ToUInt32(null));
}
else if(underlyingType == typeof(long))
{
return ((IConvertible)obj).ToInt64(null);
}
else if(underlyingType == typeof(ulong))
2003-08-21 14:06:34 +04:00
{
2005-06-01 13:49:30 +04:00
return unchecked((long)((IConvertible)obj).ToUInt64(null));
2003-08-21 14:06:34 +04:00
}
else
{
2005-06-01 13:49:30 +04:00
throw new InvalidOperationException();
2003-08-21 14:06:34 +04:00
}
}
2005-06-01 13:49:30 +04:00
internal override object GetValue(object obj)
{
return GetEnumPrimitiveValue(obj);
}
}
internal override Assembly Assembly
{
get
2003-08-21 14:06:34 +04:00
{
2005-06-01 13:49:30 +04:00
return type.Assembly;
2003-08-21 14:06:34 +04:00
}
2005-06-01 13:49:30 +04:00
}
2003-08-21 14:06:34 +04:00
2005-06-01 13:49:30 +04:00
private class ValueTypeDefaultCtor : MethodWrapper
{
internal ValueTypeDefaultCtor(DotNetTypeWrapper tw)
: base(tw, "<init>", "()V", null, PrimitiveTypeWrapper.VOID, TypeWrapper.EmptyArray, Modifiers.Public, MemberFlags.None)
{
}
2004-10-19 17:43:55 +04:00
2005-06-01 13:49:30 +04:00
internal override void EmitNewobj(ILGenerator ilgen)
2003-08-21 14:06:34 +04:00
{
2005-06-01 13:49:30 +04:00
LocalBuilder local = ilgen.DeclareLocal(DeclaringType.TypeAsTBD);
ilgen.Emit(OpCodes.Ldloc, local);
ilgen.Emit(OpCodes.Box, DeclaringType.TypeAsTBD);
}
[HideFromJava]
internal override object Invoke(object obj, object[] args, bool nonVirtual)
{
if(obj == null)
2003-08-21 14:06:34 +04:00
{
2005-06-01 13:49:30 +04:00
obj = Activator.CreateInstance(DeclaringType.TypeAsTBD);
2003-08-21 14:06:34 +04:00
}
2005-06-01 13:49:30 +04:00
return obj;
2003-08-21 14:06:34 +04:00
}
2005-06-01 13:49:30 +04:00
}
2003-08-21 14:06:34 +04:00
2005-06-01 13:49:30 +04:00
protected override void LazyPublishMembers()
{
ArrayList fieldsList = new ArrayList();
ArrayList methodsList = new ArrayList();
// special support for enums
if(type.IsEnum)
2004-10-19 17:43:55 +04:00
{
2005-06-01 13:49:30 +04:00
Type underlyingType = Enum.GetUnderlyingType(type);
if(underlyingType == typeof(sbyte))
{
underlyingType = typeof(byte);
}
else if(underlyingType == typeof(ushort))
{
underlyingType = typeof(short);
}
else if(underlyingType == typeof(uint))
{
underlyingType = typeof(int);
}
else if(underlyingType == typeof(ulong))
{
underlyingType = typeof(long);
}
TypeWrapper fieldType = ClassLoaderWrapper.GetWrapperFromType(underlyingType);
FieldInfo[] fields = type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Static);
for(int i = 0; i < fields.Length; i++)
{
if(fields[i].FieldType == type)
{
string name = fields[i].Name;
if(name == "Value")
{
name = "_Value";
}
else if(name.StartsWith("_") && name.EndsWith("Value"))
{
name = "_" + name;
}
object val = EnumValueFieldWrapper.GetEnumPrimitiveValue(fields[i].GetValue(null));
fieldsList.Add(new ConstantFieldWrapper(this, fieldType, name, fieldType.SigName, Modifiers.Public | Modifiers.Static | Modifiers.Final, fields[i], val));
}
}
fieldsList.Add(new EnumValueFieldWrapper(this, fieldType));
methodsList.Add(new EnumWrapMethodWrapper(this, fieldType));
2004-10-19 17:43:55 +04:00
}
2005-06-01 13:49:30 +04:00
else
2003-08-21 14:06:34 +04:00
{
2005-06-01 13:49:30 +04:00
FieldInfo[] fields = type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance);
for(int i = 0; i < fields.Length; i++)
2003-08-21 14:06:34 +04:00
{
2005-06-01 13:49:30 +04:00
// TODO for remapped types, instance fields need to be converted to static getter/setter methods
if(fields[i].FieldType.IsPointer)
{
// skip, pointer fields are not supported
}
else
{
// TODO handle name/signature clash
fieldsList.Add(CreateFieldWrapperDotNet(AttributeHelper.GetModifiers(fields[i], true), fields[i].Name, fields[i].FieldType, fields[i]));
}
2003-11-17 15:01:50 +03:00
}
2005-06-01 13:49:30 +04:00
// special case for delegate constructors!
if(IsDelegate(type))
{
TypeWrapper iface = InnerClasses[0];
Debug.Assert(iface is CompiledTypeWrapper);
iface.Finish();
methodsList.Add(new DelegateMethodWrapper(this, type, iface));
}
bool fabricateDefaultCtor = type.IsValueType;
ConstructorInfo[] constructors = type.GetConstructors(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance);
for(int i = 0; i < constructors.Length; i++)
2003-11-17 15:01:50 +03:00
{
2005-01-03 11:26:21 +03:00
string name;
string sig;
2005-06-01 13:49:30 +04:00
if(MakeMethodDescriptor(constructors[i], out name, out sig))
{
if(fabricateDefaultCtor && !constructors[i].IsStatic && sig == "()V")
{
fabricateDefaultCtor = false;
}
// TODO handle name/signature clash
methodsList.Add(CreateMethodWrapper(name, sig, constructors[i], false));
}
}
if(fabricateDefaultCtor)
{
// Value types have an implicit default ctor
methodsList.Add(new ValueTypeDefaultCtor(this));
}
MethodInfo[] methods = type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance);
for(int i = 0; i < methods.Length; i++)
{
if(methods[i].IsStatic && type.IsInterface)
2003-11-17 15:01:50 +03:00
{
2005-06-01 13:49:30 +04:00
// skip, Java cannot deal with static methods on interfaces
}
else
{
string name;
string sig;
if(MakeMethodDescriptor(methods[i], out name, out sig))
2004-11-04 15:50:28 +03:00
{
2005-06-01 13:49:30 +04:00
if(!methods[i].IsStatic && !methods[i].IsPrivate && BaseTypeWrapper != null)
2004-11-04 15:50:28 +03:00
{
2005-06-01 13:49:30 +04:00
MethodWrapper baseMethod = BaseTypeWrapper.GetMethodWrapper(name, sig, true);
if(baseMethod != null && baseMethod.IsFinal && !baseMethod.IsStatic && !baseMethod.IsPrivate)
{
continue;
}
2004-11-04 15:50:28 +03:00
}
2005-06-01 13:49:30 +04:00
// TODO handle name/signature clash
methodsList.Add(CreateMethodWrapper(name, sig, methods[i], false));
2004-11-04 15:50:28 +03:00
}
2003-12-20 01:19:18 +03:00
}
}
2005-06-01 13:49:30 +04:00
// HACK private interface implementations need to be published as well
// (otherwise the type appears abstract while it isn't)
if(!type.IsInterface)
2003-12-20 01:19:18 +03:00
{
2005-06-01 13:49:30 +04:00
Hashtable clash = null;
Type[] interfaces = type.GetInterfaces();
for(int i = 0; i < interfaces.Length; i++)
2003-12-20 01:19:18 +03:00
{
2005-06-01 13:49:30 +04:00
if(interfaces[i].IsPublic)
2003-12-20 01:19:18 +03:00
{
2005-06-01 13:49:30 +04:00
InterfaceMapping map = type.GetInterfaceMap(interfaces[i]);
for(int j = 0; j < map.InterfaceMethods.Length; j++)
2003-12-20 01:19:18 +03:00
{
2005-06-01 13:49:30 +04:00
if(!map.TargetMethods[j].IsPublic && map.TargetMethods[j].DeclaringType == type)
2003-12-20 01:19:18 +03:00
{
2005-06-01 13:49:30 +04:00
string name;
string sig;
if(MakeMethodDescriptor(map.InterfaceMethods[j], out name, out sig))
2004-11-04 15:50:28 +03:00
{
2005-06-01 13:49:30 +04:00
if(BaseTypeWrapper != null)
2004-11-04 15:50:28 +03:00
{
2005-06-01 13:49:30 +04:00
MethodWrapper baseMethod = BaseTypeWrapper.GetMethodWrapper(name, sig, true);
if(baseMethod != null && !baseMethod.IsStatic && baseMethod.IsPublic)
{
continue;
}
2004-11-04 15:50:28 +03:00
}
2005-06-01 13:49:30 +04:00
if(clash == null)
2005-02-02 18:11:26 +03:00
{
2005-06-01 13:49:30 +04:00
clash = new Hashtable();
foreach(MethodWrapper mw in methodsList)
{
clash.Add(mw.Name + mw.Signature, null);
}
}
if(!clash.ContainsKey(name + sig))
{
clash.Add(name + sig, null);
methodsList.Add(CreateMethodWrapper(name, sig, map.InterfaceMethods[j], true));
}
2005-02-02 18:11:26 +03:00
}
2003-12-20 01:19:18 +03:00
}
}
}
2003-11-17 15:01:50 +03:00
}
2003-08-21 14:06:34 +04:00
}
2004-04-23 18:21:43 +04:00
2005-06-01 13:49:30 +04:00
// for non-final remapped types, we need to add all the virtual methods in our alter ego (which
// appears as our base class) and make them final (to prevent Java code from overriding these
// methods, which don't really exist).
if(ClassLoaderWrapper.IsRemappedType(type) && !type.IsSealed && !type.IsInterface)
2004-04-23 18:21:43 +04:00
{
2005-06-01 13:49:30 +04:00
// Finish the type, to make sure the methods are populated
this.BaseTypeWrapper.Finish();
Hashtable h = new Hashtable();
TypeWrapper baseTypeWrapper = this.BaseTypeWrapper;
while(baseTypeWrapper != null)
2004-04-23 18:21:43 +04:00
{
2005-06-01 13:49:30 +04:00
foreach(MethodWrapper m in baseTypeWrapper.GetMethods())
2004-04-23 18:21:43 +04:00
{
2005-06-01 13:49:30 +04:00
if(!m.IsStatic && !m.IsFinal && (m.IsPublic || m.IsProtected) && m.Name != "<init>")
2004-04-23 18:21:43 +04:00
{
2005-06-01 13:49:30 +04:00
if(!h.ContainsKey(m.Name + m.Signature))
{
h.Add(m.Name + m.Signature, "");
// TODO handle name/sig clash (what should we do?)
methodsList.Add(new BaseFinalMethodWrapper(this, m));
}
2004-04-23 18:21:43 +04:00
}
}
2005-06-01 13:49:30 +04:00
baseTypeWrapper = baseTypeWrapper.BaseTypeWrapper;
}
}
}
SetMethods((MethodWrapper[])methodsList.ToArray(typeof(MethodWrapper)));
SetFields((FieldWrapper[])fieldsList.ToArray(typeof(FieldWrapper)));
2004-08-17 13:05:21 +04:00
}
2005-06-01 13:49:30 +04:00
private class BaseFinalMethodWrapper : MethodWrapper
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
private MethodWrapper m;
2004-08-17 13:05:21 +04:00
2005-06-01 13:49:30 +04:00
internal BaseFinalMethodWrapper(DotNetTypeWrapper tw, MethodWrapper m)
: base(tw, m.Name, m.Signature, m.GetMethod(), m.ReturnType, m.GetParameters(), m.Modifiers | Modifiers.Final, MemberFlags.None)
{
this.m = m;
}
2004-08-17 13:05:21 +04:00
2005-06-01 13:49:30 +04:00
internal override void EmitCall(ILGenerator ilgen)
{
// we direct EmitCall to EmitCallvirt, because we always want to end up at the instancehelper method
// (EmitCall would go to our alter ego .NET type and that wouldn't be legal)
m.EmitCallvirt(ilgen);
}
2004-08-17 13:05:21 +04:00
2005-06-01 13:49:30 +04:00
internal override void EmitCallvirt(ILGenerator ilgen)
{
m.EmitCallvirt(ilgen);
}
[HideFromJava]
internal override object Invoke(object obj, object[] args, bool nonVirtual)
{
return m.Invoke(obj, args, nonVirtual);
}
2004-10-04 23:30:53 +04:00
}
2005-06-01 13:49:30 +04:00
private bool MakeMethodDescriptor(MethodBase mb, out string name, out string sig)
2003-08-21 14:06:34 +04:00
{
2005-06-01 13:49:30 +04:00
if(Whidbey.IsGenericMethodDefinition(mb))
2003-08-21 14:06:34 +04:00
{
2005-01-03 11:26:21 +03:00
name = null;
sig = null;
return false;
2003-08-21 14:06:34 +04:00
}
2005-06-01 13:49:30 +04:00
System.Text.StringBuilder sb = new System.Text.StringBuilder();
sb.Append('(');
ParameterInfo[] parameters = mb.GetParameters();
TypeWrapper[] args = new TypeWrapper[parameters.Length];
for(int i = 0; i < parameters.Length; i++)
2003-08-21 14:06:34 +04:00
{
2005-06-01 13:49:30 +04:00
Type type = parameters[i].ParameterType;
if(type.IsPointer)
2004-10-04 23:30:53 +04:00
{
2005-01-03 11:26:21 +03:00
name = null;
sig = null;
return false;
2004-10-04 23:30:53 +04:00
}
2005-06-01 13:49:30 +04:00
if(type.IsByRef)
2003-08-26 15:24:17 +04:00
{
2005-06-01 13:49:30 +04:00
if(type.GetElementType().IsPointer)
{
name = null;
sig = null;
return false;
}
type = type.Assembly.GetType(type.GetElementType().FullName + "[]", true);
if(mb.IsAbstract)
{
// Since we cannot override methods with byref arguments, we don't report abstract
// methods with byref args.
name = null;
sig = null;
return false;
}
2003-08-26 15:24:17 +04:00
}
2005-06-01 13:49:30 +04:00
TypeWrapper tw = ClassLoaderWrapper.GetWrapperFromType(type);
args[i] = tw;
sb.Append(tw.SigName);
2003-08-21 14:06:34 +04:00
}
2005-06-01 13:49:30 +04:00
sb.Append(')');
if(mb is ConstructorInfo)
2003-08-21 14:06:34 +04:00
{
2005-06-01 13:49:30 +04:00
TypeWrapper ret = PrimitiveTypeWrapper.VOID;
if(mb.IsStatic)
{
name = "<clinit>";
}
else
{
name = "<init>";
}
sb.Append(ret.SigName);
sig = sb.ToString();
return true;
2003-08-21 14:06:34 +04:00
}
else
{
2005-06-01 13:49:30 +04:00
Type type = ((MethodInfo)mb).ReturnType;
if(type.IsPointer || type.IsByRef)
{
name = null;
sig = null;
return false;
}
TypeWrapper ret = ClassLoaderWrapper.GetWrapperFromType(type);
sb.Append(ret.SigName);
name = mb.Name;
sig = sb.ToString();
return true;
2003-08-21 14:06:34 +04:00
}
}
2005-06-01 13:49:30 +04:00
internal override TypeWrapper[] Interfaces
2003-08-21 14:06:34 +04:00
{
2005-06-01 13:49:30 +04:00
get
2003-08-21 14:06:34 +04:00
{
2005-06-01 13:49:30 +04:00
lock(this)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
if(interfaces == null)
2004-08-17 13:05:21 +04:00
{
2005-06-01 13:49:30 +04:00
Type[] interfaceTypes = type.GetInterfaces();
interfaces = new TypeWrapper[interfaceTypes.Length];
for(int i = 0; i < interfaces.Length; i++)
2004-12-02 11:43:05 +03:00
{
2005-06-01 13:49:30 +04:00
if(interfaceTypes[i].DeclaringType != null &&
interfaceTypes[i].IsDefined(typeof(HideFromJavaAttribute), false) &&
interfaceTypes[i].Name == "__Interface")
{
// we have to return the declaring type for ghost interfaces
interfaces[i] = ClassLoaderWrapper.GetWrapperFromType(interfaceTypes[i].DeclaringType);
}
else
{
interfaces[i] = ClassLoaderWrapper.GetWrapperFromType(interfaceTypes[i]);
}
2004-12-02 11:43:05 +03:00
}
2004-08-17 13:05:21 +04:00
}
2005-06-01 13:49:30 +04:00
return interfaces;
2004-08-17 13:05:21 +04:00
}
2003-08-21 14:06:34 +04:00
}
}
2005-06-01 13:49:30 +04:00
private static bool IsDelegate(Type type)
2004-09-05 13:37:58 +04:00
{
2005-06-01 13:49:30 +04:00
// HACK non-public delegates do not get the special treatment (because they are likely to refer to
// non-public types in the arg list and they're not really useful anyway)
// NOTE we don't have to check in what assembly the type lives, because this is a DotNetTypeWrapper,
// we know that it is a different assembly.
if(!type.IsAbstract && type.IsSubclassOf(typeof(MulticastDelegate)) && IsVisible(type))
2005-02-11 17:46:58 +03:00
{
2005-06-01 13:49:30 +04:00
MethodInfo invoke = type.GetMethod("Invoke");
if(invoke != null)
2005-02-11 17:46:58 +03:00
{
2005-06-01 13:49:30 +04:00
foreach(ParameterInfo p in invoke.GetParameters())
2005-02-11 17:46:58 +03:00
{
2005-06-01 13:49:30 +04:00
// TODO at the moment we don't support delegates with pointer or byref parameters
if(p.ParameterType.IsPointer || p.ParameterType.IsByRef)
{
return false;
}
2005-02-11 17:46:58 +03:00
}
2005-06-01 13:49:30 +04:00
return true;
2005-02-11 17:46:58 +03:00
}
}
2005-06-01 13:49:30 +04:00
return false;
2004-09-05 13:37:58 +04:00
}
2005-06-01 13:49:30 +04:00
internal override TypeWrapper[] InnerClasses
2003-08-21 14:06:34 +04:00
{
2005-06-01 13:49:30 +04:00
get
2003-08-21 14:06:34 +04:00
{
2005-06-01 13:49:30 +04:00
lock(this)
2003-08-21 14:06:34 +04:00
{
2005-06-01 13:49:30 +04:00
if(innerClasses == null)
2003-08-21 14:06:34 +04:00
{
2005-06-01 13:49:30 +04:00
if(IsDelegate(type))
{
innerClasses = new TypeWrapper[] { ClassLoaderWrapper.GetBootstrapClassLoader().LoadClassByDottedName(Name + DelegateInterfaceSuffix) };
}
else
2004-09-05 13:37:58 +04:00
{
2005-06-01 13:49:30 +04:00
Type[] nestedTypes = type.GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic);
ArrayList list = new ArrayList(nestedTypes.Length);
for(int i = 0; i < nestedTypes.Length; i++)
2004-10-04 23:30:53 +04:00
{
2005-06-01 13:49:30 +04:00
if(!Whidbey.IsGenericTypeDefinition(nestedTypes[i]))
{
list.Add(ClassLoaderWrapper.GetWrapperFromType(nestedTypes[i]));
}
2004-10-04 23:30:53 +04:00
}
2005-06-01 13:49:30 +04:00
innerClasses = (TypeWrapper[])list.ToArray(typeof(TypeWrapper));
2004-09-05 13:37:58 +04:00
}
2003-08-21 14:06:34 +04:00
}
}
2005-06-01 13:49:30 +04:00
return innerClasses;
2003-08-21 14:06:34 +04:00
}
}
2005-06-01 13:49:30 +04:00
internal override TypeWrapper DeclaringTypeWrapper
2003-08-21 14:06:34 +04:00
{
2005-06-01 13:49:30 +04:00
get
2003-08-21 14:06:34 +04:00
{
2005-06-01 13:49:30 +04:00
if(outerClass == null)
2003-08-21 14:06:34 +04:00
{
2005-06-01 13:49:30 +04:00
Type outer = type.DeclaringType;
if(outer != null)
{
outerClass = ClassLoaderWrapper.GetWrapperFromType(outer);
}
2003-08-21 14:06:34 +04:00
}
2005-06-01 13:49:30 +04:00
return outerClass;
2003-08-21 14:06:34 +04:00
}
}
2005-06-01 13:49:30 +04:00
internal override Modifiers ReflectiveModifiers
2003-08-21 14:06:34 +04:00
{
2005-06-01 13:49:30 +04:00
get
2003-08-21 14:06:34 +04:00
{
2005-06-01 13:49:30 +04:00
if(DeclaringTypeWrapper != null)
{
return Modifiers | Modifiers.Static;
}
return Modifiers;
2003-08-21 14:06:34 +04:00
}
}
2005-06-01 13:49:30 +04:00
private FieldWrapper CreateFieldWrapperDotNet(Modifiers modifiers, string name, Type fieldType, FieldInfo field)
2003-08-21 14:06:34 +04:00
{
2005-06-01 13:49:30 +04:00
TypeWrapper type = ClassLoaderWrapper.GetWrapperFromType(fieldType);
if(field.IsLiteral)
{
return new ConstantFieldWrapper(this, type, name, type.SigName, modifiers, field, null);
}
else
{
return FieldWrapper.Create(this, type, field, name, type.SigName, modifiers);
}
2003-08-21 14:06:34 +04:00
}
2005-06-01 13:49:30 +04:00
private MethodWrapper CreateMethodWrapper(string name, string sig, MethodBase mb, bool privateInterfaceImplHack)
2003-08-21 14:06:34 +04:00
{
2005-06-01 13:49:30 +04:00
Modifiers mods = AttributeHelper.GetModifiers(mb, true);
if(name == "Finalize" && sig == "()V" && !mb.IsStatic &&
TypeAsBaseType.IsSubclassOf(CoreClasses.java.lang.Object.Wrapper.TypeAsBaseType))
2003-08-21 14:06:34 +04:00
{
2005-06-01 13:49:30 +04:00
// TODO if the .NET also has a "finalize" method, we need to hide that one (or rename it, or whatever)
MethodWrapper mw = new SimpleCallMethodWrapper(this, "finalize", "()V", (MethodInfo)mb, null, null, mods, MemberFlags.None, SimpleOpCode.Call, SimpleOpCode.Callvirt);
mw.SetDeclaredExceptions(new string[] { "java.lang.Throwable" });
return mw;
}
ParameterInfo[] parameters = mb.GetParameters();
Type[] args = new Type[parameters.Length];
bool hasByRefArgs = false;
bool[] byrefs = null;
for(int i = 0; i < parameters.Length; i++)
{
args[i] = parameters[i].ParameterType;
if(parameters[i].ParameterType.IsByRef)
2003-08-26 15:24:17 +04:00
{
2005-06-01 13:49:30 +04:00
if(byrefs == null)
{
byrefs = new bool[args.Length];
}
byrefs[i] = true;
hasByRefArgs = true;
2003-08-26 15:24:17 +04:00
}
2003-08-21 14:06:34 +04:00
}
2005-06-01 13:49:30 +04:00
if(privateInterfaceImplHack)
2003-08-21 14:06:34 +04:00
{
2005-06-01 13:49:30 +04:00
mods &= ~Modifiers.Abstract;
2004-08-17 13:05:21 +04:00
mods |= Modifiers.Final;
2003-08-21 14:06:34 +04:00
}
2005-06-01 13:49:30 +04:00
if(hasByRefArgs)
2003-08-21 14:06:34 +04:00
{
2005-06-01 13:49:30 +04:00
if(!(mb is ConstructorInfo) && !mb.IsStatic)
{
mods |= Modifiers.Final;
}
2004-08-17 13:05:21 +04:00
// TODO pass in the argument and return types
2005-06-01 13:49:30 +04:00
return new ByRefMethodWrapper(args, byrefs, this, name, sig, mb, null, null, mods, false);
2003-08-21 14:06:34 +04:00
}
2004-08-17 13:05:21 +04:00
else
2003-08-21 14:06:34 +04:00
{
2005-06-01 13:49:30 +04:00
if(mb is ConstructorInfo)
{
// TODO pass in the argument and return types
return new SmartConstructorMethodWrapper(this, name, sig, (ConstructorInfo)mb, null, mods, MemberFlags.None);
}
else
{
// TODO pass in the argument and return types
return new SmartCallMethodWrapper(this, name, sig, (MethodInfo)mb, null, null, mods, MemberFlags.None, SimpleOpCode.Call, SimpleOpCode.Callvirt);
}
2003-08-21 14:06:34 +04:00
}
}
2005-06-01 13:49:30 +04:00
internal override Type TypeAsTBD
2003-08-21 14:06:34 +04:00
{
2005-06-01 13:49:30 +04:00
get
{
return type;
}
2003-08-21 14:06:34 +04:00
}
2004-04-23 18:21:43 +04:00
2005-06-01 13:49:30 +04:00
internal override bool IsRemapped
2004-04-23 18:21:43 +04:00
{
2005-06-01 13:49:30 +04:00
get
{
return ClassLoaderWrapper.IsRemappedType(type);
}
2004-04-23 18:21:43 +04:00
}
2004-10-19 17:43:55 +04:00
2005-06-01 13:49:30 +04:00
internal override void EmitInstanceOf(TypeWrapper context, ILGenerator ilgen)
2004-10-19 17:43:55 +04:00
{
2005-06-01 13:49:30 +04:00
if(IsRemapped)
2004-10-19 17:43:55 +04:00
{
2005-06-01 13:49:30 +04:00
TypeWrapper shadow = ClassLoaderWrapper.GetWrapperFromTypeFast(type);
MethodInfo method = shadow.TypeAsBaseType.GetMethod("__<instanceof>");
if(method != null)
{
ilgen.Emit(OpCodes.Call, method);
return;
}
2004-10-19 17:43:55 +04:00
}
2005-06-01 13:49:30 +04:00
ilgen.Emit(OpCodes.Isinst, type);
ilgen.Emit(OpCodes.Ldnull);
ilgen.Emit(OpCodes.Cgt_Un);
2004-10-19 17:43:55 +04:00
}
2005-06-01 13:49:30 +04:00
internal override void EmitCheckcast(TypeWrapper context, ILGenerator ilgen)
2004-10-19 17:43:55 +04:00
{
2005-06-01 13:49:30 +04:00
if(IsRemapped)
2004-10-19 17:43:55 +04:00
{
2005-06-01 13:49:30 +04:00
TypeWrapper shadow = ClassLoaderWrapper.GetWrapperFromTypeFast(type);
MethodInfo method = shadow.TypeAsBaseType.GetMethod("__<checkcast>");
if(method != null)
{
ilgen.Emit(OpCodes.Call, method);
return;
}
2004-10-19 17:43:55 +04:00
}
2005-06-01 13:49:30 +04:00
EmitHelper.Castclass(ilgen, type);
2004-10-19 17:43:55 +04:00
}
2005-01-03 11:26:21 +03:00
2005-06-01 13:49:30 +04:00
internal override void Finish(bool forDebugSave)
2005-01-03 11:26:21 +03:00
{
2005-06-01 13:49:30 +04:00
// TODO instead of linking here, we should just pre-link in LazyPublishMembers
foreach(MethodWrapper mw in GetMethods())
{
mw.Link();
}
foreach(FieldWrapper fw in GetFields())
{
fw.Link();
}
2005-01-03 11:26:21 +03:00
}
}
2003-08-21 14:06:34 +04:00
2005-06-01 13:49:30 +04:00
sealed class ArrayTypeWrapper : TypeWrapper
2003-08-21 14:06:34 +04:00
{
2005-06-01 13:49:30 +04:00
private static TypeWrapper[] interfaces;
private static MethodInfo clone;
private Type type;
private Modifiers reflectiveModifiers;
2005-01-03 11:26:21 +03:00
2005-06-01 13:49:30 +04:00
internal ArrayTypeWrapper(Type type, Modifiers modifiers, Modifiers reflectiveModifiers, string name, ClassLoaderWrapper classLoader)
: base(modifiers, name, CoreClasses.java.lang.Object.Wrapper, classLoader, null)
2003-08-21 14:06:34 +04:00
{
2005-06-01 13:49:30 +04:00
this.type = type;
this.reflectiveModifiers = reflectiveModifiers;
2003-08-21 14:06:34 +04:00
}
2004-08-17 13:05:21 +04:00
2005-06-01 13:49:30 +04:00
protected override void LazyPublishMembers()
2004-12-22 11:04:10 +03:00
{
2005-06-01 13:49:30 +04:00
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);
mw.Link();
SetMethods(new MethodWrapper[] { mw });
SetFields(FieldWrapper.EmptyArray);
2004-12-22 11:04:10 +03:00
}
2005-06-01 13:49:30 +04:00
internal override Modifiers ReflectiveModifiers
2003-08-21 14:06:34 +04:00
{
2005-06-01 13:49:30 +04:00
get
{
return reflectiveModifiers;
}
2003-08-21 14:06:34 +04:00
}
2005-06-01 13:49:30 +04:00
internal override Assembly Assembly
2003-08-21 14:06:34 +04:00
{
2005-06-01 13:49:30 +04:00
get
{
return type.Assembly;
}
2003-02-22 15:28:12 +03:00
}
2005-06-01 13:49:30 +04:00
internal override string SigName
2003-02-22 15:28:12 +03:00
{
2005-06-01 13:49:30 +04:00
get
2003-02-22 15:28:12 +03:00
{
2005-06-01 13:49:30 +04:00
// for arrays the signature name is the same as the normal name
return Name;
2003-02-22 15:28:12 +03:00
}
}
2005-06-01 13:49:30 +04:00
internal override TypeWrapper[] Interfaces
{
get
{
if(interfaces == null)
{
TypeWrapper[] tw = new TypeWrapper[2];
tw[0] = ClassLoaderWrapper.LoadClassCritical("java.lang.Cloneable");
tw[1] = ClassLoaderWrapper.LoadClassCritical("java.io.Serializable");
interfaces = tw;
}
return interfaces;
}
}
internal override TypeWrapper[] InnerClasses
2003-02-22 15:28:12 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return TypeWrapper.EmptyArray;
}
2003-02-22 15:28:12 +03:00
}
2005-06-01 13:49:30 +04:00
internal override TypeWrapper DeclaringTypeWrapper
2003-02-22 15:28:12 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return null;
}
2003-02-22 15:28:12 +03:00
}
2005-06-01 13:49:30 +04:00
internal override Type TypeAsTBD
2003-02-22 15:28:12 +03:00
{
2005-06-01 13:49:30 +04:00
get
{
return type;
}
2003-02-22 15:28:12 +03:00
}
2005-06-01 13:49:30 +04:00
private bool IsFinished
2003-02-22 15:28:12 +03:00
{
2005-06-01 13:49:30 +04:00
get
2003-02-22 15:28:12 +03:00
{
2005-06-01 13:49:30 +04:00
Type elem = type.GetElementType();
while(elem.IsArray)
{
elem = elem.GetElementType();
}
return !(elem is TypeBuilder);
2003-02-22 15:28:12 +03:00
}
}
2005-06-01 13:49:30 +04:00
internal override void Finish(bool forDebugSave)
2003-02-22 15:28:12 +03:00
{
2005-06-01 13:49:30 +04:00
lock(this)
2003-02-22 15:28:12 +03:00
{
2005-06-01 13:49:30 +04:00
// TODO optimize this
if(!IsFinished)
{
TypeWrapper elementTypeWrapper = ElementTypeWrapper;
Type elementType = elementTypeWrapper.TypeAsArrayType;
elementTypeWrapper.Finish();
type = elementType.Assembly.GetType(elementType.FullName + "[]", true);
ClassLoaderWrapper.SetWrapperForType(type, this);
}
2003-02-22 15:28:12 +03:00
}
}
}
}