Merge pull request #347 from JamesB7/master
[mono.git] / mcs / class / IKVM.Reflection / Emit / ModuleBuilder.cs
1 /*
2   Copyright (C) 2008-2012 Jeroen Frijters
3
4   This software is provided 'as-is', without any express or implied
5   warranty.  In no event will the authors be held liable for any damages
6   arising from the use of this software.
7
8   Permission is granted to anyone to use this software for any purpose,
9   including commercial applications, and to alter it and redistribute it
10   freely, subject to the following restrictions:
11
12   1. The origin of this software must not be misrepresented; you must not
13      claim that you wrote the original software. If you use this software
14      in a product, an acknowledgment in the product documentation would be
15      appreciated but is not required.
16   2. Altered source versions must be plainly marked as such, and must not be
17      misrepresented as being the original software.
18   3. This notice may not be removed or altered from any source distribution.
19
20   Jeroen Frijters
21   jeroen@frijters.net
22   
23 */
24 using System;
25 using System.Collections.Generic;
26 using System.IO;
27 using System.Diagnostics;
28 using System.Diagnostics.SymbolStore;
29 using System.Security.Cryptography;
30 using System.Runtime.CompilerServices;
31 using System.Runtime.InteropServices;
32 using IKVM.Reflection.Impl;
33 using IKVM.Reflection.Metadata;
34 using IKVM.Reflection.Writer;
35
36 namespace IKVM.Reflection.Emit
37 {
38         public sealed class ModuleBuilder : Module, ITypeOwner
39         {
40                 private static readonly bool usePublicKeyAssemblyReference = false;
41                 private Guid mvid = Guid.NewGuid();
42                 private long imageBaseAddress = 0x00400000;
43                 private long stackReserve = -1;
44                 private int fileAlignment = 0x200;
45                 private DllCharacteristics dllCharacteristics = DllCharacteristics.DynamicBase | DllCharacteristics.NoSEH | DllCharacteristics.NXCompat | DllCharacteristics.TerminalServerAware;
46                 private readonly AssemblyBuilder asm;
47                 internal readonly string moduleName;
48                 internal readonly string fileName;
49                 internal readonly ISymbolWriterImpl symbolWriter;
50                 private readonly TypeBuilder moduleType;
51                 private readonly List<TypeBuilder> types = new List<TypeBuilder>();
52                 private readonly Dictionary<Type, int> typeTokens = new Dictionary<Type, int>();
53                 private readonly Dictionary<Type, int> memberRefTypeTokens = new Dictionary<Type, int>();
54                 internal readonly ByteBuffer methodBodies = new ByteBuffer(128 * 1024);
55                 internal readonly List<int> tokenFixupOffsets = new List<int>();
56                 internal readonly ByteBuffer initializedData = new ByteBuffer(512);
57                 internal readonly ByteBuffer manifestResources = new ByteBuffer(512);
58                 internal ResourceSection unmanagedResources;
59                 private readonly Dictionary<MemberInfo, int> importedMembers = new Dictionary<MemberInfo, int>();
60                 private readonly Dictionary<MemberRefKey, int> importedMemberRefs = new Dictionary<MemberRefKey, int>();
61                 private readonly Dictionary<Assembly, int> referencedAssemblies = new Dictionary<Assembly, int>();
62                 private List<AssemblyName> referencedAssemblyNames;
63                 private int nextPseudoToken = -1;
64                 private readonly List<int> resolvedTokens = new List<int>();
65                 internal readonly TableHeap Tables = new TableHeap();
66                 internal readonly StringHeap Strings = new StringHeap();
67                 internal readonly UserStringHeap UserStrings = new UserStringHeap();
68                 internal readonly GuidHeap Guids = new GuidHeap();
69                 internal readonly BlobHeap Blobs = new BlobHeap();
70                 internal readonly List<VTableFixups> vtablefixups = new List<VTableFixups>();
71                 internal readonly List<UnmanagedExport> unmanagedExports = new List<UnmanagedExport>();
72                 private List<InterfaceImplCustomAttribute> interfaceImplCustomAttributes;
73
74                 internal struct VTableFixups
75                 {
76                         internal uint initializedDataOffset;
77                         internal ushort count;
78                         internal ushort type;
79
80                         internal int SlotWidth
81                         {
82                                 get { return (type & 0x02) == 0 ? 4 : 8; }
83                         }
84                 }
85
86                 struct InterfaceImplCustomAttribute
87                 {
88                         internal int type;
89                         internal int interfaceType;
90                         internal int pseudoToken;
91                 }
92
93                 struct MemberRefKey : IEquatable<MemberRefKey>
94                 {
95                         private readonly Type type;
96                         private readonly string name;
97                         private readonly Signature signature;
98
99                         internal MemberRefKey(Type type, string name, Signature signature)
100                         {
101                                 this.type = type;
102                                 this.name = name;
103                                 this.signature = signature;
104                         }
105
106                         public bool Equals(MemberRefKey other)
107                         {
108                                 return other.type.Equals(type)
109                                         && other.name == name
110                                         && other.signature.Equals(signature);
111                         }
112
113                         public override bool Equals(object obj)
114                         {
115                                 MemberRefKey? other = obj as MemberRefKey?;
116                                 return other != null && Equals(other);
117                         }
118
119                         public override int GetHashCode()
120                         {
121                                 return type.GetHashCode() + name.GetHashCode() + signature.GetHashCode();
122                         }
123                 }
124
125                 internal ModuleBuilder(AssemblyBuilder asm, string moduleName, string fileName, bool emitSymbolInfo)
126                         : base(asm.universe)
127                 {
128                         this.asm = asm;
129                         this.moduleName = moduleName;
130                         this.fileName = fileName;
131                         if (emitSymbolInfo)
132                         {
133                                 symbolWriter = SymbolSupport.CreateSymbolWriterFor(this);
134                         }
135                         // <Module> must be the first record in the TypeDef table
136                         moduleType = new TypeBuilder(this, null, "<Module>");
137                         types.Add(moduleType);
138                 }
139
140                 internal void PopulatePropertyAndEventTables()
141                 {
142                         // LAMESPEC the PropertyMap and EventMap tables are not required to be sorted by the CLI spec,
143                         // but .NET sorts them and Mono requires them to be sorted, so we have to populate the
144                         // tables in the right order
145                         foreach (TypeBuilder type in types)
146                         {
147                                 type.PopulatePropertyAndEventTables();
148                         }
149                 }
150
151                 internal void WriteTypeDefTable(MetadataWriter mw)
152                 {
153                         int fieldList = 1;
154                         int methodList = 1;
155                         foreach (TypeBuilder type in types)
156                         {
157                                 type.WriteTypeDefRecord(mw, ref fieldList, ref methodList);
158                         }
159                 }
160
161                 internal void WriteMethodDefTable(int baseRVA, MetadataWriter mw)
162                 {
163                         int paramList = 1;
164                         foreach (TypeBuilder type in types)
165                         {
166                                 type.WriteMethodDefRecords(baseRVA, mw, ref paramList);
167                         }
168                 }
169
170                 internal void WriteParamTable(MetadataWriter mw)
171                 {
172                         foreach (TypeBuilder type in types)
173                         {
174                                 type.WriteParamRecords(mw);
175                         }
176                 }
177
178                 internal void WriteFieldTable(MetadataWriter mw)
179                 {
180                         foreach (TypeBuilder type in types)
181                         {
182                                 type.WriteFieldRecords(mw);
183                         }
184                 }
185
186                 internal int AllocPseudoToken()
187                 {
188                         return nextPseudoToken--;
189                 }
190
191                 public TypeBuilder DefineType(string name)
192                 {
193                         return DefineType(name, TypeAttributes.Class);
194                 }
195
196                 public TypeBuilder DefineType(string name, TypeAttributes attr)
197                 {
198                         return DefineType(name, attr, null);
199                 }
200
201                 public TypeBuilder DefineType(string name, TypeAttributes attr, Type parent)
202                 {
203                         return DefineType(name, attr, parent, PackingSize.Unspecified, 0);
204                 }
205
206                 public TypeBuilder DefineType(string name, TypeAttributes attr, Type parent, int typesize)
207                 {
208                         return DefineType(name, attr, parent, PackingSize.Unspecified, typesize);
209                 }
210
211                 public TypeBuilder DefineType(string name, TypeAttributes attr, Type parent, PackingSize packsize)
212                 {
213                         return DefineType(name, attr, parent, packsize, 0);
214                 }
215
216                 public TypeBuilder DefineType(string name, TypeAttributes attr, Type parent, Type[] interfaces)
217                 {
218                         TypeBuilder tb = DefineType(name, attr, parent);
219                         foreach (Type iface in interfaces)
220                         {
221                                 tb.AddInterfaceImplementation(iface);
222                         }
223                         return tb;
224                 }
225
226                 public TypeBuilder DefineType(string name, TypeAttributes attr, Type parent, PackingSize packingSize, int typesize)
227                 {
228                         string ns = null;
229                         int lastdot = name.LastIndexOf('.');
230                         if (lastdot > 0)
231                         {
232                                 ns = name.Substring(0, lastdot);
233                                 name = name.Substring(lastdot + 1);
234                         }
235                         TypeBuilder typeBuilder = __DefineType(ns, name);
236                         typeBuilder.__SetAttributes(attr);
237                         typeBuilder.SetParent(parent);
238                         if (packingSize != PackingSize.Unspecified || typesize != 0)
239                         {
240                                 typeBuilder.__SetLayout((int)packingSize, typesize);
241                         }
242                         return typeBuilder;
243                 }
244
245                 public TypeBuilder __DefineType(string ns, string name)
246                 {
247                         return DefineType(this, ns, name);
248                 }
249
250                 internal TypeBuilder DefineType(ITypeOwner owner, string ns, string name)
251                 {
252                         TypeBuilder typeBuilder = new TypeBuilder(owner, ns, name);
253                         types.Add(typeBuilder);
254                         return typeBuilder;
255                 }
256
257                 public EnumBuilder DefineEnum(string name, TypeAttributes visibility, Type underlyingType)
258                 {
259                         TypeBuilder tb = DefineType(name, (visibility & TypeAttributes.VisibilityMask) | TypeAttributes.Sealed, universe.System_Enum);
260                         FieldBuilder fb = tb.DefineField("value__", underlyingType, FieldAttributes.Public | FieldAttributes.SpecialName | FieldAttributes.RTSpecialName);
261                         return new EnumBuilder(tb, fb);
262                 }
263
264                 public FieldBuilder __DefineField(string name, Type type, CustomModifiers customModifiers, FieldAttributes attributes)
265                 {
266                         return moduleType.__DefineField(name, type, customModifiers, attributes);
267                 }
268
269                 [Obsolete("Please use __DefineField(string, Type, CustomModifiers, FieldAttributes) instead.")]
270                 public FieldBuilder __DefineField(string name, Type type, Type[] requiredCustomModifiers, Type[] optionalCustomModifiers, FieldAttributes attributes)
271                 {
272                         return moduleType.DefineField(name, type, requiredCustomModifiers, optionalCustomModifiers, attributes);
273                 }
274
275                 public ConstructorBuilder __DefineModuleInitializer(MethodAttributes visibility)
276                 {
277                         return moduleType.DefineConstructor(visibility | MethodAttributes.Static | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, CallingConventions.Standard, Type.EmptyTypes);
278                 }
279
280                 public FieldBuilder DefineUninitializedData(string name, int size, FieldAttributes attributes)
281                 {
282                         return moduleType.DefineUninitializedData(name, size, attributes);
283                 }
284
285                 public FieldBuilder DefineInitializedData(string name, byte[] data, FieldAttributes attributes)
286                 {
287                         return moduleType.DefineInitializedData(name, data, attributes);
288                 }
289
290                 public MethodBuilder DefineGlobalMethod(string name, MethodAttributes attributes, Type returnType, Type[] parameterTypes)
291                 {
292                         return moduleType.DefineMethod(name, attributes, returnType, parameterTypes);
293                 }
294
295                 public MethodBuilder DefineGlobalMethod(string name, MethodAttributes attributes, CallingConventions callingConvention, Type returnType, Type[] parameterTypes)
296                 {
297                         return moduleType.DefineMethod(name, attributes, callingConvention, returnType, parameterTypes);
298                 }
299
300                 public MethodBuilder DefineGlobalMethod(string name, MethodAttributes attributes, CallingConventions callingConvention, Type returnType, Type[] requiredReturnTypeCustomModifiers, Type[] optionalReturnTypeCustomModifiers, Type[] parameterTypes, Type[][] requiredParameterTypeCustomModifiers, Type[][] optionalParameterTypeCustomModifiers)
301                 {
302                         return moduleType.DefineMethod(name, attributes, callingConvention, returnType, requiredReturnTypeCustomModifiers, optionalReturnTypeCustomModifiers, parameterTypes, requiredParameterTypeCustomModifiers, optionalParameterTypeCustomModifiers);
303                 }
304
305                 public MethodBuilder DefinePInvokeMethod(string name, string dllName, MethodAttributes attributes, CallingConventions callingConvention, Type returnType, Type[] parameterTypes, CallingConvention nativeCallConv, CharSet nativeCharSet)
306                 {
307                         return moduleType.DefinePInvokeMethod(name, dllName, attributes, callingConvention, returnType, parameterTypes, nativeCallConv, nativeCharSet);
308                 }
309
310                 public MethodBuilder DefinePInvokeMethod(string name, string dllName, string entryName, MethodAttributes attributes, CallingConventions callingConvention, Type returnType, Type[] parameterTypes, CallingConvention nativeCallConv, CharSet nativeCharSet)
311                 {
312                         return moduleType.DefinePInvokeMethod(name, dllName, entryName, attributes, callingConvention, returnType, parameterTypes, nativeCallConv, nativeCharSet);
313                 }
314
315                 public void CreateGlobalFunctions()
316                 {
317                         moduleType.CreateType();
318                 }
319
320                 internal void AddTypeForwarder(Type type)
321                 {
322                         ExportType(type);
323                         if (!type.__IsMissing)
324                         {
325                                 foreach (Type nested in type.GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic))
326                                 {
327                                         // we export all nested types (i.e. even the private ones)
328                                         // (this behavior is the same as the C# compiler)
329                                         AddTypeForwarder(nested);
330                                 }
331                         }
332                 }
333
334                 private int ExportType(Type type)
335                 {
336                         ExportedTypeTable.Record rec = new ExportedTypeTable.Record();
337                         rec.TypeDefId = type.MetadataToken;
338                         rec.TypeName = this.Strings.Add(type.__Name);
339                         string ns = type.__Namespace;
340                         rec.TypeNamespace = ns == null ? 0 : this.Strings.Add(ns);
341                         if (type.IsNested)
342                         {
343                                 rec.Flags = 0;
344                                 rec.Implementation = ExportType(type.DeclaringType);
345                         }
346                         else
347                         {
348                                 rec.Flags = 0x00200000; // CorTypeAttr.tdForwarder
349                                 rec.Implementation = ImportAssemblyRef(type.Assembly);
350                         }
351                         return 0x27000000 | this.ExportedType.FindOrAddRecord(rec);
352                 }
353
354                 public void SetCustomAttribute(ConstructorInfo con, byte[] binaryAttribute)
355                 {
356                         SetCustomAttribute(new CustomAttributeBuilder(con, binaryAttribute));
357                 }
358
359                 public void SetCustomAttribute(CustomAttributeBuilder customBuilder)
360                 {
361                         SetCustomAttribute(0x00000001, customBuilder);
362                 }
363
364                 internal void SetCustomAttribute(int token, CustomAttributeBuilder customBuilder)
365                 {
366                         Debug.Assert(!customBuilder.IsPseudoCustomAttribute);
367                         CustomAttributeTable.Record rec = new CustomAttributeTable.Record();
368                         rec.Parent = token;
369                         rec.Type = this.GetConstructorToken(customBuilder.Constructor).Token;
370                         rec.Value = customBuilder.WriteBlob(this);
371                         this.CustomAttribute.AddRecord(rec);
372                 }
373
374                 internal void AddDeclarativeSecurity(int token, System.Security.Permissions.SecurityAction securityAction, System.Security.PermissionSet permissionSet)
375                 {
376                         DeclSecurityTable.Record rec = new DeclSecurityTable.Record();
377                         rec.Action = (short)securityAction;
378                         rec.Parent = token;
379                         // like Ref.Emit, we're using the .NET 1.x xml format
380                         rec.PermissionSet = this.Blobs.Add(ByteBuffer.Wrap(System.Text.Encoding.Unicode.GetBytes(permissionSet.ToXml().ToString())));
381                         this.DeclSecurity.AddRecord(rec);
382                 }
383
384                 internal void AddDeclarativeSecurity(int token, List<CustomAttributeBuilder> declarativeSecurity)
385                 {
386                         Dictionary<int, List<CustomAttributeBuilder>> ordered = new Dictionary<int, List<CustomAttributeBuilder>>();
387                         foreach (CustomAttributeBuilder cab in declarativeSecurity)
388                         {
389                                 int action;
390                                 // check for HostProtectionAttribute without SecurityAction
391                                 if (cab.ConstructorArgumentCount == 0)
392                                 {
393                                         action = (int)System.Security.Permissions.SecurityAction.LinkDemand;
394                                 }
395                                 else
396                                 {
397                                         action = (int)cab.GetConstructorArgument(0);
398                                 }
399                                 List<CustomAttributeBuilder> list;
400                                 if (!ordered.TryGetValue(action, out list))
401                                 {
402                                         list = new List<CustomAttributeBuilder>();
403                                         ordered.Add(action, list);
404                                 }
405                                 list.Add(cab);
406                         }
407                         foreach (KeyValuePair<int, List<CustomAttributeBuilder>> kv in ordered)
408                         {
409                                 DeclSecurityTable.Record rec = new DeclSecurityTable.Record();
410                                 rec.Action = (short)kv.Key;
411                                 rec.Parent = token;
412                                 rec.PermissionSet = WriteDeclSecurityBlob(kv.Value);
413                                 this.DeclSecurity.AddRecord(rec);
414                         }
415                 }
416
417                 private int WriteDeclSecurityBlob(List<CustomAttributeBuilder> list)
418                 {
419                         string xml;
420                         if (list.Count == 1 && (xml = list[0].GetLegacyDeclSecurity()) != null)
421                         {
422                                 // write .NET 1.1 format
423                                 return this.Blobs.Add(ByteBuffer.Wrap(System.Text.Encoding.Unicode.GetBytes(xml)));
424                         }
425                         ByteBuffer namedArgs = new ByteBuffer(100);
426                         ByteBuffer bb = new ByteBuffer(list.Count * 100);
427                         bb.Write((byte)'.');
428                         bb.WriteCompressedInt(list.Count);
429                         foreach (CustomAttributeBuilder cab in list)
430                         {
431                                 bb.Write(cab.Constructor.DeclaringType.AssemblyQualifiedName);
432                                 namedArgs.Clear();
433                                 cab.WriteNamedArgumentsForDeclSecurity(this, namedArgs);
434                                 bb.WriteCompressedInt(namedArgs.Length);
435                                 bb.Write(namedArgs);
436                         }
437                         return this.Blobs.Add(bb);
438                 }
439
440                 public void DefineManifestResource(string name, Stream stream, ResourceAttributes attribute)
441                 {
442                         manifestResources.Align(8);
443                         ManifestResourceTable.Record rec = new ManifestResourceTable.Record();
444                         rec.Offset = manifestResources.Position;
445                         rec.Flags = (int)attribute;
446                         rec.Name = this.Strings.Add(name);
447                         rec.Implementation = 0;
448                         this.ManifestResource.AddRecord(rec);
449                         manifestResources.Write(0);     // placeholder for the length
450                         manifestResources.Write(stream);
451                         int savePosition = manifestResources.Position;
452                         manifestResources.Position = rec.Offset;
453                         manifestResources.Write(savePosition - (manifestResources.Position + 4));
454                         manifestResources.Position = savePosition;
455                 }
456
457                 public override Assembly Assembly
458                 {
459                         get { return asm; }
460                 }
461
462                 internal override Type FindType(TypeName name)
463                 {
464                         foreach (Type type in types)
465                         {
466                                 if (type.__Namespace == name.Namespace && type.__Name == name.Name)
467                                 {
468                                         return type;
469                                 }
470                         }
471                         return null;
472                 }
473
474                 internal override Type FindTypeIgnoreCase(TypeName lowerCaseName)
475                 {
476                         foreach (Type type in types)
477                         {
478                                 if (new TypeName(type.__Namespace, type.__Name).ToLowerInvariant() == lowerCaseName)
479                                 {
480                                         return type;
481                                 }
482                         }
483                         return null;
484                 }
485
486                 internal override void GetTypesImpl(List<Type> list)
487                 {
488                         foreach (Type type in types)
489                         {
490                                 if (type != moduleType)
491                                 {
492                                         list.Add(type);
493                                 }
494                         }
495                 }
496
497                 public ISymbolDocumentWriter DefineDocument(string url, Guid language, Guid languageVendor, Guid documentType)
498                 {
499                         return symbolWriter.DefineDocument(url, language, languageVendor, documentType);
500                 }
501
502                 public int __GetAssemblyToken(Assembly assembly)
503                 {
504                         return ImportAssemblyRef(assembly);
505                 }
506
507                 public TypeToken GetTypeToken(string name)
508                 {
509                         return new TypeToken(GetType(name, true, false).MetadataToken);
510                 }
511
512                 public TypeToken GetTypeToken(Type type)
513                 {
514                         if (type.Module == this)
515                         {
516                                 return new TypeToken(type.GetModuleBuilderToken());
517                         }
518                         else
519                         {
520                                 return new TypeToken(ImportType(type));
521                         }
522                 }
523
524                 internal int GetTypeTokenForMemberRef(Type type)
525                 {
526                         if (type.__IsMissing)
527                         {
528                                 return ImportType(type);
529                         }
530                         else if (type.IsGenericTypeDefinition)
531                         {
532                                 int token;
533                                 if (!memberRefTypeTokens.TryGetValue(type, out token))
534                                 {
535                                         ByteBuffer spec = new ByteBuffer(5);
536                                         Signature.WriteTypeSpec(this, spec, type);
537                                         token = 0x1B000000 | this.TypeSpec.AddRecord(this.Blobs.Add(spec));
538                                         memberRefTypeTokens.Add(type, token);
539                                 }
540                                 return token;
541                         }
542                         else if (type.IsModulePseudoType)
543                         {
544                                 return 0x1A000000 | this.ModuleRef.FindOrAddRecord(this.Strings.Add(type.Module.ScopeName));
545                         }
546                         else
547                         {
548                                 return GetTypeToken(type).Token;
549                         }
550                 }
551
552                 private static bool IsFromGenericTypeDefinition(MemberInfo member)
553                 {
554                         Type decl = member.DeclaringType;
555                         return decl != null && !decl.__IsMissing && decl.IsGenericTypeDefinition;
556                 }
557
558                 public FieldToken GetFieldToken(FieldInfo field)
559                 {
560                         // NOTE for some reason, when TypeBuilder.GetFieldToken() is used on a field in a generic type definition,
561                         // a memberref token is returned (confirmed on .NET) unlike for Get(Method|Constructor)Token which always
562                         // simply returns the MethodDef token (if the method is from the same module).
563                         FieldBuilder fb = field as FieldBuilder;
564                         if (fb != null && fb.Module == this && !IsFromGenericTypeDefinition(fb))
565                         {
566                                 return new FieldToken(fb.MetadataToken);
567                         }
568                         else
569                         {
570                                 return new FieldToken(ImportMember(field));
571                         }
572                 }
573
574                 public MethodToken GetMethodToken(MethodInfo method)
575                 {
576                         MethodBuilder mb = method as MethodBuilder;
577                         if (mb != null && mb.ModuleBuilder == this)
578                         {
579                                 return new MethodToken(mb.MetadataToken);
580                         }
581                         else
582                         {
583                                 return new MethodToken(ImportMember(method));
584                         }
585                 }
586
587                 // new in .NET 4.5
588                 public MethodToken GetMethodToken(MethodInfo method, IEnumerable<Type> optionalParameterTypes)
589                 {
590                         return __GetMethodToken(method, Util.ToArray(optionalParameterTypes), null);
591                 }
592
593                 public MethodToken __GetMethodToken(MethodInfo method, Type[] optionalParameterTypes, CustomModifiers[] customModifiers)
594                 {
595                         ByteBuffer sig = new ByteBuffer(16);
596                         method.MethodSignature.WriteMethodRefSig(this, sig, optionalParameterTypes, customModifiers);
597                         MemberRefTable.Record record = new MemberRefTable.Record();
598                         if (method.Module == this)
599                         {
600                                 record.Class = method.MetadataToken;
601                         }
602                         else
603                         {
604                                 record.Class = GetTypeTokenForMemberRef(method.DeclaringType ?? method.Module.GetModuleType());
605                         }
606                         record.Name = Strings.Add(method.Name);
607                         record.Signature = Blobs.Add(sig);
608                         return new MethodToken(0x0A000000 | MemberRef.FindOrAddRecord(record));
609                 }
610
611                 // when we refer to a method on a generic type definition in the IL stream,
612                 // we need to use a MemberRef (even if the method is in the same module)
613                 internal MethodToken GetMethodTokenForIL(MethodInfo method)
614                 {
615                         if (method.IsGenericMethodDefinition)
616                         {
617                                 method = method.MakeGenericMethod(method.GetGenericArguments());
618                         }
619                         if (IsFromGenericTypeDefinition(method))
620                         {
621                                 return new MethodToken(ImportMember(method));
622                         }
623                         else
624                         {
625                                 return GetMethodToken(method);
626                         }
627                 }
628
629                 public MethodToken GetConstructorToken(ConstructorInfo constructor)
630                 {
631                         if (constructor.Module == this && constructor.GetMethodInfo() is MethodBuilder)
632                         {
633                                 return new MethodToken(constructor.MetadataToken);
634                         }
635                         else
636                         {
637                                 return new MethodToken(ImportMember(constructor));
638                         }
639                 }
640
641                 // new in .NET 4.5
642                 public MethodToken GetConstructorToken(ConstructorInfo constructor, IEnumerable<Type> optionalParameterTypes)
643                 {
644                         return GetMethodToken(constructor.GetMethodInfo(), optionalParameterTypes);
645                 }
646
647                 public MethodToken __GetConstructorToken(ConstructorInfo constructor, Type[] optionalParameterTypes, CustomModifiers[] customModifiers)
648                 {
649                         return __GetMethodToken(constructor.GetMethodInfo(), optionalParameterTypes, customModifiers);
650                 }
651
652                 internal int ImportMember(MethodBase member)
653                 {
654                         int token;
655                         if (!importedMembers.TryGetValue(member, out token))
656                         {
657                                 token = member.ImportTo(this);
658                                 importedMembers.Add(member, token);
659                         }
660                         return token;
661                 }
662
663                 internal int ImportMember(FieldInfo member)
664                 {
665                         int token;
666                         if (!importedMembers.TryGetValue(member, out token))
667                         {
668                                 token = member.ImportTo(this);
669                                 importedMembers.Add(member, token);
670                         }
671                         return token;
672                 }
673
674                 internal int ImportMethodOrField(Type declaringType, string name, Signature sig)
675                 {
676                         int token;
677                         if (!importedMemberRefs.TryGetValue(new MemberRefKey(declaringType, name, sig), out token))
678                         {
679                                 MemberRefTable.Record rec = new MemberRefTable.Record();
680                                 rec.Class = GetTypeTokenForMemberRef(declaringType);
681                                 rec.Name = this.Strings.Add(name);
682                                 ByteBuffer bb = new ByteBuffer(16);
683                                 sig.WriteSig(this, bb);
684                                 rec.Signature = this.Blobs.Add(bb);
685                                 token = 0x0A000000 | this.MemberRef.AddRecord(rec);
686                                 importedMemberRefs.Add(new MemberRefKey(declaringType, name, sig), token);
687                         }
688                         return token;
689                 }
690
691                 internal int ImportType(Type type)
692                 {
693                         int token;
694                         if (!typeTokens.TryGetValue(type, out token))
695                         {
696                                 if (type.HasElementType || type.IsGenericTypeInstance || type.__IsFunctionPointer)
697                                 {
698                                         ByteBuffer spec = new ByteBuffer(5);
699                                         Signature.WriteTypeSpec(this, spec, type);
700                                         token = 0x1B000000 | this.TypeSpec.AddRecord(this.Blobs.Add(spec));
701                                 }
702                                 else
703                                 {
704                                         TypeRefTable.Record rec = new TypeRefTable.Record();
705                                         if (type.IsNested)
706                                         {
707                                                 rec.ResolutionScope = GetTypeToken(type.DeclaringType).Token;
708                                         }
709                                         else
710                                         {
711                                                 rec.ResolutionScope = ImportAssemblyRef(type.Assembly);
712                                         }
713                                         rec.TypeName = this.Strings.Add(type.__Name);
714                                         string ns = type.__Namespace;
715                                         rec.TypeNameSpace = ns == null ? 0 : this.Strings.Add(ns);
716                                         token = 0x01000000 | this.TypeRef.AddRecord(rec);
717                                 }
718                                 typeTokens.Add(type, token);
719                         }
720                         return token;
721                 }
722
723                 private int ImportAssemblyRef(Assembly asm)
724                 {
725                         int token;
726                         if (!referencedAssemblies.TryGetValue(asm, out token))
727                         {
728                                 // We can't write the AssemblyRef record here yet, because the identity of the assembly can still change
729                                 // (if it's an AssemblyBuilder).
730                                 token = AllocPseudoToken();
731                                 referencedAssemblies.Add(asm, token);
732                         }
733                         return token;
734                 }
735
736                 internal void FillAssemblyRefTable()
737                 {
738                         foreach (KeyValuePair<Assembly, int> kv in referencedAssemblies)
739                         {
740                                 if (IsPseudoToken(kv.Value))
741                                 {
742                                         RegisterTokenFixup(kv.Value, FindOrAddAssemblyRef(kv.Key.GetName(), false));
743                                 }
744                         }
745                 }
746
747                 private int FindOrAddAssemblyRef(AssemblyName name, bool alwaysAdd)
748                 {
749                         AssemblyRefTable.Record rec = new AssemblyRefTable.Record();
750                         Version ver = name.Version ?? new Version(0, 0, 0, 0);
751                         rec.MajorVersion = (ushort)ver.Major;
752                         rec.MinorVersion = (ushort)ver.Minor;
753                         rec.BuildNumber = (ushort)ver.Build;
754                         rec.RevisionNumber = (ushort)ver.Revision;
755                         rec.Flags = (int)(name.Flags & ~AssemblyNameFlags.PublicKey);
756                         const AssemblyNameFlags afPA_Specified = (AssemblyNameFlags)0x0080;
757                         const AssemblyNameFlags afPA_Mask = (AssemblyNameFlags)0x0070;
758                         if ((name.RawFlags & afPA_Specified) != 0)
759                         {
760                                 rec.Flags |= (int)(name.RawFlags & afPA_Mask);
761                         }
762                         byte[] publicKeyOrToken = null;
763                         if (usePublicKeyAssemblyReference)
764                         {
765                                 publicKeyOrToken = name.GetPublicKey();
766                         }
767                         if (publicKeyOrToken == null || publicKeyOrToken.Length == 0)
768                         {
769                                 publicKeyOrToken = name.GetPublicKeyToken() ?? Empty<byte>.Array;
770                         }
771                         else
772                         {
773                                 const int PublicKey = 0x0001;
774                                 rec.Flags |= PublicKey;
775                         }
776                         rec.PublicKeyOrToken = this.Blobs.Add(ByteBuffer.Wrap(publicKeyOrToken));
777                         rec.Name = this.Strings.Add(name.Name);
778                         rec.Culture = name.Culture == null ? 0 : this.Strings.Add(name.Culture);
779                         if (name.hash != null)
780                         {
781                                 rec.HashValue = this.Blobs.Add(ByteBuffer.Wrap(name.hash));
782                         }
783                         else
784                         {
785                                 rec.HashValue = 0;
786                         }
787                         return 0x23000000 | (alwaysAdd ? this.AssemblyRef.AddRecord(rec) : this.AssemblyRef.FindOrAddRecord(rec));
788                 }
789
790                 internal void WriteSymbolTokenMap()
791                 {
792                         for (int i = 0; i < resolvedTokens.Count; i++)
793                         {
794                                 int newToken = resolvedTokens[i];
795                                 // The symbol API doesn't support remapping arbitrary integers, the types have to be the same,
796                                 // so we copy the type from the newToken, because our pseudo tokens don't have a type.
797                                 // (see MethodToken.SymbolToken)
798                                 int oldToken = (i + 1) | (newToken & ~0xFFFFFF);
799                                 SymbolSupport.RemapToken(symbolWriter, oldToken, newToken);
800                         }
801                 }
802
803                 internal void RegisterTokenFixup(int pseudoToken, int realToken)
804                 {
805                         int index = -(pseudoToken + 1);
806                         while (resolvedTokens.Count <= index)
807                         {
808                                 resolvedTokens.Add(0);
809                         }
810                         resolvedTokens[index] = realToken;
811                 }
812
813                 internal bool IsPseudoToken(int token)
814                 {
815                         return token < 0;
816                 }
817
818                 internal int ResolvePseudoToken(int pseudoToken)
819                 {
820                         int index = -(pseudoToken + 1);
821                         return resolvedTokens[index];
822                 }
823
824                 internal void ApplyUnmanagedExports(ImageFileMachine imageFileMachine)
825                 {
826                         if (unmanagedExports.Count != 0)
827                         {
828                                 int type;
829                                 int size;
830                                 if (imageFileMachine == ImageFileMachine.I386)
831                                 {
832                                         type = 0x05;
833                                         size = 4;
834                                 }
835                                 else
836                                 {
837                                         type = 0x06;
838                                         size = 8;
839                                 }
840                                 List<MethodBuilder> methods = new List<MethodBuilder>();
841                                 for (int i = 0; i < unmanagedExports.Count; i++)
842                                 {
843                                         if (unmanagedExports[i].mb != null)
844                                         {
845                                                 methods.Add(unmanagedExports[i].mb);
846                                         }
847                                 }
848                                 if (methods.Count != 0)
849                                 {
850                                         RelativeVirtualAddress rva = __AddVTableFixups(methods.ToArray(), type);
851                                         for (int i = 0; i < unmanagedExports.Count; i++)
852                                         {
853                                                 if (unmanagedExports[i].mb != null)
854                                                 {
855                                                         UnmanagedExport exp = unmanagedExports[i];
856                                                         exp.rva = new RelativeVirtualAddress(rva.initializedDataOffset + (uint)(methods.IndexOf(unmanagedExports[i].mb) * size));
857                                                         unmanagedExports[i] = exp;
858                                                 }
859                                         }
860                                 }
861                         }
862                 }
863
864                 internal void FixupMethodBodyTokens()
865                 {
866                         int methodToken = 0x06000001;
867                         int fieldToken = 0x04000001;
868                         int parameterToken = 0x08000001;
869                         foreach (TypeBuilder type in types)
870                         {
871                                 type.ResolveMethodAndFieldTokens(ref methodToken, ref fieldToken, ref parameterToken);
872                         }
873                         foreach (int offset in tokenFixupOffsets)
874                         {
875                                 methodBodies.Position = offset;
876                                 int pseudoToken = methodBodies.GetInt32AtCurrentPosition();
877                                 methodBodies.Write(ResolvePseudoToken(pseudoToken));
878                         }
879                         foreach (VTableFixups fixup in vtablefixups)
880                         {
881                                 for (int i = 0; i < fixup.count; i++)
882                                 {
883                                         initializedData.Position = (int)fixup.initializedDataOffset + i * fixup.SlotWidth;
884                                         initializedData.Write(ResolvePseudoToken(initializedData.GetInt32AtCurrentPosition()));
885                                 }
886                         }
887                 }
888
889                 private int GetHeaderLength()
890                 {
891                         return
892                                 4 + // Signature
893                                 2 + // MajorVersion
894                                 2 + // MinorVersion
895                                 4 + // Reserved
896                                 4 + // ImageRuntimeVersion Length
897                                 StringToPaddedUTF8Length(asm.ImageRuntimeVersion) +
898                                 2 + // Flags
899                                 2 + // Streams
900                                 4 + // #~ Offset
901                                 4 + // #~ Size
902                                 4 + // StringToPaddedUTF8Length("#~")
903                                 4 + // #Strings Offset
904                                 4 + // #Strings Size
905                                 12 + // StringToPaddedUTF8Length("#Strings")
906                                 4 + // #US Offset
907                                 4 + // #US Size
908                                 4 + // StringToPaddedUTF8Length("#US")
909                                 4 + // #GUID Offset
910                                 4 + // #GUID Size
911                                 8 + // StringToPaddedUTF8Length("#GUID")
912                                 (Blobs.IsEmpty ? 0 :
913                                 (
914                                 4 + // #Blob Offset
915                                 4 + // #Blob Size
916                                 8   // StringToPaddedUTF8Length("#Blob")
917                                 ));
918                 }
919
920                 internal int MetadataLength
921                 {
922                         get
923                         {
924                                 return GetHeaderLength() + (Blobs.IsEmpty ? 0 : Blobs.Length) + Tables.Length + Strings.Length + UserStrings.Length + Guids.Length;
925                         }
926                 }
927
928                 internal void WriteMetadata(MetadataWriter mw)
929                 {
930                         mw.Write(0x424A5342);                   // Signature ("BSJB")
931                         mw.Write((ushort)1);                    // MajorVersion
932                         mw.Write((ushort)1);                    // MinorVersion
933                         mw.Write(0);                                    // Reserved
934                         byte[] version = StringToPaddedUTF8(asm.ImageRuntimeVersion);
935                         mw.Write(version.Length);               // Length
936                         mw.Write(version);
937                         mw.Write((ushort)0);                    // Flags
938                         // #Blob is the only optional heap
939                         if (Blobs.IsEmpty)
940                         {
941                                 mw.Write((ushort)4);            // Streams
942                         }
943                         else
944                         {
945                                 mw.Write((ushort)5);            // Streams
946                         }
947
948                         int offset = GetHeaderLength();
949
950                         // Streams
951                         mw.Write(offset);                               // Offset
952                         mw.Write(Tables.Length);                // Size
953                         mw.Write(StringToPaddedUTF8("#~"));
954                         offset += Tables.Length;
955
956                         mw.Write(offset);                               // Offset
957                         mw.Write(Strings.Length);               // Size
958                         mw.Write(StringToPaddedUTF8("#Strings"));
959                         offset += Strings.Length;
960
961                         mw.Write(offset);                               // Offset
962                         mw.Write(UserStrings.Length);   // Size
963                         mw.Write(StringToPaddedUTF8("#US"));
964                         offset += UserStrings.Length;
965
966                         mw.Write(offset);                               // Offset
967                         mw.Write(Guids.Length);                 // Size
968                         mw.Write(StringToPaddedUTF8("#GUID"));
969                         offset += Guids.Length;
970
971                         if (!Blobs.IsEmpty)
972                         {
973                                 mw.Write(offset);                               // Offset
974                                 mw.Write(Blobs.Length);                 // Size
975                                 mw.Write(StringToPaddedUTF8("#Blob"));
976                         }
977
978                         Tables.Write(mw);
979                         Strings.Write(mw);
980                         UserStrings.Write(mw);
981                         Guids.Write(mw);
982                         if (!Blobs.IsEmpty)
983                         {
984                                 Blobs.Write(mw);
985                         }
986                 }
987
988                 private static int StringToPaddedUTF8Length(string str)
989                 {
990                         return (System.Text.Encoding.UTF8.GetByteCount(str) + 4) & ~3;
991                 }
992
993                 private static byte[] StringToPaddedUTF8(string str)
994                 {
995                         byte[] buf = new byte[(System.Text.Encoding.UTF8.GetByteCount(str) + 4) & ~3];
996                         System.Text.Encoding.UTF8.GetBytes(str, 0, str.Length, buf, 0);
997                         return buf;
998                 }
999
1000                 internal override void ExportTypes(int fileToken, ModuleBuilder manifestModule)
1001                 {
1002                         manifestModule.ExportTypes(types.ToArray(), fileToken);
1003                 }
1004
1005                 internal void ExportTypes(Type[] types, int fileToken)
1006                 {
1007                         Dictionary<Type, int> declaringTypes = new Dictionary<Type, int>();
1008                         foreach (Type type in types)
1009                         {
1010                                 if (!type.IsModulePseudoType && IsVisible(type))
1011                                 {
1012                                         ExportedTypeTable.Record rec = new ExportedTypeTable.Record();
1013                                         rec.Flags = (int)type.Attributes;
1014                                         // LAMESPEC ECMA says that TypeDefId is a row index, but it should be a token
1015                                         rec.TypeDefId = type.MetadataToken;
1016                                         rec.TypeName = this.Strings.Add(type.__Name);
1017                                         string ns = type.__Namespace;
1018                                         rec.TypeNamespace = ns == null ? 0 : this.Strings.Add(ns);
1019                                         if (type.IsNested)
1020                                         {
1021                                                 rec.Implementation = declaringTypes[type.DeclaringType];
1022                                         }
1023                                         else
1024                                         {
1025                                                 rec.Implementation = fileToken;
1026                                         }
1027                                         int exportTypeToken = 0x27000000 | this.ExportedType.AddRecord(rec);
1028                                         declaringTypes.Add(type, exportTypeToken);
1029                                 }
1030                         }
1031                 }
1032
1033                 private static bool IsVisible(Type type)
1034                 {
1035                         // NOTE this is not the same as Type.IsVisible, because that doesn't take into account family access
1036                         return type.IsPublic || ((type.IsNestedFamily || type.IsNestedFamORAssem || type.IsNestedPublic) && IsVisible(type.DeclaringType));
1037                 }
1038
1039                 internal void AddConstant(int parentToken, object defaultValue)
1040                 {
1041                         ConstantTable.Record rec = new ConstantTable.Record();
1042                         rec.Parent = parentToken;
1043                         ByteBuffer val = new ByteBuffer(16);
1044                         if (defaultValue == null)
1045                         {
1046                                 rec.Type = Signature.ELEMENT_TYPE_CLASS;
1047                                 val.Write((int)0);
1048                         }
1049                         else if (defaultValue is bool)
1050                         {
1051                                 rec.Type = Signature.ELEMENT_TYPE_BOOLEAN;
1052                                 val.Write((bool)defaultValue ? (byte)1 : (byte)0);
1053                         }
1054                         else if (defaultValue is char)
1055                         {
1056                                 rec.Type = Signature.ELEMENT_TYPE_CHAR;
1057                                 val.Write((char)defaultValue);
1058                         }
1059                         else if (defaultValue is sbyte)
1060                         {
1061                                 rec.Type = Signature.ELEMENT_TYPE_I1;
1062                                 val.Write((sbyte)defaultValue);
1063                         }
1064                         else if (defaultValue is byte)
1065                         {
1066                                 rec.Type = Signature.ELEMENT_TYPE_U1;
1067                                 val.Write((byte)defaultValue);
1068                         }
1069                         else if (defaultValue is short)
1070                         {
1071                                 rec.Type = Signature.ELEMENT_TYPE_I2;
1072                                 val.Write((short)defaultValue);
1073                         }
1074                         else if (defaultValue is ushort)
1075                         {
1076                                 rec.Type = Signature.ELEMENT_TYPE_U2;
1077                                 val.Write((ushort)defaultValue);
1078                         }
1079                         else if (defaultValue is int)
1080                         {
1081                                 rec.Type = Signature.ELEMENT_TYPE_I4;
1082                                 val.Write((int)defaultValue);
1083                         }
1084                         else if (defaultValue is uint)
1085                         {
1086                                 rec.Type = Signature.ELEMENT_TYPE_U4;
1087                                 val.Write((uint)defaultValue);
1088                         }
1089                         else if (defaultValue is long)
1090                         {
1091                                 rec.Type = Signature.ELEMENT_TYPE_I8;
1092                                 val.Write((long)defaultValue);
1093                         }
1094                         else if (defaultValue is ulong)
1095                         {
1096                                 rec.Type = Signature.ELEMENT_TYPE_U8;
1097                                 val.Write((ulong)defaultValue);
1098                         }
1099                         else if (defaultValue is float)
1100                         {
1101                                 rec.Type = Signature.ELEMENT_TYPE_R4;
1102                                 val.Write((float)defaultValue);
1103                         }
1104                         else if (defaultValue is double)
1105                         {
1106                                 rec.Type = Signature.ELEMENT_TYPE_R8;
1107                                 val.Write((double)defaultValue);
1108                         }
1109                         else if (defaultValue is string)
1110                         {
1111                                 rec.Type = Signature.ELEMENT_TYPE_STRING;
1112                                 foreach (char c in (string)defaultValue)
1113                                 {
1114                                         val.Write(c);
1115                                 }
1116                         }
1117                         else if (defaultValue is DateTime)
1118                         {
1119                                 rec.Type = Signature.ELEMENT_TYPE_I8;
1120                                 val.Write(((DateTime)defaultValue).Ticks);
1121                         }
1122                         else
1123                         {
1124                                 throw new ArgumentException();
1125                         }
1126                         rec.Value = this.Blobs.Add(val);
1127                         this.Constant.AddRecord(rec);
1128                 }
1129
1130                 ModuleBuilder ITypeOwner.ModuleBuilder
1131                 {
1132                         get { return this; }
1133                 }
1134
1135                 public override Type ResolveType(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
1136                 {
1137                         if (genericTypeArguments != null || genericMethodArguments != null)
1138                         {
1139                                 throw new NotImplementedException();
1140                         }
1141                         return types[(metadataToken & 0xFFFFFF) - 1];
1142                 }
1143
1144                 public override MethodBase ResolveMethod(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
1145                 {
1146                         if (genericTypeArguments != null || genericMethodArguments != null)
1147                         {
1148                                 throw new NotImplementedException();
1149                         }
1150                         // this method is inefficient, but since it isn't used we don't care
1151                         if ((metadataToken >> 24) == MemberRefTable.Index)
1152                         {
1153                                 foreach (KeyValuePair<MemberInfo, int> kv in importedMembers)
1154                                 {
1155                                         if (kv.Value == metadataToken)
1156                                         {
1157                                                 return (MethodBase)kv.Key;
1158                                         }
1159                                 }
1160                         }
1161                         // HACK if we're given a SymbolToken, we need to convert back
1162                         if ((metadataToken & 0xFF000000) == 0x06000000)
1163                         {
1164                                 metadataToken = -(metadataToken & 0x00FFFFFF);
1165                         }
1166                         foreach (Type type in types)
1167                         {
1168                                 MethodBase method = ((TypeBuilder)type).LookupMethod(metadataToken);
1169                                 if (method != null)
1170                                 {
1171                                         return method;
1172                                 }
1173                         }
1174                         return ((TypeBuilder)moduleType).LookupMethod(metadataToken);
1175                 }
1176
1177                 public override FieldInfo ResolveField(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
1178                 {
1179                         throw new NotImplementedException();
1180                 }
1181
1182                 public override MemberInfo ResolveMember(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
1183                 {
1184                         throw new NotImplementedException();
1185                 }
1186
1187                 public override string ResolveString(int metadataToken)
1188                 {
1189                         throw new NotImplementedException();
1190                 }
1191
1192                 public override string FullyQualifiedName
1193                 {
1194                         get { return Path.GetFullPath(Path.Combine(asm.dir, fileName)); }
1195                 }
1196
1197                 public override string Name
1198                 {
1199                         get { return fileName; }
1200                 }
1201
1202                 public override Guid ModuleVersionId
1203                 {
1204                         get { return mvid; }
1205                 }
1206
1207                 public void __SetModuleVersionId(Guid guid)
1208                 {
1209                         mvid = guid;
1210                 }
1211
1212                 public override Type[] __ResolveOptionalParameterTypes(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments, out CustomModifiers[] customModifiers)
1213                 {
1214                         throw new NotImplementedException();
1215                 }
1216
1217                 public override string ScopeName
1218                 {
1219                         get { return moduleName; }
1220                 }
1221
1222                 public ISymbolWriter GetSymWriter()
1223                 {
1224                         return symbolWriter;
1225                 }
1226
1227                 public void DefineUnmanagedResource(string resourceFileName)
1228                 {
1229                         // This method reads the specified resource file (Win32 .res file) and converts it into the appropriate format and embeds it in the .rsrc section,
1230                         // also setting the Resource Directory entry.
1231                         unmanagedResources = new ResourceSection();
1232                         unmanagedResources.ExtractResources(System.IO.File.ReadAllBytes(resourceFileName));
1233                 }
1234
1235                 public bool IsTransient()
1236                 {
1237                         return false;
1238                 }
1239
1240                 public void SetUserEntryPoint(MethodInfo entryPoint)
1241                 {
1242                         int token = entryPoint.MetadataToken;
1243                         if (token < 0)
1244                         {
1245                                 token = -token | 0x06000000;
1246                         }
1247                         if (symbolWriter != null)
1248                         {
1249                                 symbolWriter.SetUserEntryPoint(new SymbolToken(token));
1250                         }
1251                 }
1252
1253                 public StringToken GetStringConstant(string str)
1254                 {
1255                         return new StringToken(this.UserStrings.Add(str) | (0x70 << 24));
1256                 }
1257
1258                 public SignatureToken GetSignatureToken(SignatureHelper sigHelper)
1259                 {
1260                         return new SignatureToken(this.StandAloneSig.FindOrAddRecord(this.Blobs.Add(sigHelper.GetSignature(this))) | (StandAloneSigTable.Index << 24));
1261                 }
1262
1263                 public SignatureToken GetSignatureToken(byte[] sigBytes, int sigLength)
1264                 {
1265                         return new SignatureToken(this.StandAloneSig.FindOrAddRecord(this.Blobs.Add(ByteBuffer.Wrap(sigBytes, sigLength))) | (StandAloneSigTable.Index << 24));
1266                 }
1267
1268                 public MethodInfo GetArrayMethod(Type arrayClass, string methodName, CallingConventions callingConvention, Type returnType, Type[] parameterTypes)
1269                 {
1270                         return new ArrayMethod(this, arrayClass, methodName, callingConvention, returnType, parameterTypes);
1271                 }
1272
1273                 public MethodToken GetArrayMethodToken(Type arrayClass, string methodName, CallingConventions callingConvention, Type returnType, Type[] parameterTypes)
1274                 {
1275                         return GetMethodToken(GetArrayMethod(arrayClass, methodName, callingConvention, returnType, parameterTypes));
1276                 }
1277
1278                 internal override Type GetModuleType()
1279                 {
1280                         return moduleType;
1281                 }
1282
1283                 internal override IKVM.Reflection.Reader.ByteReader GetBlob(int blobIndex)
1284                 {
1285                         return Blobs.GetBlob(blobIndex);
1286                 }
1287
1288                 internal int GetSignatureBlobIndex(Signature sig)
1289                 {
1290                         ByteBuffer bb = new ByteBuffer(16);
1291                         sig.WriteSig(this, bb);
1292                         return this.Blobs.Add(bb);
1293                 }
1294
1295                 // non-standard API
1296                 public new long __ImageBase
1297                 {
1298                         get { return imageBaseAddress; }
1299                         set { imageBaseAddress = value; }
1300                 }
1301
1302                 protected override long GetImageBaseImpl()
1303                 {
1304                         return imageBaseAddress;
1305                 }
1306
1307                 public new long __StackReserve
1308                 {
1309                         get { return stackReserve; }
1310                         set { stackReserve = value; }
1311                 }
1312
1313                 protected override long GetStackReserveImpl()
1314                 {
1315                         return stackReserve;
1316                 }
1317
1318                 [Obsolete("Use __StackReserve property.")]
1319                 public void __SetStackReserve(long stackReserve)
1320                 {
1321                         __StackReserve = stackReserve;
1322                 }
1323
1324                 internal ulong GetStackReserve(ulong defaultValue)
1325                 {
1326                         return stackReserve == -1 ? defaultValue : (ulong)stackReserve;
1327                 }
1328
1329                 public new int __FileAlignment
1330                 {
1331                         get { return fileAlignment; }
1332                         set { fileAlignment = value; }
1333                 }
1334
1335                 protected override int GetFileAlignmentImpl()
1336                 {
1337                         return fileAlignment;
1338                 }
1339
1340                 public new DllCharacteristics __DllCharacteristics
1341                 {
1342                         get { return dllCharacteristics; }
1343                         set { dllCharacteristics = value; }
1344                 }
1345
1346                 protected override DllCharacteristics GetDllCharacteristicsImpl()
1347                 {
1348                         return dllCharacteristics;
1349                 }
1350
1351                 public override int MDStreamVersion
1352                 {
1353                         get { return asm.mdStreamVersion; }
1354                 }
1355
1356                 private int AddTypeRefByName(int resolutionScope, string ns, string name)
1357                 {
1358                         TypeRefTable.Record rec = new TypeRefTable.Record();
1359                         rec.ResolutionScope = resolutionScope;
1360                         rec.TypeName = this.Strings.Add(name);
1361                         rec.TypeNameSpace = ns == null ? 0 : this.Strings.Add(ns);
1362                         return 0x01000000 | this.TypeRef.AddRecord(rec);
1363                 }
1364
1365                 public void __Save(PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine)
1366                 {
1367                         SaveImpl(null, portableExecutableKind, imageFileMachine);
1368                 }
1369
1370                 public void __Save(Stream stream, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine)
1371                 {
1372                         if (!stream.CanRead || !stream.CanWrite || !stream.CanSeek || stream.Position != 0)
1373                         {
1374                                 throw new ArgumentException("Stream must support read/write/seek and current position must be zero.", "stream");
1375                         }
1376                         SaveImpl(stream, portableExecutableKind, imageFileMachine);
1377                 }
1378
1379                 private void SaveImpl(Stream streamOrNull, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine)
1380                 {
1381                         PopulatePropertyAndEventTables();
1382                         IList<CustomAttributeData> attributes = asm.GetCustomAttributesData(null);
1383                         if (attributes.Count > 0)
1384                         {
1385                                 int mscorlib = ImportAssemblyRef(universe.Mscorlib);
1386                                 int[] placeholderTokens = new int[4];
1387                                 string[] placeholderTypeNames = new string[] { "AssemblyAttributesGoHere", "AssemblyAttributesGoHereM", "AssemblyAttributesGoHereS", "AssemblyAttributesGoHereSM" };
1388                                 foreach (CustomAttributeData cad in attributes)
1389                                 {
1390                                         int index;
1391                                         if (cad.Constructor.DeclaringType.BaseType == universe.System_Security_Permissions_CodeAccessSecurityAttribute)
1392                                         {
1393                                                 if (cad.Constructor.DeclaringType.IsAllowMultipleCustomAttribute)
1394                                                 {
1395                                                         index = 3;
1396                                                 }
1397                                                 else
1398                                                 {
1399                                                         index = 2;
1400                                                 }
1401                                         }
1402                                         else if (cad.Constructor.DeclaringType.IsAllowMultipleCustomAttribute)
1403                                         {
1404                                                 index = 1;
1405                                         }
1406                                         else
1407                                         {
1408                                                 index = 0;
1409                                         }
1410                                         if (placeholderTokens[index] == 0)
1411                                         {
1412                                                 // we manually add a TypeRef without looking it up in mscorlib, because Mono and Silverlight's mscorlib don't have these types
1413                                                 placeholderTokens[index] = AddTypeRefByName(mscorlib, "System.Runtime.CompilerServices", placeholderTypeNames[index]);
1414                                         }
1415                                         SetCustomAttribute(placeholderTokens[index], cad.__ToBuilder());
1416                                 }
1417                         }
1418                         FillAssemblyRefTable();
1419                         ModuleWriter.WriteModule(null, null, this, PEFileKinds.Dll, portableExecutableKind, imageFileMachine, unmanagedResources, 0, streamOrNull);
1420                 }
1421
1422                 public void __AddAssemblyReference(AssemblyName assemblyName)
1423                 {
1424                         __AddAssemblyReference(assemblyName, null);
1425                 }
1426
1427                 public void __AddAssemblyReference(AssemblyName assemblyName, Assembly assembly)
1428                 {
1429                         if (referencedAssemblyNames == null)
1430                         {
1431                                 referencedAssemblyNames = new List<AssemblyName>();
1432                         }
1433                         referencedAssemblyNames.Add((AssemblyName)assemblyName.Clone());
1434                         int token = FindOrAddAssemblyRef(assemblyName, true);
1435                         if (assembly != null)
1436                         {
1437                                 referencedAssemblies.Add(assembly, token);
1438                         }
1439                 }
1440
1441                 public override AssemblyName[] __GetReferencedAssemblies()
1442                 {
1443                         List<AssemblyName> list = new List<AssemblyName>();
1444                         if (referencedAssemblyNames != null)
1445                         {
1446                                 foreach (AssemblyName name in referencedAssemblyNames)
1447                                 {
1448                                         if (!list.Contains(name))
1449                                         {
1450                                                 list.Add(name);
1451                                         }
1452                                 }
1453                         }
1454                         foreach (Assembly asm in referencedAssemblies.Keys)
1455                         {
1456                                 AssemblyName name = asm.GetName();
1457                                 if (!list.Contains(name))
1458                                 {
1459                                         list.Add(name);
1460                                 }
1461                         }
1462                         return list.ToArray();
1463                 }
1464
1465                 public void __AddModuleReference(string module)
1466                 {
1467                         this.ModuleRef.FindOrAddRecord(module == null ? 0 : this.Strings.Add(module));
1468                 }
1469
1470                 public override string[] __GetReferencedModules()
1471                 {
1472                         string[] arr = new string[this.ModuleRef.RowCount];
1473                         for (int i = 0; i < arr.Length; i++)
1474                         {
1475                                 arr[i] = this.Strings.Find(this.ModuleRef.records[i]);
1476                         }
1477                         return arr;
1478                 }
1479
1480                 public override Type[] __GetReferencedTypes()
1481                 {
1482                         List<Type> list = new List<Type>();
1483                         foreach (KeyValuePair<Type, int> kv in typeTokens)
1484                         {
1485                                 if (kv.Value >> 24 == TypeRefTable.Index)
1486                                 {
1487                                         list.Add(kv.Key);
1488                                 }
1489                         }
1490                         return list.ToArray();
1491                 }
1492
1493                 public override Type[] __GetExportedTypes()
1494                 {
1495                         throw new NotImplementedException();
1496                 }
1497
1498                 public int __AddModule(int flags, string name, byte[] hash)
1499                 {
1500                         FileTable.Record file = new FileTable.Record();
1501                         file.Flags = flags;
1502                         file.Name = this.Strings.Add(name);
1503                         file.HashValue = this.Blobs.Add(ByteBuffer.Wrap(hash));
1504                         return 0x26000000 + this.File.AddRecord(file);
1505                 }
1506
1507                 public int __AddManifestResource(int offset, ResourceAttributes flags, string name, int implementation)
1508                 {
1509                         ManifestResourceTable.Record res = new ManifestResourceTable.Record();
1510                         res.Offset = offset;
1511                         res.Flags = (int)flags;
1512                         res.Name = this.Strings.Add(name);
1513                         res.Implementation = implementation;
1514                         return 0x28000000 + this.ManifestResource.AddRecord(res);
1515                 }
1516
1517                 public void __SetCustomAttributeFor(int token, CustomAttributeBuilder customBuilder)
1518                 {
1519                         SetCustomAttribute(token, customBuilder);
1520                 }
1521
1522                 public RelativeVirtualAddress __AddVTableFixups(MethodBuilder[] methods, int type)
1523                 {
1524                         initializedData.Align(8);
1525                         VTableFixups fixups;
1526                         fixups.initializedDataOffset = (uint)initializedData.Position;
1527                         fixups.count = (ushort)methods.Length;
1528                         fixups.type = (ushort)type;
1529                         foreach (MethodBuilder mb in methods)
1530                         {
1531                                 initializedData.Write(mb.MetadataToken);
1532                                 if (fixups.SlotWidth == 8)
1533                                 {
1534                                         initializedData.Write(0);
1535                                 }
1536                         }
1537                         vtablefixups.Add(fixups);
1538                         return new RelativeVirtualAddress(fixups.initializedDataOffset);
1539                 }
1540
1541                 public void __AddUnmanagedExportStub(string name, int ordinal, RelativeVirtualAddress rva)
1542                 {
1543                         AddUnmanagedExport(name, ordinal, null, rva);
1544                 }
1545
1546                 internal void AddUnmanagedExport(string name, int ordinal, MethodBuilder methodBuilder, RelativeVirtualAddress rva)
1547                 {
1548                         UnmanagedExport export;
1549                         export.name = name;
1550                         export.ordinal = ordinal;
1551                         export.mb = methodBuilder;
1552                         export.rva = rva;
1553                         unmanagedExports.Add(export);
1554                 }
1555
1556                 internal void SetInterfaceImplementationCustomAttribute(TypeBuilder typeBuilder, Type interfaceType, CustomAttributeBuilder cab)
1557                 {
1558                         // NOTE since interfaceimpls are extremely common and custom attributes on them are extremely rare,
1559                         // we store (and resolve) the custom attributes in such away as to avoid impacting the common case performance
1560                         if (interfaceImplCustomAttributes == null)
1561                         {
1562                                 interfaceImplCustomAttributes = new List<InterfaceImplCustomAttribute>();
1563                         }
1564                         InterfaceImplCustomAttribute rec;
1565                         rec.type = typeBuilder.MetadataToken;
1566                         int token = GetTypeToken(interfaceType).Token;
1567                         switch (token >> 24)
1568                         {
1569                                 case TypeDefTable.Index:
1570                                         token = (token & 0xFFFFFF) << 2 | 0;
1571                                         break;
1572                                 case TypeRefTable.Index:
1573                                         token = (token & 0xFFFFFF) << 2 | 1;
1574                                         break;
1575                                 case TypeSpecTable.Index:
1576                                         token = (token & 0xFFFFFF) << 2 | 2;
1577                                         break;
1578                                 default:
1579                                         throw new InvalidOperationException();
1580                         }
1581                         rec.interfaceType = token;
1582                         rec.pseudoToken = AllocPseudoToken();
1583                         interfaceImplCustomAttributes.Add(rec);
1584                         SetCustomAttribute(rec.pseudoToken, cab);
1585                 }
1586
1587                 internal void ResolveInterfaceImplPseudoTokens()
1588                 {
1589                         if (interfaceImplCustomAttributes != null)
1590                         {
1591                                 foreach (InterfaceImplCustomAttribute rec in interfaceImplCustomAttributes)
1592                                 {
1593                                         for (int i = 0; i < InterfaceImpl.records.Length; i++)
1594                                         {
1595                                                 if (InterfaceImpl.records[i].Class == rec.type && InterfaceImpl.records[i].Interface == rec.interfaceType)
1596                                                 {
1597                                                         RegisterTokenFixup(rec.pseudoToken, (InterfaceImplTable.Index << 24) | (i + 1));
1598                                                         break;
1599                                                 }
1600                                         }
1601                                 }
1602                         }
1603                 }
1604
1605                 internal void FixupPseudoToken(ref int token)
1606                 {
1607                         if (IsPseudoToken(token))
1608                         {
1609                                 token = ResolvePseudoToken(token);
1610                         }
1611                 }
1612         }
1613
1614         struct UnmanagedExport
1615         {
1616                 internal string name;
1617                 internal int ordinal;
1618                 internal RelativeVirtualAddress rva;
1619                 internal MethodBuilder mb;
1620         }
1621
1622         public struct RelativeVirtualAddress
1623         {
1624                 internal readonly uint initializedDataOffset;
1625
1626                 internal RelativeVirtualAddress(uint initializedDataOffset)
1627                 {
1628                         this.initializedDataOffset = initializedDataOffset;
1629                 }
1630
1631                 public static RelativeVirtualAddress operator +(RelativeVirtualAddress rva, int offset)
1632                 {
1633                         return new RelativeVirtualAddress(rva.initializedDataOffset + (uint)offset);
1634                 }
1635         }
1636
1637         class ArrayMethod : MethodInfo
1638         {
1639                 private readonly Module module;
1640                 private readonly Type arrayClass;
1641                 private readonly string methodName;
1642                 private readonly CallingConventions callingConvention;
1643                 private readonly Type returnType;
1644                 protected readonly Type[] parameterTypes;
1645                 private MethodSignature methodSignature;
1646
1647                 internal ArrayMethod(Module module, Type arrayClass, string methodName, CallingConventions callingConvention, Type returnType, Type[] parameterTypes)
1648                 {
1649                         this.module = module;
1650                         this.arrayClass = arrayClass;
1651                         this.methodName = methodName;
1652                         this.callingConvention = callingConvention;
1653                         this.returnType = returnType ?? module.universe.System_Void;
1654                         this.parameterTypes = Util.Copy(parameterTypes);
1655                 }
1656
1657                 public override MethodBody GetMethodBody()
1658                 {
1659                         throw new InvalidOperationException();
1660                 }
1661
1662                 public override int __MethodRVA
1663                 {
1664                         get { throw new InvalidOperationException(); }
1665                 }
1666
1667                 public override MethodImplAttributes GetMethodImplementationFlags()
1668                 {
1669                         throw new NotSupportedException();
1670                 }
1671
1672                 public override ParameterInfo[] GetParameters()
1673                 {
1674                         throw new NotSupportedException();
1675                 }
1676
1677                 internal override int ImportTo(ModuleBuilder module)
1678                 {
1679                         return module.ImportMethodOrField(arrayClass, methodName, MethodSignature);
1680                 }
1681
1682                 public override MethodAttributes Attributes
1683                 {
1684                         get { throw new NotSupportedException(); }
1685                 }
1686
1687                 public override CallingConventions CallingConvention
1688                 {
1689                         get { return callingConvention; }
1690                 }
1691
1692                 public override Type DeclaringType
1693                 {
1694                         get { return arrayClass; }
1695                 }
1696
1697                 internal override MethodSignature MethodSignature
1698                 {
1699                         get
1700                         {
1701                                 if (methodSignature == null)
1702                                 {
1703                                         methodSignature = MethodSignature.MakeFromBuilder(returnType, parameterTypes, new PackedCustomModifiers(), callingConvention, 0);
1704                                 }
1705                                 return methodSignature;
1706                         }
1707                 }
1708
1709                 public override Module Module
1710                 {
1711                         // like .NET, we return the module that GetArrayMethod was called on, not the module associated with the array type
1712                         get { return module; }
1713                 }
1714
1715                 public override string Name
1716                 {
1717                         get { return methodName; }
1718                 }
1719
1720                 internal override int ParameterCount
1721                 {
1722                         get { return parameterTypes.Length; }
1723                 }
1724
1725                 public override ParameterInfo ReturnParameter
1726                 {
1727                         get { throw new NotImplementedException(); }
1728                 }
1729
1730                 public override Type ReturnType
1731                 {
1732                         get { return returnType; }
1733                 }
1734
1735                 internal override bool HasThis
1736                 {
1737                         get { return (callingConvention & (CallingConventions.HasThis | CallingConventions.ExplicitThis)) == CallingConventions.HasThis; }
1738                 }
1739         }
1740 }