Difference between revisions of "User:Pedro Oval/Mono code memory usage/CIL"

From Second Life Wiki
Jump to navigation Jump to search
(All at once)
m (Bytecode not included, so mentioning the assembler is out of place. Other fixes.)
Line 1: Line 1:
Here's the CIL code generated by the script below, which gives some insight of what's happening under the hood.
Here's the CIL code generated by the script below, which gives some insight of what's happening under the hood.


Compilation was done using the viewer's built-in compiler as suggested by [[User:Becky Pippen/LSL Performance]]. Assembly was done using <code>ilasm</code> from the Mono suite.
Compilation was done using the viewer's built-in compiler as suggested by [[User:Becky Pippen/LSL Performance]].
 
Script that gets compiled:
Script that gets compiled:


Line 823: Line 822:
'''Important notes:'''
'''Important notes:'''


* <code>ldloc.s 0</code> (opcode 11, argument 00) is probably contracted to the abbreviation <code>ldloc.0</code> (opcode 06) at assembly time, resulting in the length of 2 obtained in the [[User:Pedro Oval/Mono code memory usage|tests]]. Or possibly the server-side compiler added an optimization of this case (!). Either way, the evidence for this is confirmed by the fact that <code>x;</code> takes 2 bytes if it's one of the first four variables (there are 1-byte opcodes for ldloc.0 through ldloc.3), and 3 bytes otherwise. This applies to all appearances of this opcode and the similar <code>stloc.s</code>.
* <code>ldloc.s 0</code> (opcode 11, argument 00) is probably contracted to the abbreviation <code>ldloc.0</code> (opcode 06) at assembly time, resulting in the length of 2 obtained in the [[User:Pedro Oval/Mono code memory usage|tests]]. Or possibly the server-side compiler added an optimization of this case (!). Either way, the evidence for this is confirmed by the fact that <code>x;</code> takes 2 bytes if it's one of the first four local variables (there are 1-byte opcodes for ldloc.0 through ldloc.3), and 3 bytes otherwise. This applies to all appearances of this opcode and the similar <code>stloc.s</code>.
* Local variable definitions seem to take a variable and big number of bytes (averaging about 47 bytes for local integers) if there is a function call anywhere in the event where they are defined.
* Local variable definitions seem to take a variable and big number of bytes (averaging about 47 bytes for local integers) if there is a function call anywhere in the event where they are defined. Reason unknown.
* As things are now, having more than 256 local variables causes wraparound, making the 257th be an alias to the 1st, and so on.
* Backward jumps seem to take many more bytes than what the CIL result above suggests. Forward jumps, however, seem predictable enough.
* Backward jumps seem to take much more bytes than what the CIL result above suggests. Forward jumps, however, seem predictable enough.
* As things are now, having more than 256 local variables causes wraparound, making the 257th be an alias to the 1st, and so on. If they aren't the same type, an exception is raised.
* Global variable and function names do take code memory.
* Global variable and function names do take code memory.

Revision as of 16:41, 30 May 2014

Here's the CIL code generated by the script below, which gives some insight of what's happening under the hood.

Compilation was done using the viewer's built-in compiler as suggested by User:Becky Pippen/LSL Performance. Script that gets compiled:

<lsl> integer i; u(){}

