David Redding

Blog? What blog? Theres no blog to see here. Please move along
posts - 54, comments - 53, trackbacks - 31

My Links

News

!--Avatar-->
www.flickr.com
This is a Flickr badge showing public photos from dredding. Make your own badge here.

Twitter












Tag Cloud

Article Categories

Archives

Post Categories

.Net Resource Sites

.Net User Group Sites

Language Resource Sites

Mason Sites

My Bloggin' Buddies

Watashi no "IL Code" seksu desu

    So, I may not be entirely up on my un-couth Japanese sayings, but one thing is for sure, IL code, to the average developer (Read: Me) might as well be written in the same Romaji thats in the title.  That is, it's hard to make heads or tails of, and since you most likely never, or only rarely look at it, you get very little opportunity to actually study it.  I've been the same way for the past few years, acknowledging that IL exists, and just like that ugly friend, I don't actually acknowledge there being a relationship between "It" and I in public.

    That all changed for me last Friday when my buddy Joshua Haynes dropped me a note abut my "Unloved Operators" Tech in 5 minutes post .  He was interested enough in how the ?? operator stacks up against the if(x==null) else structure that, he compiled an example and then sent me the IL code, looking for my opinion. 

    So I was stuck.  I could not admit defeat because of my ignorance of IL.  So I leapt into action, quickly throwing out all the TLA's I could in an attempt to undermine my friends intelligence.  He quickly blocked, pivoted and swatted away my attack.  Before he could completely recover I attempted the Clinton-Dodge-the-issue move I had learned from CNN, but Joshuah quickly saw through funny analogy's and interesting tangents and held his ground firmly, so....I gave in and made a trip to the oracle Google.  Come to find out, it can be difficult to research an answer, as compared to just pulling out of god knows where.  But I think that I figured out how do answer Josh's imposing "What do you think?" question.  below is the code and the IL that he sent me.

Person myself = null;
Person myFriend = new Person("Johhny", "Cash");
Person newFriend = myself ?? myFriend;
Console.WriteLine("The new Friend likes: {0}", newFriend.FullName());

if (myself != null)
   newFriend = myself;
else
   newFriend = myFriend;
Console.WriteLine("The new Friend likes: {0}", newFriend.FullName());

IL_0012:  stloc.1
  IL_0013:  ldloc.0
  IL_0014:  dup
  IL_0015:  brtrue.s   IL_0019
  IL_0017:  pop
  IL_0018:  ldloc.1
  IL_0019:  stloc.2
  IL_001a:  ldstr      "The new Friend likes: {0}"
  IL_001f:  ldloc.2
  IL_0020:  callvirt   instance string Test.Person::FullName()
  IL_0025:  call       void [mscorlib]System.Console::WriteLine(string,
                                                                object)
  IL_002a:  nop
  IL_002b:  ldloc.0
  IL_002c:  ldnull
  IL_002d:  ceq
  IL_002f:  stloc.3
  IL_0030:  ldloc.3
  IL_0031:  brtrue.s   IL_0037
  IL_0033:  ldloc.0
  IL_0034:  stloc.2
  IL_0035:  br.s       IL_0039
  IL_0037:  ldloc.1
  IL_0038:  stloc.2
  IL_0039:  ldstr      "The new Friend likes: {0}"
  IL_003e:  ldloc.2
  IL_003f:  callvirt   instance string Test.Person::FullName()
  IL_0044:  call       void [mscorlib]System.Console::WriteLine(string,
                                                                object)
The top is the ?? test and below is if statements. What do you think?

   So, starting from the top, I began to investigate what each call was.

    The first thing i needed to figure out was, what was the "IL_xxx" marker? simple, line numbers, easy enough.  Next up, what does this mean:

brtrue.s   IL_0037

a little googling and i found that "br" means "Branch" so "brtrue" must mean "True branch from a decision" (the .s seems to indicate Short form, or something of that nature).  So combine that with a line number and we have a basic go-to statement of

IF True GoTo: IL_0037

Ok, so that tackles the low hanging fruit.  The next thing on the list was these

stloc.x
ldloc.x

To google for these, i had to rack my brain for a bit.  I discovered that there is an OpCodes object that lives in the system.refelction.emit namespace.  And surprisingly enough, it has codes that match what I'm seeing the the IL.  So I quickly discovered the following entries.

 

Stloc_0 Pops the current value from the top of the evaluation stack and stores it in a the local variable list at index 0.

 

Ldloc_0 Loads the local variable at index 0 onto the evaluation stack.

Alright, so basically, both of these commands manipulate the Stack (more on "The stack vs The Heap" in another post).  Stack, from wikipedia For now, lets just call the Stack = Fast memory but limited The Heap =Slow Memory, but massive.  Think of the stack as a tower of single bricks.  Each brick represents a single amount of data.  When you "Pop" an item of the stack you grab the top most item and remove it (in our case, we also "Pop" from an indexed item), when you Push (again, in our situation "Load into"CEQ Compares) your putting something.

