The question seems like a dirty hack you should not do but let me explain first. The ultimate goal is to have method local statics like in C++.
void Func()
{
static methodLocalObject = new ExpensiveThing();
// use methodlocal Object
}
What has this to do with the instruction pointer? I want to cache data depending on my caller. To make this fast I walk back in the stack to get the address of my caller and use this as unique key for a dictionary to store the data. That would allow to create a reflection based tracer which does not use Reflection every time to get the name of the current method and type but only once and store the reflection infos in a hash table.
The answers so far were only mono based. I want to try a generic solution which works on .NET 3.5/4.0 32/64 bit. I do know that the calling convention for 64 bit is quite different so it could get challenging to get something reliable. But on the other hand I have full control inside my method how the stack does look like. The stack does look very different between .NET 3.5 and 4.0 and it differs of course also between release builds. I still have to check if NGen does create code with a different stack layout as well. One possibility would be to use a C++ helper method which takes 5 magic integer arguments (on x64 only the 5th will be on the stack) and check where I can find them on the stack. Another possiblity would be to simply use the whole stack until I find my magic marker on the stack as a key and use this part of the stack as unique enough key. But I am not sure if this approach can work at all or if there are better alternatives. I do know I can walk the stack in a safe way via the profiling or debugging apis but neither of them are fast.
For a tracing library the usual approach is to walk the stack using reflection to get the current method name and type.
class Tracer
{
[MethodImpl(MethodImplOptions.NoInlining)]
public Tracer()
{
StackFrame frame = new StackTrace().GetFrame(1); // get caller
Console.WriteLine("Entered method {0}.{1}", frame.GetMethod().DeclaringType.FullName, frame.GetMethod().Name);
}
}
But this is very slow. The other solution is to pass the data directly via strings which is much faster but it needs more typing. The alternate solution would be to use the instruction pointer of the calling function (if this can be determined in a very fast way) to get around the expensive reflection calls. Then this would be possible:
class Tracer
{
static Dictionary<Int64, string> _CachedMethods = new Dictionary<Int64, string>();
[MethodImpl(MethodImplOptions.NoInlining)]
public Tracer()
{
Int64 eip = GetEIpOfParentFrame();
string name;
lock (_CachedMethods)
{
if (!_CachedMethods.TryGetValue(eip, out name))
{
var callingMethod = new StackTrace().GetFrame(1).GetMethod();
name = callingMethod.DeclaringType + "." + callingMethod.Name;
_CachedMethods[eip] = name;
}
}
Console.WriteLine("Entered method {0}", name);
}
Int64 GetEIpOfParentFrame()
{
return 0; // todo this is the question how to get it
}
}
I know that the solution needs to be unmanaged. In C++ there is a compiler intrinsic called _ReturnAddress but according to the docs it does not work with managed code. Another way to ask the same question: Does anybody know the calling convention and stack layout for managed methods for .NET 3.5/4 x32/x64?
Yours, Alois Kraus
See Question&Answers more detail:os