Annex B Sample Programs


This section contains only informative text.


This Annex shows two complete examples written using ilasm.

ANNOTATION

To illustrate how CIL maps to high-level languages, these examples are annotated with near-equivalent programs in high-level languages. The program in section B.1 was written in Microsoft C#, and the program in section B.2 was written in Visual Basic.


B.1 Mutually Recursive Program (with tail. Calls)

The following is an example of a mutually recursive program that uses tail. calls. The methods below determine whether a number is even or odd.

 
 .assembly extern mscorlib { } .assembly test.exe { } .class EvenOdd { .method private static bool IsEven(int32 N) cil managed   { .maxstack   2     ldarg.0             // N     ldc.i4.0     bne.un      NonZero     ldc.i4.1     ret NonZero:     ldarg.0     ldc.i4.1     sub     tail.     call bool EvenOdd::IsOdd(int32)     ret   } // end of method "EvenOdd::IsEven"   .method private static bool IsOdd(int32 N) cil managed   { .maxstack   2     // Demonstrates use of argument names and labels     // Notice that the assembler does not convert these     // automatically to their short versions     ldarg       N     ldc.i4.0     bne.un      NonZero     ldc.i4.0     ret NonZero:     ldarg       N     ldc.i4.1     sub     tail.     call bool EvenOdd::IsEven(int32)     ret   } // end of method "EvenOdd::IsOdd"   .method public static void Test(int32 N) cil managed   { .maxstack   1     ldarg       N     call        void [mscorlib]System.Console::Write(int32)     ldstr       " is "     call        void [mscorlib]System.Console::Write(string)     ldarg       N     call        bool EvenOdd::IsEven(int32)     brfalse     LoadOdd     ldstr       "even" Print:     call        void [mscorlib]System.Console::WriteLine(string)     ret LoadOdd:     ldstr       "odd"     br          Print   } // end of method "EvenOdd::Test" } // end of class "EvenOdd" //Global method .method public static void main() cil managed { .entrypoint   .maxstack     1   ldc.i4.5   call          void EvenOdd::Test(int32)   ldc.i4.2   call          void EvenOdd::Test(int32)   ldc.i4        100   call          void EvenOdd::Test(int32)   ldc.i4        1000001   call          void EvenOdd::Test(int32)   ret } // end of global method "main" 

ANNOTATION

The following code simulates in C# the operations of the above program, although C# does not generate tail. for the calls, so the program fails on the final line with an out-of-stack exception.

 
 class EvenOdd { private static bool IsEven(int N)   { if (N==0) return true;         else return IsOdd(N-1);  /* Should be tail. call */   }   private static bool IsOdd(int N)   { if (N==0) return false;          else return IsEven(N-1);       /* Should be tail. call */   }   public static void Test(int N)   { System.Console.Write(N);         System.Console.Write(" is ");         System.Console.WriteLine(EvenOdd.IsEven(N) ? "even" : "odd");   }   static void Main(string[] args)   { EvenOdd.Test(5);     EvenOdd.Test(2);         EvenOdd.Test(100);     EvenOdd.Test(1000001);   } } 


B.2 Using Value Types

The following program shows how rational numbers can be implemented using value types.

 
 .assembly extern mscorlib { } .assembly rational.exe { } .class private sealed Rational extends [mscorlib]System.ValueType                              implements [mscorlib]System.IComparable { .field public int32 Numerator   .field public int32 Denominator   .method virtual public int32 CompareTo(object o)   // Implements IComparable::CompareTo(Object)   { ldarg.0     // "this" as a managed pointer     ldfld int32 value class Rational::Numerator     ldarg.1     // "o" as an object     unbox value class Rational     ldfld int32 value class Rational::Numerator     beq.s TryDenom     ldc.i4.0     ret TryDenom:     ldarg.0     // "this" as a managed pointer     ldfld int32 value class Rational::Denominator     ldarg.1     // "o" as an object     unbox value class Rational     ldfld int32 class Rational::Denominator     ceq     ret   }   .method virtual public string ToString()   // Implements Object::ToString   { .locals init (class [mscorlib]System.Text.StringBuilder SB,                   string S, object N, object D)     newobj void [mscorlib]System.Text.StringBuilder::.ctor()     stloc.s SB     ldstr "The value is: {0}/{1}"     stloc.s S     ldarg.0     // managed pointer to self     dup     ldfld int32 value class Rational::Numerator     box [mscorlib]System.Int32     stloc.s N     ldfld int32 value class Rational::Denominator     box [mscorlib]System.Int32     stloc.s D     ldloc.s SB     ldloc.s S     ldloc.s N     ldloc.s D     call instance class [mscorlib]System.Text.StringBuilder       [mscorlib]System.Text.StringBuilder::AppendFormat(string,                   object, object)     callvirt instance string [mscorlib]System.Object::ToString()     ret   }   .method public value class Rational Mul(value class Rational)   {     .locals init (value class Rational Result)     ldloca.s Result     dup     ldarg.0     // "this"     ldfld int32 value class Rational::Numerator     ldarga.s    1     // arg     ldfld int32 value class Rational::Numerator     mul     stfld int32 value class Rational::Numerator     ldarg.0     // "this"     ldfld int32 value class Rational::Denominator     ldarga.s    1     // arg     ldfld int32 value class Rational::Denominator     mul     stfld int32 value class Rational::Denominator     ldloc.s Result     ret   } } .method static void main() {   .entrypoint   .locals init (value class Rational Half,                 value class Rational Third,                 value class Rational Temporary,                 object H, object T)   // Initialize Half, Third, H, and T   ldloca.s Half   dup   ldc.i4.1   stfld int32 value class Rational::Numerator   ldc.i4.2   stfld  int32 value class Rational::Denominator   ldloca.s Third   dup   ldc.i4.1   stfld int32 value class Rational::Numerator   ldc.i4.3   stfld int32 value class Rational::Denominator   ldloc.s Half   box value class Rational   stloc.s H   ldloc.s Third   box value class Rational   stloc.s T   // WriteLine(H.IComparable::CompareTo(H))   // Call CompareTo via interface using boxed instance   ldloc H   dup   callvirt int32 [mscorlib]System.IComparable::CompareTo(object)   call void [mscorlib]System.Console::WriteLine(bool)   // WriteLine(Half.CompareTo(T))   // Call CompareTo via value type directly   ldloca.s Half   ldloc T   call instance int32   value class Rational::CompareTo(object)   call void [mscorlib]System.Console::WriteLine(bool)   // WriteLine(Half.ToString())   // Call virtual method via value type directly   ldloca.s Half   call instance string class Rational::ToString()   call void [mscorlib]System.Console::WriteLine(string)   // WriteLine(T.ToString)   // Call virtual method inherited from Object, via boxed instance   ldloc T   callvirt string [mscorlib]System.Object::ToString()   call void [mscorlib]System.Console::WriteLine(string)   // WriteLine((Half.Mul(T)).ToString())   // Mul is called on two value types, returning a value type   // ToString is then called directly on that value type   // Note that we are required to introduce a temporary variable   //   since the call to ToString requires   //   a managed pointer (address)   ldloca.s Half   ldloc.s Third   call instance value class Rational          Rational::Mul(value class Rational)   stloc.s Temporary   ldloca.s Temporary   call instance string Rational::ToString()   call void [mscorlib]System.Console::WriteLine(string)   ret } 

ANNOTATION

An interesting part of this example is its use of boxing and unboxing. In the method CompareTo, the third and fourth instructions are ldarg and unbox. That's because ldarg.1 is the argument o, which is a boxed object. To be able to use the ldfld instruction, you need the value type contained in the boxed object, so you need to call unbox to get a reference to the value type. If what you were passing were not of type Rational, unbox would give you an exception; otherwise it would give you the unboxed value and you could fetch the field out of it. Similarly, after the label TryDenom, there's another unbox, to get the denominator.

Next, in the method ToString, there are two boxed int32s. We have loaded the numerator and denominator fields, which are 32-bit integers, Then we want to store the numerator in the variable N and the denominator in the variable D, which are of type object, so we have to box them.

The next box operations are in main(). We want to take the Rational value Half and store it in H, which is of type object, so it must be boxed. Similarly, the Rational value Third must be boxed to store it in the object type T.

In a high-level language, boxing and unboxing are handled by the compiler, as shown in the following equivalent Visual Basic code:

 

Option Explicit On Option Strict On Module Module1 Private Structure Rational Implements System.IComparable Public Numerator As Integer Public Denominator As Integer Public Function CompareTo(ByVal o As Object) As Integer _ Implements System.IComparable.CompareTo 'Return 0 if I'm different from o, 1 if we're the same 'Assumes that rationals are stored in a canonical format If Me.Numerator <> CType(o, Rational).Numerator Then graphics/ccc.gif Return 0 If Me.Denominator <> CType(o, Rational).Denominator graphics/ccc.gif Then Return 0 Return 1 End Function Public Overrides Function ToString() As String Dim SB As New System.Text.StringBuilder, S As String, graphics/ccc.gif N As Object, D As Object S = "The value is: {0}/{1}" N = Me.Numerator D = Me.Denominator SB.AppendFormat(S, N, D) Return SB.ToString() End Function Public Function Mul(ByVal R As Rational) As Rational 'Multiplies two rationals, but does NOT put into graphics/ccc.gif canonical form Dim Result As Rational Result.Numerator = Me.Numerator * R.Numerator Result.Denominator = Me.Denominator * R.Denominator Return Result End Function End Structure Sub Main() Dim Half As Rational, Third As Rational, Temporary As graphics/ccc.gif Rational Dim H As Object, T As Object Half.Numerator = 1 Half.Denominator = 2 Third.Numerator = 1 Third.Denominator = 3 H = Half T = Third System.Console.WriteLine(CBool(CType(H, Rational) graphics/ccc.gif.CompareTo(H))) System.Console.WriteLine(CBool(Half.CompareTo(T))) System.Console.WriteLine(Half.ToString()) System.Console.WriteLine(T.ToString()) Temporary = Half.Mul(Third) System.Console.WriteLine(Temporary.ToString()) End Sub End Module




The Common Language Infrastructure Annotated Standard (Microsoft. NET Development Series)
The Common Language Infrastructure Annotated Standard (Microsoft. NET Development Series)
ISBN: N/A
EAN: N/A
Year: 2002
Pages: 121

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