There were a few other things to check out before I could move on.  For instance, what does ldnull and ceq do?

Ldnull Pushes a null reference (type O) onto the evaluation stack.

Ceq Compares two values. If they are equal, the integer value 1 (int32) is pushed onto the evaluation stack; otherwise 0 (int32) is pushed onto the evaluation stack.

    Ok, simple enough. LdNull puts a Null Reference Type onto my stack, and Ceq checks for equality.  This will become important later on.

    Ok, so I'm armed with some basic implements of the trade, time to start interpreting.  The second section seems a bit more straight forward, so lets start there.

  IL_002a:  nop 
                    means no-operation, do nothing, waste time, etc...
  IL_002b:  ldloc.0
                    Load into a local var whatever is in location 0 on the stack (object "MySelf")
  IL_002c:  ldnull
                    Load a reference to a value on the heap, into my stack...
  IL_002d:  ceq
                    Compare the last two values to each other and stuff them into the stack (if x == null)
  IL_002f:  stloc.3
                     Pop item at index 3 of the stack and into the local variable
  IL_0030:  ldloc.3
                    Load the value stored in index 3 of the stack to the local variable stack (the result of ceq)
  IL_0031:  brtrue.s   IL_0037
                    if that value is 1, skip to line 37
  IL_0033:  ldloc.0
                    Load the value stored at index 0 of variables into the stack (remember, the person "MySelf")
  IL_0034:  stloc.2
                    Pop the item at index 0 of the stack into the local variables (what we just loaded);
  IL_0035:  br.s       IL_0039
                    Branches us directly to line 39. do not pass go, do not collect $200
  IL_0037:  ldloc.1
                    in our else statement, Load item at index 1 into the stack (remember, make x = y if null , essentially)
  IL_0038:  stloc.2
                   
pop off item 2 from the stack into the local variable (the actual variable getting assigned)
  IL_0039:  ldstr      "The new Friend likes: {0}"
                    
load  this string into the stack
  IL_003e:  ldloc.2
                    
load variable 2 into the stack (the "NewFriend" object)
  IL_003f:  callvirt   instance string Test.Person::FullName()
                     
call the following method and load it's value
  IL_0044:  call       void [mscorlib]System.Console::WriteLine(string,
                                                                object)
                     
call this method, which has full access to the stack, so were passing it, in this order, the string "The New Friend Likes:{0}" and then stack item[1] which = the return of Test.Person.FullName property.

    Well, that was quite a bit.  So the simple rundown is....it does exactly what our code tells it to.  Interesting to note though, is were newing up an object of type "Null" and doing an object comparison between it and "Myself".  This isn't bad, but it's a tad slow.  You also have to load up every property and variable to see if they do actually equate.  Find in most situations, but like in the previous post, if you make a comparison of Type B to Null from Type A, when Type B Has references Type A doesn't, your going to error out...because your loading values in Type B, that Type A is ignorant of....GetItGotItGood.

     Ok, so we've seen what the commands do, lets take the short route examining how the ?? works in IL.

  IL_0012:  stloc.1
  IL_0013:  ldloc.0

  IL_0014:  dup
                   
Duplicate the item on top of the stack and pushes the duplicate into the stack
  IL_0015:  brtrue.s   IL_0019
                    If the values are the same (if the value of the object is empty like the first register) jump to 19
  IL_0017:  pop
                    Else pop the first item off the stack and get rid of it
  IL_0018:  ldloc.1
  IL_0019:  stloc.2

  IL_001a:  ldstr      "The new Friend likes: {0}"
  IL_001f:  ldloc.2

  IL_0020:  callvirt   instance string Test.Person::FullName()
  IL_0025:  call       void [mscorlib]System.Console::WriteLine(string,
                                                                object)

    First off, we have obviously fewer instructions. Secondly, and most important, notice that were not doing any object comparisons or loading any objects from the heap.  so the breakdown after examining the two IL statements is this

If(x == Null) is like saying (If object x is the same as object Null)
and
x??y is like saying (If object x is as empty as Brittney Spears head)

    So in short, ?? is faster, and easier to evaluate because were only comparing it to an empty value in the stack, not a reference type.  Obviously the speed gain is minuscule, but it's still there.

    Ok, so IL probably will only help you gain geek cred and debug issues that you'd rather not be debugging.  But understanding IL code is worth serious geek cred, and helps you prove (or dis-prove) your theories on how your .net code works.   And hey, chicks dig the serious geek ;)

Print | posted on Monday, March 31, 2008 10:52 AM | Filed Under [ Techie .Net Stuff Other Misc Tech Stuff ]


Feedback

No comments posted yet.


Post Comment

Title  
Name  
Email
Url
Comment   
Please add 7 and 7 and type the answer here:

Powered by: