Add Code

CCI Code Model

To this point, HelloCodeModel has been working entirely with metadata and the CCI Metadata API. To complete the assembly, you must create a method body and a code block for Main.

CCI Metadata adds code to the assembly as a flat list of MSIL instructions, which is usually suitable only for creating short simple code blocks. HelloCodeModel uses the CCI Code API to create the code block. CCI Code represents code in a structured way that is similar to normal source code. It is much easier to work with than a list of MSIL instructions, especially for large or complex code blocks.

Create the Method Body

CCI Code applications represent method bodies with Microsoft.Cci.MutableCodeModel.SourceMethodBody objects. The following example shows how HelloCodeModel creates the Main method body.
var body = new SourceMethodBody(host, null, null)
{
  MethodDefinition = mainMethod,
  LocalsAreZeroed = true
};
mainMethod.Body = body;
var block = new BlockStatement();
body.Block = block;

The SourceMethodBody constructor has three parameters:
  1. The host, which is used to obtain access to certain global objects and services such as the NameTable object.
  2. A optional source location provider, which maps locations in the code block to PrimarySourceLocation objects. HelloCodeModel doesn’t use this object, so the parameter is set to null.
  3. An optional contract provider object, which associates contracts, such as preconditions and postconditions, with methods, types and loops. HelloCodeModel doesn’t use this object, so the parameter is set to null.
HelloCodeModel sets two properties:
  • MethodDefinition establishes a link between the method body and its metadata by assigning the Main method’s MethodDefinition object to the *MethodDefinition property.
  • Setting LocalsAreZeroed to true initializes all locals to zero by zeroing the stack on method entry.
HelloCodeModel creates a link between the metadata and its method body by assigning the method’s SourceMethodBody object to MethodDefinition.Body.

Finally, HelloCodeModel creates a Microsoft.Cci.Ast.BlockStatement to hold the method’s code block and assigns it to the SourceMethodBody object’s Block property.

Create Type and Method Definitions

You must create definition objects for any methods that are to be called, and for their types. CCI Code includes helper objects that create an appropriate definition object and return its immutable representation.

For more discussion of immutable representations, see Mutable and Immutable Representations.

Hello.exe calls one method, System.Console.WriteLine, which is in mscorlib.dll. HelloCodeModel creates the method’s type definition object as follows.
INamedTypeDefinition systemConsole = UnitHelper.FindType(nameTable,
                                                         coreAssembly,
                                                         "System.Console");

Microsoft.Cci.UnitHelper.FindType creates a NamedTypeDefinition object for specified type and returns its immutable Microsoft.Cci.INamedTypeDefinition interface.
FindType has three parameters:
  1. The NameTable object.
  2. The assembly that contains the method, the .NET core assembly in this case.
  3. The fully-qualified type name, as an ordinary string.
HelloCodeModel creates the WriteLine method definition object as follows.
IMethodDefinition writeLine = TypeHelper.GetMethod(systemConsole,
                                                   nameTable.GetNameFor("WriteLine"),
                                                   host.PlatformType.SystemString);

Microsoft.Cci.TypeHelper.GetMethod creates a MethodDefinition object for WriteLine and returns the object’s immutable IMethodDefinition interface. GetMethod has three parameters:
  1. The type definition object from the previous example.
  2. An IName interface interface for the method name, created in the usual way.
  3. A list of the method’s parameter types, in order. In this case, the method has a single string parameter.

Add a Code Block to the Method Body

The final step is to use CCI Code to add a code block to the Main method body, as follows:
var call = new MethodCall()
{
  IsStaticCall = true,
  MethodToCall = writeLine,
  Type = host.PlatformType.SystemVoid
};
call.Arguments.Add(new CompileTimeConstant()
                   {
                     Type = host.PlatformType.SystemString, 
                     Value = "hello"
                   });
block.Statements.Add(new ExpressionStatement() { Expression = call });
block.Statements.Add(new ReturnStatement());

The Main code block consists of a single method call, Console.WriteLine. CCI Code represents method calls by Microsoft.Cci.Ast.MethodCall objects. HelloCodeModel initializes the MethodCall properties, as follows:
  • IsStaticCall specifies a static method.
  • MethodCall specifies the method to be called, which is represented by its MethodDefinition object.
  • Type specifies the method’s return type, which is represented by its ITypeDefinition object. DefaultHost.PlatformType contains ITypeDefinition objects for standard system types, such as SystemVoid.
If the method has parameters, you must add the values to the IMethodCall.Arguments collection. To do so, pass an Microsoft.Cci.Ast.Expression object representing the value to MethodCall.Arguments.Add, once for each parameter. HelloCodeModel passes a single string constant to WriteLine. CCI Code represents constants by CompileTimeConstant objects, which inherit from Expression. HelloCodeModel sets the CompileTimeConstant object’s properties as follows:
  • Type is the parameter type, and is set to the ITypeDefinition object for System.String.
  • Value is the parameter value, and is set to “hello”.
Finally, add the statements that make up the code block to the BlockStatement object, in execution order:
  • The WriteLine call is represented by a Microsoft.Cci.Ast.ExpressionStatement object, with its Expression property set to the MethodCall object.
  • The return statement is represented by a Microsoft.Cci.Ast.ReturnStatement object. Main doesn’t return a value, so HelloCodeModel uses the default object. For methods that return a value, set ReturnStatement.Expression to an Expression object that represents the value.
Note: Because Main is a void type, the ReturnStatement object is not strictly necessary. The CodeModelToIL converter inserts an implicit return statement at the end of a void method if the last statement of the method is not an unconditional transfer. However, CCI Code generally follows MSIL practice, which requires a return statement, so Main includes a ReturnStatement object.

Next: Write the Assembly to a File
Return to Beginning

Last edited Mar 9, 2010 at 7:48 PM by Guy_Smith, version 1

Comments

No comments yet.