Instead of mangling field names and using NameSigAttribute, we now use modopt to modify the signature and record the real type.

This commit is contained in:
jfrijters 2011-11-24 09:08:04 +00:00
Родитель 917376e242
Коммит 6dce5cc447
3 изменённых файлов: 208 добавлений и 115 удалений

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

@ -37,9 +37,6 @@ namespace IKVM.Internal
{
sealed class DynamicClassLoader : TypeWrapperFactory
{
// note that MangleNestedTypeName() assumes that there are less than 16 special characters
private static readonly char[] specialCharacters = { '\\', '+', ',', '[', ']', '*', '&', '\u0000' };
private static readonly string specialCharactersString = new String(specialCharacters);
#if !STATIC_COMPILER
private static List<AssemblyBuilder> saveDebugAssemblies;
private static List<DynamicClassLoader> saveClassLoaders;
@ -137,36 +134,6 @@ namespace IKVM.Internal
}
#endif // !STATIC_COMPILER
internal static string EscapeName(string name)
{
// TODO the escaping of special characters is not required on .NET 2.0
// (but it doesn't really hurt that much either, the only overhead is the
// extra InnerClassAttribute to record the real name of the class)
// Note that even though .NET 2.0 automatically escapes the special characters,
// the name that gets passed in ResolveEventArgs.Name of the TypeResolve event
// contains the unescaped type name.
if(name.IndexOfAny(specialCharacters) >= 0)
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
foreach(char c in name)
{
if(specialCharactersString.IndexOf(c) >= 0)
{
if(c == 0)
{
// we can't escape the NUL character, so we replace it with a space.
sb.Append(' ');
continue;
}
sb.Append('\\');
}
sb.Append(c);
}
name = sb.ToString();
}
return name;
}
internal override bool ReserveName(string name)
{
lock(dynamicTypes)
@ -184,7 +151,7 @@ namespace IKVM.Internal
{
lock(dynamicTypes)
{
mangledTypeName = EscapeName(mangledTypeName);
mangledTypeName = TypeNameUtil.EscapeName(mangledTypeName);
// FXBUG the CLR (both 1.1 and 2.0) doesn't like type names that end with a single period,
// it loses the trailing period in the name that gets passed in the TypeResolve event.
if(dynamicTypes.ContainsKey(mangledTypeName) || mangledTypeName.EndsWith("."))
@ -268,7 +235,7 @@ namespace IKVM.Internal
AttributeHelper.SetEditorBrowsableNever(proxyHelperContainer);
proxyHelpers = new List<TypeBuilder>();
}
proxyHelpers.Add(proxyHelperContainer.DefineNestedType(MangleNestedTypeName(type.FullName), TypeAttributes.NestedPublic | TypeAttributes.Interface | TypeAttributes.Abstract, null, new Type[] { type }));
proxyHelpers.Add(proxyHelperContainer.DefineNestedType(TypeNameUtil.MangleNestedTypeName(type.FullName), TypeAttributes.NestedPublic | TypeAttributes.Interface | TypeAttributes.Abstract, null, new Type[] { type }));
}
internal TypeBuilder DefineProxy(TypeWrapper proxyClass, TypeWrapper[] interfaces)
@ -298,7 +265,7 @@ namespace IKVM.Internal
{
sb.Append(tw.Name.Length).Append('|').Append(tw.Name);
}
return MangleNestedTypeName(sb.ToString());
return TypeNameUtil.MangleNestedTypeName(sb.ToString());
}
internal static string GetProxyName(TypeWrapper[] interfaces)
@ -308,37 +275,7 @@ namespace IKVM.Internal
internal static string GetProxyHelperName(Type type)
{
return "__<Proxy>+" + MangleNestedTypeName(type.FullName);
}
private static string MangleNestedTypeName(string name)
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
foreach (char c in name)
{
int index = specialCharactersString.IndexOf(c);
if(c == '.')
{
sb.Append("_");
}
else if(c == '_')
{
sb.Append("^-");
}
else if(index == -1)
{
sb.Append(c);
if(c == '^')
{
sb.Append(c);
}
}
else
{
sb.Append('^').AppendFormat("{0:X1}", index);
}
}
return sb.ToString();
return "__<Proxy>+" + TypeNameUtil.MangleNestedTypeName(type.FullName);
}
internal override Type DefineUnloadable(string name)
@ -359,7 +296,7 @@ namespace IKVM.Internal
unloadableContainer = moduleBuilder.DefineType("__<Unloadable>", TypeAttributes.Interface | TypeAttributes.Abstract);
AttributeHelper.HideFromJava(unloadableContainer);
}
type = unloadableContainer.DefineNestedType(MangleNestedTypeName(name), TypeAttributes.NestedPrivate | TypeAttributes.Interface | TypeAttributes.Abstract);
type = unloadableContainer.DefineNestedType(TypeNameUtil.MangleNestedTypeName(name), TypeAttributes.NestedPrivate | TypeAttributes.Interface | TypeAttributes.Abstract);
unloadables.Add(name, type);
return type;
}

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

