User:Pedro Oval/Mono code memory usage/CIL
< User:Pedro Oval | Mono code memory usage
Jump to navigation
Jump to search
Revision as of 16:41, 30 May 2014 by Pedro Oval (talk | contribs) (Bytecode not included, so mentioning the assembler is out of place. Other fixes.)
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 abbreviationldloc.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 thatx;
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 similarstloc.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.