IKVM11  11
Java SE 11 Virtual Machine for .NET
Loading...
Searching...
No Matches
Signature.cs
Go to the documentation of this file.
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*/
24using System;
25using System.Collections.Generic;
26using System.Reflection.Metadata.Ecma335;
27
32
33using static IKVM.Reflection.Module;
34
35using CallingConvention = System.Runtime.InteropServices.CallingConvention;
36
37namespace IKVM.Reflection
38{
39
40 abstract class Signature
41 {
42
43 internal const byte DEFAULT = 0x00;
44 internal const byte VARARG = 0x05;
45 internal const byte GENERIC = 0x10;
46 internal const byte HASTHIS = 0x20;
47 internal const byte EXPLICITTHIS = 0x40;
48 internal const byte FIELD = 0x06;
49 internal const byte LOCAL_SIG = 0x07;
50 internal const byte PROPERTY = 0x08;
51 internal const byte GENERICINST = 0x0A;
52 internal const byte SENTINEL = 0x41;
53 internal const byte ELEMENT_TYPE_VOID = 0x01;
54 internal const byte ELEMENT_TYPE_BOOLEAN = 0x02;
55 internal const byte ELEMENT_TYPE_CHAR = 0x03;
56 internal const byte ELEMENT_TYPE_I1 = 0x04;
57 internal const byte ELEMENT_TYPE_U1 = 0x05;
58 internal const byte ELEMENT_TYPE_I2 = 0x06;
59 internal const byte ELEMENT_TYPE_U2 = 0x07;
60 internal const byte ELEMENT_TYPE_I4 = 0x08;
61 internal const byte ELEMENT_TYPE_U4 = 0x09;
62 internal const byte ELEMENT_TYPE_I8 = 0x0a;
63 internal const byte ELEMENT_TYPE_U8 = 0x0b;
64 internal const byte ELEMENT_TYPE_R4 = 0x0c;
65 internal const byte ELEMENT_TYPE_R8 = 0x0d;
66 internal const byte ELEMENT_TYPE_STRING = 0x0e;
67 internal const byte ELEMENT_TYPE_PTR = 0x0f;
68 internal const byte ELEMENT_TYPE_BYREF = 0x10;
69 internal const byte ELEMENT_TYPE_VALUETYPE = 0x11;
70 internal const byte ELEMENT_TYPE_CLASS = 0x12;
71 internal const byte ELEMENT_TYPE_VAR = 0x13;
72 internal const byte ELEMENT_TYPE_ARRAY = 0x14;
73 internal const byte ELEMENT_TYPE_GENERICINST = 0x15;
74 internal const byte ELEMENT_TYPE_TYPEDBYREF = 0x16;
75 internal const byte ELEMENT_TYPE_I = 0x18;
76 internal const byte ELEMENT_TYPE_U = 0x19;
77 internal const byte ELEMENT_TYPE_FNPTR = 0x1b;
78 internal const byte ELEMENT_TYPE_OBJECT = 0x1c;
79 internal const byte ELEMENT_TYPE_SZARRAY = 0x1d;
80 internal const byte ELEMENT_TYPE_MVAR = 0x1e;
81 internal const byte ELEMENT_TYPE_CMOD_REQD = 0x1f;
82 internal const byte ELEMENT_TYPE_CMOD_OPT = 0x20;
83 internal const byte ELEMENT_TYPE_PINNED = 0x45;
84
85 internal abstract void Write(ModuleBuilder module, ByteBuffer bb);
86
87 static Type ReadGenericInst(ModuleReader module, ByteReader br, IGenericContext context)
88 {
89 Type type;
90 switch (br.ReadByte())
91 {
92 case ELEMENT_TYPE_CLASS:
93 type = ReadTypeDefOrRefEncoded(module, br, context).MarkNotValueType();
94 break;
95 case ELEMENT_TYPE_VALUETYPE:
96 type = ReadTypeDefOrRefEncoded(module, br, context).MarkValueType();
97 break;
98 default:
99 throw new BadImageFormatException();
100 }
101
102 if (!type.__IsMissing && !type.IsGenericTypeDefinition)
103 throw new BadImageFormatException();
104
105 int genArgCount = br.ReadCompressedUInt();
106 var args = new Type[genArgCount];
107 CustomModifiers[] mods = null;
108 for (int i = 0; i < genArgCount; i++)
109 {
110 // 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
111 var cm = CustomModifiers.Read(module, br, context);
112 if (!cm.IsEmpty)
113 {
114 mods ??= new CustomModifiers[genArgCount];
115 mods[i] = cm;
116 }
117
118 args[i] = ReadType(module, br, context);
119 }
120
121 return GenericTypeInstance.Make(type, args, mods);
122 }
123
124 internal static Type ReadTypeSpec(ModuleReader module, ByteReader br, IGenericContext context)
125 {
126 // LAMESPEC a TypeSpec can contain custom modifiers (C++/CLI generates "newarr (TypeSpec with custom modifiers)")
127 CustomModifiers.Skip(br);
128 // LAMESPEC anything can be adorned by (useless) custom modifiers
129 // also, VAR and MVAR are also used in TypeSpec (contrary to what the spec says)
130 return ReadType(module, br, context);
131 }
132
133 private static Type ReadFunctionPointer(ModuleReader module, ByteReader br, IGenericContext context)
134 {
135 __StandAloneMethodSig sig = MethodSignature.ReadStandAloneMethodSig(module, br, context);
136 if (module.Universe.EnableFunctionPointers)
137 {
138 return FunctionPointerType.Make(module.Universe, sig);
139 }
140 else
141 {
142 // by default, like .NET we return System.IntPtr here
143 return module.Universe.System_IntPtr;
144 }
145 }
146
147 internal static Type[] ReadMethodSpec(ModuleReader module, ByteReader br, IGenericContext context)
148 {
149 if (br.ReadByte() != GENERICINST)
150 throw new BadImageFormatException();
151
152 var args = new Type[br.ReadCompressedUInt()];
153 for (int i = 0; i < args.Length; i++)
154 {
155 CustomModifiers.Skip(br);
156 args[i] = ReadType(module, br, context);
157 }
158
159 return args;
160 }
161
162 static int[] ReadArraySizes(ByteReader br)
163 {
164 var num = br.ReadCompressedUInt();
165 if (num == 0)
166 return null;
167
168 var arr = new int[num];
169 for (var i = 0; i < num; i++)
170 arr[i] = br.ReadCompressedUInt();
171
172 return arr;
173 }
174
175 private static int[] ReadArrayBounds(ByteReader br)
176 {
177 var num = br.ReadCompressedUInt();
178 if (num == 0)
179 return null;
180
181 var arr = new int[num];
182 for (var i = 0; i < num; i++)
183 arr[i] = br.ReadCompressedInt();
184
185 return arr;
186 }
187
188 static Type ReadTypeOrVoid(ModuleReader module, ByteReader br, IGenericContext context)
189 {
190 if (br.PeekByte() == ELEMENT_TYPE_VOID)
191 {
192 br.ReadByte();
193 return module.Universe.System_Void;
194 }
195 else
196 {
197 return ReadType(module, br, context);
198 }
199 }
200
201 // see ECMA 335 CLI spec June 2006 section 23.2.12 for this production
202 protected static Type ReadType(ModuleReader module, ByteReader br, IGenericContext context)
203 {
204 CustomModifiers mods;
205 switch (br.ReadByte())
206 {
207 case ELEMENT_TYPE_CLASS:
208 return ReadTypeDefOrRefEncoded(module, br, context).MarkNotValueType();
209 case ELEMENT_TYPE_VALUETYPE:
210 return ReadTypeDefOrRefEncoded(module, br, context).MarkValueType();
211 case ELEMENT_TYPE_BOOLEAN:
212 return module.Universe.System_Boolean;
213 case ELEMENT_TYPE_CHAR:
214 return module.Universe.System_Char;
215 case ELEMENT_TYPE_I1:
216 return module.Universe.System_SByte;
217 case ELEMENT_TYPE_U1:
218 return module.Universe.System_Byte;
219 case ELEMENT_TYPE_I2:
220 return module.Universe.System_Int16;
221 case ELEMENT_TYPE_U2:
222 return module.Universe.System_UInt16;
223 case ELEMENT_TYPE_I4:
224 return module.Universe.System_Int32;
225 case ELEMENT_TYPE_U4:
226 return module.Universe.System_UInt32;
227 case ELEMENT_TYPE_I8:
228 return module.Universe.System_Int64;
229 case ELEMENT_TYPE_U8:
230 return module.Universe.System_UInt64;
231 case ELEMENT_TYPE_R4:
232 return module.Universe.System_Single;
233 case ELEMENT_TYPE_R8:
234 return module.Universe.System_Double;
235 case ELEMENT_TYPE_I:
236 return module.Universe.System_IntPtr;
237 case ELEMENT_TYPE_U:
238 return module.Universe.System_UIntPtr;
239 case ELEMENT_TYPE_STRING:
240 return module.Universe.System_String;
241 case ELEMENT_TYPE_OBJECT:
242 return module.Universe.System_Object;
243 case ELEMENT_TYPE_VAR:
244 return context.GetGenericTypeArgument(br.ReadCompressedUInt());
245 case ELEMENT_TYPE_MVAR:
246 return context.GetGenericMethodArgument(br.ReadCompressedUInt());
247 case ELEMENT_TYPE_GENERICINST:
248 return ReadGenericInst(module, br, context);
249 case ELEMENT_TYPE_SZARRAY:
250 mods = CustomModifiers.Read(module, br, context);
251 return ReadType(module, br, context).__MakeArrayType(mods);
252 case ELEMENT_TYPE_ARRAY:
253 mods = CustomModifiers.Read(module, br, context);
254 return ReadType(module, br, context).__MakeArrayType(br.ReadCompressedUInt(), ReadArraySizes(br), ReadArrayBounds(br), mods);
255 case ELEMENT_TYPE_PTR:
256 mods = CustomModifiers.Read(module, br, context);
257 return ReadTypeOrVoid(module, br, context).__MakePointerType(mods);
258 case ELEMENT_TYPE_FNPTR:
259 return ReadFunctionPointer(module, br, context);
260 default:
261 throw new BadImageFormatException();
262 }
263 }
264
265 internal static void ReadLocalVarSig(ModuleReader module, ByteReader br, IGenericContext context, List<LocalVariableInfo> list)
266 {
267 if (br.Length < 2 || br.ReadByte() != LOCAL_SIG)
268 throw new BadImageFormatException("Invalid local variable signature");
269
270 var count = br.ReadCompressedUInt();
271 for (int i = 0; i < count; i++)
272 {
273 if (br.PeekByte() == ELEMENT_TYPE_TYPEDBYREF)
274 {
275 br.ReadByte();
276 list.Add(new LocalVariableInfo(i, module.Universe.System_TypedReference, false));
277 }
278 else
279 {
280 var mods1 = CustomModifiers.Read(module, br, context);
281 var pinned = false;
282 if (br.PeekByte() == ELEMENT_TYPE_PINNED)
283 {
284 br.ReadByte();
285 pinned = true;
286 }
287
288 var mods2 = CustomModifiers.Read(module, br, context);
289 var type = ReadTypeOrByRef(module, br, context);
290 list.Add(new LocalVariableInfo(i, type, pinned, mods2));
291 }
292 }
293 }
294
295 static Type ReadTypeOrByRef(ModuleReader module, ByteReader br, IGenericContext context)
296 {
297 if (br.PeekByte() == ELEMENT_TYPE_BYREF)
298 {
299 br.ReadByte();
300 // LAMESPEC it is allowed (by C++/CLI, ilasm and peverify) to have custom modifiers after the BYREF
301 // (which makes sense, as it is analogous to pointers)
302 var mods = CustomModifiers.Read(module, br, context);
303 // C++/CLI generates void& local variables, so we need to use ReadTypeOrVoid here
304 return ReadTypeOrVoid(module, br, context).__MakeByRefType(mods);
305 }
306 else
307 {
308 return ReadType(module, br, context);
309 }
310 }
311
312 protected static Type ReadRetType(ModuleReader module, ByteReader br, IGenericContext context)
313 {
314 switch (br.PeekByte())
315 {
316 case ELEMENT_TYPE_VOID:
317 br.ReadByte();
318 return module.Universe.System_Void;
319 case ELEMENT_TYPE_TYPEDBYREF:
320 br.ReadByte();
321 return module.Universe.System_TypedReference;
322 default:
323 return ReadTypeOrByRef(module, br, context);
324 }
325 }
326
327 protected static Type ReadParam(ModuleReader module, ByteReader br, IGenericContext context)
328 {
329 switch (br.PeekByte())
330 {
331 case ELEMENT_TYPE_TYPEDBYREF:
332 br.ReadByte();
333 return module.Universe.System_TypedReference;
334 default:
335 return ReadTypeOrByRef(module, br, context);
336 }
337 }
338
339 protected static void WriteType(ModuleBuilder module, ByteBuffer bb, Type type)
340 {
341 while (type.HasElementType)
342 {
343 byte sigElementType = type.SigElementType;
344 bb.Write(sigElementType);
345 if (sigElementType == ELEMENT_TYPE_ARRAY)
346 {
347 // LAMESPEC the Type production (23.2.12) doesn't include CustomMod* for arrays, but the verifier allows it and ildasm also supports it
348 WriteCustomModifiers(module, bb, type.__GetCustomModifiers());
349 WriteType(module, bb, type.GetElementType());
350 bb.WriteCompressedUInt(type.GetArrayRank());
351
352 var sizes = type.__GetArraySizes();
353 bb.WriteCompressedUInt(sizes.Length);
354 for (int i = 0; i < sizes.Length; i++)
355 bb.WriteCompressedUInt(sizes[i]);
356
357 var lobounds = type.__GetArrayLowerBounds();
358 bb.WriteCompressedUInt(lobounds.Length);
359 for (int i = 0; i < lobounds.Length; i++)
360 bb.WriteCompressedInt(lobounds[i]);
361
362 return;
363 }
364 WriteCustomModifiers(module, bb, type.__GetCustomModifiers());
365 type = type.GetElementType();
366 }
367
368 if (type.__IsBuiltIn)
369 {
370 bb.Write(type.SigElementType);
371 }
372 else if (type.IsGenericParameter)
373 {
374 bb.Write(type.SigElementType);
375 bb.WriteCompressedUInt(type.GenericParameterPosition);
376 }
377 else if (!type.__IsMissing && type.IsGenericType)
378 {
379 WriteGenericSignature(module, bb, type);
380 }
381 else if (type.IsFunctionPointer)
382 {
383 bb.Write(ELEMENT_TYPE_FNPTR);
384 WriteStandAloneMethodSig(module, bb, type.__MethodSignature);
385 }
386 else
387 {
388 if (type.IsValueType)
389 bb.Write(ELEMENT_TYPE_VALUETYPE);
390 else
391 bb.Write(ELEMENT_TYPE_CLASS);
392
393 bb.WriteTypeDefOrRefEncoded(module.GetTypeToken(type).Token);
394 }
395 }
396
397 static void WriteGenericSignature(ModuleBuilder module, ByteBuffer bb, Type type)
398 {
399 var typeArguments = type.GetGenericArguments();
400 var customModifiers = type.__GetGenericArgumentsCustomModifiers();
401 if (!type.IsGenericTypeDefinition)
402 type = type.GetGenericTypeDefinition();
403
404 bb.Write(ELEMENT_TYPE_GENERICINST);
405 if (type.IsValueType)
406 bb.Write(ELEMENT_TYPE_VALUETYPE);
407 else
408 bb.Write(ELEMENT_TYPE_CLASS);
409
410 bb.WriteTypeDefOrRefEncoded(module.GetTypeToken(type).Token);
411 bb.WriteCompressedUInt(typeArguments.Length);
412 for (var i = 0; i < typeArguments.Length; i++)
413 {
414 WriteCustomModifiers(module, bb, customModifiers[i]);
415 WriteType(module, bb, typeArguments[i]);
416 }
417 }
418
419 protected static void WriteCustomModifiers(ModuleBuilder module, ByteBuffer bb, CustomModifiers modifiers)
420 {
421 foreach (var entry in modifiers)
422 {
423 bb.Write(entry.IsRequired ? ELEMENT_TYPE_CMOD_REQD : ELEMENT_TYPE_CMOD_OPT);
424 bb.WriteTypeDefOrRefEncoded(module.GetTypeTokenForMemberRef(entry.Type));
425 }
426 }
427
428 internal static Type ReadTypeDefOrRefEncoded(ModuleReader module, ByteReader br, IGenericContext context)
429 {
430 var encoded = br.ReadCompressedUInt();
431 return (encoded & 3) switch
432 {
433 0 => module.ResolveType((TypeDefTable.Index << 24) + (encoded >> 2), null, null),
434 1 => module.ResolveType((TypeRefTable.Index << 24) + (encoded >> 2), null, null),
435 2 => module.ResolveType((TypeSpecTable.Index << 24) + (encoded >> 2), context),
436 _ => throw new BadImageFormatException(),
437 };
438 }
439
440 internal static void WriteStandAloneMethodSig(ModuleBuilder module, ByteBuffer bb, __StandAloneMethodSig sig)
441 {
442 if (sig.IsUnmanaged)
443 {
444 switch (sig.UnmanagedCallingConvention)
445 {
446 case CallingConvention.Cdecl:
447 bb.Write((byte)0x01); // C
448 break;
449 case CallingConvention.StdCall:
450 case CallingConvention.Winapi:
451 bb.Write((byte)0x02); // STDCALL
452 break;
453 case CallingConvention.ThisCall:
454 bb.Write((byte)0x03); // THISCALL
455 break;
456 case CallingConvention.FastCall:
457 bb.Write((byte)0x04); // FASTCALL
458 break;
459 default:
460 throw new ArgumentOutOfRangeException("callingConvention");
461 }
462 }
463 else
464 {
465 var callingConvention = sig.CallingConvention;
466 var flags = 0;
467 if ((callingConvention & CallingConventions.HasThis) != 0)
468 flags |= HASTHIS;
469 if ((callingConvention & CallingConventions.ExplicitThis) != 0)
470 flags |= EXPLICITTHIS;
471 if ((callingConvention & CallingConventions.VarArgs) != 0)
472 flags |= VARARG;
473
474 bb.Write(flags);
475 }
476
477 var parameterTypes = sig.ParameterTypes;
478 var optionalParameterTypes = sig.OptionalParameterTypes;
479 bb.WriteCompressedUInt(parameterTypes.Length + optionalParameterTypes.Length);
480 WriteCustomModifiers(module, bb, sig.GetReturnTypeCustomModifiers());
481 WriteType(module, bb, sig.ReturnType);
482
483 int index = 0;
484 foreach (var t in parameterTypes)
485 {
486 WriteCustomModifiers(module, bb, sig.GetParameterCustomModifiers(index++));
487 WriteType(module, bb, t);
488 }
489
490 // note that optional parameters are only allowed for managed signatures (but we don't enforce that)
491 if (optionalParameterTypes.Length > 0)
492 {
493 bb.Write(SENTINEL);
494 foreach (var t in optionalParameterTypes)
495 {
496 WriteCustomModifiers(module, bb, sig.GetParameterCustomModifiers(index++));
497 WriteType(module, bb, t);
498 }
499 }
500 }
501
502 internal static void WriteTypeSpec(ModuleBuilder module, ByteBuffer bb, Type type)
503 {
504 WriteType(module, bb, type);
505 }
506
507 internal static void WriteMethodSpec(ModuleBuilder module, ByteBuffer bb, Type[] genArgs)
508 {
509 bb.Write(GENERICINST);
510 bb.WriteCompressedUInt(genArgs.Length);
511 foreach (var arg in genArgs)
512 WriteType(module, bb, arg);
513 }
514
515 // this reads just the optional parameter types, from a MethodRefSig
516 internal static Type[] ReadOptionalParameterTypes(ModuleReader module, ByteReader br, IGenericContext context, out CustomModifiers[] customModifiers)
517 {
518 br.ReadByte();
519 var paramCount = br.ReadCompressedUInt();
520 CustomModifiers.Skip(br);
521 ReadRetType(module, br, context);
522 for (int i = 0; i < paramCount; i++)
523 {
524 if (br.PeekByte() == SENTINEL)
525 {
526 br.ReadByte();
527 var types = new Type[paramCount - i];
528 customModifiers = new CustomModifiers[types.Length];
529 for (int j = 0; j < types.Length; j++)
530 {
531 customModifiers[j] = CustomModifiers.Read(module, br, context);
532 types[j] = ReadType(module, br, context);
533 }
534
535 return types;
536 }
537
538 CustomModifiers.Skip(br);
539 ReadType(module, br, context);
540 }
541
542 customModifiers = Array.Empty<CustomModifiers>();
543 return Type.EmptyTypes;
544 }
545
546 protected static Type[] BindTypeParameters(IGenericBinder binder, Type[] types)
547 {
548 if (types == null || types.Length == 0)
549 return Type.EmptyTypes;
550
551 var expanded = new Type[types.Length];
552 for (var i = 0; i < types.Length; i++)
553 expanded[i] = types[i].BindTypeParameters(binder);
554
555 return expanded;
556 }
557
558 internal static void WriteSignatureHelper(ModuleBuilder module, ByteBuffer bb, byte flags, ushort paramCount, List<Type> args)
559 {
560 bb.Write(flags);
561 if (flags != FIELD)
562 bb.WriteCompressedUInt(paramCount);
563
564 foreach (var type in args)
565 {
566 if (type == null)
567 bb.Write(ELEMENT_TYPE_VOID);
568 else if (type is MarkerType)
569 bb.Write(type.SigElementType);
570 else
571 WriteType(module, bb, type);
572 }
573 }
574
575 }
576
577}
IKVM.Reflection.Type Type
System.Runtime.InteropServices.CallingConvention CallingConvention
Definition Signature.cs:35
Represents a method signature from IL metadadata.
static Type ReadType(ModuleReader module, ByteReader br, IGenericContext context)
Definition Signature.cs:202
static void WriteCustomModifiers(ModuleBuilder module, ByteBuffer bb, CustomModifiers modifiers)
Definition Signature.cs:419
static void WriteType(ModuleBuilder module, ByteBuffer bb, Type type)
Definition Signature.cs:339
static Type[] BindTypeParameters(IGenericBinder binder, Type[] types)
Definition Signature.cs:546
static Type ReadParam(ModuleReader module, ByteReader br, IGenericContext context)
Definition Signature.cs:327
static Type ReadRetType(ModuleReader module, ByteReader br, IGenericContext context)
Definition Signature.cs:312
Type GetGenericMethodArgument(int index)
Type GetGenericTypeArgument(int index)