X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fclass%2FIKVM.Reflection%2FEmit%2FModuleBuilder.cs;h=8ffe17ba95714a7604e26c1e4f36e7e0c69afe5f;hb=10eadfdd38d35fbc2906008375984770dcc478bc;hp=db0e58b6a23d9072cf1e74294685f2b4fd9e9f14;hpb=c251b192a55c255f278c9b9ad2ec949264a36526;p=mono.git diff --git a/mcs/class/IKVM.Reflection/Emit/ModuleBuilder.cs b/mcs/class/IKVM.Reflection/Emit/ModuleBuilder.cs index db0e58b6a23..8ffe17ba957 100644 --- a/mcs/class/IKVM.Reflection/Emit/ModuleBuilder.cs +++ b/mcs/class/IKVM.Reflection/Emit/ModuleBuilder.cs @@ -1,5 +1,5 @@ /* - Copyright (C) 2008-2011 Jeroen Frijters + Copyright (C) 2008-2012 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,7 @@ using System.IO; using System.Diagnostics; using System.Diagnostics.SymbolStore; using System.Security.Cryptography; +using System.Resources; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using IKVM.Reflection.Impl; @@ -41,6 +42,8 @@ namespace IKVM.Reflection.Emit private Guid mvid = Guid.NewGuid(); private long imageBaseAddress = 0x00400000; private long stackReserve = -1; + private int fileAlignment = 0x200; + private DllCharacteristics dllCharacteristics = DllCharacteristics.DynamicBase | DllCharacteristics.NoSEH | DllCharacteristics.NXCompat | DllCharacteristics.TerminalServerAware; private readonly AssemblyBuilder asm; internal readonly string moduleName; internal readonly string fileName; @@ -54,8 +57,8 @@ namespace IKVM.Reflection.Emit internal readonly ByteBuffer initializedData = new ByteBuffer(512); internal readonly ByteBuffer manifestResources = new ByteBuffer(512); internal ResourceSection unmanagedResources; - private readonly Dictionary importedMembers = new Dictionary(); private readonly Dictionary importedMemberRefs = new Dictionary(); + private readonly Dictionary importedMethodSpecs = new Dictionary(); private readonly Dictionary referencedAssemblies = new Dictionary(); private List referencedAssemblyNames; private int nextPseudoToken = -1; @@ -68,6 +71,32 @@ namespace IKVM.Reflection.Emit internal readonly List vtablefixups = new List(); internal readonly List unmanagedExports = new List(); private List interfaceImplCustomAttributes; + private List resourceWriters; + private bool saved; + + private struct ResourceWriterRecord + { + private readonly string name; + private readonly ResourceWriter rw; + private readonly MemoryStream mem; + private readonly ResourceAttributes attributes; + + internal ResourceWriterRecord(string name, ResourceWriter rw, MemoryStream mem, ResourceAttributes attributes) + { + this.name = name; + this.rw = rw; + this.mem = mem; + this.attributes = attributes; + } + + internal void Emit(ModuleBuilder mb) + { + rw.Generate(); + mem.Position = 0; + mb.DefineManifestResource(name, mem, attributes); + rw.Close(); + } + } internal struct VTableFixups { @@ -118,6 +147,46 @@ namespace IKVM.Reflection.Emit { return type.GetHashCode() + name.GetHashCode() + signature.GetHashCode(); } + + internal MethodBase LookupMethod() + { + return type.FindMethod(name, (MethodSignature)signature); + } + } + + struct MethodSpecKey : IEquatable + { + private readonly Type type; + private readonly string name; + private readonly MethodSignature signature; + private readonly Type[] genericParameters; + + internal MethodSpecKey(Type type, string name, MethodSignature signature, Type[] genericParameters) + { + this.type = type; + this.name = name; + this.signature = signature; + this.genericParameters = genericParameters; + } + + public bool Equals(MethodSpecKey other) + { + return other.type.Equals(type) + && other.name == name + && other.signature.Equals(signature) + && Util.ArrayEquals(other.genericParameters, genericParameters); + } + + public override bool Equals(object obj) + { + MethodSpecKey? other = obj as MethodSpecKey?; + return other != null && Equals(other); + } + + public override int GetHashCode() + { + return type.GetHashCode() + name.GetHashCode() + signature.GetHashCode() + Util.GetHashCode(genericParameters); + } } internal ModuleBuilder(AssemblyBuilder asm, string moduleName, string fileName, bool emitSymbolInfo) @@ -334,17 +403,16 @@ namespace IKVM.Reflection.Emit ExportedTypeTable.Record rec = new ExportedTypeTable.Record(); rec.TypeDefId = type.MetadataToken; rec.TypeName = this.Strings.Add(type.__Name); + string ns = type.__Namespace; + rec.TypeNamespace = ns == null ? 0 : this.Strings.Add(ns); if (type.IsNested) { rec.Flags = 0; - rec.TypeNamespace = 0; rec.Implementation = ExportType(type.DeclaringType); } else { rec.Flags = 0x00200000; // CorTypeAttr.tdForwarder - string ns = type.__Namespace; - rec.TypeNamespace = ns == null ? 0 : this.Strings.Add(ns); rec.Implementation = ImportAssemblyRef(type.Assembly); } return 0x27000000 | this.ExportedType.FindOrAddRecord(rec); @@ -365,7 +433,7 @@ namespace IKVM.Reflection.Emit Debug.Assert(!customBuilder.IsPseudoCustomAttribute); CustomAttributeTable.Record rec = new CustomAttributeTable.Record(); rec.Parent = token; - rec.Type = this.GetConstructorToken(customBuilder.Constructor).Token; + rec.Type = asm.IsWindowsRuntime ? customBuilder.Constructor.ImportTo(this) : GetConstructorToken(customBuilder.Constructor).Token; rec.Value = customBuilder.WriteBlob(this); this.CustomAttribute.AddRecord(rec); } @@ -453,6 +521,36 @@ namespace IKVM.Reflection.Emit manifestResources.Position = savePosition; } + public IResourceWriter DefineResource(string name, string description) + { + return DefineResource(name, description, ResourceAttributes.Public); + } + + public IResourceWriter DefineResource(string name, string description, ResourceAttributes attribute) + { + // FXBUG we ignore the description, because there is no such thing + + if (resourceWriters == null) + { + resourceWriters = new List(); + } + MemoryStream mem = new MemoryStream(); + ResourceWriter rw = new ResourceWriter(mem); + resourceWriters.Add(new ResourceWriterRecord(name, rw, mem, attribute)); + return rw; + } + + internal void EmitResources() + { + if (resourceWriters != null) + { + foreach (ResourceWriterRecord rwr in resourceWriters) + { + rwr.Emit(this); + } + } + } + public override Assembly Assembly { get { return asm; } @@ -470,6 +568,18 @@ namespace IKVM.Reflection.Emit return null; } + internal override Type FindTypeIgnoreCase(TypeName lowerCaseName) + { + foreach (Type type in types) + { + if (new TypeName(type.__Namespace, type.__Name).ToLowerInvariant() == lowerCaseName) + { + return type; + } + } + return null; + } + internal override void GetTypesImpl(List list) { foreach (Type type in types) @@ -486,6 +596,11 @@ namespace IKVM.Reflection.Emit return symbolWriter.DefineDocument(url, language, languageVendor, documentType); } + public int __GetAssemblyToken(Assembly assembly) + { + return ImportAssemblyRef(assembly); + } + public TypeToken GetTypeToken(string name) { return new TypeToken(GetType(name, true, false).MetadataToken); @@ -493,7 +608,7 @@ namespace IKVM.Reflection.Emit public TypeToken GetTypeToken(Type type) { - if (type.Module == this) + if (type.Module == this && !asm.IsWindowsRuntime) { return new TypeToken(type.GetModuleBuilderToken()); } @@ -549,7 +664,7 @@ namespace IKVM.Reflection.Emit } else { - return new FieldToken(ImportMember(field)); + return new FieldToken(field.ImportTo(this)); } } @@ -562,8 +677,32 @@ namespace IKVM.Reflection.Emit } else { - return new MethodToken(ImportMember(method)); + return new MethodToken(method.ImportTo(this)); + } + } + + // new in .NET 4.5 + public MethodToken GetMethodToken(MethodInfo method, IEnumerable optionalParameterTypes) + { + return __GetMethodToken(method, Util.ToArray(optionalParameterTypes), null); + } + + public MethodToken __GetMethodToken(MethodInfo method, Type[] optionalParameterTypes, CustomModifiers[] customModifiers) + { + ByteBuffer sig = new ByteBuffer(16); + method.MethodSignature.WriteMethodRefSig(this, sig, optionalParameterTypes, customModifiers); + MemberRefTable.Record record = new MemberRefTable.Record(); + if (method.Module == this) + { + record.Class = method.MetadataToken; + } + else + { + record.Class = GetTypeTokenForMemberRef(method.DeclaringType ?? method.Module.GetModuleType()); } + record.Name = Strings.Add(method.Name); + record.Signature = Blobs.Add(sig); + return new MethodToken(0x0A000000 | MemberRef.FindOrAddRecord(record)); } // when we refer to a method on a generic type definition in the IL stream, @@ -576,7 +715,7 @@ namespace IKVM.Reflection.Emit } if (IsFromGenericTypeDefinition(method)) { - return new MethodToken(ImportMember(method)); + return new MethodToken(method.ImportTo(this)); } else { @@ -584,44 +723,32 @@ namespace IKVM.Reflection.Emit } } + internal int GetMethodTokenWinRT(MethodInfo method) + { + return asm.IsWindowsRuntime ? method.ImportTo(this) : GetMethodToken(method).Token; + } + public MethodToken GetConstructorToken(ConstructorInfo constructor) { - if (constructor.Module == this && constructor.GetMethodInfo() is MethodBuilder) - { - return new MethodToken(constructor.MetadataToken); - } - else - { - return new MethodToken(ImportMember(constructor)); - } + return GetMethodToken(constructor.GetMethodInfo()); } - internal int ImportMember(MethodBase member) + // new in .NET 4.5 + public MethodToken GetConstructorToken(ConstructorInfo constructor, IEnumerable optionalParameterTypes) { - int token; - if (!importedMembers.TryGetValue(member, out token)) - { - token = member.ImportTo(this); - importedMembers.Add(member, token); - } - return token; + return GetMethodToken(constructor.GetMethodInfo(), optionalParameterTypes); } - internal int ImportMember(FieldInfo member) + public MethodToken __GetConstructorToken(ConstructorInfo constructor, Type[] optionalParameterTypes, CustomModifiers[] customModifiers) { - int token; - if (!importedMembers.TryGetValue(member, out token)) - { - token = member.ImportTo(this); - importedMembers.Add(member, token); - } - return token; + return __GetMethodToken(constructor.GetMethodInfo(), optionalParameterTypes, customModifiers); } internal int ImportMethodOrField(Type declaringType, string name, Signature sig) { int token; - if (!importedMemberRefs.TryGetValue(new MemberRefKey(declaringType, name, sig), out token)) + MemberRefKey key = new MemberRefKey(declaringType, name, sig); + if (!importedMemberRefs.TryGetValue(key, out token)) { MemberRefTable.Record rec = new MemberRefTable.Record(); rec.Class = GetTypeTokenForMemberRef(declaringType); @@ -630,7 +757,35 @@ namespace IKVM.Reflection.Emit sig.WriteSig(this, bb); rec.Signature = this.Blobs.Add(bb); token = 0x0A000000 | this.MemberRef.AddRecord(rec); - importedMemberRefs.Add(new MemberRefKey(declaringType, name, sig), token); + importedMemberRefs.Add(key, token); + } + return token; + } + + internal int ImportMethodSpec(Type declaringType, MethodInfo method, Type[] genericParameters) + { + Debug.Assert(method.__IsMissing || method.GetMethodOnTypeDefinition() == method); + int token; + MethodSpecKey key = new MethodSpecKey(declaringType, method.Name, method.MethodSignature, genericParameters); + if (!importedMethodSpecs.TryGetValue(key, out token)) + { + MethodSpecTable.Record rec = new MethodSpecTable.Record(); + MethodBuilder mb = method as MethodBuilder; + if (mb != null && mb.ModuleBuilder == this && !declaringType.IsGenericType) + { + rec.Method = mb.MetadataToken; + } + else + { + // we're calling ImportMethodOrField directly here, because 'method' may be a MethodDef on a generic TypeDef and 'declaringType' the type instance + // (in order words the method and type have already been decoupled by the caller) + rec.Method = ImportMethodOrField(declaringType, method.Name, method.MethodSignature); + } + Writer.ByteBuffer spec = new Writer.ByteBuffer(10); + Signature.WriteMethodSpec(this, spec, genericParameters); + rec.Instantiation = this.Blobs.Add(spec); + token = 0x2B000000 | this.MethodSpec.FindOrAddRecord(rec); + importedMethodSpecs.Add(key, token); } return token; } @@ -640,7 +795,7 @@ namespace IKVM.Reflection.Emit int token; if (!typeTokens.TryGetValue(type, out token)) { - if (type.HasElementType || type.IsGenericTypeInstance) + if (type.HasElementType || type.IsConstructedGenericType || type.__IsFunctionPointer) { ByteBuffer spec = new ByteBuffer(5); Signature.WriteTypeSpec(this, spec, type); @@ -653,6 +808,10 @@ namespace IKVM.Reflection.Emit { rec.ResolutionScope = GetTypeToken(type.DeclaringType).Token; } + else if (type.Module == this) + { + rec.ResolutionScope = 1; + } else { rec.ResolutionScope = ImportAssemblyRef(type.Assembly); @@ -674,9 +833,7 @@ namespace IKVM.Reflection.Emit { // We can't write the AssemblyRef record here yet, because the identity of the assembly can still change // (if it's an AssemblyBuilder). - // We set the high bit of rid in the token to make sure we emit obviously broken metadata, - // if we forget to patch up the token somewhere. - token = 0x23800001 + referencedAssemblies.Count; + token = AllocPseudoToken(); referencedAssemblies.Add(asm, token); } return token; @@ -684,30 +841,11 @@ namespace IKVM.Reflection.Emit internal void FillAssemblyRefTable() { - int[] realtokens = new int[referencedAssemblies.Count]; foreach (KeyValuePair kv in referencedAssemblies) { - if ((kv.Value & 0x7F800000) == 0x23800000) + if (IsPseudoToken(kv.Value)) { - realtokens[(kv.Value & 0x7FFFFF) - 1] = FindOrAddAssemblyRef(kv.Key.GetName(), false); - } - } - // now fixup the resolution scopes in TypeRef - for (int i = 0; i < this.TypeRef.records.Length; i++) - { - int resolutionScope = this.TypeRef.records[i].ResolutionScope; - if ((resolutionScope & 0x7F800000) == 0x23800000) - { - this.TypeRef.records[i].ResolutionScope = realtokens[(resolutionScope & 0x7FFFFF) - 1]; - } - } - // and implementation in ExportedType - for (int i = 0; i < this.ExportedType.records.Length; i++) - { - int implementation = this.ExportedType.records[i].Implementation; - if ((implementation & 0x7F800000) == 0x23800000) - { - this.ExportedType.records[i].Implementation = realtokens[(implementation & 0x7FFFFF) - 1]; + RegisterTokenFixup(kv.Value, FindOrAddAssemblyRef(kv.Key.GetName(), false)); } } } @@ -727,6 +865,10 @@ namespace IKVM.Reflection.Emit { rec.Flags |= (int)(name.RawFlags & afPA_Mask); } + if (name.ContentType == AssemblyContentType.WindowsRuntime) + { + rec.Flags |= 0x0200; + } byte[] publicKeyOrToken = null; if (usePublicKeyAssemblyReference) { @@ -979,7 +1121,8 @@ namespace IKVM.Reflection.Emit { ExportedTypeTable.Record rec = new ExportedTypeTable.Record(); rec.Flags = (int)type.Attributes; - rec.TypeDefId = type.MetadataToken & 0xFFFFFF; + // LAMESPEC ECMA says that TypeDefId is a row index, but it should be a token + rec.TypeDefId = type.MetadataToken; rec.TypeName = this.Strings.Add(type.__Name); string ns = type.__Namespace; rec.TypeNamespace = ns == null ? 0 : this.Strings.Add(ns); @@ -1099,9 +1242,9 @@ namespace IKVM.Reflection.Emit get { return this; } } - public override Type ResolveType(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments) + internal override Type ResolveType(int metadataToken, IGenericContext context) { - if (genericTypeArguments != null || genericMethodArguments != null) + if (metadataToken >> 24 != TypeDefTable.Index) { throw new NotImplementedException(); } @@ -1117,11 +1260,11 @@ namespace IKVM.Reflection.Emit // this method is inefficient, but since it isn't used we don't care if ((metadataToken >> 24) == MemberRefTable.Index) { - foreach (KeyValuePair kv in importedMembers) + foreach (KeyValuePair kv in importedMemberRefs) { if (kv.Value == metadataToken) { - return (MethodBase)kv.Key; + return kv.Key.LookupMethod(); } } } @@ -1271,14 +1414,21 @@ namespace IKVM.Reflection.Emit return imageBaseAddress; } - public override long __StackReserve + public new long __StackReserve { get { return stackReserve; } + set { stackReserve = value; } + } + + protected override long GetStackReserveImpl() + { + return stackReserve; } + [Obsolete("Use __StackReserve property.")] public void __SetStackReserve(long stackReserve) { - this.stackReserve = stackReserve; + __StackReserve = stackReserve; } internal ulong GetStackReserve(ulong defaultValue) @@ -1286,6 +1436,28 @@ namespace IKVM.Reflection.Emit return stackReserve == -1 ? defaultValue : (ulong)stackReserve; } + public new int __FileAlignment + { + get { return fileAlignment; } + set { fileAlignment = value; } + } + + protected override int GetFileAlignmentImpl() + { + return fileAlignment; + } + + public new DllCharacteristics __DllCharacteristics + { + get { return dllCharacteristics; } + set { dllCharacteristics = value; } + } + + protected override DllCharacteristics GetDllCharacteristicsImpl() + { + return dllCharacteristics; + } + public override int MDStreamVersion { get { return asm.mdStreamVersion; } @@ -1316,6 +1488,7 @@ namespace IKVM.Reflection.Emit private void SaveImpl(Stream streamOrNull, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine) { + SetIsSaved(); PopulatePropertyAndEventTables(); IList attributes = asm.GetCustomAttributesData(null); if (attributes.Count > 0) @@ -1354,6 +1527,7 @@ namespace IKVM.Reflection.Emit } } FillAssemblyRefTable(); + EmitResources(); ModuleWriter.WriteModule(null, null, this, PEFileKinds.Dll, portableExecutableKind, imageFileMachine, unmanagedResources, 0, streamOrNull); } @@ -1539,6 +1713,33 @@ namespace IKVM.Reflection.Emit } } } + + internal void FixupPseudoToken(ref int token) + { + if (IsPseudoToken(token)) + { + token = ResolvePseudoToken(token); + } + } + + internal void SetIsSaved() + { + if (saved) + { + throw new InvalidOperationException(); + } + saved = true; + } + + internal bool IsSaved + { + get { return saved; } + } + + internal override string GetString(int index) + { + return this.Strings.Find(index); + } } struct UnmanagedExport @@ -1638,7 +1839,7 @@ namespace IKVM.Reflection.Emit public override Module Module { - // like .NET, we return the module that GetArrayMethod was called on, not the module associated with the array type + // FXBUG like .NET, we return the module that GetArrayMethod was called on, not the module associated with the array type get { return module; } } @@ -1654,6 +1855,7 @@ namespace IKVM.Reflection.Emit public override ParameterInfo ReturnParameter { + // FXBUG like .NET, we throw NotImplementedException get { throw new NotImplementedException(); } } @@ -1666,5 +1868,15 @@ namespace IKVM.Reflection.Emit { get { return (callingConvention & (CallingConventions.HasThis | CallingConventions.ExplicitThis)) == CallingConventions.HasThis; } } + + internal override int GetCurrentToken() + { + return this.MetadataToken; + } + + internal override bool IsBaked + { + get { return arrayClass.IsBaked; } + } } }