Variable Argument Lists

Variable Argument Lists

Encounters with variable argument list (vararg) methods in earlier chapters revealed the following information:

  • The calling convention of these methods is vararg.

  • Only mandatory parameters, if any, are specified in the vararg method declaration:

    .method public static vararg void Print(string Format)  { ... }

  • If and only if optional parameters are specified in a vararg method reference at the call site, they are preceded by a sentinel—an ellipsis in ILAsm notation—and a comma:

    call vararg void Print(string, ..., int32float32string)

I’m not sure that requiring the sentinel to appear as an independent comma-separated argument was a good idea. After all, a sentinel is not a true element type but is a modifier of the element type immediately following. Nevertheless, such is ILAsm notation in the first release of the common language runtime, and we’ll have to live with it at least for a while.

The vararg method signature at the call site obviously differs from the signature specified when the method is defined, because it carries information about optional parameters. That’s why the vararg methods are always referenced by MemberRef tokens and never by MethodDef tokens, even if the method is defined in the current module. (In that case, the MemberRef record corresponding to the vararg call site will have the respective MethodDef as its parent, which is slightly disturbing, but only at first sight.)

Now let’s see how the vararg methods are implemented. IL offers no specific instructions for argument list parsing beyond the arglist instruction, which merely creates the argument list structure. To work with this structure and iterate through the argument list, you need to work with the .NET Framework class library value type [mscorlib]System.ArgIterator. This value type should be initialized with the argument list structure, which is an instance of the value type [mscorlib]System.RuntimeArgumentHandle, returned by the arglist instruction. ArgIterator offers such useful methods as GetRemainingCount and GetNextArg.

To make a long story short, let’s review the following code snippet from the sample file Vararg.il on the companion CD:

// Compute sum of undefined number of arguments .method public static vararg unsigned int64     Sum(/* all arguments optional */) {    .locals init(value class [mscorlib]System.ArgIterator Args,                 unsigned int64 Sum,                 int32 NumArgs)    ldc.i8 0    stloc Sum       ldloca Args    arglist // Create argument list structure    // Initialize ArgIterator with this structure:    call instance void [mscorlib]System.ArgIterator::.ctor(       value class [mscorlib]System.RuntimeArgumentHandle)         // Get the optional argument count:    ldloca Args    call instance int32 System.ArgIterator::GetRemainingCount()    stloc NumArgs         // Main cycle:  LOOP:    ldloc NumArgs    brfalse RETURN // if(NumArgs == 0) goto RETURN;    // Get next argument:    ldloca Args    call instance typedref [mscorlib]System.ArgIterator::GetNextArg()    // Interpret it as unsigned int64:    refanyval [mscorlib]System.UInt64    ldind.u8    // Add it to Sum:    ldloc Sum    add    stloc Sum // Sum += *((int64*)&next_arg)    // Decrease NumArgs and go for next argument:    ldloc NumArgs    ldc.i4.m1    add    stloc NumArgs    br LOOP  RETURN:    ldloc Sum    Ret }

In this code, we did not specify any mandatory arguments and thus took the return value of GetRemainingCount for the argument count. Actually, GetRemainingCount returns only the number of optional arguments, which means that if we had specified N mandatory arguments, the total argument count would have been greater by N.

The GetNextArg method returns a typed reference, typedref, which is cast to a managed pointer to an 8-byte unsigned integer by the instruction refanyval [mscorlib]System.UInt64. If the type of the argument cannot be converted to the required type, the JIT compiler throws an InvalidCast exception.



Inside Microsoft. NET IL Assembler
Inside Microsoft .NET IL Assembler
ISBN: 0735615470
EAN: 2147483647
Year: 2005
Pages: 147
Authors: SERGE LIDIN

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net