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 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 #if !STATIC_COMPILER
private static List<AssemblyBuilder> saveDebugAssemblies; private static List<AssemblyBuilder> saveDebugAssemblies;
private static List<DynamicClassLoader> saveClassLoaders; private static List<DynamicClassLoader> saveClassLoaders;
@ -137,36 +134,6 @@ namespace IKVM.Internal
} }
#endif // !STATIC_COMPILER #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) internal override bool ReserveName(string name)
{ {
lock(dynamicTypes) lock(dynamicTypes)
@ -184,7 +151,7 @@ namespace IKVM.Internal
{ {
lock(dynamicTypes) 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, // 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. // it loses the trailing period in the name that gets passed in the TypeResolve event.
if(dynamicTypes.ContainsKey(mangledTypeName) || mangledTypeName.EndsWith(".")) if(dynamicTypes.ContainsKey(mangledTypeName) || mangledTypeName.EndsWith("."))
@ -268,7 +235,7 @@ namespace IKVM.Internal
AttributeHelper.SetEditorBrowsableNever(proxyHelperContainer); AttributeHelper.SetEditorBrowsableNever(proxyHelperContainer);
proxyHelpers = new List<TypeBuilder>(); 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) internal TypeBuilder DefineProxy(TypeWrapper proxyClass, TypeWrapper[] interfaces)
@ -298,7 +265,7 @@ namespace IKVM.Internal
{ {
sb.Append(tw.Name.Length).Append('|').Append(tw.Name); sb.Append(tw.Name.Length).Append('|').Append(tw.Name);
} }
return MangleNestedTypeName(sb.ToString()); return TypeNameUtil.MangleNestedTypeName(sb.ToString());
} }
internal static string GetProxyName(TypeWrapper[] interfaces) internal static string GetProxyName(TypeWrapper[] interfaces)
@ -308,37 +275,7 @@ namespace IKVM.Internal
internal static string GetProxyHelperName(Type type) internal static string GetProxyHelperName(Type type)
{ {
return "__<Proxy>+" + MangleNestedTypeName(type.FullName); return "__<Proxy>+" + TypeNameUtil.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();
} }
internal override Type DefineUnloadable(string name) internal override Type DefineUnloadable(string name)
@ -359,7 +296,7 @@ namespace IKVM.Internal
unloadableContainer = moduleBuilder.DefineType("__<Unloadable>", TypeAttributes.Interface | TypeAttributes.Abstract); unloadableContainer = moduleBuilder.DefineType("__<Unloadable>", TypeAttributes.Interface | TypeAttributes.Abstract);
AttributeHelper.HideFromJava(unloadableContainer); 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); unloadables.Add(name, type);
return type; return type;
} }

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

