none
Tail calls and DynamicMethod RRS feed

  • Question

  • Hi

     

    From a bit of experimenting, it appears one cannot tail call a DynamicMethod as there seems to be an extra level of redirection that is not being tail called, resulting in stack growth.

     

    Using a non-DynamicMethod way to emit the same IL, does in fact do a proper tail call, and subsequently no growth in in the call stack.

     

    Is there a way around this?

     

    Cheers

     

    leppie

    Monday, March 31, 2008 12:22 PM

Answers

  •  

    I found a workaround, or rather the trouble spot.

     

    When using the:

    public DynamicMethod(
     string name,
     Type returnType,
     Type[] parameterTypes
    )
    constructor overload, it will create the DynamicMethod in an anonymously hosted assembly. 
    Using the other overload specifying your own module, works correctly.
    Issue resolved.
    Friday, April 4, 2008 11:21 AM

All replies

  •  

    I found a workaround, or rather the trouble spot.

     

    When using the:

    public DynamicMethod(
     string name,
     Type returnType,
     Type[] parameterTypes
    )
    constructor overload, it will create the DynamicMethod in an anonymously hosted assembly. 
    Using the other overload specifying your own module, works correctly.
    Issue resolved.
    Friday, April 4, 2008 11:21 AM
  • Some more information:

     

    From what I can see, it appears the anonymously hosted assembly does not have sufficient security permissions to allow a tail call.

     

    This overload was introduced in .NET 2.0 SP1.

     

    Friday, April 4, 2008 3:52 PM
  • Poking around JIT source code in the rotor, I found that tail calls between different assemblies are not allowed unless SkipVerification is allowed (not recommended):

    sscli20\clr\src\vm\jitinterface.cpp:6100:CEEInfo::canTailCall()

        // If the callee is not known (callvirt, calli) or the caller and callee are
        // in different assemblies, we cannot allow the tailcall (since we'd
        // optimize away what might be the only stack frame for a given assembly,
        // skipping a security check).
        if (pCallee == NULL ||
                 pCallee->GetModule()->GetClassLoader() != pCaller->GetModule()->GetClassLoader())
        {
            //                 |   non-virt non-xasm call   |   callvirt or xasm
            // specifies .tail |       Allowed              |   only if SkipVerify
            // no .tail        |       Allowed              |   Not allowed

            //If the code is marked as Skip Verification, then it is responsbile to
            //make sure that specifying .tail doesn't open up a security hole.

            if (fIsTailPrefix)
            {
                if (!Security::CanTailCall(pCaller))
                {
                    result = false;
                    goto exit;

    Refusing the SkipVerification permission on your assembly can uncover all sorts of subtle problems, many bloggers recommend it.

    Sunday, August 24, 2008 1:23 AM
  • BTW, the anonymous hosting assembly by itself has Unrestricted permission set, but dynamic methods inherit the creator's permissions.
    Sunday, August 24, 2008 1:28 AM