diff --git a/reflect/Assembly.cs b/reflect/Assembly.cs index 3bb527ec..9ba213e6 100644 --- a/reflect/Assembly.cs +++ b/reflect/Assembly.cs @@ -50,15 +50,29 @@ namespace IKVM.Reflection public abstract ManifestResourceInfo GetManifestResourceInfo(string resourceName); public abstract System.IO.Stream GetManifestResourceStream(string resourceName); - internal abstract Type GetTypeImpl(string typeName); - - // The differences between ResolveType and GetTypeImpl are: - // - ResolveType is only used when a type is assumed to exist (because another module's metadata claim it) - // - ResolveType takes the unescaped namespace and name parts as they exist in the metadata - // - ResolveType is overridden in MissingAssembly to return a MissingType - internal virtual Type ResolveType(string ns, string name) + internal Type GetTypeImpl(string typeName) { - return GetTypeImpl(TypeNameParser.Escape(ns == null ? name : ns + "." + name)); + Type type = FindType(TypeName.Split(TypeNameParser.Unescape(typeName))); + if (type == null && __IsMissing) + { + throw new MissingAssemblyException((MissingAssembly)this); + } + return type; + } + + internal abstract Type FindType(TypeName name); + + // The differences between ResolveType and FindType are: + // - ResolveType is only used when a type is assumed to exist (because another module's metadata claims it) + // - ResolveType can return a MissingType + internal Type ResolveType(TypeName typeName) + { + return FindType(typeName) ?? GetMissingType(typeName); + } + + internal virtual Type GetMissingType(TypeName name) + { + return null; } public Module[] GetModules() diff --git a/reflect/Emit/AssemblyBuilder.cs b/reflect/Emit/AssemblyBuilder.cs index e63cd596..633f09df 100644 --- a/reflect/Emit/AssemblyBuilder.cs +++ b/reflect/Emit/AssemblyBuilder.cs @@ -64,7 +64,7 @@ namespace IKVM.Reflection.Emit private readonly List customAttributes = new List(); private readonly List declarativeSecurity = new List(); private readonly List typeForwarders = new List(); - private Dictionary missingTypes; + private Dictionary missingTypes; private struct ResourceFile { @@ -73,6 +73,34 @@ namespace IKVM.Reflection.Emit internal ResourceAttributes Attributes; } + private struct ScopedTypeName : IEquatable + { + private readonly Type declaringType; + private readonly TypeName name; + + internal ScopedTypeName(Type declaringType, TypeName name) + { + this.declaringType = declaringType; + this.name = name; + } + + public override bool Equals(object obj) + { + ScopedTypeName? other = obj as ScopedTypeName?; + return other != null && ((IEquatable)other.Value).Equals(this); + } + + public override int GetHashCode() + { + return declaringType == null ? name.GetHashCode() : declaringType.GetHashCode() * 7 + name.GetHashCode(); + } + + bool IEquatable.Equals(ScopedTypeName other) + { + return other.declaringType == declaringType && other.name == name; + } + } + internal AssemblyBuilder(Universe universe, AssemblyName name, string dir, PermissionSet requiredPermissions, PermissionSet optionalPermissions, PermissionSet refusedPermissions) : base(universe) { @@ -508,11 +536,11 @@ namespace IKVM.Reflection.Emit return list.ToArray(); } - internal override Type GetTypeImpl(string typeName) + internal override Type FindType(TypeName typeName) { foreach (ModuleBuilder mb in modules) { - Type type = mb.GetTypeImpl(typeName); + Type type = mb.FindType(typeName); if (type != null) { return type; @@ -520,7 +548,7 @@ namespace IKVM.Reflection.Emit } foreach (Module module in addedModules) { - Type type = module.GetTypeImpl(typeName); + Type type = module.FindType(typeName); if (type != null) { return type; @@ -529,23 +557,23 @@ namespace IKVM.Reflection.Emit return null; } - internal override Type ResolveType(string ns, string name) + internal override Type GetMissingType(TypeName name) { - return base.ResolveType(ns, name) ?? GetMissingType(this.ManifestModule, null, ns, name); + return GetMissingType(this.ManifestModule, null, name); } - internal Type GetMissingType(Module module, Type declaringType, string ns, string name) + internal Type GetMissingType(Module module, Type declaringType, TypeName name) { if (missingTypes == null) { return null; } - Type mt = new MissingType(module, declaringType, ns, name); + ScopedTypeName stn = new ScopedTypeName(declaringType, name); Type type; - if (!missingTypes.TryGetValue(mt.FullName, out type)) + if (!missingTypes.TryGetValue(stn, out type)) { - missingTypes.Add(mt.FullName, mt); - type = mt; + type = new MissingType(module, declaringType, name.Namespace, name.Name); + missingTypes.Add(stn, type); } return type; } @@ -554,7 +582,7 @@ namespace IKVM.Reflection.Emit { if (missingTypes == null) { - missingTypes = new Dictionary(); + missingTypes = new Dictionary(); } } @@ -692,7 +720,7 @@ namespace IKVM.Reflection.Emit get { return assembly; } } - internal override Type GetTypeImpl(string typeName) + internal override Type FindType(TypeName typeName) { return null; } diff --git a/reflect/Emit/ModuleBuilder.cs b/reflect/Emit/ModuleBuilder.cs index ada466b3..5623f196 100644 --- a/reflect/Emit/ModuleBuilder.cs +++ b/reflect/Emit/ModuleBuilder.cs @@ -48,7 +48,6 @@ namespace IKVM.Reflection.Emit private readonly List types = new List(); private readonly Dictionary typeTokens = new Dictionary(); private readonly Dictionary memberRefTypeTokens = new Dictionary(); - private readonly Dictionary fullNameToType = new Dictionary(); internal readonly ByteBuffer methodBodies = new ByteBuffer(128 * 1024); internal readonly List tokenFixupOffsets = new List(); internal readonly ByteBuffer initializedData = new ByteBuffer(512); @@ -227,7 +226,6 @@ namespace IKVM.Reflection.Emit { TypeBuilder typeBuilder = new TypeBuilder(owner, ns, name, attr); types.Add(typeBuilder); - fullNameToType.Add(typeBuilder.FullName, typeBuilder); return typeBuilder; } @@ -433,11 +431,16 @@ namespace IKVM.Reflection.Emit get { return asm; } } - internal override Type GetTypeImpl(string typeName) + internal override Type FindType(TypeName name) { - TypeBuilder type; - fullNameToType.TryGetValue(typeName, out type); - return type; + foreach (Type type in types) + { + if (type.__Namespace == name.Namespace && type.__Name == name.Name) + { + return type; + } + } + return null; } internal override void GetTypesImpl(List list) diff --git a/reflect/Emit/TypeBuilder.cs b/reflect/Emit/TypeBuilder.cs index 28ab084d..584f10bc 100644 --- a/reflect/Emit/TypeBuilder.cs +++ b/reflect/Emit/TypeBuilder.cs @@ -1038,9 +1038,9 @@ namespace IKVM.Reflection.Emit get { return token == 0x02000001; } } - internal override Type ResolveNestedType(string ns, string name) + internal override Type ResolveNestedType(TypeName typeName) { - return base.ResolveNestedType(ns, name) ?? ((AssemblyBuilder)ModuleBuilder.Assembly).GetMissingType(this.Module, this, ns, name); + return base.ResolveNestedType(typeName) ?? ((AssemblyBuilder)ModuleBuilder.Assembly).GetMissingType(this.Module, this, typeName); } } diff --git a/reflect/Missing.cs b/reflect/Missing.cs index 7b3b4257..f8117905 100644 --- a/reflect/Missing.cs +++ b/reflect/Missing.cs @@ -98,7 +98,7 @@ namespace IKVM.Reflection sealed class MissingAssembly : Assembly { - private readonly Dictionary types = new Dictionary(); + private readonly Dictionary types = new Dictionary(); private readonly MissingModule module; private readonly string name; @@ -109,14 +109,13 @@ namespace IKVM.Reflection this.name = name; } - internal override Type ResolveType(string ns, string name) + internal override Type GetMissingType(TypeName name) { - string fullName = ns == null ? name : ns + "." + name; Type type; - if (!types.TryGetValue(fullName, out type)) + if (!types.TryGetValue(name, out type)) { - type = new MissingType(module, null, ns, name); - types.Add(fullName, type); + type = new MissingType(module, null, name.Namespace, name.Name); + types.Add(name, type); } return type; } @@ -196,9 +195,9 @@ namespace IKVM.Reflection get { return true; } } - internal override Type GetTypeImpl(string typeName) + internal override Type FindType(TypeName typeName) { - throw new MissingAssemblyException(this); + return null; } internal override IList GetCustomAttributesData(Type attributeType) @@ -277,9 +276,9 @@ namespace IKVM.Reflection get { throw new MissingModuleException(this); } } - internal override Type GetTypeImpl(string typeName) + internal override Type FindType(TypeName typeName) { - throw new MissingModuleException(this); + return null; } internal override void GetTypesImpl(System.Collections.Generic.List list) @@ -354,7 +353,7 @@ namespace IKVM.Reflection private readonly Type declaringType; private readonly string ns; private readonly string name; - private Dictionary types; + private Dictionary types; internal MissingType(Module module, Type declaringType, string ns, string name) { @@ -364,18 +363,17 @@ namespace IKVM.Reflection this.name = name; } - internal override Type ResolveNestedType(string ns, string name) + internal override Type ResolveNestedType(TypeName typeName) { if (types == null) { - types = new Dictionary(); + types = new Dictionary(); } - string fullName = ns == null ? name : ns + "." + name; Type type; - if (!types.TryGetValue(fullName, out type)) + if (!types.TryGetValue(typeName, out type)) { - type = new MissingType(module, this, ns, name); - types.Add(fullName, type); + type = new MissingType(module, this, typeName.Namespace, typeName.Name); + types.Add(typeName, type); } return type; } diff --git a/reflect/Module.cs b/reflect/Module.cs index 7f5acb75..d8460d8c 100644 --- a/reflect/Module.cs +++ b/reflect/Module.cs @@ -287,9 +287,20 @@ namespace IKVM.Reflection public abstract Type[] __ResolveOptionalParameterTypes(int metadataToken); public abstract string ScopeName { get; } - internal abstract Type GetTypeImpl(string typeName); internal abstract void GetTypesImpl(List list); + internal Type GetTypeImpl(string typeName) + { + Type type = FindType(TypeName.Split(TypeNameParser.Unescape(typeName))); + if (type == null && __IsMissing) + { + throw new MissingModuleException((MissingModule)this); + } + return type; + } + + internal abstract Type FindType(TypeName name); + public Type GetType(string className) { return GetType(className, false, false); diff --git a/reflect/Reader/AssemblyReader.cs b/reflect/Reader/AssemblyReader.cs index 08d66ddf..0905895e 100644 --- a/reflect/Reader/AssemblyReader.cs +++ b/reflect/Reader/AssemblyReader.cs @@ -101,14 +101,14 @@ namespace IKVM.Reflection.Reader return list.ToArray(); } - internal override Type GetTypeImpl(string typeName) + internal override Type FindType(TypeName typeName) { - Type type = manifestModule.GetType(typeName); + Type type = manifestModule.FindType(typeName); for (int i = 0; type == null && i < externalModules.Length; i++) { if ((manifestModule.File.records[i].Flags & ContainsNoMetaData) == 0) { - type = GetModule(i).GetType(typeName); + type = GetModule(i).FindType(typeName); } } return type; diff --git a/reflect/Reader/GenericTypeParameter.cs b/reflect/Reader/GenericTypeParameter.cs index 2f961f94..cbed322a 100644 --- a/reflect/Reader/GenericTypeParameter.cs +++ b/reflect/Reader/GenericTypeParameter.cs @@ -131,7 +131,7 @@ namespace IKVM.Reflection.Reader get { throw new InvalidOperationException(); } } - internal override Type GetTypeImpl(string typeName) + internal override Type FindType(TypeName typeName) { throw new InvalidOperationException(); } diff --git a/reflect/Reader/ModuleReader.cs b/reflect/Reader/ModuleReader.cs index 87f38e62..987244d4 100644 --- a/reflect/Reader/ModuleReader.cs +++ b/reflect/Reader/ModuleReader.cs @@ -1,5 +1,5 @@ /* - Copyright (C) 2009-2010 Jeroen Frijters + Copyright (C) 2009-2011 Jeroen Frijters This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -74,8 +74,8 @@ namespace IKVM.Reflection.Reader private MethodBase[] methods; private MemberInfo[] memberRefs; private Dictionary strings = new Dictionary(); - private Dictionary types = new Dictionary(); - private Dictionary forwardedTypes = new Dictionary(); + private Dictionary types = new Dictionary(); + private Dictionary forwardedTypes = new Dictionary(); private sealed class LazyForwardedType { @@ -87,12 +87,16 @@ namespace IKVM.Reflection.Reader this.assemblyRef = assemblyRef; } - internal Type GetType(ModuleReader module, string typeName) + internal Type GetType(ModuleReader module, TypeName typeName) { if (type == null) { Assembly asm = module.ResolveAssemblyRef(assemblyRef); - type = asm.GetType(typeName, true); + type = asm.ResolveType(typeName); + if (type == null) + { + throw new TypeLoadException(typeName.ToString()); + } } return type; } @@ -251,9 +255,9 @@ namespace IKVM.Reflection.Reader { moduleType = type; } - else + else if (!type.IsNestedByFlags) { - types.Add(type.FullName, type); + types.Add(new TypeName(type.__Namespace, type.__Name), type); } } // add forwarded types to forwardedTypes dictionary (because Module.GetType(string) should return them) @@ -262,8 +266,8 @@ namespace IKVM.Reflection.Reader int implementation = ExportedType.records[i].Implementation; if (implementation >> 24 == AssemblyRefTable.Index) { - string typeName = GetTypeName(ExportedType.records[i].TypeNamespace, ExportedType.records[i].TypeName); - forwardedTypes.Add(TypeNameParser.Escape(typeName), new LazyForwardedType((implementation & 0xFFFFFF) - 1)); + TypeName typeName = GetTypeName(ExportedType.records[i].TypeNamespace, ExportedType.records[i].TypeName); + forwardedTypes.Add(typeName, new LazyForwardedType((implementation & 0xFFFFFF) - 1)); } } } @@ -362,10 +366,10 @@ namespace IKVM.Reflection.Reader case AssemblyRefTable.Index: { Assembly assembly = ResolveAssemblyRef((scope & 0xFFFFFF) - 1); - Type type = assembly.ResolveType(GetString(TypeRef.records[index].TypeNameSpace), GetString(TypeRef.records[index].TypeName)); + TypeName typeName = GetTypeName(TypeRef.records[index].TypeNameSpace, TypeRef.records[index].TypeName); + Type type = assembly.ResolveType(typeName); if (type == null) { - string typeName = GetTypeName(TypeRef.records[index].TypeNameSpace, TypeRef.records[index].TypeName); throw new TypeLoadException(String.Format("Type '{0}' not found in assembly '{1}'", typeName, assembly.FullName)); } typeRefs[index] = type; @@ -374,7 +378,8 @@ namespace IKVM.Reflection.Reader case TypeRefTable.Index: { Type outer = ResolveType(scope, null); - typeRefs[index] = outer.ResolveNestedType(GetString(TypeRef.records[index].TypeNameSpace), GetString(TypeRef.records[index].TypeName)); + TypeName typeName = GetTypeName(TypeRef.records[index].TypeNameSpace, TypeRef.records[index].TypeName); + typeRefs[index] = outer.ResolveNestedType(typeName); break; } case ModuleTable.Index: @@ -382,13 +387,13 @@ namespace IKVM.Reflection.Reader { throw new NotImplementedException("self reference scope?"); } - typeRefs[index] = GetType(TypeNameParser.Escape(GetTypeName(TypeRef.records[index].TypeNameSpace, TypeRef.records[index].TypeName))); + typeRefs[index] = FindType(GetTypeName(TypeRef.records[index].TypeNameSpace, TypeRef.records[index].TypeName)); break; case ModuleRefTable.Index: { Module module = ResolveModuleRef(ModuleRef.records[(scope & 0xFFFFFF) - 1]); - string typeName = GetTypeName(TypeRef.records[index].TypeNameSpace, TypeRef.records[index].TypeName); - Type type = module.GetType(TypeNameParser.Escape(typeName)); + TypeName typeName = GetTypeName(TypeRef.records[index].TypeNameSpace, TypeRef.records[index].TypeName); + Type type = module.FindType(typeName); if (type == null) { throw new TypeLoadException(String.Format("Type '{0}' not found in module '{1}'", typeName, module.Name)); @@ -477,16 +482,9 @@ namespace IKVM.Reflection.Reader } } - private string GetTypeName(int typeNamespace, int typeName) + private TypeName GetTypeName(int typeNamespace, int typeName) { - if (typeNamespace == 0) - { - return GetString(typeName); - } - else - { - return GetString(typeNamespace) + "." + GetString(typeName); - } + return new TypeName(GetString(typeNamespace), GetString(typeName)); } private Assembly ResolveAssemblyRef(int index) @@ -561,7 +559,7 @@ namespace IKVM.Reflection.Reader get { return assembly; } } - internal override Type GetTypeImpl(string typeName) + internal override Type FindType(TypeName typeName) { PopulateTypeDef(); Type type; @@ -981,21 +979,21 @@ namespace IKVM.Reflection.Reader public override IList __GetPlaceholderAssemblyCustomAttributes(bool multiple, bool security) { - string typeName; + TypeName typeName; switch ((multiple ? 1 : 0) + (security ? 2 : 0)) { case 0: - typeName = "System.Runtime.CompilerServices.AssemblyAttributesGoHere"; + typeName = new TypeName("System.Runtime.CompilerServices", "AssemblyAttributesGoHere"); break; case 1: - typeName = "System.Runtime.CompilerServices.AssemblyAttributesGoHereM"; + typeName = new TypeName("System.Runtime.CompilerServices", "AssemblyAttributesGoHereM"); break; case 2: - typeName = "System.Runtime.CompilerServices.AssemblyAttributesGoHereS"; + typeName = new TypeName("System.Runtime.CompilerServices", "AssemblyAttributesGoHereS"); break; case 3: default: - typeName = "System.Runtime.CompilerServices.AssemblyAttributesGoHereSM"; + typeName = new TypeName("System.Runtime.CompilerServices", "AssemblyAttributesGoHereSM"); break; } List list = new List(); diff --git a/reflect/Reader/ResourceModule.cs b/reflect/Reader/ResourceModule.cs index e80170d2..386e5ca2 100644 --- a/reflect/Reader/ResourceModule.cs +++ b/reflect/Reader/ResourceModule.cs @@ -110,7 +110,7 @@ namespace IKVM.Reflection.Reader throw new NotSupportedException(); } - internal override Type GetTypeImpl(string typeName) + internal override Type FindType(TypeName typeName) { return null; } diff --git a/reflect/Reader/TypeDefImpl.cs b/reflect/Reader/TypeDefImpl.cs index 6a0fbc34..fd008621 100644 --- a/reflect/Reader/TypeDefImpl.cs +++ b/reflect/Reader/TypeDefImpl.cs @@ -305,12 +305,17 @@ namespace IKVM.Reflection.Reader return sb.ToString(); } + internal bool IsNestedByFlags + { + get { return (this.Attributes & TypeAttributes.VisibilityMask & ~TypeAttributes.Public) != 0; } + } + public override Type DeclaringType { get { // note that we cannot use Type.IsNested for this, because that calls DeclaringType - if ((this.Attributes & TypeAttributes.VisibilityMask & ~TypeAttributes.Public) == 0) + if (!IsNestedByFlags) { return null; } diff --git a/reflect/Type.cs b/reflect/Type.cs index 20f1574b..6cc25c4c 100644 --- a/reflect/Type.cs +++ b/reflect/Type.cs @@ -747,35 +747,17 @@ namespace IKVM.Reflection return GetConstructor(bindingAttr, binder, types, modifiers); } - private static bool MatchTypeNames(string ns, string name, string fullName) + internal virtual Type ResolveNestedType(TypeName typeName) { - if (ns == null) - { - return name == fullName; - } - else if (ns.Length + 1 + name.Length == fullName.Length) - { - return fullName[ns.Length] == '.' - && String.CompareOrdinal(ns, 0, fullName, 0, ns.Length) == 0 - && String.CompareOrdinal(name, 0, fullName, ns.Length + 1, name.Length) == 0; - } - else - { - return false; - } - } - - internal virtual Type ResolveNestedType(string ns, string name) - { - return GetNestedTypeCorrectly(ns == null ? name : ns + "." + name); + return FindNestedType(typeName); } // unlike the public API, this takes the namespace and name into account - internal Type GetNestedTypeCorrectly(string name) + internal Type FindNestedType(TypeName name) { foreach (Type type in __GetDeclaredTypes()) { - if (MatchTypeNames(type.__Namespace, type.__Name, name)) + if (type.__Namespace == name.Namespace && type.__Name == name.Name) { return type; } diff --git a/reflect/TypeNameParser.cs b/reflect/TypeNameParser.cs index 77686f03..025d7f69 100644 --- a/reflect/TypeNameParser.cs +++ b/reflect/TypeNameParser.cs @@ -1,5 +1,5 @@ /* - Copyright (C) 2009 Jeroen Frijters + Copyright (C) 2009-2011 Jeroen Frijters This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -27,6 +27,79 @@ using System.Text; namespace IKVM.Reflection { + // this respresents a type name as in metadata: + // - ns will be null for empty the namespace (never the empty string) + // - the strings are not escaped + struct TypeName : IEquatable + { + private readonly string ns; + private readonly string name; + + internal TypeName(string ns, string name) + { + if (name == null) + { + throw new ArgumentNullException("name"); + } + this.ns = ns; + this.name = name; + } + + internal string Name + { + get { return name; } + } + + internal string Namespace + { + get { return ns; } + } + + public static bool operator ==(TypeName o1, TypeName o2) + { + return o1.ns == o2.ns && o1.name == o2.name; + } + + public static bool operator !=(TypeName o1, TypeName o2) + { + return o1.ns != o2.ns || o1.name != o2.name; + } + + public override int GetHashCode() + { + return ns == null ? name.GetHashCode() : ns.GetHashCode() * 37 + name.GetHashCode(); + } + + public override bool Equals(object obj) + { + TypeName? other = obj as TypeName?; + return other != null && other.Value == this; + } + + public override string ToString() + { + return ns == null ? name : ns + "." + name; + } + + bool IEquatable.Equals(TypeName other) + { + return this == other; + } + + internal static TypeName Split(string name) + { + int dot = name.LastIndexOf('.'); + if (dot == -1) + { + return new TypeName(null, name); + } + else + { + return new TypeName(name.Substring(0, dot), name.Substring(dot + 1)); + } + } + } + struct TypeNameParser { private const string SpecialChars = "\\+,[]*&"; @@ -407,7 +480,7 @@ namespace IKVM.Reflection { foreach (string nest in nested) { - type = type.GetNestedTypeCorrectly(TypeNameParser.Unescape(nest)); + type = type.FindNestedType(TypeName.Split(TypeNameParser.Unescape(nest))); if (type == null) { if (throwOnError) diff --git a/reflect/Universe.cs b/reflect/Universe.cs index 4e32b79b..1aed38f8 100644 --- a/reflect/Universe.cs +++ b/reflect/Universe.cs @@ -149,7 +149,11 @@ namespace IKVM.Reflection private Type ImportMscorlibType(System.Type type) { - return Mscorlib.GetTypeImpl(type.FullName); + // We use FindType instead of ResolveType here, because on some versions of mscorlib some of + // the special types we use/support are missing and the type properties are defined to + // return null in that case. + // Note that we don't have to unescape type.Name here, because none of the names contain special characters. + return Mscorlib.FindType(new TypeName(type.Namespace, type.Name)); } internal Type System_Object