@ -1138,7 +1138,7 @@ namespace IKVM.Internal
private static string GetInnerClassName(string outer, string inner) private static string GetInnerClassName(string outer, string inner)
{ {
Debug.Assert(CheckInnerOuterNames(inner, outer)); Debug.Assert(CheckInnerOuterNames(inner, outer));
return DynamicClassLoader.EscapeName(inner.Substring(outer.Length + 1)); return TypeNameUtil.EscapeName(inner.Substring(outer.Length + 1));
} }
#endif // STATIC_COMPILER #endif // STATIC_COMPILER
@ -1279,24 +1279,12 @@ namespace IKVM.Internal
{ {
fieldAttribs |= FieldAttributes.InitOnly; fieldAttribs |= FieldAttributes.InitOnly;
} }
return typeBuilder.DefineField(fw.Name, fw.FieldTypeWrapper.TypeAsSignatureType, fieldAttribs); return DefineField(fw.Name, fw.FieldTypeWrapper, fieldAttribs, fw.IsVolatile);
} }
#endif // STATIC_COMPILER #endif // STATIC_COMPILER
FieldBuilder field; FieldBuilder field;
ClassFile.Field fld = classFile.Fields[fieldIndex]; ClassFile.Field fld = classFile.Fields[fieldIndex];
string fieldName = fld.Name; string realFieldName = 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;
FieldAttributes attribs = 0; FieldAttributes attribs = 0;
MethodAttributes methodAttribs = MethodAttributes.HideBySig; MethodAttributes methodAttribs = MethodAttributes.HideBySig;
#if STATIC_COMPILER #if STATIC_COMPILER
@ -1336,7 +1324,7 @@ namespace IKVM.Internal
{ {
Profiler.Count("Static Final Constant"); Profiler.Count("Static Final Constant");
attribs |= FieldAttributes.Literal; attribs |= FieldAttributes.Literal;
field = typeBuilder.DefineField(fieldName, type, attribs); field = DefineField(fld.Name, fw.FieldTypeWrapper, attribs, false);
field.SetConstant(constantValue); field.SetConstant(constantValue);
} }
else else
@ -1378,16 +1366,11 @@ namespace IKVM.Internal
// see https://sourceforge.net/tracker/?func=detail&atid=525264&aid=3056721&group_id=69637 // 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 // 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. // these fields so that we know where to insert the corresponding accessor property FieldWrapper.
realFieldName = NamePrefix.Type2AccessStubBackingField + fieldName; realFieldName = NamePrefix.Type2AccessStubBackingField + fld.Name;
} }
#endif #endif
Type[] modreq = Type.EmptyTypes; field = DefineField(realFieldName, fw.FieldTypeWrapper, attribs, fld.IsVolatile);
if (fld.IsVolatile)
{
modreq = new Type[] { Types.IsVolatile };
}
field = typeBuilder.DefineField(realFieldName, type, modreq, Type.EmptyTypes, attribs);
if (fld.IsTransient) if (fld.IsTransient)
{ {
CustomAttributeBuilder transientAttrib = new CustomAttributeBuilder(JVM.Import(typeof(NonSerializedAttribute)).GetConstructor(Type.EmptyTypes), new object[0]); CustomAttributeBuilder transientAttrib = new CustomAttributeBuilder(JVM.Import(typeof(NonSerializedAttribute)).GetConstructor(Type.EmptyTypes), new object[0]);
@ -1396,7 +1379,7 @@ namespace IKVM.Internal
if (isWrappedFinal) if (isWrappedFinal)
{ {
methodAttribs |= MethodAttributes.SpecialName; 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); AttributeHelper.HideFromJava(getter);
CodeEmitter ilgen = CodeEmitter.Create(getter); CodeEmitter ilgen = CodeEmitter.Create(getter);
if (fld.IsStatic) if (fld.IsStatic)
@ -1411,13 +1394,13 @@ namespace IKVM.Internal
ilgen.Emit(OpCodes.Ret); ilgen.Emit(OpCodes.Ret);
ilgen.DoEmit(); 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); pb.SetGetMethod(getter);
if (!fld.IsStatic) if (!fld.IsStatic)
{ {
// this method exist for use by reflection only // 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) // (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 = CodeEmitter.Create(setter);
ilgen.Emit(OpCodes.Ldarg_0); ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Ldarg_1); ilgen.Emit(OpCodes.Ldarg_1);
@ -1428,7 +1411,7 @@ namespace IKVM.Internal
} }
((GetterFieldWrapper)fw).SetGetter(getter); ((GetterFieldWrapper)fw).SetGetter(getter);
#if STATIC_COMPILER #if STATIC_COMPILER
if (setNameSig) if (fw.FieldTypeWrapper.IsErasedOrBoxedPrimitiveOrRemapped)
{ {
AttributeHelper.SetNameSig(getter, fld.Name, fld.Signature); AttributeHelper.SetNameSig(getter, fld.Name, fld.Signature);
} }
@ -1457,10 +1440,6 @@ namespace IKVM.Internal
{ {
AttributeHelper.SetModifiers(field, fld.Modifiers, fld.IsInternal); AttributeHelper.SetModifiers(field, fld.Modifiers, fld.IsInternal);
} }
if (setNameSig)
{
AttributeHelper.SetNameSig(field, fld.Name, fld.Signature);
}
if (fld.DeprecatedAttribute) if (fld.DeprecatedAttribute)
{ {
AttributeHelper.SetDeprecatedAttribute(field); AttributeHelper.SetDeprecatedAttribute(field);
@ -1474,6 +1453,58 @@ namespace IKVM.Internal
return field; 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) internal override void EmitRunClassConstructor(CodeEmitter ilgen)
{ {
if (clinitMethod != null) 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) 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 }); 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 abstract class Annotation
{ {
// NOTE this method returns null if the type could not be found // 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 internal bool IsNonPrimitiveValueType
{ {
get get
@ -4272,17 +4373,36 @@ namespace IKVM.Internal
return new GetterFieldWrapper(this, type, null, name, type.SigName, modifiers, getter, prop); 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) private FieldWrapper CreateFieldWrapper(FieldInfo field)
{ {
ExModifiers modifiers = AttributeHelper.GetModifiers(field, false); ExModifiers modifiers = AttributeHelper.GetModifiers(field, false);
string name = field.Name; Type[] modopt = field.GetOptionalCustomModifiers();
TypeWrapper type = ClassLoaderWrapper.GetWrapperFromType(field.FieldType); TypeWrapper type = modopt.Length == 0
NameSigAttribute attr = AttributeHelper.GetNameSig(field); ? ClassLoaderWrapper.GetWrapperFromType(field.FieldType)
if(attr != null) : TypeWrapperFromModOpt(modopt[0]);
{
name = attr.Name;
SigTypePatchUp(attr.Sig, ref type);
}
if(field.IsLiteral) if(field.IsLiteral)
{ {
@ -4295,11 +4415,11 @@ namespace IKVM.Internal
{ {
flags |= MemberFlags.InternalAccess; 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 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; } get { return ultimateElementTypeWrapper.IsFastClassLiteralSafe || ultimateElementTypeWrapper.IsPrimitive; }
} }
internal override TypeWrapper GetUltimateElementTypeWrapper()
{
return ultimateElementTypeWrapper;
}
internal static Type MakeArrayType(Type type, int dims) internal static Type MakeArrayType(Type type, int dims)
{ {
// NOTE this is not just an optimization, but it is also required to // NOTE this is not just an optimization, but it is also required to