@ -1138,7 +1138,7 @@ namespace IKVM.Internal
private static string GetInnerClassName(string outer, string inner)
{
Debug.Assert(CheckInnerOuterNames(inner, outer));
return DynamicClassLoader.EscapeName(inner.Substring(outer.Length + 1));
return TypeNameUtil.EscapeName(inner.Substring(outer.Length + 1));
}
#endif // STATIC_COMPILER
@ -1279,24 +1279,12 @@ namespace IKVM.Internal
{
fieldAttribs |= FieldAttributes.InitOnly;
}
return typeBuilder.DefineField(fw.Name, fw.FieldTypeWrapper.TypeAsSignatureType, fieldAttribs);
return DefineField(fw.Name, fw.FieldTypeWrapper, fieldAttribs, fw.IsVolatile);
}
#endif // STATIC_COMPILER
FieldBuilder field;
ClassFile.Field fld = classFile.Fields[fieldIndex];
string fieldName = fld.Name;
TypeWrapper typeWrapper = fw.FieldTypeWrapper;
Type type = typeWrapper.TypeAsSignatureType;
bool setNameSig = typeWrapper.IsErasedOrBoxedPrimitiveOrRemapped;
if (setNameSig)
{
// 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;
}
string realFieldName = fieldName;
string realFieldName = fld.Name;
FieldAttributes attribs = 0;
MethodAttributes methodAttribs = MethodAttributes.HideBySig;
#if STATIC_COMPILER
@ -1336,7 +1324,7 @@ namespace IKVM.Internal
{
Profiler.Count("Static Final Constant");
attribs |= FieldAttributes.Literal;
field = typeBuilder.DefineField(fieldName, type, attribs);
field = DefineField(fld.Name, fw.FieldTypeWrapper, attribs, false);
field.SetConstant(constantValue);
}
else
@ -1378,16 +1366,11 @@ namespace IKVM.Internal
// see https://sourceforge.net/tracker/?func=detail&atid=525264&aid=3056721&group_id=69637
// additional note: now that we maintain the ordering of the fields, we need to recognize
// these fields so that we know where to insert the corresponding accessor property FieldWrapper.
realFieldName = NamePrefix.Type2AccessStubBackingField + fieldName;
realFieldName = NamePrefix.Type2AccessStubBackingField + fld.Name;
}
#endif
Type[] modreq = Type.EmptyTypes;
if (fld.IsVolatile)
{
modreq = new Type[] { Types.IsVolatile };
}
field = typeBuilder.DefineField(realFieldName, type, modreq, Type.EmptyTypes, attribs);
field = DefineField(realFieldName, fw.FieldTypeWrapper, attribs, fld.IsVolatile);
if (fld.IsTransient)
{
CustomAttributeBuilder transientAttrib = new CustomAttributeBuilder(JVM.Import(typeof(NonSerializedAttribute)).GetConstructor(Type.EmptyTypes), new object[0]);
@ -1396,7 +1379,7 @@ namespace IKVM.Internal
if (isWrappedFinal)
{
methodAttribs |= MethodAttributes.SpecialName;
MethodBuilder getter = typeBuilder.DefineMethod(GenerateUniqueMethodName("get_" + fieldName, type, Type.EmptyTypes), methodAttribs, CallingConventions.Standard, type, Type.EmptyTypes);
MethodBuilder getter = typeBuilder.DefineMethod(GenerateUniqueMethodName("get_" + fld.Name, fw.FieldTypeWrapper.TypeAsSignatureType, Type.EmptyTypes), methodAttribs, CallingConventions.Standard, fw.FieldTypeWrapper.TypeAsSignatureType, Type.EmptyTypes);
AttributeHelper.HideFromJava(getter);
CodeEmitter ilgen = CodeEmitter.Create(getter);
if (fld.IsStatic)
@ -1411,13 +1394,13 @@ namespace IKVM.Internal
ilgen.Emit(OpCodes.Ret);
ilgen.DoEmit();
PropertyBuilder pb = typeBuilder.DefineProperty(fieldName, PropertyAttributes.None, type, Type.EmptyTypes);
PropertyBuilder pb = typeBuilder.DefineProperty(fld.Name, PropertyAttributes.None, fw.FieldTypeWrapper.TypeAsSignatureType, Type.EmptyTypes);
pb.SetGetMethod(getter);
if (!fld.IsStatic)
{
// this method exist for use by reflection only
// (that's why it only exists for instance fields, final static fields are not settable by reflection)
MethodBuilder setter = typeBuilder.DefineMethod("__<set>", MethodAttributes.PrivateScope, CallingConventions.Standard, Types.Void, new Type[] { type });
MethodBuilder setter = typeBuilder.DefineMethod("__<set>", MethodAttributes.PrivateScope, CallingConventions.Standard, Types.Void, new Type[] { fw.FieldTypeWrapper.TypeAsSignatureType });
ilgen = CodeEmitter.Create(setter);
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Ldarg_1);
@ -1428,7 +1411,7 @@ namespace IKVM.Internal
}
((GetterFieldWrapper)fw).SetGetter(getter);
#if STATIC_COMPILER
if (setNameSig)
if (fw.FieldTypeWrapper.IsErasedOrBoxedPrimitiveOrRemapped)
{
AttributeHelper.SetNameSig(getter, fld.Name, fld.Signature);
}
@ -1457,10 +1440,6 @@ namespace IKVM.Internal
{
AttributeHelper.SetModifiers(field, fld.Modifiers, fld.IsInternal);
}
if (setNameSig)
{
AttributeHelper.SetNameSig(field, fld.Name, fld.Signature);
}
if (fld.DeprecatedAttribute)
{
AttributeHelper.SetDeprecatedAttribute(field);
@ -1474,6 +1453,58 @@ namespace IKVM.Internal
return field;
}
private FieldBuilder DefineField(string name, TypeWrapper tw, FieldAttributes attribs, bool isVolatile)
{
Type[] modreq = isVolatile ? new Type[] { Types.IsVolatile } : Type.EmptyTypes;
return typeBuilder.DefineField(name, tw.TypeAsSignatureType, modreq, GetModOpt(tw), attribs);
}
private Type[] GetModOpt(TypeWrapper tw)
{
Type[] modopt = Type.EmptyTypes;
if (tw.IsUnloadable)
{
modopt = new Type[] { wrapper.GetClassLoader().GetTypeWrapperFactory().DefineUnloadable(tw.Name) };
}
else
{
TypeWrapper tw1 = tw.IsArray ? tw.GetUltimateElementTypeWrapper() : tw;
if (tw1.IsErasedOrBoxedPrimitiveOrRemapped)
{
#if STATIC_COMPILER
modopt = new Type[] { GetModOptHelper(tw) };
#else
// FXBUG Ref.Emit refuses arrays in custom modifiers, so we add an array type for each dimension
// (note that in this case we only add the custom modifiers to make the signature unique, we never read back this information)
modopt = new Type[tw.ArrayRank + 1];
modopt[0] = GetModOptHelper(tw1);
for (int i = 1; i < modopt.Length; i++)
{
modopt[i] = typeof(Array);
}
#endif
}
}
return modopt;
}
private Type GetModOptHelper(TypeWrapper tw)
{
Debug.Assert(!tw.IsUnloadable);
if (tw.IsArray)
{
return ArrayTypeWrapper.MakeArrayType(GetModOptHelper(tw.GetUltimateElementTypeWrapper()), tw.ArrayRank);
}
else if (tw.IsGhost)
{
return tw.TypeAsTBD;
}
else
{
return tw.TypeAsBaseType;
}
}
internal override void EmitRunClassConstructor(CodeEmitter ilgen)
{
if (clinitMethod != null)

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

@ -812,12 +812,6 @@ namespace IKVM.Internal
}
}
internal static void SetNameSig(FieldBuilder fb, string name, string sig)
{
CustomAttributeBuilder customAttributeBuilder = new CustomAttributeBuilder(typeofNameSigAttribute.GetConstructor(new Type[] { Types.String, Types.String }), new object[] { name, sig });
fb.SetCustomAttribute(customAttributeBuilder);
}
internal static void SetNameSig(PropertyBuilder pb, string name, string sig)
{
CustomAttributeBuilder customAttributeBuilder = new CustomAttributeBuilder(typeofNameSigAttribute.GetConstructor(new Type[] { Types.String, Types.String }), new object[] { name, sig });
@ -1363,6 +1357,108 @@ namespace IKVM.Internal
}
}
static class TypeNameUtil
{
// note that MangleNestedTypeName() assumes that there are less than 16 special characters
private static readonly char[] specialCharacters = { '\\', '+', ',', '[', ']', '*', '&', '\u0000' };
private static readonly string specialCharactersString = new String(specialCharacters);
internal static string EscapeName(string name)
{
// TODO the escaping of special characters is not required on .NET 2.0
// (but it doesn't really hurt that much either, the only overhead is the
// extra InnerClassAttribute to record the real name of the class)
// Note that even though .NET 2.0 automatically escapes the special characters,
// the name that gets passed in ResolveEventArgs.Name of the TypeResolve event
// contains the unescaped type name.
if (name.IndexOfAny(specialCharacters) >= 0)
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
foreach (char c in name)
{
if (specialCharactersString.IndexOf(c) >= 0)
{
if (c == 0)
{
// we can't escape the NUL character, so we replace it with a space.
sb.Append(' ');
continue;
}
sb.Append('\\');
}
sb.Append(c);
}
name = sb.ToString();
}
return name;
}
internal static string MangleNestedTypeName(string name)
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
foreach (char c in name)
{
int index = specialCharactersString.IndexOf(c);
if (c == '.')
{
sb.Append("_");
}
else if (c == '_')
{
sb.Append("^-");
}
else if (index == -1)
{
sb.Append(c);
if (c == '^')
{
sb.Append(c);
}
}
else
{
sb.Append('^').AppendFormat("{0:X1}", index);
}
}
return sb.ToString();
}
internal static string UnmangleNestedTypeName(string name)
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
for (int i = 0; i < name.Length; i++)
{
char c = name[i];
int index = specialCharactersString.IndexOf(c);
if (c == '_')
{
sb.Append('.');
}
else if (c == '^')
{
c = name[++i];
if (c == '-')
{
sb.Append('_');
}
else if (c == '^')
{
sb.Append('^');
}
else
{
sb.Append(specialCharactersString[c - '0']);
}
}
else
{
sb.Append(c);
}
}
return sb.ToString();
}
}
abstract class Annotation
{
// NOTE this method returns null if the type could not be found
@ -2129,6 +2225,11 @@ namespace IKVM.Internal
}
}
internal virtual TypeWrapper GetUltimateElementTypeWrapper()
{
throw new InvalidOperationException();
}
internal bool IsNonPrimitiveValueType
{
get
@ -4272,17 +4373,36 @@ namespace IKVM.Internal
return new GetterFieldWrapper(this, type, null, name, type.SigName, modifiers, getter, prop);
}
private static TypeWrapper TypeWrapperFromModOpt(Type modopt)
{
int rank = 0;
while (ReflectUtil.IsVector(modopt))
{
rank++;
modopt = modopt.GetElementType();
}
if (rank != 0)
{
return TypeWrapperFromModOpt(modopt).MakeArrayType(rank);
}
else if (modopt == Types.Void || modopt.IsPrimitive || ClassLoaderWrapper.IsRemappedType(modopt))
{
return DotNetTypeWrapper.GetWrapperFromDotNetType(modopt);
}
else
{
return ClassLoaderWrapper.GetWrapperFromType(modopt)
?? new UnloadableTypeWrapper(TypeNameUtil.UnmangleNestedTypeName(modopt.Name));
}
}
private FieldWrapper CreateFieldWrapper(FieldInfo field)
{
ExModifiers modifiers = AttributeHelper.GetModifiers(field, false);
string name = field.Name;
TypeWrapper type = ClassLoaderWrapper.GetWrapperFromType(field.FieldType);
NameSigAttribute attr = AttributeHelper.GetNameSig(field);
if(attr != null)
{
name = attr.Name;
SigTypePatchUp(attr.Sig, ref type);
}
Type[] modopt = field.GetOptionalCustomModifiers();
TypeWrapper type = modopt.Length == 0
? ClassLoaderWrapper.GetWrapperFromType(field.FieldType)
: TypeWrapperFromModOpt(modopt[0]);
if(field.IsLiteral)
{
@ -4295,11 +4415,11 @@ namespace IKVM.Internal
{
flags |= MemberFlags.InternalAccess;
}
return new ConstantFieldWrapper(this, type, name, type.SigName, modifiers.Modifiers, field, null, flags);
return new ConstantFieldWrapper(this, type, field.Name, type.SigName, modifiers.Modifiers, field, null, flags);
}
else
{
return FieldWrapper.Create(this, type, field, name, type.SigName, modifiers);
return FieldWrapper.Create(this, type, field, field.Name, type.SigName, modifiers);
}
}
@ -4735,6 +4855,11 @@ namespace IKVM.Internal
get { return ultimateElementTypeWrapper.IsFastClassLiteralSafe || ultimateElementTypeWrapper.IsPrimitive; }
}
internal override TypeWrapper GetUltimateElementTypeWrapper()
{
return ultimateElementTypeWrapper;
}
internal static Type MakeArrayType(Type type, int dims)
{
// NOTE this is not just an optimization, but it is also required to