Some preliminary info
Given the following C# function:
public static void func<T>(T t)
{
System.Console.WriteLine(t);
}
It is compiled into the following CIL:
.method public hidebysig static void func<T>(!!T t) cil managed
{
ldarg.0
box !!T
call void [mscorlib]System.Console::WriteLine(object)
ret
}
The signature of the above method is 10 01 01 01 1E 00
where:
10 - Calling convention (IMAGE_CEE_CS_CALLCONV_GENERIC) 01 - Function generic arguments count (which is 1) 01 - Function arguments count (which is 1) 01 - Return type (ELEMENT_TYPE_VOID) 1E - First argument type (ELEMENT_TYPE_MVAR) 00 - Index of above MVAR (which is 0)
Also see the following instruction with it's actual byte code:
box !!T - 8C 1B000001
1B000001
points to the first entry in the TypeSpec table, which points to the blob 02 1E 00
where:
02 - Blob length 1E - Type type (ELEMENT_TYPE_MVAR) 00 - Index of above MVAR (which is 0)
As we can see, the method signature contains the generic argument in a descriptive way, where we have the actual type signature.
However, when using an OpCode which requires a TypeDef/Ref/Spec, a TypeSpec is supplied, and the TypeSpec points to a signature with the type information.
So my question is:
I'm writing a profiler which does some IL Rewriting, and given the function signature, I would like to add some OpCodes to the function body which will operate with the arguments.
Using the IMetaDataImport2
interface, how can I get the TypeSpec token I would need for a given generic parameter?
I can see 2 options:
IMetaDataEmit
interface to create a new TypeSpecHowever, for obvious reasons, I would like to avoid those 2 options and choose a more sensible alternative.
So I ended up going with my first suggestion.
I guess it's not ideal, but it does work.
Here's the code, if anyone is interested (error handling omitted):
HCORENUM typeSpecEnum = NULL;
mdTypeSpec typeSpec = mdTypeSpecNil;
ULONG outNum = -1;
// Loop through enum
while (true)
{
// Get next enum
HRESULT hr = pMetadataImport->EnumTypeSpecs(&typeSpecEnum, &typeSpec, 1, &outNum);
if (hr == S_FALSE && outNum == 0) // According to doc, this means no more. End loop
break;
// Get the signature of this typespec
PCCOR_SIGNATURE curSpecSig = NULL;
ULONG curSpecSigLen = -1;
pMetadataImport->GetTypeSpecFromToken(typeSpec, &curSpecSig, &curSpecSigLen);
if (curSpecSigLen == <my_len> && memcmp(curSpecSig, <my_sig>, <my_len>) == 0)
; // Token found
else
typeSpec = mdTypeSpecNil; // Reset and goto next token
}
pMetadataImport->CloseEnum(typeSpecEnum); // Don't forget to close enum
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With