2 Copyright (C) 2009-2012 Jeroen Frijters
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.
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:
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.
25 using System.Collections.Generic;
26 using System.Diagnostics;
29 using CallingConvention = System.Runtime.InteropServices.CallingConvention;
30 using IKVM.Reflection.Reader;
31 using IKVM.Reflection.Emit;
32 using IKVM.Reflection.Writer;
33 using IKVM.Reflection.Metadata;
35 namespace IKVM.Reflection
37 abstract class Signature
39 internal const byte DEFAULT = 0x00;
40 internal const byte VARARG = 0x05;
41 internal const byte GENERIC = 0x10;
42 internal const byte HASTHIS = 0x20;
43 internal const byte EXPLICITTHIS = 0x40;
44 internal const byte FIELD = 0x06;
45 internal const byte LOCAL_SIG = 0x07;
46 internal const byte PROPERTY = 0x08;
47 internal const byte GENERICINST = 0x0A;
48 internal const byte SENTINEL = 0x41;
49 internal const byte ELEMENT_TYPE_VOID = 0x01;
50 internal const byte ELEMENT_TYPE_BOOLEAN = 0x02;
51 internal const byte ELEMENT_TYPE_CHAR = 0x03;
52 internal const byte ELEMENT_TYPE_I1 = 0x04;
53 internal const byte ELEMENT_TYPE_U1 = 0x05;
54 internal const byte ELEMENT_TYPE_I2 = 0x06;
55 internal const byte ELEMENT_TYPE_U2 = 0x07;
56 internal const byte ELEMENT_TYPE_I4 = 0x08;
57 internal const byte ELEMENT_TYPE_U4 = 0x09;
58 internal const byte ELEMENT_TYPE_I8 = 0x0a;
59 internal const byte ELEMENT_TYPE_U8 = 0x0b;
60 internal const byte ELEMENT_TYPE_R4 = 0x0c;
61 internal const byte ELEMENT_TYPE_R8 = 0x0d;
62 internal const byte ELEMENT_TYPE_STRING = 0x0e;
63 internal const byte ELEMENT_TYPE_PTR = 0x0f;
64 internal const byte ELEMENT_TYPE_BYREF = 0x10;
65 internal const byte ELEMENT_TYPE_VALUETYPE = 0x11;
66 internal const byte ELEMENT_TYPE_CLASS = 0x12;
67 internal const byte ELEMENT_TYPE_VAR = 0x13;
68 internal const byte ELEMENT_TYPE_ARRAY = 0x14;
69 internal const byte ELEMENT_TYPE_GENERICINST = 0x15;
70 internal const byte ELEMENT_TYPE_TYPEDBYREF = 0x16;
71 internal const byte ELEMENT_TYPE_I = 0x18;
72 internal const byte ELEMENT_TYPE_U = 0x19;
73 internal const byte ELEMENT_TYPE_FNPTR = 0x1b;
74 internal const byte ELEMENT_TYPE_OBJECT = 0x1c;
75 internal const byte ELEMENT_TYPE_SZARRAY = 0x1d;
76 internal const byte ELEMENT_TYPE_MVAR = 0x1e;
77 internal const byte ELEMENT_TYPE_CMOD_REQD = 0x1f;
78 internal const byte ELEMENT_TYPE_CMOD_OPT = 0x20;
79 internal const byte ELEMENT_TYPE_PINNED = 0x45;
81 internal abstract void WriteSig(ModuleBuilder module, ByteBuffer bb);
83 private static Type ReadGenericInst(ModuleReader module, ByteReader br, IGenericContext context)
86 switch (br.ReadByte())
88 case ELEMENT_TYPE_CLASS:
89 type = ReadTypeDefOrRefEncoded(module, br, context).MarkNotValueType();
91 case ELEMENT_TYPE_VALUETYPE:
92 type = ReadTypeDefOrRefEncoded(module, br, context).MarkValueType();
95 throw new BadImageFormatException();
97 if (!type.__IsMissing && !type.IsGenericTypeDefinition)
99 throw new BadImageFormatException();
101 int genArgCount = br.ReadCompressedInt();
102 Type[] args = new Type[genArgCount];
103 CustomModifiers[] mods = null;
104 for (int i = 0; i < genArgCount; i++)
106 // LAMESPEC the Type production (23.2.12) doesn't include CustomMod* for genericinst, but C++ uses it, the verifier allows it and ildasm also supports it
107 CustomModifiers cm = CustomModifiers.Read(module, br, context);
112 mods = new CustomModifiers[genArgCount];
116 args[i] = ReadType(module, br, context);
118 return GenericTypeInstance.Make(type, args, mods);
121 internal static Type ReadTypeSpec(ModuleReader module, ByteReader br, IGenericContext context)
123 // LAMESPEC a TypeSpec can contain custom modifiers (C++/CLI generates "newarr (TypeSpec with custom modifiers)")
124 CustomModifiers.Skip(br);
125 // LAMESPEC anything can be adorned by (useless) custom modifiers
126 // also, VAR and MVAR are also used in TypeSpec (contrary to what the spec says)
127 return ReadType(module, br, context);
130 private static Type ReadFunctionPointer(ModuleReader module, ByteReader br, IGenericContext context)
132 __StandAloneMethodSig sig = MethodSignature.ReadStandAloneMethodSig(module, br, context);
133 if (module.universe.EnableFunctionPointers)
135 return FunctionPointerType.Make(module.universe, sig);
139 // by default, like .NET we return System.IntPtr here
140 return module.universe.System_IntPtr;
144 internal static Type[] ReadMethodSpec(ModuleReader module, ByteReader br, IGenericContext context)
146 if (br.ReadByte() != GENERICINST)
148 throw new BadImageFormatException();
150 Type[] args = new Type[br.ReadCompressedInt()];
151 for (int i = 0; i < args.Length; i++)
153 args[i] = ReadType(module, br, context);
158 private static int[] ReadArrayBounds(ByteReader br)
160 int num = br.ReadCompressedInt();
165 int[] arr = new int[num];
166 for (int i = 0; i < num; i++)
168 arr[i] = br.ReadCompressedInt();
173 private static Type ReadTypeOrVoid(ModuleReader module, ByteReader br, IGenericContext context)
175 if (br.PeekByte() == ELEMENT_TYPE_VOID)
178 return module.universe.System_Void;
182 return ReadType(module, br, context);
186 // see ECMA 335 CLI spec June 2006 section 23.2.12 for this production
187 protected static Type ReadType(ModuleReader module, ByteReader br, IGenericContext context)
189 CustomModifiers mods;
190 switch (br.ReadByte())
192 case ELEMENT_TYPE_CLASS:
193 return ReadTypeDefOrRefEncoded(module, br, context).MarkNotValueType();
194 case ELEMENT_TYPE_VALUETYPE:
195 return ReadTypeDefOrRefEncoded(module, br, context).MarkValueType();
196 case ELEMENT_TYPE_BOOLEAN:
197 return module.universe.System_Boolean;
198 case ELEMENT_TYPE_CHAR:
199 return module.universe.System_Char;
200 case ELEMENT_TYPE_I1:
201 return module.universe.System_SByte;
202 case ELEMENT_TYPE_U1:
203 return module.universe.System_Byte;
204 case ELEMENT_TYPE_I2:
205 return module.universe.System_Int16;
206 case ELEMENT_TYPE_U2:
207 return module.universe.System_UInt16;
208 case ELEMENT_TYPE_I4:
209 return module.universe.System_Int32;
210 case ELEMENT_TYPE_U4:
211 return module.universe.System_UInt32;
212 case ELEMENT_TYPE_I8:
213 return module.universe.System_Int64;
214 case ELEMENT_TYPE_U8:
215 return module.universe.System_UInt64;
216 case ELEMENT_TYPE_R4:
217 return module.universe.System_Single;
218 case ELEMENT_TYPE_R8:
219 return module.universe.System_Double;
221 return module.universe.System_IntPtr;
223 return module.universe.System_UIntPtr;
224 case ELEMENT_TYPE_STRING:
225 return module.universe.System_String;
226 case ELEMENT_TYPE_OBJECT:
227 return module.universe.System_Object;
228 case ELEMENT_TYPE_VAR:
229 return context.GetGenericTypeArgument(br.ReadCompressedInt());
230 case ELEMENT_TYPE_MVAR:
231 return context.GetGenericMethodArgument(br.ReadCompressedInt());
232 case ELEMENT_TYPE_GENERICINST:
233 return ReadGenericInst(module, br, context);
234 case ELEMENT_TYPE_SZARRAY:
235 mods = CustomModifiers.Read(module, br, context);
236 return ReadType(module, br, context).__MakeArrayType(mods);
237 case ELEMENT_TYPE_ARRAY:
238 mods = CustomModifiers.Read(module, br, context);
239 return ReadType(module, br, context).__MakeArrayType(br.ReadCompressedInt(), ReadArrayBounds(br), ReadArrayBounds(br), mods);
240 case ELEMENT_TYPE_PTR:
241 mods = CustomModifiers.Read(module, br, context);
242 return ReadTypeOrVoid(module, br, context).__MakePointerType(mods);
243 case ELEMENT_TYPE_FNPTR:
244 return ReadFunctionPointer(module, br, context);
246 throw new BadImageFormatException();
250 internal static void ReadLocalVarSig(ModuleReader module, ByteReader br, IGenericContext context, List<LocalVariableInfo> list)
252 if (br.Length < 2 || br.ReadByte() != LOCAL_SIG)
254 throw new BadImageFormatException("Invalid local variable signature");
256 int count = br.ReadCompressedInt();
257 for (int i = 0; i < count; i++)
259 if (br.PeekByte() == ELEMENT_TYPE_TYPEDBYREF)
262 list.Add(new LocalVariableInfo(i, module.universe.System_TypedReference, false, new CustomModifiers()));
266 CustomModifiers mods1 = CustomModifiers.Read(module, br, context);
268 if (br.PeekByte() == ELEMENT_TYPE_PINNED)
273 CustomModifiers mods2 = CustomModifiers.Read(module, br, context);
274 Type type = ReadTypeOrByRef(module, br, context);
275 list.Add(new LocalVariableInfo(i, type, pinned, CustomModifiers.Combine(mods1, mods2)));
280 private static Type ReadTypeOrByRef(ModuleReader module, ByteReader br, IGenericContext context)
282 if (br.PeekByte() == ELEMENT_TYPE_BYREF)
285 // LAMESPEC it is allowed (by C++/CLI, ilasm and peverify) to have custom modifiers after the BYREF
286 // (which makes sense, as it is analogous to pointers)
287 CustomModifiers mods = CustomModifiers.Read(module, br, context);
288 // C++/CLI generates void& local variables, so we need to use ReadTypeOrVoid here
289 return ReadTypeOrVoid(module, br, context).__MakeByRefType(mods);
293 return ReadType(module, br, context);
297 protected static Type ReadRetType(ModuleReader module, ByteReader br, IGenericContext context)
299 switch (br.PeekByte())
301 case ELEMENT_TYPE_VOID:
303 return module.universe.System_Void;
304 case ELEMENT_TYPE_TYPEDBYREF:
306 return module.universe.System_TypedReference;
308 return ReadTypeOrByRef(module, br, context);
312 protected static Type ReadParam(ModuleReader module, ByteReader br, IGenericContext context)
314 switch (br.PeekByte())
316 case ELEMENT_TYPE_TYPEDBYREF:
318 return module.universe.System_TypedReference;
320 return ReadTypeOrByRef(module, br, context);
324 protected static void WriteType(ModuleBuilder module, ByteBuffer bb, Type type)
326 while (type.HasElementType)
330 bb.Write(ELEMENT_TYPE_SZARRAY);
332 else if (type.IsArray)
334 int rank = type.GetArrayRank();
335 bb.Write(ELEMENT_TYPE_ARRAY);
336 // LAMESPEC the Type production (23.2.12) doesn't include CustomMod* for arrays, but the verifier allows it and ildasm also supports it
337 WriteCustomModifiers(module, bb, type.__GetCustomModifiers());
338 WriteType(module, bb, type.GetElementType());
339 bb.WriteCompressedInt(rank);
340 int[] sizes = type.__GetArraySizes();
341 bb.WriteCompressedInt(sizes.Length);
342 for (int i = 0; i < sizes.Length; i++)
344 bb.WriteCompressedInt(sizes[i]);
346 int[] lobounds = type.__GetArrayLowerBounds();
347 bb.WriteCompressedInt(lobounds.Length);
348 for (int i = 0; i < lobounds.Length; i++)
350 bb.WriteCompressedInt(lobounds[i]);
354 else if (type.IsByRef)
356 bb.Write(ELEMENT_TYPE_BYREF);
358 else if (type.IsPointer)
360 bb.Write(ELEMENT_TYPE_PTR);
362 WriteCustomModifiers(module, bb, type.__GetCustomModifiers());
363 type = type.GetElementType();
365 Universe u = module.universe;
366 if (type == u.System_Void)
368 bb.Write(ELEMENT_TYPE_VOID);
370 else if (type == u.System_Int32)
372 bb.Write(ELEMENT_TYPE_I4);
374 else if (type == u.System_Boolean)
376 bb.Write(ELEMENT_TYPE_BOOLEAN);
378 else if (type == u.System_String)
380 bb.Write(ELEMENT_TYPE_STRING);
382 else if (type == u.System_Char)
384 bb.Write(ELEMENT_TYPE_CHAR);
386 else if (type == u.System_SByte)
388 bb.Write(ELEMENT_TYPE_I1);
390 else if (type == u.System_Byte)
392 bb.Write(ELEMENT_TYPE_U1);
394 else if (type == u.System_Int16)
396 bb.Write(ELEMENT_TYPE_I2);
398 else if (type == u.System_UInt16)
400 bb.Write(ELEMENT_TYPE_U2);
402 else if (type == u.System_UInt32)
404 bb.Write(ELEMENT_TYPE_U4);
406 else if (type == u.System_Int64)
408 bb.Write(ELEMENT_TYPE_I8);
410 else if (type == u.System_UInt64)
412 bb.Write(ELEMENT_TYPE_U8);
414 else if (type == u.System_Single)
416 bb.Write(ELEMENT_TYPE_R4);
418 else if (type == u.System_Double)
420 bb.Write(ELEMENT_TYPE_R8);
422 else if (type == u.System_IntPtr)
424 bb.Write(ELEMENT_TYPE_I);
426 else if (type == u.System_UIntPtr)
428 bb.Write(ELEMENT_TYPE_U);
430 else if (type == u.System_TypedReference)
432 bb.Write(ELEMENT_TYPE_TYPEDBYREF);
434 else if (type == u.System_Object)
436 bb.Write(ELEMENT_TYPE_OBJECT);
438 else if (type.IsGenericParameter)
440 if (type is UnboundGenericMethodParameter || type.DeclaringMethod != null)
442 bb.Write(ELEMENT_TYPE_MVAR);
446 bb.Write(ELEMENT_TYPE_VAR);
448 bb.WriteCompressedInt(type.GenericParameterPosition);
450 else if (!type.__IsMissing && type.IsGenericType)
452 WriteGenericSignature(module, bb, type);
454 else if (type.__IsFunctionPointer)
456 bb.Write(ELEMENT_TYPE_FNPTR);
457 WriteStandAloneMethodSig(module, bb, type.__MethodSignature);
461 if (type.IsValueType)
463 bb.Write(ELEMENT_TYPE_VALUETYPE);
467 bb.Write(ELEMENT_TYPE_CLASS);
469 bb.WriteTypeDefOrRefEncoded(module.GetTypeToken(type).Token);
473 private static void WriteGenericSignature(ModuleBuilder module, ByteBuffer bb, Type type)
475 Type[] typeArguments = type.GetGenericArguments();
476 CustomModifiers[] customModifiers = type.__GetGenericArgumentsCustomModifiers();
477 if (!type.IsGenericTypeDefinition)
479 type = type.GetGenericTypeDefinition();
481 bb.Write(ELEMENT_TYPE_GENERICINST);
482 if (type.IsValueType)
484 bb.Write(ELEMENT_TYPE_VALUETYPE);
488 bb.Write(ELEMENT_TYPE_CLASS);
490 bb.WriteTypeDefOrRefEncoded(module.GetTypeToken(type).Token);
491 bb.WriteCompressedInt(typeArguments.Length);
492 for (int i = 0; i < typeArguments.Length; i++)
494 WriteCustomModifiers(module, bb, customModifiers[i]);
495 WriteType(module, bb, typeArguments[i]);
499 protected static void WriteCustomModifiers(ModuleBuilder module, ByteBuffer bb, CustomModifiers modifiers)
501 foreach (CustomModifiers.Entry entry in modifiers)
503 bb.Write(entry.IsRequired ? ELEMENT_TYPE_CMOD_REQD : ELEMENT_TYPE_CMOD_OPT);
504 bb.WriteTypeDefOrRefEncoded(module.GetTypeTokenForMemberRef(entry.Type));
508 internal static Type ReadTypeDefOrRefEncoded(ModuleReader module, ByteReader br, IGenericContext context)
510 int encoded = br.ReadCompressedInt();
514 return module.ResolveType((TypeDefTable.Index << 24) + (encoded >> 2), null, null);
516 return module.ResolveType((TypeRefTable.Index << 24) + (encoded >> 2), null, null);
518 return module.ResolveType((TypeSpecTable.Index << 24) + (encoded >> 2), context);
520 throw new BadImageFormatException();
524 internal static void WriteStandAloneMethodSig(ModuleBuilder module, ByteBuffer bb, __StandAloneMethodSig sig)
528 switch (sig.UnmanagedCallingConvention)
530 case CallingConvention.Cdecl:
531 bb.Write((byte)0x01); // C
533 case CallingConvention.StdCall:
534 case CallingConvention.Winapi:
535 bb.Write((byte)0x02); // STDCALL
537 case CallingConvention.ThisCall:
538 bb.Write((byte)0x03); // THISCALL
540 case CallingConvention.FastCall:
541 bb.Write((byte)0x04); // FASTCALL
544 throw new ArgumentOutOfRangeException("callingConvention");
549 CallingConventions callingConvention = sig.CallingConvention;
551 if ((callingConvention & CallingConventions.HasThis) != 0)
555 if ((callingConvention & CallingConventions.ExplicitThis) != 0)
557 flags |= EXPLICITTHIS;
559 if ((callingConvention & CallingConventions.VarArgs) != 0)
565 Type[] parameterTypes = sig.ParameterTypes;
566 Type[] optionalParameterTypes = sig.OptionalParameterTypes;
567 bb.WriteCompressedInt(parameterTypes.Length + optionalParameterTypes.Length);
568 WriteCustomModifiers(module, bb, sig.GetReturnTypeCustomModifiers());
569 WriteType(module, bb, sig.ReturnType);
571 foreach (Type t in parameterTypes)
573 WriteCustomModifiers(module, bb, sig.GetParameterCustomModifiers(index++));
574 WriteType(module, bb, t);
576 // note that optional parameters are only allowed for managed signatures (but we don't enforce that)
577 if (optionalParameterTypes.Length > 0)
580 foreach (Type t in optionalParameterTypes)
582 WriteCustomModifiers(module, bb, sig.GetParameterCustomModifiers(index++));
583 WriteType(module, bb, t);
588 internal static void WriteTypeSpec(ModuleBuilder module, ByteBuffer bb, Type type)
590 WriteType(module, bb, type);
593 internal static void WriteMethodSpec(ModuleBuilder module, ByteBuffer bb, Type[] genArgs)
595 bb.Write(GENERICINST);
596 bb.WriteCompressedInt(genArgs.Length);
597 foreach (Type arg in genArgs)
599 WriteType(module, bb, arg);
603 // this reads just the optional parameter types, from a MethodRefSig
604 internal static Type[] ReadOptionalParameterTypes(ModuleReader module, ByteReader br, IGenericContext context, out CustomModifiers[] customModifiers)
607 int paramCount = br.ReadCompressedInt();
608 CustomModifiers.Skip(br);
609 ReadRetType(module, br, context);
610 for (int i = 0; i < paramCount; i++)
612 if (br.PeekByte() == SENTINEL)
615 Type[] types = new Type[paramCount - i];
616 customModifiers = new CustomModifiers[types.Length];
617 for (int j = 0; j < types.Length; j++)
619 customModifiers[j] = CustomModifiers.Read(module, br, context);
620 types[j] = ReadType(module, br, context);
624 CustomModifiers.Skip(br);
625 ReadType(module, br, context);
627 customModifiers = Empty<CustomModifiers>.Array;
628 return Type.EmptyTypes;
631 protected static Type[] BindTypeParameters(IGenericBinder binder, Type[] types)
633 if (types == null || types.Length == 0)
635 return Type.EmptyTypes;
637 Type[] expanded = new Type[types.Length];
638 for (int i = 0; i < types.Length; i++)
640 expanded[i] = types[i].BindTypeParameters(binder);
645 internal static void WriteSignatureHelper(ModuleBuilder module, ByteBuffer bb, byte flags, ushort paramCount, List<Type> args)
650 bb.WriteCompressedInt(paramCount);
652 foreach (Type type in args)
654 if (type == MarkerType.ModOpt)
656 bb.Write(ELEMENT_TYPE_CMOD_OPT);
658 else if (type == MarkerType.ModReq)
660 bb.Write(ELEMENT_TYPE_CMOD_REQD);
662 else if (type == MarkerType.Sentinel)
666 else if (type == MarkerType.Pinned)
668 bb.Write(ELEMENT_TYPE_PINNED);
670 else if (type == null)
672 bb.Write(ELEMENT_TYPE_VOID);
676 WriteType(module, bb, type);