From 6dce5cc4475cdf58efc005eeead299ea03cf36be Mon Sep 17 00:00:00 2001 From: jfrijters Date: Thu, 24 Nov 2011 09:08:04 +0000 Subject: [PATCH] Instead of mangling field names and using NameSigAttribute, we now use modopt to modify the signature and record the real type. --- runtime/DynamicClassLoader.cs | 73 ++-------------- runtime/DynamicTypeWrapper.cs | 93 +++++++++++++------- runtime/TypeWrapper.cs | 157 ++++++++++++++++++++++++++++++---- 3 files changed, 208 insertions(+), 115 deletions(-) diff --git a/runtime/DynamicClassLoader.cs b/runtime/DynamicClassLoader.cs index 22c46ce4..1b4837b0 100644 --- a/runtime/DynamicClassLoader.cs +++ b/runtime/DynamicClassLoader.cs @@ -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 saveDebugAssemblies; private static List 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(); } - 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 "__+" + 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 "__+" + TypeNameUtil.MangleNestedTypeName(type.FullName); } internal override Type DefineUnloadable(string name) @@ -359,7 +296,7 @@ namespace IKVM.Internal unloadableContainer = moduleBuilder.DefineType("__", 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; } diff --git a/runtime/DynamicTypeWrapper.cs b/runtime/DynamicTypeWrapper.cs index 1de63ccf..545047f8 100644 --- a/runtime/DynamicTypeWrapper.cs +++ b/runtime/DynamicTypeWrapper.cs @@ -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("__", MethodAttributes.PrivateScope, CallingConventions.Standard, Types.Void, new Type[] { type }); + MethodBuilder setter = typeBuilder.DefineMethod("__", 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) diff --git a/runtime/TypeWrapper.cs b/runtime/TypeWrapper.cs index bcee128f..f9ce5b62 100644 --- a/runtime/TypeWrapper.cs +++ b/runtime/TypeWrapper.cs @@ -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