Thursday, March 6, 2014

AX 2012 X++ compilation from a .NET developers perspective

The last month or two I have been “forced” to look at X++ and AX2012, and getting started writing X++ is easy, if you have a background as a .NET developer.

When you start writing and compiling code in AX, you quickly get frustrated as a .NET developer. Why does it not work, - my “compilation” did not throw any errors! It works when I run the job manually, but automatically I does not!

So I realized that there was some fundamental AX2012 that I did not understand as a .NET developer, and much of the frustration was due not understand how the AX compiler works. For many (if not most!) developers this might not be a problem at all, or at least to at some point. In my case it was from the beginning.

I will try to explain how I understand as a .NET developer how the X++ compiler and runtime execution works.

At a high level, the process of compiling and X++ is illustrated in this diagram.


When you are compiling in AX, you don’t compile directly into .NET CIL, it only compiles to p-code. CIL is generated by actively choosing to generate it - either incrementally or full (full generation takes maybe 10-15 min). The Compilation results in P-code are stored in the model store (SQL database). 

Depending on the entry points your code will either be executed either directly in p-code or in CIL. From P-Code you can also easily switch to CIL execution – which is what the application does in most of the more complex proceses. However much code is still executed I P-Code.

Compilation is a three-phased process requiring all code fragments to be received from database (model store). “the three-phased process”, can be read in greater detail in this post: http://bit.ly/1e0WM3I

Phase1: Limited compile only for metadata "class declarations and method signatures"
Phase2: Full compile for metadata and code bodies.
Phase3 to PhaseN: Recompile the error elements, until success or error stabilization.

I have tried for fun to create a detailed diagram, but sometime it’s just easier to tell by code, rather than a diagram :-) decide yourself. First you see the example

First I show a diagram and next a good C# pseudo code example.


C# pseudo code example, borrowed from the post bit.ly/1e0WM3I

// Phase1: Limited compile only for metadata
// (of class declarations and method signatures).
foreach(Element in AOT)
{
       Element.CompileHeaders();
}
// Phase2: Full compile for metadata and code bodies.
foreach(Element in AOT)
{
       compileSuceeded = Element.Compile();
       if (compileSuceeded == false)
       {
              ListOfBadElements.Add(Element);
       }
}
// Phase3 to PhaseN: Recompile the errored elements
// until success or error stabilization.
if (ListOfBadElements.Count > 0)
{
       while(true)
       {
              foreach(Element in ListOfBadElements)
              {
                     compileSuceeded = Element.Compile();
                     if (compileSuceeded == false)
                     {
                           NewListOfBadElements.Add(Element)
                     }
              }
              
              if (ListOfBadElements.Count == NewListOfBadElements.Count)
              {
                     break; // The list of elements with errors has been stabilized.
              }
              ListOfBadElements = NewListOfBadElements.GetCopy();
              NewListOfBadElements.Reset();
       }
}

So what is the different between p-code and CIL? In short: p-code is lazy regarding type-checking and CIL is strongly typed, the same way as when your C# code has been compiled to CIL.

P-code
p-code is the byte code, which been compiled from X++ by the AX compiler.
First when I started writing this post I was comparing p-code as JavaScript? Because of the less restrictive type checking at runtime than compiled CIL has, but this is not true! After some good discussions with Achim (Dynamics AX Technical Architect) and Stig (Consultant), I concluded that we are not playing around coding in byte code (P-Code) but you do in JavaScript. P-Code runs in interpreted mode on either the client or the server.

CIL
Batch jobs and the Business Connector always run in CIL code, and CIL can run on both the server, or the client. CIL runs on the CLR infrastructure, which is much faster than the interpreted p-code.

Be aware when using interpreted P-code
The last thing I want to mention in this post is to be aware when using interpreted P-code. It has less restrictive type-checking at runtime than compiled with CIL, and this can cause your problems. I have probably found an AX bug where a method requiring a sub-type argument but actually getting a super-type instead. This can work fine in p-code, if the code is not calling something that is sub-type specific, but would give you and error in CIL because it’s strictly typed. And this will raise an “unable to cast the super-type to a sub-type”.






2 comments:

  1. "and CIL can run on both the server, or the client." <- this is incorrect, you can only switch to CLR on server tier

    ReplyDelete
  2. This comment has been removed by a blog administrator.

    ReplyDelete