default {

   state_entry()
   {
       integer x;
       integer y = 0;
       integer z;
       float f;
       float g;
       vector v;
       list a;
       ;;;;;;;;;{{{{{{{{}}}}}}}}
       return;
       x;
       (x);
       (integer)x;
       (float)x;
       f;
       (float)f;
       (integer)f;
       v;
       v.z;
       -x;
       ~x;
       !x;
       --x;
       ++x;
       x--;
       x++;
       x=y;
       x==y;
       x=y=z;
       f=x;
       f=(float)x;
       x!=y;
       x+y;
       x-y;
       x+-y;
       x*y;
       x/y;
       x%y;
       x&y;
       x&&y;
       x|y;
       x||y;
       x^y;
       x<<y;
       x>>y;
       x<y;
       x>y;
       x<=y;
       x>=y;
       x+=y;
       x-=y;
       x+=-y;
       x*=y;
       x/=y;
       x%=y;
       if (x) ;
       if (x) ; else ;
       0;
       x^x;
       1;
       -1;
       0xffffffff;
       ALL_SIDES;
       x|~x;
       x+1;
       -~x;
       x-1;
       x+-1;
       ~-x;
       x*y+y-1;
       (x+1)*y-1;
       ~(~x*y)
       while (x) ;
       do ; while (x);
       for (;x;) ;
       @label; if (x) jump label;
       0.0;
       f=0.0;
       f=0;
       <0.0, 0.0, 0.0>;
       ZERO_VECTOR;
       <0, 0, 0>;
       <-1.0, -1.0, 0.0>;
       TOUCH_INVALID_TEXCOORD;
       <-1, -1, 0>;
       <0xffffffff, 0xffffffff, 0>;
       v+v;
       v-v;
       v*v;
       v%v;
       [];
       a=[];
       a+[x];
       a+x;
       [x]+a;
       x+a;
       [x];
       []+x;
       (list)x;
       [x,y];
       []+x+y;
       (string)a;
       i;
       u();
   }

} </lsl>

Compiled and annotated result:

