Wrap always_inline and noinline attributes in compiler checks and use MSVC equivalent.
[mono.git] / mcs / class / IKVM.Reflection / Reader / ModuleReader.cs
1 /*
2   Copyright (C) 2009-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.IO;
26 using System.Text;
27 using System.Collections.Generic;
28 using IKVM.Reflection.Metadata;
29
30 namespace IKVM.Reflection.Reader
31 {
32         sealed class StreamHeader
33         {
34                 internal uint Offset;
35                 internal uint Size;
36                 internal string Name;
37
38                 internal void Read(BinaryReader br)
39                 {
40                         Offset = br.ReadUInt32();
41                         Size = br.ReadUInt32();
42                         byte[] buf = new byte[32];
43                         byte b;
44                         int len = 0;
45                         while ((b = br.ReadByte()) != 0)
46                         {
47                                 buf[len++] = b;
48                         }
49                         Name = Encoding.UTF8.GetString(buf, 0, len); ;
50                         int padding = -1 + ((len + 4) & ~3) - len;
51                         br.BaseStream.Seek(padding, SeekOrigin.Current);
52                 }
53         }
54
55         sealed class ModuleReader : Module
56         {
57                 internal readonly Stream stream;
58                 private readonly string location;
59                 private Assembly assembly;
60                 private readonly PEReader peFile = new PEReader();
61                 private readonly CliHeader cliHeader = new CliHeader();
62                 private string imageRuntimeVersion;
63                 private int metadataStreamVersion;
64                 private byte[] stringHeap;
65                 private byte[] blobHeap;
66                 private byte[] userStringHeap;
67                 private byte[] guidHeap;
68                 private TypeDefImpl[] typeDefs;
69                 private TypeDefImpl moduleType;
70                 private Assembly[] assemblyRefs;
71                 private Type[] typeRefs;
72                 private Type[] typeSpecs;
73                 private FieldInfo[] fields;
74                 private MethodBase[] methods;
75                 private MemberInfo[] memberRefs;
76                 private Dictionary<int, string> strings = new Dictionary<int, string>();
77                 private Dictionary<TypeName, Type> types = new Dictionary<TypeName, Type>();
78                 private Dictionary<TypeName, LazyForwardedType> forwardedTypes = new Dictionary<TypeName, LazyForwardedType>();
79
80                 private sealed class LazyForwardedType
81                 {
82                         private readonly int assemblyRef;
83                         private Type type;
84
85                         internal LazyForwardedType(int assemblyRef)
86                         {
87                                 this.assemblyRef = assemblyRef;
88                         }
89
90                         internal Type GetType(ModuleReader module, TypeName typeName)
91                         {
92                                 if (type == null)
93                                 {
94                                         Assembly asm = module.ResolveAssemblyRef(assemblyRef);
95                                         type = asm.ResolveType(typeName);
96                                         if (type == null)
97                                         {
98                                                 throw new TypeLoadException(typeName.ToString());
99                                         }
100                                 }
101                                 return type;
102                         }
103                 }
104
105                 internal ModuleReader(AssemblyReader assembly, Universe universe, Stream stream, string location)
106                         : base(universe)
107                 {
108                         this.stream = stream;
109                         this.location = location;
110                         Read();
111                         if (assembly == null && AssemblyTable.records.Length != 0)
112                         {
113                                 assembly = new AssemblyReader(location, this);
114                         }
115                         this.assembly = assembly;
116                 }
117
118                 private void Read()
119                 {
120                         BinaryReader br = new BinaryReader(stream);
121                         peFile.Read(br);
122                         stream.Seek(peFile.RvaToFileOffset(peFile.GetComDescriptorVirtualAddress()), SeekOrigin.Begin);
123                         cliHeader.Read(br);
124                         stream.Seek(peFile.RvaToFileOffset(cliHeader.MetaData.VirtualAddress), SeekOrigin.Begin);
125                         foreach (StreamHeader sh in ReadStreamHeaders(br, out imageRuntimeVersion))
126                         {
127                                 switch (sh.Name)
128                                 {
129                                         case "#Strings":
130                                                 stringHeap = ReadHeap(stream, sh);
131                                                 break;
132                                         case "#Blob":
133                                                 blobHeap = ReadHeap(stream, sh);
134                                                 break;
135                                         case "#US":
136                                                 userStringHeap = ReadHeap(stream, sh);
137                                                 break;
138                                         case "#GUID":
139                                                 guidHeap = ReadHeap(stream, sh);
140                                                 break;
141                                         case "#~":
142                                         case "#-":
143                                                 stream.Seek(peFile.RvaToFileOffset(cliHeader.MetaData.VirtualAddress + sh.Offset), SeekOrigin.Begin);
144                                                 ReadTables(br);
145                                                 break;
146                                         default:
147                                                 throw new BadImageFormatException("Unsupported stream: " + sh.Name);
148                                 }
149                         }
150                 }
151
152                 internal void SetAssembly(Assembly assembly)
153                 {
154                         this.assembly = assembly;
155                 }
156
157                 private static StreamHeader[] ReadStreamHeaders(BinaryReader br, out string Version)
158                 {
159                         uint Signature = br.ReadUInt32();
160                         if (Signature != 0x424A5342)
161                         {
162                                 throw new BadImageFormatException("Invalid metadata signature");
163                         }
164                         /*ushort MajorVersion =*/ br.ReadUInt16();
165                         /*ushort MinorVersion =*/ br.ReadUInt16();
166                         /*uint Reserved =*/ br.ReadUInt32();
167                         uint Length = br.ReadUInt32();
168                         byte[] buf = br.ReadBytes((int)Length);
169                         Version = Encoding.UTF8.GetString(buf).TrimEnd('\u0000');
170                         /*ushort Flags =*/ br.ReadUInt16();
171                         ushort Streams = br.ReadUInt16();
172                         StreamHeader[] streamHeaders = new StreamHeader[Streams];
173                         for (int i = 0; i < streamHeaders.Length; i++)
174                         {
175                                 streamHeaders[i] = new StreamHeader();
176                                 streamHeaders[i].Read(br);
177                         }
178                         return streamHeaders;
179                 }
180
181                 private void ReadTables(BinaryReader br)
182                 {
183                         Table[] tables = GetTables();
184                         /*uint Reserved0 =*/ br.ReadUInt32();
185                         byte MajorVersion = br.ReadByte();
186                         byte MinorVersion = br.ReadByte();
187                         metadataStreamVersion = MajorVersion << 16 | MinorVersion;
188                         byte HeapSizes = br.ReadByte();
189                         /*byte Reserved7 =*/ br.ReadByte();
190                         ulong Valid = br.ReadUInt64();
191                         ulong Sorted = br.ReadUInt64();
192                         for (int i = 0; i < 64; i++)
193                         {
194                                 if ((Valid & (1UL << i)) != 0)
195                                 {
196                                         tables[i].Sorted = (Sorted & (1UL << i)) != 0;
197                                         tables[i].RowCount = br.ReadInt32();
198                                 }
199                                 else if (tables[i] != null)
200                                 {
201                                         tables[i].RowCount = 0;
202                                 }
203                         }
204                         MetadataReader mr = new MetadataReader(this, br.BaseStream, HeapSizes);
205                         for (int i = 0; i < 64; i++)
206                         {
207                                 if ((Valid & (1UL << i)) != 0)
208                                 {
209                                         tables[i].Read(mr);
210                                 }
211                         }
212                         if (ParamPtr.RowCount != 0)
213                         {
214                                 throw new NotImplementedException("ParamPtr table support has not yet been implemented.");
215                         }
216                 }
217
218                 private byte[] ReadHeap(Stream stream, StreamHeader sh)
219                 {
220                         byte[] buf = new byte[sh.Size];
221                         stream.Seek(peFile.RvaToFileOffset(cliHeader.MetaData.VirtualAddress + sh.Offset), SeekOrigin.Begin);
222                         for (int pos = 0; pos < buf.Length; )
223                         {
224                                 int read = stream.Read(buf, pos, buf.Length - pos);
225                                 if (read == 0)
226                                 {
227                                         throw new BadImageFormatException();
228                                 }
229                                 pos += read;
230                         }
231                         return buf;
232                 }
233
234                 internal void SeekRVA(int rva)
235                 {
236                         stream.Seek(peFile.RvaToFileOffset((uint)rva), SeekOrigin.Begin);
237                 }
238
239                 internal override void GetTypesImpl(List<Type> list)
240                 {
241                         PopulateTypeDef();
242                         foreach (TypeDefImpl type in typeDefs)
243                         {
244                                 if (type != moduleType)
245                                 {
246                                         list.Add(type);
247                                 }
248                         }
249                 }
250
251                 private void PopulateTypeDef()
252                 {
253                         if (typeDefs == null)
254                         {
255                                 typeDefs = new TypeDefImpl[TypeDef.records.Length];
256                                 for (int i = 0; i < typeDefs.Length; i++)
257                                 {
258                                         TypeDefImpl type = new TypeDefImpl(this, i);
259                                         typeDefs[i] = type;
260                                         if (type.IsModulePseudoType)
261                                         {
262                                                 moduleType = type;
263                                         }
264                                         else if (!type.IsNestedByFlags)
265                                         {
266                                                 types.Add(new TypeName(type.__Namespace, type.__Name), type);
267                                         }
268                                 }
269                                 // add forwarded types to forwardedTypes dictionary (because Module.GetType(string) should return them)
270                                 for (int i = 0; i < ExportedType.records.Length; i++)
271                                 {
272                                         int implementation = ExportedType.records[i].Implementation;
273                                         if (implementation >> 24 == AssemblyRefTable.Index)
274                                         {
275                                                 TypeName typeName = GetTypeName(ExportedType.records[i].TypeNamespace, ExportedType.records[i].TypeName);
276                                                 forwardedTypes.Add(typeName, new LazyForwardedType((implementation & 0xFFFFFF) - 1));
277                                         }
278                                 }
279                         }
280                 }
281
282                 internal override string GetString(int index)
283                 {
284                         if (index == 0)
285                         {
286                                 return null;
287                         }
288                         string str;
289                         if (!strings.TryGetValue(index, out str))
290                         {
291                                 int len = 0;
292                                 while (stringHeap[index + len] != 0)
293                                 {
294                                         len++;
295                                 }
296                                 str = Encoding.UTF8.GetString(stringHeap, index, len);
297                                 strings.Add(index, str);
298                         }
299                         return str;
300                 }
301
302                 private static int ReadCompressedInt(byte[] buffer, ref int offset)
303                 {
304                         byte b1 = buffer[offset++];
305                         if (b1 <= 0x7F)
306                         {
307                                 return b1;
308                         }
309                         else if ((b1 & 0xC0) == 0x80)
310                         {
311                                 byte b2 = buffer[offset++];
312                                 return ((b1 & 0x3F) << 8) | b2;
313                         }
314                         else
315                         {
316                                 byte b2 = buffer[offset++];
317                                 byte b3 = buffer[offset++];
318                                 byte b4 = buffer[offset++];
319                                 return ((b1 & 0x3F) << 24) + (b2 << 16) + (b3 << 8) + b4;
320                         }
321                 }
322
323                 internal byte[] GetBlobCopy(int blobIndex)
324                 {
325                         int len = ReadCompressedInt(blobHeap, ref blobIndex);
326                         byte[] buf = new byte[len];
327                         Buffer.BlockCopy(blobHeap, blobIndex, buf, 0, len);
328                         return buf;
329                 }
330
331                 internal override ByteReader GetBlob(int blobIndex)
332                 {
333                         return ByteReader.FromBlob(blobHeap, blobIndex);
334                 }
335
336                 public override string ResolveString(int metadataToken)
337                 {
338                         string str;
339                         if (!strings.TryGetValue(metadataToken, out str))
340                         {
341                                 if ((metadataToken >> 24) != 0x70)
342                                 {
343                                         throw TokenOutOfRangeException(metadataToken);
344                                 }
345                                 int index = metadataToken & 0xFFFFFF;
346                                 int len = ReadCompressedInt(userStringHeap, ref index) & ~1;
347                                 StringBuilder sb = new StringBuilder(len / 2);
348                                 for (int i = 0; i < len; i += 2)
349                                 {
350                                         char ch = (char)(userStringHeap[index + i] | userStringHeap[index + i + 1] << 8);
351                                         sb.Append(ch);
352                                 }
353                                 str = sb.ToString();
354                                 strings.Add(metadataToken, str);
355                         }
356                         return str;
357                 }
358
359                 internal override Type ResolveType(int metadataToken, IGenericContext context)
360                 {
361                         int index = (metadataToken & 0xFFFFFF) - 1;
362                         if (index < 0)
363                         {
364                                 throw TokenOutOfRangeException(metadataToken);
365                         }
366                         else if ((metadataToken >> 24) == TypeDefTable.Index && index < TypeDef.RowCount)
367                         {
368                                 PopulateTypeDef();
369                                 return typeDefs[index];
370                         }
371                         else if ((metadataToken >> 24) == TypeRefTable.Index && index < TypeRef.RowCount)
372                         {
373                                 if (typeRefs == null)
374                                 {
375                                         typeRefs = new Type[TypeRef.records.Length];
376                                 }
377                                 if (typeRefs[index] == null)
378                                 {
379                                         int scope = TypeRef.records[index].ResolutionScope;
380                                         switch (scope >> 24)
381                                         {
382                                                 case AssemblyRefTable.Index:
383                                                         {
384                                                                 Assembly assembly = ResolveAssemblyRef((scope & 0xFFFFFF) - 1);
385                                                                 TypeName typeName = GetTypeName(TypeRef.records[index].TypeNameSpace, TypeRef.records[index].TypeName);
386                                                                 typeRefs[index] = assembly.ResolveType(typeName);
387                                                                 break;
388                                                         }
389                                                 case TypeRefTable.Index:
390                                                         {
391                                                                 Type outer = ResolveType(scope, null);
392                                                                 TypeName typeName = GetTypeName(TypeRef.records[index].TypeNameSpace, TypeRef.records[index].TypeName);
393                                                                 typeRefs[index] = outer.ResolveNestedType(typeName);
394                                                                 break;
395                                                         }
396                                                 case ModuleTable.Index:
397                                                 case ModuleRefTable.Index:
398                                                         {
399                                                                 Module module;
400                                                                 if (scope >> 24 == ModuleTable.Index)
401                                                                 {
402                                                                         if (scope == 0 || scope == 1)
403                                                                         {
404                                                                                 module = this;
405                                                                         }
406                                                                         else
407                                                                         {
408                                                                                 throw new NotImplementedException("self reference scope?");
409                                                                         }
410                                                                 }
411                                                                 else
412                                                                 {
413                                                                         module = ResolveModuleRef(ModuleRef.records[(scope & 0xFFFFFF) - 1]);
414                                                                 }
415                                                                 TypeName typeName = GetTypeName(TypeRef.records[index].TypeNameSpace, TypeRef.records[index].TypeName);
416                                                                 typeRefs[index] = module.FindType(typeName) ?? module.universe.GetMissingTypeOrThrow(module, null, typeName);
417                                                                 break;
418                                                         }
419                                                 default:
420                                                         throw new NotImplementedException("ResolutionScope = " + scope.ToString("X"));
421                                         }
422                                 }
423                                 return typeRefs[index];
424                         }
425                         else if ((metadataToken >> 24) == TypeSpecTable.Index && index < TypeSpec.RowCount)
426                         {
427                                 if (typeSpecs == null)
428                                 {
429                                         typeSpecs = new Type[TypeSpec.records.Length];
430                                 }
431                                 Type type = typeSpecs[index];
432                                 if (type == null)
433                                 {
434                                         TrackingGenericContext tc = context == null ? null : new TrackingGenericContext(context);
435                                         type = Signature.ReadTypeSpec(this, ByteReader.FromBlob(blobHeap, TypeSpec.records[index]), tc);
436                                         if (tc == null || !tc.IsUsed)
437                                         {
438                                                 typeSpecs[index] = type;
439                                         }
440                                 }
441                                 return type;
442                         }
443                         else
444                         {
445                                 throw TokenOutOfRangeException(metadataToken);
446                         }
447                 }
448
449                 private Module ResolveModuleRef(int moduleNameIndex)
450                 {
451                         string moduleName = GetString(moduleNameIndex);
452                         Module module = assembly.GetModule(moduleName);
453                         if (module == null)
454                         {
455                                 throw new FileNotFoundException(moduleName);
456                         }
457                         return module;
458                 }
459
460                 private sealed class TrackingGenericContext : IGenericContext
461                 {
462                         private readonly IGenericContext context;
463                         private bool used;
464
465                         internal TrackingGenericContext(IGenericContext context)
466                         {
467                                 this.context = context;
468                         }
469
470                         internal bool IsUsed
471                         {
472                                 get { return used; }
473                         }
474
475                         public Type GetGenericTypeArgument(int index)
476                         {
477                                 used = true;
478                                 return context.GetGenericTypeArgument(index);
479                         }
480
481                         public Type GetGenericMethodArgument(int index)
482                         {
483                                 used = true;
484                                 return context.GetGenericMethodArgument(index);
485                         }
486                 }
487
488                 private TypeName GetTypeName(int typeNamespace, int typeName)
489                 {
490                         return new TypeName(GetString(typeNamespace), GetString(typeName));
491                 }
492
493                 internal Assembly ResolveAssemblyRef(int index)
494                 {
495                         if (assemblyRefs == null)
496                         {
497                                 assemblyRefs = new Assembly[AssemblyRef.RowCount];
498                         }
499                         if (assemblyRefs[index] == null)
500                         {
501                                 assemblyRefs[index] = ResolveAssemblyRefImpl(ref AssemblyRef.records[index]);
502                         }
503                         return assemblyRefs[index];
504                 }
505
506                 private Assembly ResolveAssemblyRefImpl(ref AssemblyRefTable.Record rec)
507                 {
508                         const int PublicKey = 0x0001;
509                         string name = String.Format("{0}, Version={1}.{2}.{3}.{4}, Culture={5}, {6}={7}",
510                                 GetString(rec.Name),
511                                 rec.MajorVersion,
512                                 rec.MinorVersion,
513                                 rec.BuildNumber,
514                                 rec.RevisionNumber,
515                                 rec.Culture == 0 ? "neutral" : GetString(rec.Culture),
516                                 (rec.Flags & PublicKey) == 0 ? "PublicKeyToken" : "PublicKey",
517                                 PublicKeyOrTokenToString(rec.PublicKeyOrToken));
518                         return universe.Load(name, this.Assembly, true);
519                 }
520
521                 private string PublicKeyOrTokenToString(int publicKeyOrToken)
522                 {
523                         if (publicKeyOrToken == 0)
524                         {
525                                 return "null";
526                         }
527                         ByteReader br = GetBlob(publicKeyOrToken);
528                         if (br.Length == 0)
529                         {
530                                 return "null";
531                         }
532                         StringBuilder sb = new StringBuilder(br.Length * 2);
533                         while (br.Length > 0)
534                         {
535                                 sb.AppendFormat("{0:x2}", br.ReadByte());
536                         }
537                         return sb.ToString();
538                 }
539
540                 public override Guid ModuleVersionId
541                 {
542                         get
543                         {
544                                 byte[] buf = new byte[16];
545                                 Buffer.BlockCopy(guidHeap, 16 * (ModuleTable.records[0].Mvid - 1), buf, 0, 16);
546                                 return new Guid(buf);
547                         }
548                 }
549
550                 public override string FullyQualifiedName
551                 {
552                         get { return location ?? "<Unknown>"; }
553                 }
554
555                 public override string Name
556                 {
557                         get { return location == null ? "<Unknown>" : System.IO.Path.GetFileName(location); }
558                 }
559
560                 public override Assembly Assembly
561                 {
562                         get { return assembly; }
563                 }
564
565                 internal override Type FindType(TypeName typeName)
566                 {
567                         PopulateTypeDef();
568                         Type type;
569                         if (!types.TryGetValue(typeName, out type))
570                         {
571                                 LazyForwardedType fw;
572                                 if (forwardedTypes.TryGetValue(typeName, out fw))
573                                 {
574                                         return fw.GetType(this, typeName);
575                                 }
576                         }
577                         return type;
578                 }
579
580                 internal override Type FindTypeIgnoreCase(TypeName lowerCaseName)
581                 {
582                         PopulateTypeDef();
583                         foreach (Type type in types.Values)
584                         {
585                                 if (new TypeName(type.__Namespace, type.__Name).ToLowerInvariant() == lowerCaseName)
586                                 {
587                                         return type;
588                                 }
589                         }
590                         foreach (TypeName name in forwardedTypes.Keys)
591                         {
592                                 if (name.ToLowerInvariant() == lowerCaseName)
593                                 {
594                                         return forwardedTypes[name].GetType(this, name);
595                                 }
596                         }
597                         return null;
598                 }
599
600                 private Exception TokenOutOfRangeException(int metadataToken)
601                 {
602                         return new ArgumentOutOfRangeException("metadataToken", String.Format("Token 0x{0:x8} is not valid in the scope of module {1}.", metadataToken, this.Name));
603                 }
604
605                 public override MemberInfo ResolveMember(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
606                 {
607                         switch (metadataToken >> 24)
608                         {
609                                 case FieldTable.Index:
610                                         return ResolveField(metadataToken, genericTypeArguments, genericMethodArguments);
611                                 case MemberRefTable.Index:
612                                         int index = (metadataToken & 0xFFFFFF) - 1;
613                                         if (index < 0 || index >= MemberRef.RowCount)
614                                         {
615                                                 goto default;
616                                         }
617                                         return GetMemberRef(index, genericTypeArguments, genericMethodArguments);
618                                 case MethodDefTable.Index:
619                                 case MethodSpecTable.Index:
620                                         return ResolveMethod(metadataToken, genericTypeArguments, genericMethodArguments);
621                                 default:
622                                         throw TokenOutOfRangeException(metadataToken);
623                         }
624                 }
625
626                 internal FieldInfo GetFieldAt(TypeDefImpl owner, int index)
627                 {
628                         if (fields == null)
629                         {
630                                 fields = new FieldInfo[Field.records.Length];
631                         }
632                         if (fields[index] == null)
633                         {
634                                 fields[index] = new FieldDefImpl(this, owner ?? FindFieldOwner(index), index);
635                         }
636                         return fields[index];
637                 }
638
639                 public override FieldInfo ResolveField(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
640                 {
641                         int index = (metadataToken & 0xFFFFFF) - 1;
642                         if (index < 0)
643                         {
644                                 throw TokenOutOfRangeException(metadataToken);
645                         }
646                         else if ((metadataToken >> 24) == FieldTable.Index && index < Field.RowCount)
647                         {
648                                 return GetFieldAt(null, index);
649                         }
650                         else if ((metadataToken >> 24) == MemberRefTable.Index && index < MemberRef.RowCount)
651                         {
652                                 FieldInfo field = GetMemberRef(index, genericTypeArguments, genericMethodArguments) as FieldInfo;
653                                 if (field != null)
654                                 {
655                                         return field;
656                                 }
657                                 throw new ArgumentException(String.Format("Token 0x{0:x8} is not a valid FieldInfo token in the scope of module {1}.", metadataToken, this.Name), "metadataToken");
658                         }
659                         else
660                         {
661                                 throw TokenOutOfRangeException(metadataToken);
662                         }
663                 }
664
665                 private TypeDefImpl FindFieldOwner(int fieldIndex)
666                 {
667                         // TODO use binary search?
668                         for (int i = 0; i < TypeDef.records.Length; i++)
669                         {
670                                 int field = TypeDef.records[i].FieldList - 1;
671                                 int end = TypeDef.records.Length > i + 1 ? TypeDef.records[i + 1].FieldList - 1 : Field.records.Length;
672                                 if (field <= fieldIndex && fieldIndex < end)
673                                 {
674                                         PopulateTypeDef();
675                                         return typeDefs[i];
676                                 }
677                         }
678                         throw new InvalidOperationException();
679                 }
680
681                 internal MethodBase GetMethodAt(TypeDefImpl owner, int index)
682                 {
683                         if (methods == null)
684                         {
685                                 methods = new MethodBase[MethodDef.records.Length];
686                         }
687                         if (methods[index] == null)
688                         {
689                                 MethodDefImpl method = new MethodDefImpl(this, owner ?? FindMethodOwner(index), index);
690                                 methods[index] = method.IsConstructor ? new ConstructorInfoImpl(method) : (MethodBase)method;
691                         }
692                         return methods[index];
693                 }
694
695                 public override MethodBase ResolveMethod(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
696                 {
697                         int index = (metadataToken & 0xFFFFFF) - 1;
698                         if (index < 0)
699                         {
700                                 throw TokenOutOfRangeException(metadataToken);
701                         }
702                         else if ((metadataToken >> 24) == MethodDefTable.Index && index < MethodDef.RowCount)
703                         {
704                                 return GetMethodAt(null, index);
705                         }
706                         else if ((metadataToken >> 24) == MemberRefTable.Index && index < MemberRef.RowCount)
707                         {
708                                 MethodBase method = GetMemberRef(index, genericTypeArguments, genericMethodArguments) as MethodBase;
709                                 if (method != null)
710                                 {
711                                         return method;
712                                 }
713                                 throw new ArgumentException(String.Format("Token 0x{0:x8} is not a valid MethodBase token in the scope of module {1}.", metadataToken, this.Name), "metadataToken");
714                         }
715                         else if ((metadataToken >> 24) == MethodSpecTable.Index && index < MethodSpec.RowCount)
716                         {
717                                 MethodInfo method = (MethodInfo)ResolveMethod(MethodSpec.records[index].Method, genericTypeArguments, genericMethodArguments);
718                                 ByteReader instantiation = ByteReader.FromBlob(blobHeap, MethodSpec.records[index].Instantiation);
719                                 return method.MakeGenericMethod(Signature.ReadMethodSpec(this, instantiation, new GenericContext(genericTypeArguments, genericMethodArguments)));
720                         }
721                         else
722                         {
723                                 throw TokenOutOfRangeException(metadataToken);
724                         }
725                 }
726
727                 public override Type[] __ResolveOptionalParameterTypes(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments, out CustomModifiers[] customModifiers)
728                 {
729                         int index = (metadataToken & 0xFFFFFF) - 1;
730                         if (index < 0)
731                         {
732                                 throw TokenOutOfRangeException(metadataToken);
733                         }
734                         else if ((metadataToken >> 24) == MemberRefTable.Index && index < MemberRef.RowCount)
735                         {
736                                 int sig = MemberRef.records[index].Signature;
737                                 return Signature.ReadOptionalParameterTypes(this, GetBlob(sig), new GenericContext(genericTypeArguments, genericMethodArguments), out customModifiers);
738                         }
739                         else if ((metadataToken >> 24) == MethodDefTable.Index && index < MethodDef.RowCount)
740                         {
741                                 // for convenience, we support passing a MethodDef token as well, because in some places
742                                 // it makes sense to have a vararg method that is referred to by its methoddef (e.g. ldftn).
743                                 // Note that MethodSpec doesn't make sense, because generic methods cannot be vararg.
744                                 customModifiers = Empty<CustomModifiers>.Array;
745                                 return Type.EmptyTypes;
746                         }
747                         else
748                         {
749                                 throw TokenOutOfRangeException(metadataToken);
750                         }
751                 }
752
753                 public override string ScopeName
754                 {
755                         get { return GetString(ModuleTable.records[0].Name); }
756                 }
757
758                 private TypeDefImpl FindMethodOwner(int methodIndex)
759                 {
760                         // TODO use binary search?
761                         for (int i = 0; i < TypeDef.records.Length; i++)
762                         {
763                                 int method = TypeDef.records[i].MethodList - 1;
764                                 int end = TypeDef.records.Length > i + 1 ? TypeDef.records[i + 1].MethodList - 1 : MethodDef.records.Length;
765                                 if (method <= methodIndex && methodIndex < end)
766                                 {
767                                         PopulateTypeDef();
768                                         return typeDefs[i];
769                                 }
770                         }
771                         throw new InvalidOperationException();
772                 }
773
774                 private MemberInfo GetMemberRef(int index, Type[] genericTypeArguments, Type[] genericMethodArguments)
775                 {
776                         if (memberRefs == null)
777                         {
778                                 memberRefs = new MemberInfo[MemberRef.records.Length];
779                         }
780                         if (memberRefs[index] == null)
781                         {
782                                 int owner = MemberRef.records[index].Class;
783                                 int sig = MemberRef.records[index].Signature;
784                                 string name = GetString(MemberRef.records[index].Name);
785                                 switch (owner >> 24)
786                                 {
787                                         case MethodDefTable.Index:
788                                                 return GetMethodAt(null, (owner & 0xFFFFFF) - 1);
789                                         case ModuleRefTable.Index:
790                                                 memberRefs[index] = ResolveTypeMemberRef(ResolveModuleType(owner), name, ByteReader.FromBlob(blobHeap, sig));
791                                                 break;
792                                         case TypeDefTable.Index:
793                                         case TypeRefTable.Index:
794                                                 memberRefs[index] = ResolveTypeMemberRef(ResolveType(owner), name, ByteReader.FromBlob(blobHeap, sig));
795                                                 break;
796                                         case TypeSpecTable.Index:
797                                         {
798                                                 Type type = ResolveType(owner, genericTypeArguments, genericMethodArguments);
799                                                 if (type.IsArray)
800                                                 {
801                                                         MethodSignature methodSig = MethodSignature.ReadSig(this, ByteReader.FromBlob(blobHeap, sig), new GenericContext(genericTypeArguments, genericMethodArguments));
802                                                         return type.FindMethod(name, methodSig)
803                                                                 ?? universe.GetMissingMethodOrThrow(type, name, methodSig);
804                                                 }
805                                                 else if (type.IsConstructedGenericType)
806                                                 {
807                                                         MemberInfo member = ResolveTypeMemberRef(type.GetGenericTypeDefinition(), name, ByteReader.FromBlob(blobHeap, sig));
808                                                         MethodBase mb = member as MethodBase;
809                                                         if (mb != null)
810                                                         {
811                                                                 member = mb.BindTypeParameters(type);
812                                                         }
813                                                         FieldInfo fi = member as FieldInfo;
814                                                         if (fi != null)
815                                                         {
816                                                                 member = fi.BindTypeParameters(type);
817                                                         }
818                                                         return member;
819                                                 }
820                                                 else
821                                                 {
822                                                         return ResolveTypeMemberRef(type, name, ByteReader.FromBlob(blobHeap, sig));
823                                                 }
824                                         }
825                                         default:
826                                                 throw new BadImageFormatException();
827                                 }
828                         }
829                         return memberRefs[index];
830                 }
831
832                 private Type ResolveModuleType(int token)
833                 {
834                         int index = (token & 0xFFFFFF) - 1;
835                         string name = GetString(ModuleRef.records[index]);
836                         Module module = assembly.GetModule(name);
837                         if (module == null || module.IsResource())
838                         {
839                                 throw new BadImageFormatException();
840                         }
841                         return module.GetModuleType();
842                 }
843
844                 private MemberInfo ResolveTypeMemberRef(Type type, string name, ByteReader sig)
845                 {
846                         if (sig.PeekByte() == Signature.FIELD)
847                         {
848                                 Type org = type;
849                                 FieldSignature fieldSig = FieldSignature.ReadSig(this, sig, type);
850                                 FieldInfo field = type.FindField(name, fieldSig);
851                                 if (field == null && universe.MissingMemberResolution)
852                                 {
853                                         return universe.GetMissingFieldOrThrow(type, name, fieldSig);
854                                 }
855                                 while (field == null && (type = type.BaseType) != null)
856                                 {
857                                         field = type.FindField(name, fieldSig);
858                                 }
859                                 if (field != null)
860                                 {
861                                         return field;
862                                 }
863                                 throw new MissingFieldException(org.ToString(), name);
864                         }
865                         else
866                         {
867                                 Type org = type;
868                                 MethodSignature methodSig = MethodSignature.ReadSig(this, sig, type);
869                                 MethodBase method = type.FindMethod(name, methodSig);
870                                 if (method == null && universe.MissingMemberResolution)
871                                 {
872                                         return universe.GetMissingMethodOrThrow(type, name, methodSig);
873                                 }
874                                 while (method == null && (type = type.BaseType) != null)
875                                 {
876                                         method = type.FindMethod(name, methodSig);
877                                 }
878                                 if (method != null)
879                                 {
880                                         return method;
881                                 }
882                                 throw new MissingMethodException(org.ToString(), name);
883                         }
884                 }
885
886                 internal ByteReader GetStandAloneSig(int index)
887                 {
888                         return ByteReader.FromBlob(blobHeap, StandAloneSig.records[index]);
889                 }
890
891                 public override byte[] ResolveSignature(int metadataToken)
892                 {
893                         int index = (metadataToken & 0xFFFFFF) - 1;
894                         if ((metadataToken >> 24) == StandAloneSigTable.Index && index >= 0 && index < StandAloneSig.RowCount)
895                         {
896                                 ByteReader br = GetStandAloneSig(index);
897                                 return br.ReadBytes(br.Length);
898                         }
899                         else
900                         {
901                                 throw TokenOutOfRangeException(metadataToken);
902                         }
903                 }
904
905                 public override __StandAloneMethodSig __ResolveStandAloneMethodSig(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
906                 {
907                         int index = (metadataToken & 0xFFFFFF) - 1;
908                         if ((metadataToken >> 24) == StandAloneSigTable.Index && index >= 0 && index < StandAloneSig.RowCount)
909                         {
910                                 return MethodSignature.ReadStandAloneMethodSig(this, GetStandAloneSig(index), new GenericContext(genericTypeArguments, genericMethodArguments));
911                         }
912                         else
913                         {
914                                 throw TokenOutOfRangeException(metadataToken);
915                         }
916                 }
917
918                 internal MethodInfo GetEntryPoint()
919                 {
920                         if (cliHeader.EntryPointToken != 0 && (cliHeader.Flags & CliHeader.COMIMAGE_FLAGS_NATIVE_ENTRYPOINT) == 0)
921                         {
922                                 return (MethodInfo)ResolveMethod((int)cliHeader.EntryPointToken);
923                         }
924                         return null;
925                 }
926
927                 internal string[] GetManifestResourceNames()
928                 {
929                         string[] names = new string[ManifestResource.records.Length];
930                         for (int i = 0; i < ManifestResource.records.Length; i++)
931                         {
932                                 names[i] = GetString(ManifestResource.records[i].Name);
933                         }
934                         return names;
935                 }
936
937                 internal ManifestResourceInfo GetManifestResourceInfo(string resourceName)
938                 {
939                         for (int i = 0; i < ManifestResource.records.Length; i++)
940                         {
941                                 if (resourceName == GetString(ManifestResource.records[i].Name))
942                                 {
943                                         ManifestResourceInfo info = new ManifestResourceInfo(this, i);
944                                         Assembly asm = info.ReferencedAssembly;
945                                         if (asm != null && !asm.__IsMissing && asm.GetManifestResourceInfo(resourceName) == null)
946                                         {
947                                                 return null;
948                                         }
949                                         return info;
950                                 }
951                         }
952                         return null;
953                 }
954
955                 internal Stream GetManifestResourceStream(string resourceName)
956                 {
957                         for (int i = 0; i < ManifestResource.records.Length; i++)
958                         {
959                                 if (resourceName == GetString(ManifestResource.records[i].Name))
960                                 {
961                                         if (ManifestResource.records[i].Implementation != 0x26000000)
962                                         {
963                                                 ManifestResourceInfo info = new ManifestResourceInfo(this, i);
964                                                 switch (ManifestResource.records[i].Implementation >> 24)
965                                                 {
966                                                         case FileTable.Index:
967                                                                 string fileName = Path.Combine(Path.GetDirectoryName(location), info.FileName);
968                                                                 if (System.IO.File.Exists(fileName))
969                                                                 {
970                                                                         // note that, like System.Reflection, we return null for zero length files and
971                                                                         // ManifestResource.Offset is ignored
972                                                                         FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read | FileShare.Delete);
973                                                                         if (fs.Length == 0)
974                                                                         {
975                                                                                 fs.Close();
976                                                                                 return null;
977                                                                         }
978                                                                         return fs;
979                                                                 }
980                                                                 return null;
981                                                         case AssemblyRefTable.Index:
982                                                                 Assembly asm = info.ReferencedAssembly;
983                                                                 if (asm.__IsMissing)
984                                                                 {
985                                                                         return null;
986                                                                 }
987                                                                 return asm.GetManifestResourceStream(resourceName);
988                                                         default:
989                                                                 throw new BadImageFormatException();
990                                                 }
991                                         }
992                                         SeekRVA((int)cliHeader.Resources.VirtualAddress + ManifestResource.records[i].Offset);
993                                         BinaryReader br = new BinaryReader(stream);
994                                         int length = br.ReadInt32();
995                                         return new MemoryStream(br.ReadBytes(length));
996                                 }
997                         }
998                         return null;
999                 }
1000
1001                 public override AssemblyName[] __GetReferencedAssemblies()
1002                 {
1003                         List<AssemblyName> list = new List<AssemblyName>();
1004                         for (int i = 0; i < AssemblyRef.records.Length; i++)
1005                         {
1006                                 AssemblyName name = new AssemblyName();
1007                                 name.Name = GetString(AssemblyRef.records[i].Name);
1008                                 name.Version = new Version(
1009                                         AssemblyRef.records[i].MajorVersion,
1010                                         AssemblyRef.records[i].MinorVersion,
1011                                         AssemblyRef.records[i].BuildNumber,
1012                                         AssemblyRef.records[i].RevisionNumber);
1013                                 if (AssemblyRef.records[i].PublicKeyOrToken != 0)
1014                                 {
1015                                         byte[] keyOrToken = GetBlobCopy(AssemblyRef.records[i].PublicKeyOrToken);
1016                                         const int PublicKey = 0x0001;
1017                                         if ((AssemblyRef.records[i].Flags & PublicKey) != 0)
1018                                         {
1019                                                 name.SetPublicKey(keyOrToken);
1020                                         }
1021                                         else
1022                                         {
1023                                                 name.SetPublicKeyToken(keyOrToken);
1024                                         }
1025                                 }
1026                                 else
1027                                 {
1028                                         name.SetPublicKeyToken(Empty<byte>.Array);
1029                                 }
1030                                 if (AssemblyRef.records[i].Culture != 0)
1031                                 {
1032                                         name.Culture = GetString(AssemblyRef.records[i].Culture);
1033                                 }
1034                                 else
1035                                 {
1036                                         name.Culture = "";
1037                                 }
1038                                 if (AssemblyRef.records[i].HashValue != 0)
1039                                 {
1040                                         name.hash = GetBlobCopy(AssemblyRef.records[i].HashValue);
1041                                 }
1042                                 name.Flags = (AssemblyNameFlags)AssemblyRef.records[i].Flags;
1043                                 list.Add(name);
1044                         }
1045                         return list.ToArray();
1046                 }
1047
1048                 public override void __ResolveReferencedAssemblies(Assembly[] assemblies)
1049                 {
1050                         if (assemblyRefs == null)
1051                         {
1052                                 assemblyRefs = new Assembly[AssemblyRef.RowCount];
1053                         }
1054                         for (int i = 0; i < assemblies.Length; i++)
1055                         {
1056                                 if (assemblyRefs[i] == null)
1057                                 {
1058                                         assemblyRefs[i] = assemblies[i];
1059                                 }
1060                         }
1061                 }
1062
1063                 public override string[] __GetReferencedModules()
1064                 {
1065                         string[] arr = new string[this.ModuleRef.RowCount];
1066                         for (int i = 0; i < arr.Length; i++)
1067                         {
1068                                 arr[i] = GetString(this.ModuleRef.records[i]);
1069                         }
1070                         return arr;
1071                 }
1072
1073                 public override Type[] __GetReferencedTypes()
1074                 {
1075                         Type[] arr = new Type[this.TypeRef.RowCount];
1076                         for (int i = 0; i < arr.Length; i++)
1077                         {
1078                                 arr[i] = ResolveType((TypeRefTable.Index << 24) + i + 1);
1079                         }
1080                         return arr;
1081                 }
1082
1083                 public override Type[] __GetExportedTypes()
1084                 {
1085                         Type[] arr = new Type[this.ExportedType.RowCount];
1086                         for (int i = 0; i < arr.Length; i++)
1087                         {
1088                                 arr[i] = ResolveExportedType(i);
1089                         }
1090                         return arr;
1091                 }
1092
1093                 private Type ResolveExportedType(int index)
1094                 {
1095                         TypeName typeName = GetTypeName(ExportedType.records[index].TypeNamespace, ExportedType.records[index].TypeName);
1096                         int implementation = ExportedType.records[index].Implementation;
1097                         int token = ExportedType.records[index].TypeDefId;
1098                         switch (implementation >> 24)
1099                         {
1100                                 case AssemblyRefTable.Index:
1101                                         return ResolveAssemblyRef((implementation & 0xFFFFFF) - 1).ResolveType(typeName).SetMetadataTokenForMissing(token);
1102                                 case ExportedTypeTable.Index:
1103                                         return ResolveExportedType((implementation & 0xFFFFFF) - 1).ResolveNestedType(typeName).SetMetadataTokenForMissing(token);
1104                                 default:
1105                                         throw new NotImplementedException();
1106                         }
1107                 }
1108
1109                 internal override Type GetModuleType()
1110                 {
1111                         PopulateTypeDef();
1112                         return moduleType;
1113                 }
1114
1115                 public override string __ImageRuntimeVersion
1116                 {
1117                         get { return imageRuntimeVersion; }
1118                 }
1119
1120                 public override int MDStreamVersion
1121                 {
1122                         get { return metadataStreamVersion; }
1123                 }
1124
1125                 public override void __GetDataDirectoryEntry(int index, out int rva, out int length)
1126                 {
1127                         peFile.GetDataDirectoryEntry(index, out rva, out length);
1128                 }
1129
1130                 public override long __RelativeVirtualAddressToFileOffset(int rva)
1131                 {
1132                         return peFile.RvaToFileOffset((uint)rva);
1133                 }
1134
1135                 public override bool __GetSectionInfo(int rva, out string name, out int characteristics)
1136                 {
1137                         return peFile.GetSectionInfo(rva, out name, out characteristics);
1138                 }
1139
1140                 public override int __ReadDataFromRVA(int rva, byte[] data, int offset, int length)
1141                 {
1142                         SeekRVA(rva);
1143                         int totalBytesRead = 0;
1144                         while (length > 0)
1145                         {
1146                                 int read = stream.Read(data, offset, length);
1147                                 if (read == 0)
1148                                 {
1149                                         // C++ assemblies can have fields that have an RVA that lies outside of the file
1150                                         break;
1151                                 }
1152                                 offset += read;
1153                                 length -= read;
1154                                 totalBytesRead += read;
1155                         }
1156                         return totalBytesRead;
1157                 }
1158
1159                 public override void GetPEKind(out PortableExecutableKinds peKind, out ImageFileMachine machine)
1160                 {
1161                         peKind = 0;
1162                         if ((cliHeader.Flags & CliHeader.COMIMAGE_FLAGS_ILONLY) != 0)
1163                         {
1164                                 peKind |= PortableExecutableKinds.ILOnly;
1165                         }
1166                         switch (cliHeader.Flags & (CliHeader.COMIMAGE_FLAGS_32BITREQUIRED | CliHeader.COMIMAGE_FLAGS_32BITPREFERRED))
1167                         {
1168                                 case CliHeader.COMIMAGE_FLAGS_32BITREQUIRED:
1169                                         peKind |= PortableExecutableKinds.Required32Bit;
1170                                         break;
1171                                 case CliHeader.COMIMAGE_FLAGS_32BITREQUIRED | CliHeader.COMIMAGE_FLAGS_32BITPREFERRED:
1172                                         peKind |= PortableExecutableKinds.Preferred32Bit;
1173                                         break;
1174                                 default:
1175                                         // COMIMAGE_FLAGS_32BITPREFERRED by itself is illegal, so we ignore it
1176                                         // (not setting any flag is ok)
1177                                         break;
1178                         }
1179                         if (peFile.OptionalHeader.Magic == IMAGE_OPTIONAL_HEADER.IMAGE_NT_OPTIONAL_HDR64_MAGIC)
1180                         {
1181                                 peKind |= PortableExecutableKinds.PE32Plus;
1182                         }
1183
1184                         machine = (ImageFileMachine)peFile.FileHeader.Machine;
1185                 }
1186
1187                 public override int __Subsystem
1188                 {
1189                         get { return peFile.OptionalHeader.Subsystem; }
1190                 }
1191
1192                 public override IList<CustomAttributeData> __GetPlaceholderAssemblyCustomAttributes(bool multiple, bool security)
1193                 {
1194                         TypeName typeName;
1195                         switch ((multiple ? 1 : 0) + (security ? 2 : 0))
1196                         {
1197                                 case 0:
1198                                         typeName = new TypeName("System.Runtime.CompilerServices", "AssemblyAttributesGoHere");
1199                                         break;
1200                                 case 1:
1201                                         typeName = new TypeName("System.Runtime.CompilerServices", "AssemblyAttributesGoHereM");
1202                                         break;
1203                                 case 2:
1204                                         typeName = new TypeName("System.Runtime.CompilerServices", "AssemblyAttributesGoHereS");
1205                                         break;
1206                                 case 3:
1207                                 default:
1208                                         typeName = new TypeName("System.Runtime.CompilerServices", "AssemblyAttributesGoHereSM");
1209                                         break;
1210                         }
1211                         List<CustomAttributeData> list = new List<CustomAttributeData>();
1212                         for (int i = 0; i < CustomAttribute.records.Length; i++)
1213                         {
1214                                 if ((CustomAttribute.records[i].Parent >> 24) == TypeRefTable.Index)
1215                                 {
1216                                         int index = (CustomAttribute.records[i].Parent & 0xFFFFFF) - 1;
1217                                         if (typeName == GetTypeName(TypeRef.records[index].TypeNameSpace, TypeRef.records[index].TypeName))
1218                                         {
1219                                                 list.Add(new CustomAttributeData(this, i));
1220                                         }
1221                                 }
1222                         }
1223                         return list;
1224                 }
1225
1226                 internal override void Dispose()
1227                 {
1228                         stream.Close();
1229                 }
1230
1231                 internal override void ExportTypes(int fileToken, IKVM.Reflection.Emit.ModuleBuilder manifestModule)
1232                 {
1233                         PopulateTypeDef();
1234                         manifestModule.ExportTypes(typeDefs, fileToken);
1235                 }
1236
1237                 protected override long GetImageBaseImpl()
1238                 {
1239                         return (long)peFile.OptionalHeader.ImageBase;
1240                 }
1241
1242                 protected override long GetStackReserveImpl()
1243                 {
1244                         return (long)peFile.OptionalHeader.SizeOfStackReserve;
1245                 }
1246
1247                 protected override int GetFileAlignmentImpl()
1248                 {
1249                         return (int)peFile.OptionalHeader.FileAlignment;
1250                 }
1251
1252                 protected override DllCharacteristics GetDllCharacteristicsImpl()
1253                 {
1254                         return (DllCharacteristics)peFile.OptionalHeader.DllCharacteristics;
1255                 }
1256
1257                 public override int __EntryPointRVA
1258                 {
1259                         get { return (cliHeader.Flags & CliHeader.COMIMAGE_FLAGS_NATIVE_ENTRYPOINT) != 0 ? (int)cliHeader.EntryPointToken : 0; }
1260                 }
1261
1262                 public override int __EntryPointToken
1263                 {
1264                         get { return (cliHeader.Flags & CliHeader.COMIMAGE_FLAGS_NATIVE_ENTRYPOINT) == 0 ? (int)cliHeader.EntryPointToken : 0; }
1265                 }
1266         }
1267 }