.assembly extern mscorlib {.ver 1:0:5000:0}
.assembly extern LslLibrary {.ver 0:1:0:0}
.assembly extern LslUserScript {.ver 0:1:0:0}
.assembly extern ScriptTypes {.ver 0:1:0:0}
.assembly 'LSL_y' {.ver 0:0:0:0}
.class public auto ansi serializable beforefieldinit LSL_y extends [LslUserScript]LindenLab.SecondLife.LslUserScript
{
  .field public int32 'i'
  .method public hidebysig  specialname  rtspecialname instance default void .ctor ()  cil managed
  {
    .maxstack 500
    // Globals:
    // integer i;
    ldarg.0
    ldc.i4.0
    stfld int32 LSL_y::'i'

    ldarg.0
    call instance void [LslUserScript]LindenLab.SecondLife.LslUserScript::.ctor()
    ret
  }
  .method public hidebysig instance default void 'gu'() cil managed
  {
    .maxstack 500
    ret
  }


  .method public hidebysig instance default void edefaultstate_entry() cil managed
  {
    .maxstack 500
    .locals init (int32, int32, int32, float32, float32, class [ScriptTypes]LindenLab.SecondLife.Vector, class [mscorlib]System.Collections.ArrayList)
    // integer x;
    ldc.i4.0
    stloc.s 0
    // integer y;
    ldc.i4 0
    stloc.s 1
    // integer z;
    ldc.i4.0
    stloc.s 2
    // float f;
    ldc.r8 0
    stloc.s 3
    // float g;
    ldc.r8 0
    stloc.s 4
    // vector v;
    ldc.r8 0
    ldc.r8 0
    ldc.r8 0
    call class [ScriptTypes]LindenLab.SecondLife.Vector class [LslUserScript]LindenLab.SecondLife.LslUserScript::'CreateVector'(float32, float32, float32)
    stloc.s 5
    // list a;
    call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::CreateList()
    stloc.s 6

    // ;;; {{{ }}} generate no code

    // return;
    ret

    // x;
    ldloc.s 0
    pop

    // (x);
    ldloc.s 0
    pop

    // (integer)x;
    ldloc.s 0
    pop

    // (float)x;
    ldloc.s 0
    conv.r8
    pop

    // f;
    ldloc.s 3
    pop

    // (float)f;
    ldloc.s 3
    pop

    // (integer)f;
    ldloc.s 3
    call int32 [LslLibrary]LindenLab.SecondLife.LslRunTime::ToInteger(float32)
    pop

    // v;
    ldloc.s 5
    pop

    // v.z;
    ldloca.s 5
    ldfld float32 class [ScriptTypes]LindenLab.SecondLife.Vector::z
    pop

    // -x;
    ldloc.s 0
    neg
    pop

    // ~x;
    ldloc.s 0
    not
    pop

    // !x;
    ldloc.s 0
    ldc.i4.0
    ceq
    pop

    // --x;
    ldloc.s 0
    ldc.i4.1
    sub
    dup
    stloc.s 0
    pop

    // ++x;
    ldloc.s 0
    ldc.i4.1
    add
    dup
    stloc.s 0
    pop

    // x--;
    ldloc.s 0
    ldloc.s 0
    ldc.i4.1
    sub
    dup
    stloc.s 0
    pop
    pop

    // x++;
    ldloc.s 0
    ldloc.s 0
    ldc.i4.1
    add
    dup
    stloc.s 0
    pop
    pop

    // x = y;
    ldloc.s 1
    dup
    stloc.s 0
    pop

    // x == y;
    ldloc.s 1
    ldloc.s 0
    ceq
    pop

    // x = y = z;
    ldloc.s 2
    dup
    stloc.s 1
    dup
    stloc.s 0
    pop

    // f = x;
    ldloc.s 0
    conv.r8
    dup
    stloc.s 3
    pop

    // f = (float)x;
    ldloc.s 0
    conv.r8
    dup
    stloc.s 3
    pop

    // x != y; implemented as: !(x==y)
    ldloc.s 1  // this part is x == y
    ldloc.s 0
    ceq
    ldc.i4.0   // this part is 'not'
    ceq
    pop

    // x + y;
    ldloc.s 1
    ldloc.s 0
    add
    pop

    // x - y;
    ldloc.s 1
    ldloc.s 0
    call int32 [LslUserScript]LindenLab.SecondLife.LslUserScript::Subtract(int32, int32)
    pop

    // x + -y;
    ldloc.s 1
    neg
    ldloc.s 0
    add
    pop

    // x * y;
    ldloc.s 1
    ldloc.s 0
    mul
    pop

    // x / y;
    ldloc.s 1
    ldloc.s 0
    call int32 [LslUserScript]LindenLab.SecondLife.LslUserScript::Divide(int32, int32)
    pop

    // x % y;
    ldloc.s 1
    ldloc.s 0
    call int32 [LslUserScript]LindenLab.SecondLife.LslUserScript::Modulo(int32, int32)
    pop

    // x & y;
    ldloc.s 1
    ldloc.s 0
    and
    pop

    // x && y; implemented as: !(!x | !y)
    ldloc.s 1    // !x
    ldc.i4.0
    ceq
    ldloc.s 0    // !y
    ldc.i4.0
    ceq
    or           // !x | !y
    ldc.i4.0     // !(!x | !y)
    ceq
    pop

    // x | y;
    ldloc.s 1
    ldloc.s 0
    or
    pop

    // x || y; implemented as: !!(x | y)
    ldloc.s 1    // x | y
    ldloc.s 0
    or
    ldc.i4.0     // !(x | y)
    ceq
    ldc.i4.0     // !!(x | y)
    ceq
    pop

    // x ^ y;
    ldloc.s 1
    ldloc.s 0
    xor
    pop

    // x << y;
    ldloc.s 1
    ldloc.s 0
    call int32 [LslUserScript]LindenLab.SecondLife.LslUserScript::ShiftLeft(int32, int32)
    pop

    // x >> y;
    ldloc.s 1
    ldloc.s 0
    call int32 [LslUserScript]LindenLab.SecondLife.LslUserScript::ShiftRight(int32, int32)
    pop

    // x < y; implemented as: y > x
    ldloc.s 1
    ldloc.s 0
    cgt
    pop

    // x > y; implemented as: y < x;
    ldloc.s 1
    ldloc.s 0
    clt
    pop

    // x <= y; implemented as: !(y < x)
    ldloc.s 1
    ldloc.s 0
    clt
    ldc.i4.0
    ceq
    pop

    // x >= y; implemented as: !(y > x)
    ldloc.s 1
    ldloc.s 0
    cgt
    ldc.i4.0
    ceq
    pop

    // x += y;
    ldloc.s 1
    ldloc.s 0
    add
    dup
    stloc.s 0
    pop

    // x -= y;
    ldloc.s 1
    ldloc.s 0
    call int32 [LslUserScript]LindenLab.SecondLife.LslUserScript::Subtract(int32, int32)
    dup
    stloc.s 0
    pop

    // x += -y;
    ldloc.s 1
    neg
    ldloc.s 0
    add
    dup
    stloc.s 0
    pop

    // x *= y;
    ldloc.s 1
    ldloc.s 0
    mul
    dup
    stloc.s 0
    pop

    // x /= y;
    ldloc.s 1
    ldloc.s 0
    call int32 [LslUserScript]LindenLab.SecondLife.LslUserScript::Divide(int32, int32)
    dup
    stloc.s 0
    pop

    // x %= y;
    ldloc.s 1
    ldloc.s 0
    call int32 [LslUserScript]LindenLab.SecondLife.LslUserScript::Modulo(int32, int32)
    dup
    stloc.s 0
    pop

    // if (x) ;
    ldloc.s 0
    brfalse LabelTempJump0
    // THEN branch code would go here
LabelTempJump0:

    // if (x) ; else ;
    ldloc.s 0
    brfalse LabelTempJump1
    // THEN branch code would go here
    br LabelTempJump2
LabelTempJump1:
    // ELSE branch code would go here
LabelTempJump2:

    // 0;
    ldc.i4 0
    pop

    // x ^ x;
    ldloc.s 0
    ldloc.s 0
    xor
    pop

    // 1;
    ldc.i4 1
    pop

    // -1; note the negative sign takes code
    ldc.i4 1
    neg
    pop

    // 0xffffffff; note it equals -1 without taking memory
    ldc.i4 -1
    pop

    // ALL_SIDES; ditto
    ldc.i4 -1
    pop

    // x | ~x;
    ldloc.s 0
    not
    ldloc.s 0
    or
    pop

    // x + 1;
    ldc.i4 1
    ldloc.s 0
    add
    pop

    // -~x;
    ldloc.s 0
    not
    neg
    pop

    // x - 1;
    ldc.i4 1
    ldloc.s 0
    call int32 [LslUserScript]LindenLab.SecondLife.LslUserScript::Subtract(int32, int32)
    pop

    // x + -1;
    ldc.i4 1
    neg
    ldloc.s 0
    add
    pop

    // ~-x;
    ldloc.s 0
    neg
    not
    pop

    // x*y + y - 1;
    ldc.i4 1
    ldloc.s 1
    ldloc.s 1
    ldloc.s 0
    mul
    add
    call int32 [LslUserScript]LindenLab.SecondLife.LslUserScript::Subtract(int32, int32)
    pop

    // (x + 1)*y - 1;
    ldc.i4 1
    ldloc.s 1
    ldc.i4 1
    ldloc.s 0
    add
    mul
    call int32 [LslUserScript]LindenLab.SecondLife.LslUserScript::Subtract(int32, int32)
    pop

    // ~(~x*y);
    ldloc.s 1
    ldloc.s 0
    not
    mul
    not
    pop

    // while (x) ;
LabelTempJump3:
    ldloc.s 0
    brfalse LabelTempJump4
    br LabelTempJump3
LabelTempJump4:

    // do ; while (x);
LabelTempJump5:
    ldloc.s 0
    brtrue LabelTempJump5

    // for (; x; ) ;
LabelTempJump6:
    ldloc.s 0
    brfalse LabelTempJump7
    br LabelTempJump6
LabelTempJump7:

    // @label; if (x) jump label;
'label':
    ldloc.s 0
    brfalse LabelTempJump8
    br 'label'
LabelTempJump8:

    // 0.0;
    ldc.r8 (00 00 00 00 00 00 00 00)
    pop

    // f = 0.0;
    ldc.r8 (00 00 00 00 00 00 00 00)
    dup
    stloc.s 3
    pop

    // f = 0;
    ldc.i4 0
    conv.r8
    dup
    stloc.s 3
    pop

    // <0.0, 0.0, 0.0>;
    ldc.r8 (00 00 00 00 00 00 00 00)
    ldc.r8 (00 00 00 00 00 00 00 00)
    ldc.r8 (00 00 00 00 00 00 00 00)
    call class [ScriptTypes]LindenLab.SecondLife.Vector class [LslUserScript]LindenLab.SecondLife.LslUserScript::'CreateVector'(float32, float32, float32)
    pop

    // ZERO_VECTOR;
    ldc.r8 (00 00 00 00 00 00 00 00)
    ldc.r8 (00 00 00 00 00 00 00 00)
    ldc.r8 (00 00 00 00 00 00 00 00)
    call class [ScriptTypes]LindenLab.SecondLife.Vector class [LslUserScript]LindenLab.SecondLife.LslUserScript::'CreateVector'(float32, float32, float32)
    pop

    // <0, 0, 0>;
    ldc.i4 0
    conv.r8
    ldc.i4 0
    conv.r8
    ldc.i4 0
    conv.r8
    call class [ScriptTypes]LindenLab.SecondLife.Vector class [LslUserScript]LindenLab.SecondLife.LslUserScript::'CreateVector'(float32, float32, float32)
    pop

    // <-1.0, -1.0, 0.0>;
    ldc.r8 (00 00 00 00 00 00 f0 3f)
    neg
    ldc.r8 (00 00 00 00 00 00 f0 3f)
    neg
    ldc.r8 (00 00 00 00 00 00 00 00)
    call class [ScriptTypes]LindenLab.SecondLife.Vector class [LslUserScript]LindenLab.SecondLife.LslUserScript::'CreateVector'(float32, float32, float32)
    pop

    // TOUCH_INVALID_TEXCOORD;
    ldc.r8 (00 00 00 00 00 00 f0 bf)
    ldc.r8 (00 00 00 00 00 00 f0 bf)
    ldc.r8 (00 00 00 00 00 00 00 00)
    call class [ScriptTypes]LindenLab.SecondLife.Vector class [LslUserScript]LindenLab.SecondLife.LslUserScript::'CreateVector'(float32, float32, float32)
    pop

    // <-1, -1, 0>;
    ldc.i4 1
    neg
    conv.r8
    ldc.i4 1
    neg
    conv.r8
    ldc.i4 0
    conv.r8
    call class [ScriptTypes]LindenLab.SecondLife.Vector class [LslUserScript]LindenLab.SecondLife.LslUserScript::'CreateVector'(float32, float32, float32)
    pop

    // <0xffffffff, 0xffffffff, 0>;
    ldc.i4 -1
    conv.r8
    ldc.i4 -1
    conv.r8
    ldc.i4 0
    conv.r8
    call class [ScriptTypes]LindenLab.SecondLife.Vector class [LslUserScript]LindenLab.SecondLife.LslUserScript::'CreateVector'(float32, float32, float32)
    pop

    // v + v;
    ldloc.s 5
    ldloc.s 5
    call class [ScriptTypes]LindenLab.SecondLife.Vector class [LslUserScript]LindenLab.SecondLife.LslUserScript::'Add'(class [ScriptTypes]LindenLab.SecondLife.Vector, class [ScriptTypes]LindenLab.SecondLife.Vector)
    pop

    // v - v;
    ldloc.s 5
    ldloc.s 5
    call class [ScriptTypes]LindenLab.SecondLife.Vector class [LslUserScript]LindenLab.SecondLife.LslUserScript::'Subtract'(class [ScriptTypes]LindenLab.SecondLife.Vector, class [ScriptTypes]LindenLab.SecondLife.Vector)
    pop

    // v * v;
    ldloc.s 5
    ldloc.s 5
    call float32 class [LslUserScript]LindenLab.SecondLife.LslUserScript::'Multiply'(class [ScriptTypes]LindenLab.SecondLife.Vector, class [ScriptTypes]LindenLab.SecondLife.Vector)
    pop

    // v % v;
    ldloc.s 5
    ldloc.s 5
    call class [ScriptTypes]LindenLab.SecondLife.Vector class [LslUserScript]LindenLab.SecondLife.LslUserScript::'Modulo'(class [ScriptTypes]LindenLab.SecondLife.Vector, class [ScriptTypes]LindenLab.SecondLife.Vector)
    pop

    // [];
    call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::CreateList()
    pop

    // a = [];
    call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::CreateList()
    dup
    stloc.s 6
    pop

    // a + [x];
    ldloc.s 0
    box [mscorlib]System.Int32
    call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::CreateList()
    call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::Prepend(object, class [mscorlib]System.Collections.ArrayList)
    ldloc.s 6
    call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::Append(class [mscorlib]System.Collections.ArrayList, class [mscorlib]System.Collections.ArrayList)
    pop

    // a + x;
    ldloc.s 0
    ldloc.s 6
    call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::Append(int32, class [mscorlib]System.Collections.ArrayList)
    pop

    // [x] + a;
    ldloc.s 6
    ldloc.s 0
    box [mscorlib]System.Int32
    call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::CreateList()
    call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::Prepend(object, class [mscorlib]System.Collections.ArrayList)
    call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::Append(class [mscorlib]System.Collections.ArrayList, class [mscorlib]System.Collections.ArrayList)
    pop

    // x + a;
    ldloc.s 6
    ldloc.s 0
    box [mscorlib]System.Int32
    call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::Prepend(class [mscorlib]System.Collections.ArrayList, object)
    pop

    // [x];
    ldloc.s 0
    box [mscorlib]System.Int32
    call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::CreateList()
    call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::Prepend(object, class [mscorlib]System.Collections.ArrayList)
    pop

    // []+x;
    ldloc.s 0
    call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::CreateList()
    call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::Append(int32, class [mscorlib]System.Collections.ArrayList)
    pop

    // (list)x;
    ldloc.s 0
    box [mscorlib]System.Int32
    call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::CreateList(object)
    pop

    // [x, y];
    ldloc.s 0
    box [mscorlib]System.Int32
    ldloc.s 1
    box [mscorlib]System.Int32
    call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::CreateList()
    call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::Prepend(object, class [mscorlib]System.Collections.ArrayList)
    call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::Prepend(object, class [mscorlib]System.Collections.ArrayList)
    pop

    // []+x+y;
    ldloc.s 1
    ldloc.s 0
    call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::CreateList()
    call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::Append(int32, class [mscorlib]System.Collections.ArrayList)
    call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::Append(int32, class [mscorlib]System.Collections.ArrayList)
    pop

    // (string)a;
    ldloc.s 6
    call string [LslLibrary]LindenLab.SecondLife.LslRunTime::ListToString(class [mscorlib]System.Collections.ArrayList)
    pop

    // i; (global).
    ldarg.0
    ldfld int32 LSL_y::'i'
    pop

    // u();
    ldarg.0
    call instance void class LSL_y::'gu'()

    // end of event
    ret
  }

}

Important notes:

  • ldloc.s 0 (opcode 11, argument 00) is probably contracted to the abbreviation ldloc.0 (opcode 06) at assembly time, resulting in the length of 2 obtained in the tests. Or possibly the server-side compiler added an optimization of this case (!). Either way, the evidence for this is confirmed by the fact that x; takes 2 bytes if it's one of the first four local variables (there are 1-byte opcodes for ldloc.0 through ldloc.3), and 3 bytes otherwise. This applies to all appearances of this opcode and the similar stloc.s.
  • Local variable definitions seem to take a variable and big number of bytes (averaging about 47 bytes for local integers) if there is a function call anywhere in the event where they are defined. Reason unknown.
  • Backward jumps seem to take many more bytes than what the CIL result above suggests. Forward jumps, however, seem predictable enough.
  • As things are now, having more than 256 local variables causes wraparound, making the 257th be an alias to the 1st, and so on. If they aren't the same type, an exception is raised.
  • Global variable and function names do take code memory.