Difference between revisions of "User:Pedro Oval/Mono code memory usage/CIL"
Jump to navigation
Jump to search
Pedro Oval (talk | contribs) m (Bytecode not included, so mentioning the assembler is out of place. Other fixes.) |
Kizmut Smit (talk | contribs) m (+cat :3) |
||
(11 intermediate revisions by one other user not shown) | |||
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]]. | 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. | ||
Script that gets compiled: | Script that gets compiled: | ||
< | <source lang="lsl2"> | ||
integer i; | integer i; | ||
u(){} | u(){} | ||
Line 118: | Line 119: | ||
} | } | ||
} | } | ||
</ | </source> | ||
Compiled and annotated result: | Compiled and annotated result: | ||
<pre> | <pre> | ||
.assembly extern mscorlib {.ver 1:0:5000:0} | .assembly extern mscorlib {.ver 1:0:5000:0} | ||
.assembly extern LslLibrary {.ver 0:1:0:0} | .assembly extern LslLibrary {.ver 0:1:0:0} | ||
.assembly extern LslUserScript {.ver 0:1:0:0} | .assembly extern LslUserScript {.ver 0:1:0:0} | ||
.assembly extern ScriptTypes {.ver 0:1:0:0} | .assembly extern ScriptTypes {.ver 0:1:0:0} | ||
.assembly 'LSL_y' {.ver 0:0:0:0} | .assembly 'LSL_y' {.ver 0:0:0:0} | ||
.class public auto ansi serializable beforefieldinit LSL_y extends [LslUserScript]LindenLab.SecondLife.LslUserScript | .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 initialization | |||
// integer i; | |||
02 ldarg.0 | |||
16 ldc.i4.0 | |||
7D 01 00 00 04 stfld int32 LSL_y::'i' | |||
02 ldarg.0 | |||
28 01 00 00 0A call instance void [LslUserScript]LindenLab.SecondLife.LslUserScript::.ctor() | |||
2A ret | |||
} | |||
.method public hidebysig instance default void 'gu'() cil managed | |||
{ | |||
.maxstack 500 | |||
2A 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; | |||
16 ldc.i4.0 | |||
13 00 stloc.s 0 | |||
// integer y = 0; | |||
20 00 00 00 00 ldc.i4 0 | |||
13 01 stloc.s 1 | |||
// integer z; | |||
16 ldc.i4.0 | |||
13 02 stloc.s 2 | |||
// float f; | |||
23 00 00 00 00 ldc.r8 0 | |||
00 00 00 00 | |||
13 03 stloc.s 3 | |||
// float g; | |||
23 00 00 00 00 ldc.r8 0 | |||
00 00 00 00 | |||
13 04 stloc.s 4 | |||
// vector v; | |||
23 00 00 00 00 ldc.r8 0 | |||
00 00 00 00 | |||
23 00 00 00 00 ldc.r8 0 | |||
00 00 00 00 | |||
23 00 00 00 00 ldc.r8 0 | |||
00 00 00 00 | |||
28 02 00 00 0A call class [ScriptTypes]LindenLab.SecondLife.Vector class [LslUserScript]LindenLab.SecondLife.LslUserScript::'CreateVector'(float32, float32, float32) | |||
13 05 stloc.s 5 | |||
// list a; | |||
28 03 00 00 0A call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::CreateList() | |||
13 06 stloc.s 6 | |||
// ;;; {{{ }}} generate no code | |||
// return; | |||
2A ret | |||
// x; | |||
11 00 ldloc.s 0 | |||
26 pop | |||
// (x); | |||
11 00 ldloc.s 0 | |||
26 pop | |||
// (integer)x; | |||
11 00 ldloc.s 0 | |||
26 pop | |||
// (float)x; | |||
11 00 ldloc.s 0 | |||
6C conv.r8 | |||
26 pop | |||
// f; | |||
11 03 ldloc.s 3 | |||
26 pop | |||
// (float)f; | |||
11 03 ldloc.s 3 | |||
26 pop | |||
// (integer)f; | |||
11 03 ldloc.s 3 | |||
28 04 00 00 0A call int32 [LslLibrary]LindenLab.SecondLife.LslRunTime::ToInteger(float32) | |||
26 pop | |||
// v; | |||
11 05 ldloc.s 5 | |||
26 pop | |||
// v.z; | |||
12 05 ldloca.s 5 | |||
78 05 00 00 0A ldfld float32 class [ScriptTypes]LindenLab.SecondLife.Vector::z | |||
26 pop | |||
// -x; | |||
11 00 ldloc.s 0 | |||
65 neg | |||
26 pop | |||
// ~x; | |||
11 00 ldloc.s 0 | |||
66 not | |||
26 pop | |||
// !x; | |||
11 00 ldloc.s 0 | |||
16 ldc.i4.0 | |||
FE 01 ceq | |||
26 pop | |||
// --x; | |||
11 00 ldloc.s 0 | |||
17 ldc.i4.1 | |||
59 sub | |||
25 dup | |||
13 00 stloc.s 0 | |||
26 pop | |||
// ++x; | |||
11 00 ldloc.s 0 | |||
17 ldc.i4.1 | |||
58 add | |||
25 dup | |||
13 00 stloc.s 0 | |||
26 pop | |||
// x--; | |||
11 00 ldloc.s 0 | |||
11 00 ldloc.s 0 | |||
17 ldc.i4.1 | |||
59 sub | |||
25 dup | |||
13 00 stloc.s 0 | |||
26 pop | |||
26 pop | |||
// x++; | |||
11 00 ldloc.s 0 | |||
11 00 ldloc.s 0 | |||
17 ldc.i4.1 | |||
58 add | |||
25 dup | |||
13 00 stloc.s 0 | |||
26 pop | |||
26 pop | |||
// x = y; | |||
11 01 ldloc.s 1 | |||
25 dup | |||
13 00 stloc.s 0 | |||
26 pop | |||
// x == y; | |||
11 01 ldloc.s 1 | |||
11 00 ldloc.s 0 | |||
FE 01 ceq | |||
26 pop | |||
// x = y = z; | |||
11 02 ldloc.s 2 | |||
25 dup | |||
13 01 stloc.s 1 | |||
25 dup | |||
13 00 stloc.s 0 | |||
26 pop | |||
// f = x; | |||
11 00 ldloc.s 0 | |||
6C conv.r8 | |||
25 dup | |||
13 03 stloc.s 3 | |||
26 pop | |||
// f = (float)x; | |||
11 00 ldloc.s 0 | |||
6C conv.r8 | |||
25 dup | |||
13 03 stloc.s 3 | |||
26 pop | |||
// x != y; implemented as: !(x==y) | |||
11 01 ldloc.s 1 // this part is x == y | |||
11 00 ldloc.s 0 | |||
FE 01 ceq | |||
16 ldc.i4.0 // this part is 'not' | |||
FE 01 ceq | |||
26 pop | |||
// x + y; | |||
11 01 ldloc.s 1 | |||
11 00 ldloc.s 0 | |||
58 add | |||
26 pop | |||
// x - y; | |||
11 01 ldloc.s 1 | |||
11 00 ldloc.s 0 | |||
28 06 00 00 0A call int32 [LslUserScript]LindenLab.SecondLife.LslUserScript::Subtract(int32, int32) | |||
26 pop | |||
// x + -y; | |||
11 01 ldloc.s 1 | |||
65 neg | |||
11 00 ldloc.s 0 | |||
58 add | |||
26 pop | |||
// x * y; | |||
11 01 ldloc.s 1 | |||
11 00 ldloc.s 0 | |||
5A mul | |||
26 pop | |||
// x / y; | |||
11 01 ldloc.s 1 | |||
11 00 ldloc.s 0 | |||
28 07 00 00 0A call int32 [LslUserScript]LindenLab.SecondLife.LslUserScript::Divide(int32, int32) | |||
26 pop | |||
// x % y; | |||
11 01 ldloc.s 1 | |||
11 00 ldloc.s 0 | |||
28 08 00 00 0A call int32 [LslUserScript]LindenLab.SecondLife.LslUserScript::Modulo(int32, int32) | |||
26 pop | |||
// x & y; | |||
11 01 ldloc.s 1 | |||
11 00 ldloc.s 0 | |||
5F and | |||
26 pop | |||
// x && y; implemented as: !(!x | !y) | |||
11 01 ldloc.s 1 // !x | |||
16 ldc.i4.0 | |||
FE 01 ceq | |||
11 00 ldloc.s 0 // !y | |||
16 ldc.i4.0 | |||
FE 01 ceq | |||
60 or // !x | !y | |||
16 ldc.i4.0 // !(!x | !y) | |||
FE 01 ceq | |||
26 pop | |||
// x | y; | |||
11 01 ldloc.s 1 | |||
11 00 ldloc.s 0 | |||
60 or | |||
26 pop | |||
// x || y; implemented as: !!(x | y) | |||
11 01 ldloc.s 1 // x | y | |||
11 00 ldloc.s 0 | |||
60 or | |||
16 ldc.i4.0 // !(x | y) | |||
FE 01 ceq | |||
16 ldc.i4.0 // !!(x | y) | |||
FE 01 ceq | |||
26 pop | |||
// x ^ y; | |||
11 01 ldloc.s 1 | |||
11 00 ldloc.s 0 | |||
61 xor | |||
26 pop | |||
// x << y; | |||
11 01 ldloc.s 1 | |||
11 00 ldloc.s 0 | |||
28 09 00 00 0A call int32 [LslUserScript]LindenLab.SecondLife.LslUserScript::ShiftLeft(int32, int32) | |||
26 pop | |||
// x >> y; | |||
11 01 ldloc.s 1 | |||
11 00 ldloc.s 0 | |||
28 0A 00 00 0A call int32 [LslUserScript]LindenLab.SecondLife.LslUserScript::ShiftRight(int32, int32) | |||
26 pop | |||
// x < y; implemented as: y > x | |||
11 01 ldloc.s 1 | |||
11 00 ldloc.s 0 | |||
FE 02 cgt | |||
26 pop | |||
// x > y; implemented as: y < x; | |||
11 01 ldloc.s 1 | |||
11 00 ldloc.s 0 | |||
FE 04 clt | |||
26 pop | |||
// x <= y; implemented as: !(y < x) | |||
11 01 ldloc.s 1 | |||
11 00 ldloc.s 0 | |||
FE 04 clt | |||
16 ldc.i4.0 | |||
FE 01 ceq | |||
26 pop | |||
// x >= y; implemented as: !(y > x) | |||
11 01 ldloc.s 1 | |||
11 00 ldloc.s 0 | |||
FE 02 cgt | |||
16 ldc.i4.0 | |||
FE 01 ceq | |||
26 pop | |||
// x += y; | |||
11 01 ldloc.s 1 | |||
11 00 ldloc.s 0 | |||
58 add | |||
25 dup | |||
13 00 stloc.s 0 | |||
26 pop | |||
// x -= y; | |||
11 01 ldloc.s 1 | |||
11 00 ldloc.s 0 | |||
28 06 00 00 0A call int32 [LslUserScript]LindenLab.SecondLife.LslUserScript::Subtract(int32, int32) | |||
25 dup | |||
13 00 stloc.s 0 | |||
26 pop | |||
// x += -y; | |||
11 01 ldloc.s 1 | |||
65 neg | |||
11 00 ldloc.s 0 | |||
58 add | |||
25 dup | |||
13 00 stloc.s 0 | |||
26 pop | |||
// x *= y; | |||
11 01 ldloc.s 1 | |||
11 00 ldloc.s 0 | |||
5A mul | |||
25 dup | |||
13 00 stloc.s 0 | |||
26 pop | |||
// x /= y; | |||
11 01 ldloc.s 1 | |||
11 00 ldloc.s 0 | |||
28 07 00 00 0A call int32 [LslUserScript]LindenLab.SecondLife.LslUserScript::Divide(int32, int32) | |||
25 dup | |||
13 00 stloc.s 0 | |||
26 pop | |||
// x %= y; | |||
11 01 ldloc.s 1 | |||
11 00 ldloc.s 0 | |||
28 08 00 00 0A call int32 [LslUserScript]LindenLab.SecondLife.LslUserScript::Modulo(int32, int32) | |||
25 dup | |||
13 00 stloc.s 0 | |||
26 pop | |||
// if (x) ; | |||
11 00 ldloc.s 0 | |||
39 00 00 00 00 brfalse LabelTempJump0 | |||
// THEN branch code goes here | |||
LabelTempJump0: | LabelTempJump0: | ||
// if (x) ; else ; | |||
11 00 ldloc.s 0 | |||
39 05 00 00 00 brfalse LabelTempJump1 | |||
// THEN branch code would go here | |||
38 00 00 00 00 br LabelTempJump2 | |||
// ELSE branch code would go here | |||
LabelTempJump1: | |||
LabelTempJump2: | LabelTempJump2: | ||
// 0; | |||
20 00 00 00 00 ldc.i4 0 | |||
26 pop | |||
// x ^ x; | |||
11 00 ldloc.s 0 | |||
11 00 ldloc.s 0 | |||
61 xor | |||
26 pop | |||
// 1; | |||
20 01 00 00 00 ldc.i4 1 | |||
26 pop | |||
// -1; note the negative sign takes code memory | |||
20 01 00 00 00 ldc.i4 1 | |||
65 neg | |||
26 pop | |||
// 0xffffffff; note it equals -1 without the sign taking memory | |||
20 FF FF FF FF ldc.i4 -1 | |||
26 pop | |||
// ALL_SIDES; ditto | |||
20 FF FF FF FF ldc.i4 -1 | |||
26 pop | |||
// x | ~x; | |||
11 00 ldloc.s 0 | |||
66 not | |||
11 00 ldloc.s 0 | |||
60 or | |||
26 pop | |||
// x + 1; | |||
20 01 00 00 00 ldc.i4 1 | |||
11 00 ldloc.s 0 | |||
58 add | |||
26 pop | |||
// -~x; | |||
11 00 ldloc.s 0 | |||
66 not | |||
65 neg | |||
26 pop | |||
// x - 1; | |||
20 01 00 00 00 ldc.i4 1 | |||
11 00 ldloc.s 0 | |||
28 06 00 00 0A call int32 [LslUserScript]LindenLab.SecondLife.LslUserScript::Subtract(int32, int32) | |||
26 pop | |||
// x + -1; | |||
20 01 00 00 00 ldc.i4 1 | |||
65 neg | |||
11 00 ldloc.s 0 | |||
58 add | |||
26 pop | |||
// ~-x; | |||
11 00 ldloc.s 0 | |||
65 neg | |||
66 not | |||
26 pop | |||
// x*y + y - 1; | |||
20 01 00 00 00 ldc.i4 1 | |||
11 01 ldloc.s 1 | |||
11 01 ldloc.s 1 | |||
11 00 ldloc.s 0 | |||
5A mul | |||
58 add | |||
28 06 00 00 0A call int32 [LslUserScript]LindenLab.SecondLife.LslUserScript::Subtract(int32, int32) | |||
26 pop | |||
// (x + 1)*y - 1; | |||
20 01 00 00 00 ldc.i4 1 | |||
11 01 ldloc.s 1 | |||
20 01 00 00 00 ldc.i4 1 | |||
11 00 ldloc.s 0 | |||
58 add | |||
5A mul | |||
28 06 00 00 0A call int32 [LslUserScript]LindenLab.SecondLife.LslUserScript::Subtract(int32, int32) | |||
26 pop | |||
// ~(~x*y); | |||
11 01 ldloc.s 1 | |||
11 00 ldloc.s 0 | |||
66 not | |||
5A mul | |||
66 not | |||
26 pop | |||
// while (x) ; | |||
LabelTempJump3: | LabelTempJump3: | ||
11 00 ldloc.s 0 | |||
39 05 00 00 00 brfalse LabelTempJump4 | |||
// Looped code would go here | |||
LabelTempJump4: | 38 F4 FF FF FF br LabelTempJump3 | ||
LabelTempJump4: | |||
// do ; while (x); | |||
LabelTempJump5: | LabelTempJump5: | ||
// Looped code would go here | |||
11 00 ldloc.s 0 | |||
3A F9 FF FF FF brtrue LabelTempJump5 | |||
// for (; x; ) ; | |||
LabelTempJump6: | LabelTempJump6: | ||
11 00 ldloc.s 0 | |||
39 05 00 00 00 brfalse LabelTempJump7 | |||
// Looped code would go here | |||
LabelTempJump7: | 38 F4 FF FF FF br LabelTempJump6 | ||
LabelTempJump7: | |||
// @label; if (x) jump label; | |||
'label': | 'label': | ||
// Looped code would go here | |||
11 00 ldloc.s 0 | |||
39 05 00 00 00 brfalse LabelTempJump8 | |||
LabelTempJump8: | 38 F4 FF FF FF br 'label' | ||
LabelTempJump8: | |||
// 0.0; | |||
23 00 00 00 00 ldc.r8 (00 00 00 00 00 00 00 00) | |||
00 00 00 00 | |||
26 pop | |||
// f = 0.0; | |||
23 00 00 00 00 ldc.r8 (00 00 00 00 00 00 00 00) | |||
00 00 00 00 | |||
25 dup | |||
13 03 stloc.s 3 | |||
26 pop | |||
// f = 0; | |||
20 00 00 00 00 ldc.i4 0 | |||
6C conv.r8 | |||
25 dup | |||
13 03 stloc.s 3 | |||
26 pop | |||
// <0.0, 0.0, 0.0>; | |||
23 00 00 00 00 ldc.r8 (00 00 00 00 00 00 00 00) | |||
00 00 00 00 | |||
23 00 00 00 00 ldc.r8 (00 00 00 00 00 00 00 00) | |||
00 00 00 00 | |||
23 00 00 00 00 ldc.r8 (00 00 00 00 00 00 00 00) | |||
00 00 00 00 | |||
28 02 00 00 0A call class [ScriptTypes]LindenLab.SecondLife.Vector class [LslUserScript]LindenLab.SecondLife.LslUserScript::'CreateVector'(float32, float32, float32) | |||
26 pop | |||
// ZERO_VECTOR; | |||
23 00 00 00 00 ldc.r8 (00 00 00 00 00 00 00 00) | |||
00 00 00 00 | |||
23 00 00 00 00 ldc.r8 (00 00 00 00 00 00 00 00) | |||
00 00 00 00 | |||
23 00 00 00 00 ldc.r8 (00 00 00 00 00 00 00 00) | |||
00 00 00 00 | |||
28 02 00 00 0A call class [ScriptTypes]LindenLab.SecondLife.Vector class [LslUserScript]LindenLab.SecondLife.LslUserScript::'CreateVector'(float32, float32, float32) | |||
26 pop | |||
// <0, 0, 0>; | |||
20 00 00 00 00 ldc.i4 0 | |||
6C conv.r8 | |||
20 00 00 00 00 ldc.i4 0 | |||
6C conv.r8 | |||
20 00 00 00 00 ldc.i4 0 | |||
6C conv.r8 | |||
28 02 00 00 0A call class [ScriptTypes]LindenLab.SecondLife.Vector class [LslUserScript]LindenLab.SecondLife.LslUserScript::'CreateVector'(float32, float32, float32) | |||
26 pop | |||
// <-1.0, -1.0, 0.0>; | |||
23 00 00 00 00 ldc.r8 (00 00 00 00 00 00 f0 3f) | |||
00 00 F0 3F | |||
65 neg | |||
23 00 00 00 00 ldc.r8 (00 00 00 00 00 00 f0 3f) | |||
00 00 F0 3F | |||
65 neg | |||
23 00 00 00 00 ldc.r8 (00 00 00 00 00 00 00 00) | |||
00 00 00 00 | |||
28 02 00 00 0A call class [ScriptTypes]LindenLab.SecondLife.Vector class [LslUserScript]LindenLab.SecondLife.LslUserScript::'CreateVector'(float32, float32, float32) | |||
26 pop | |||
// TOUCH_INVALID_TEXCOORD; | |||
23 00 00 00 00 ldc.r8 (00 00 00 00 00 00 f0 bf) | |||
00 00 F0 BF | |||
23 00 00 00 00 ldc.r8 (00 00 00 00 00 00 f0 bf) | |||
00 00 F0 BF | |||
23 00 00 00 00 ldc.r8 (00 00 00 00 00 00 00 00) | |||
00 00 00 00 | |||
28 02 00 00 0A call class [ScriptTypes]LindenLab.SecondLife.Vector class [LslUserScript]LindenLab.SecondLife.LslUserScript::'CreateVector'(float32, float32, float32) | |||
26 pop | |||
// <-1, -1, 0>; | |||
20 01 00 00 00 ldc.i4 1 | |||
65 neg | |||
6C conv.r8 | |||
20 01 00 00 00 ldc.i4 1 | |||
65 neg | |||
6C conv.r8 | |||
20 00 00 00 00 ldc.i4 0 | |||
6C conv.r8 | |||
28 02 00 00 0A call class [ScriptTypes]LindenLab.SecondLife.Vector class [LslUserScript]LindenLab.SecondLife.LslUserScript::'CreateVector'(float32, float32, float32) | |||
26 pop | |||
// <0xffffffff, 0xffffffff, 0>; | |||
20 FF FF FF FF ldc.i4 -1 | |||
6C conv.r8 | |||
20 FF FF FF FF ldc.i4 -1 | |||
6C conv.r8 | |||
20 00 00 00 00 ldc.i4 0 | |||
6C conv.r8 | |||
28 02 00 00 0A call class [ScriptTypes]LindenLab.SecondLife.Vector class [LslUserScript]LindenLab.SecondLife.LslUserScript::'CreateVector'(float32, float32, float32) | |||
26 pop | |||
// v + v; | |||
11 05 ldloc.s 5 | |||
11 05 ldloc.s 5 | |||
28 0B 00 00 0A call class [ScriptTypes]LindenLab.SecondLife.Vector class [LslUserScript]LindenLab.SecondLife.LslUserScript::'Add'(class [ScriptTypes]LindenLab.SecondLife.Vector, class [ScriptTypes]LindenLab.SecondLife.Vector) | |||
26 pop | |||
// v - v; | |||
11 05 ldloc.s 5 | |||
11 05 ldloc.s 5 | |||
28 0C 00 00 0A call class [ScriptTypes]LindenLab.SecondLife.Vector class [LslUserScript]LindenLab.SecondLife.LslUserScript::'Subtract'(class [ScriptTypes]LindenLab.SecondLife.Vector, class [ScriptTypes]LindenLab.SecondLife.Vector) | |||
26 pop | |||
// v * v; | |||
11 05 ldloc.s 5 | |||
11 05 ldloc.s 5 | |||
28 0D 00 00 0A call float32 class [LslUserScript]LindenLab.SecondLife.LslUserScript::'Multiply'(class [ScriptTypes]LindenLab.SecondLife.Vector, class [ScriptTypes]LindenLab.SecondLife.Vector) | |||
26 pop | |||
// v % v; | |||
11 05 ldloc.s 5 | |||
11 05 ldloc.s 5 | |||
28 0E 00 00 0A call class [ScriptTypes]LindenLab.SecondLife.Vector class [LslUserScript]LindenLab.SecondLife.LslUserScript::'Modulo'(class [ScriptTypes]LindenLab.SecondLife.Vector, class [ScriptTypes]LindenLab.SecondLife.Vector) | |||
26 pop | |||
// []; | |||
28 03 00 00 0A call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::CreateList() | |||
26 pop | |||
// a = []; | |||
28 03 00 00 0A call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::CreateList() | |||
25 dup | |||
13 06 stloc.s 6 | |||
26 pop | |||
// a + [x]; | |||
11 00 ldloc.s 0 | |||
8C 01 00 00 1B box [mscorlib]System.Int32 | |||
28 03 00 00 0A call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::CreateList() | |||
28 0F 00 00 0A call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::Prepend(object, class [mscorlib]System.Collections.ArrayList) | |||
11 06 ldloc.s 6 | |||
28 10 00 00 0A call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::Append(class [mscorlib]System.Collections.ArrayList, class [mscorlib]System.Collections.ArrayList) | |||
26 pop | |||
// a + x; | |||
11 00 ldloc.s 0 | |||
11 06 ldloc.s 6 | |||
28 11 00 00 0A call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::Append(int32, class [mscorlib]System.Collections.ArrayList) | |||
26 pop | |||
// [x] + a; | |||
11 06 ldloc.s 6 | |||
11 00 ldloc.s 0 | |||
8C 01 00 00 1B box [mscorlib]System.Int32 | |||
28 03 00 00 0A call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::CreateList() | |||
28 0F 00 00 0A call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::Prepend(object, class [mscorlib]System.Collections.ArrayList) | |||
28 10 00 00 0A call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::Append(class [mscorlib]System.Collections.ArrayList, class [mscorlib]System.Collections.ArrayList) | |||
26 pop | |||
// x + a; | |||
11 06 ldloc.s 6 | |||
11 00 ldloc.s 0 | |||
8C 01 00 00 1B box [mscorlib]System.Int32 | |||
28 12 00 00 0A call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::Prepend(class [mscorlib]System.Collections.ArrayList, object) | |||
26 pop | |||
// [x]; | |||
11 00 ldloc.s 0 | |||
8C 01 00 00 1B box [mscorlib]System.Int32 | |||
28 03 00 00 0A call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::CreateList() | |||
28 0F 00 00 0A call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::Prepend(object, class [mscorlib]System.Collections.ArrayList) | |||
26 pop | |||
// []+x; | |||
11 00 ldloc.s 0 | |||
28 03 00 00 0A call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::CreateList() | |||
28 11 00 00 0A call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::Append(int32, class [mscorlib]System.Collections.ArrayList) | |||
26 pop | |||
// (list)x; | |||
11 00 ldloc.s 0 | |||
8C 01 00 00 1B box [mscorlib]System.Int32 | |||
28 13 00 00 0A call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::CreateList(object) | |||
26 pop | |||
// [x, y]; | |||
11 00 ldloc.s 0 | |||
8C 01 00 00 1B box [mscorlib]System.Int32 | |||
11 01 ldloc.s 1 | |||
8C 01 00 00 1B box [mscorlib]System.Int32 | |||
28 03 00 00 0A call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::CreateList() | |||
28 0F 00 00 0A call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::Prepend(object, class [mscorlib]System.Collections.ArrayList) | |||
28 0F 00 00 0A call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::Prepend(object, class [mscorlib]System.Collections.ArrayList) | |||
26 pop | |||
// []+x+y; | |||
11 01 ldloc.s 1 | |||
11 00 ldloc.s 0 | |||
28 03 00 00 0A call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::CreateList() | |||
28 11 00 00 0A call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::Append(int32, class [mscorlib]System.Collections.ArrayList) | |||
28 11 00 00 0A call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::Append(int32, class [mscorlib]System.Collections.ArrayList) | |||
26 pop | |||
// (string)a; | |||
11 06 ldloc.s 6 | |||
28 14 00 00 0A call string [LslLibrary]LindenLab.SecondLife.LslRunTime::ListToString(class [mscorlib]System.Collections.ArrayList) | |||
26 pop | |||
// i; | |||
02 ldarg.0 | |||
7B 01 00 00 04 ldfld int32 LSL_y::'i' | |||
26 pop | |||
// u(); | |||
02 ldarg.0 | |||
28 02 00 00 06 call instance void class LSL_y::'gu'() | |||
// end of event | |||
2A ret | |||
} | |||
} | } | ||
</pre> | </pre> | ||
===== 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 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>. | * <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|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 | * 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 in which 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. | * 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 | * As things are now, having more than 256 local variables in a single function or event causes wraparound, making the 257th be an alias to the 1st, and so on. If they aren't the same type, the script crashes at runtime with an uncaught exception. That's a consequence of using <code>ldloc.s</code> / <code>stloc.s</code> without switching to the long version (<code>ldloc</code> / <code>stloc</code>) when the argument is greater than 255. | ||
* Global variable and function names do take code memory. | |||
===== Additional memory usage notes: ===== | |||
* Global variable, function, and function parameter names do take code memory from the script (as part of some symbol table). Fortunately they take 1 byte per character only, as opposed to Mono strings, which take at least 2 bytes per character (they are UTF-16). That extra code is only taken once per variable, regardless of how many times it is used. | |||
* In addition to the state code and state change command code, the state names themselves take code memory from the script, as follows: | |||
** The state name by itself takes no code memory, but internally, each event name includes the state name. The internal name for the event is e.g. <code>edefaultstate_entry</code> (for state <code>default</code>, event <code>state_entry</code>), <code>eblahtimer</code> (for state blah, event <code>timer</code>). These names take 1 byte per character. | |||
** If a state switch statement appears in the code, the state name takes additionally 2 bytes per character. (But these strings are reused, so multiple state switch statements don't take additional space for the strings.) | |||
Although not mentioned above, every single-byte string needs an additional terminating zero byte, and every UTF-16 string needs an additional length prefix byte (or more if longer than 127 bytes, i.e. 63 characters if in the ASCII range) plus an additional terminating zero byte. | |||
{{Resource Conservation Portal Nav|cat=memory}} |
Latest revision as of 16:56, 29 March 2015
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 ilasm
from the Mono suite.
Script that gets compiled:
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();
}
}
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 initialization // integer i; 02 ldarg.0 16 ldc.i4.0 7D 01 00 00 04 stfld int32 LSL_y::'i' 02 ldarg.0 28 01 00 00 0A call instance void [LslUserScript]LindenLab.SecondLife.LslUserScript::.ctor() 2A ret } .method public hidebysig instance default void 'gu'() cil managed { .maxstack 500 2A 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; 16 ldc.i4.0 13 00 stloc.s 0 // integer y = 0; 20 00 00 00 00 ldc.i4 0 13 01 stloc.s 1 // integer z; 16 ldc.i4.0 13 02 stloc.s 2 // float f; 23 00 00 00 00 ldc.r8 0 00 00 00 00 13 03 stloc.s 3 // float g; 23 00 00 00 00 ldc.r8 0 00 00 00 00 13 04 stloc.s 4 // vector v; 23 00 00 00 00 ldc.r8 0 00 00 00 00 23 00 00 00 00 ldc.r8 0 00 00 00 00 23 00 00 00 00 ldc.r8 0 00 00 00 00 28 02 00 00 0A call class [ScriptTypes]LindenLab.SecondLife.Vector class [LslUserScript]LindenLab.SecondLife.LslUserScript::'CreateVector'(float32, float32, float32) 13 05 stloc.s 5 // list a; 28 03 00 00 0A call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::CreateList() 13 06 stloc.s 6 // ;;; {{{ }}} generate no code // return; 2A ret // x; 11 00 ldloc.s 0 26 pop // (x); 11 00 ldloc.s 0 26 pop // (integer)x; 11 00 ldloc.s 0 26 pop // (float)x; 11 00 ldloc.s 0 6C conv.r8 26 pop // f; 11 03 ldloc.s 3 26 pop // (float)f; 11 03 ldloc.s 3 26 pop // (integer)f; 11 03 ldloc.s 3 28 04 00 00 0A call int32 [LslLibrary]LindenLab.SecondLife.LslRunTime::ToInteger(float32) 26 pop // v; 11 05 ldloc.s 5 26 pop // v.z; 12 05 ldloca.s 5 78 05 00 00 0A ldfld float32 class [ScriptTypes]LindenLab.SecondLife.Vector::z 26 pop // -x; 11 00 ldloc.s 0 65 neg 26 pop // ~x; 11 00 ldloc.s 0 66 not 26 pop // !x; 11 00 ldloc.s 0 16 ldc.i4.0 FE 01 ceq 26 pop // --x; 11 00 ldloc.s 0 17 ldc.i4.1 59 sub 25 dup 13 00 stloc.s 0 26 pop // ++x; 11 00 ldloc.s 0 17 ldc.i4.1 58 add 25 dup 13 00 stloc.s 0 26 pop // x--; 11 00 ldloc.s 0 11 00 ldloc.s 0 17 ldc.i4.1 59 sub 25 dup 13 00 stloc.s 0 26 pop 26 pop // x++; 11 00 ldloc.s 0 11 00 ldloc.s 0 17 ldc.i4.1 58 add 25 dup 13 00 stloc.s 0 26 pop 26 pop // x = y; 11 01 ldloc.s 1 25 dup 13 00 stloc.s 0 26 pop // x == y; 11 01 ldloc.s 1 11 00 ldloc.s 0 FE 01 ceq 26 pop // x = y = z; 11 02 ldloc.s 2 25 dup 13 01 stloc.s 1 25 dup 13 00 stloc.s 0 26 pop // f = x; 11 00 ldloc.s 0 6C conv.r8 25 dup 13 03 stloc.s 3 26 pop // f = (float)x; 11 00 ldloc.s 0 6C conv.r8 25 dup 13 03 stloc.s 3 26 pop // x != y; implemented as: !(x==y) 11 01 ldloc.s 1 // this part is x == y 11 00 ldloc.s 0 FE 01 ceq 16 ldc.i4.0 // this part is 'not' FE 01 ceq 26 pop // x + y; 11 01 ldloc.s 1 11 00 ldloc.s 0 58 add 26 pop // x - y; 11 01 ldloc.s 1 11 00 ldloc.s 0 28 06 00 00 0A call int32 [LslUserScript]LindenLab.SecondLife.LslUserScript::Subtract(int32, int32) 26 pop // x + -y; 11 01 ldloc.s 1 65 neg 11 00 ldloc.s 0 58 add 26 pop // x * y; 11 01 ldloc.s 1 11 00 ldloc.s 0 5A mul 26 pop // x / y; 11 01 ldloc.s 1 11 00 ldloc.s 0 28 07 00 00 0A call int32 [LslUserScript]LindenLab.SecondLife.LslUserScript::Divide(int32, int32) 26 pop // x % y; 11 01 ldloc.s 1 11 00 ldloc.s 0 28 08 00 00 0A call int32 [LslUserScript]LindenLab.SecondLife.LslUserScript::Modulo(int32, int32) 26 pop // x & y; 11 01 ldloc.s 1 11 00 ldloc.s 0 5F and 26 pop // x && y; implemented as: !(!x | !y) 11 01 ldloc.s 1 // !x 16 ldc.i4.0 FE 01 ceq 11 00 ldloc.s 0 // !y 16 ldc.i4.0 FE 01 ceq 60 or // !x | !y 16 ldc.i4.0 // !(!x | !y) FE 01 ceq 26 pop // x | y; 11 01 ldloc.s 1 11 00 ldloc.s 0 60 or 26 pop // x || y; implemented as: !!(x | y) 11 01 ldloc.s 1 // x | y 11 00 ldloc.s 0 60 or 16 ldc.i4.0 // !(x | y) FE 01 ceq 16 ldc.i4.0 // !!(x | y) FE 01 ceq 26 pop // x ^ y; 11 01 ldloc.s 1 11 00 ldloc.s 0 61 xor 26 pop // x << y; 11 01 ldloc.s 1 11 00 ldloc.s 0 28 09 00 00 0A call int32 [LslUserScript]LindenLab.SecondLife.LslUserScript::ShiftLeft(int32, int32) 26 pop // x >> y; 11 01 ldloc.s 1 11 00 ldloc.s 0 28 0A 00 00 0A call int32 [LslUserScript]LindenLab.SecondLife.LslUserScript::ShiftRight(int32, int32) 26 pop // x < y; implemented as: y > x 11 01 ldloc.s 1 11 00 ldloc.s 0 FE 02 cgt 26 pop // x > y; implemented as: y < x; 11 01 ldloc.s 1 11 00 ldloc.s 0 FE 04 clt 26 pop // x <= y; implemented as: !(y < x) 11 01 ldloc.s 1 11 00 ldloc.s 0 FE 04 clt 16 ldc.i4.0 FE 01 ceq 26 pop // x >= y; implemented as: !(y > x) 11 01 ldloc.s 1 11 00 ldloc.s 0 FE 02 cgt 16 ldc.i4.0 FE 01 ceq 26 pop // x += y; 11 01 ldloc.s 1 11 00 ldloc.s 0 58 add 25 dup 13 00 stloc.s 0 26 pop // x -= y; 11 01 ldloc.s 1 11 00 ldloc.s 0 28 06 00 00 0A call int32 [LslUserScript]LindenLab.SecondLife.LslUserScript::Subtract(int32, int32) 25 dup 13 00 stloc.s 0 26 pop // x += -y; 11 01 ldloc.s 1 65 neg 11 00 ldloc.s 0 58 add 25 dup 13 00 stloc.s 0 26 pop // x *= y; 11 01 ldloc.s 1 11 00 ldloc.s 0 5A mul 25 dup 13 00 stloc.s 0 26 pop // x /= y; 11 01 ldloc.s 1 11 00 ldloc.s 0 28 07 00 00 0A call int32 [LslUserScript]LindenLab.SecondLife.LslUserScript::Divide(int32, int32) 25 dup 13 00 stloc.s 0 26 pop // x %= y; 11 01 ldloc.s 1 11 00 ldloc.s 0 28 08 00 00 0A call int32 [LslUserScript]LindenLab.SecondLife.LslUserScript::Modulo(int32, int32) 25 dup 13 00 stloc.s 0 26 pop // if (x) ; 11 00 ldloc.s 0 39 00 00 00 00 brfalse LabelTempJump0 // THEN branch code goes here LabelTempJump0: // if (x) ; else ; 11 00 ldloc.s 0 39 05 00 00 00 brfalse LabelTempJump1 // THEN branch code would go here 38 00 00 00 00 br LabelTempJump2 // ELSE branch code would go here LabelTempJump1: LabelTempJump2: // 0; 20 00 00 00 00 ldc.i4 0 26 pop // x ^ x; 11 00 ldloc.s 0 11 00 ldloc.s 0 61 xor 26 pop // 1; 20 01 00 00 00 ldc.i4 1 26 pop // -1; note the negative sign takes code memory 20 01 00 00 00 ldc.i4 1 65 neg 26 pop // 0xffffffff; note it equals -1 without the sign taking memory 20 FF FF FF FF ldc.i4 -1 26 pop // ALL_SIDES; ditto 20 FF FF FF FF ldc.i4 -1 26 pop // x | ~x; 11 00 ldloc.s 0 66 not 11 00 ldloc.s 0 60 or 26 pop // x + 1; 20 01 00 00 00 ldc.i4 1 11 00 ldloc.s 0 58 add 26 pop // -~x; 11 00 ldloc.s 0 66 not 65 neg 26 pop // x - 1; 20 01 00 00 00 ldc.i4 1 11 00 ldloc.s 0 28 06 00 00 0A call int32 [LslUserScript]LindenLab.SecondLife.LslUserScript::Subtract(int32, int32) 26 pop // x + -1; 20 01 00 00 00 ldc.i4 1 65 neg 11 00 ldloc.s 0 58 add 26 pop // ~-x; 11 00 ldloc.s 0 65 neg 66 not 26 pop // x*y + y - 1; 20 01 00 00 00 ldc.i4 1 11 01 ldloc.s 1 11 01 ldloc.s 1 11 00 ldloc.s 0 5A mul 58 add 28 06 00 00 0A call int32 [LslUserScript]LindenLab.SecondLife.LslUserScript::Subtract(int32, int32) 26 pop // (x + 1)*y - 1; 20 01 00 00 00 ldc.i4 1 11 01 ldloc.s 1 20 01 00 00 00 ldc.i4 1 11 00 ldloc.s 0 58 add 5A mul 28 06 00 00 0A call int32 [LslUserScript]LindenLab.SecondLife.LslUserScript::Subtract(int32, int32) 26 pop // ~(~x*y); 11 01 ldloc.s 1 11 00 ldloc.s 0 66 not 5A mul 66 not 26 pop // while (x) ; LabelTempJump3: 11 00 ldloc.s 0 39 05 00 00 00 brfalse LabelTempJump4 // Looped code would go here 38 F4 FF FF FF br LabelTempJump3 LabelTempJump4: // do ; while (x); LabelTempJump5: // Looped code would go here 11 00 ldloc.s 0 3A F9 FF FF FF brtrue LabelTempJump5 // for (; x; ) ; LabelTempJump6: 11 00 ldloc.s 0 39 05 00 00 00 brfalse LabelTempJump7 // Looped code would go here 38 F4 FF FF FF br LabelTempJump6 LabelTempJump7: // @label; if (x) jump label; 'label': // Looped code would go here 11 00 ldloc.s 0 39 05 00 00 00 brfalse LabelTempJump8 38 F4 FF FF FF br 'label' LabelTempJump8: // 0.0; 23 00 00 00 00 ldc.r8 (00 00 00 00 00 00 00 00) 00 00 00 00 26 pop // f = 0.0; 23 00 00 00 00 ldc.r8 (00 00 00 00 00 00 00 00) 00 00 00 00 25 dup 13 03 stloc.s 3 26 pop // f = 0; 20 00 00 00 00 ldc.i4 0 6C conv.r8 25 dup 13 03 stloc.s 3 26 pop // <0.0, 0.0, 0.0>; 23 00 00 00 00 ldc.r8 (00 00 00 00 00 00 00 00) 00 00 00 00 23 00 00 00 00 ldc.r8 (00 00 00 00 00 00 00 00) 00 00 00 00 23 00 00 00 00 ldc.r8 (00 00 00 00 00 00 00 00) 00 00 00 00 28 02 00 00 0A call class [ScriptTypes]LindenLab.SecondLife.Vector class [LslUserScript]LindenLab.SecondLife.LslUserScript::'CreateVector'(float32, float32, float32) 26 pop // ZERO_VECTOR; 23 00 00 00 00 ldc.r8 (00 00 00 00 00 00 00 00) 00 00 00 00 23 00 00 00 00 ldc.r8 (00 00 00 00 00 00 00 00) 00 00 00 00 23 00 00 00 00 ldc.r8 (00 00 00 00 00 00 00 00) 00 00 00 00 28 02 00 00 0A call class [ScriptTypes]LindenLab.SecondLife.Vector class [LslUserScript]LindenLab.SecondLife.LslUserScript::'CreateVector'(float32, float32, float32) 26 pop // <0, 0, 0>; 20 00 00 00 00 ldc.i4 0 6C conv.r8 20 00 00 00 00 ldc.i4 0 6C conv.r8 20 00 00 00 00 ldc.i4 0 6C conv.r8 28 02 00 00 0A call class [ScriptTypes]LindenLab.SecondLife.Vector class [LslUserScript]LindenLab.SecondLife.LslUserScript::'CreateVector'(float32, float32, float32) 26 pop // <-1.0, -1.0, 0.0>; 23 00 00 00 00 ldc.r8 (00 00 00 00 00 00 f0 3f) 00 00 F0 3F 65 neg 23 00 00 00 00 ldc.r8 (00 00 00 00 00 00 f0 3f) 00 00 F0 3F 65 neg 23 00 00 00 00 ldc.r8 (00 00 00 00 00 00 00 00) 00 00 00 00 28 02 00 00 0A call class [ScriptTypes]LindenLab.SecondLife.Vector class [LslUserScript]LindenLab.SecondLife.LslUserScript::'CreateVector'(float32, float32, float32) 26 pop // TOUCH_INVALID_TEXCOORD; 23 00 00 00 00 ldc.r8 (00 00 00 00 00 00 f0 bf) 00 00 F0 BF 23 00 00 00 00 ldc.r8 (00 00 00 00 00 00 f0 bf) 00 00 F0 BF 23 00 00 00 00 ldc.r8 (00 00 00 00 00 00 00 00) 00 00 00 00 28 02 00 00 0A call class [ScriptTypes]LindenLab.SecondLife.Vector class [LslUserScript]LindenLab.SecondLife.LslUserScript::'CreateVector'(float32, float32, float32) 26 pop // <-1, -1, 0>; 20 01 00 00 00 ldc.i4 1 65 neg 6C conv.r8 20 01 00 00 00 ldc.i4 1 65 neg 6C conv.r8 20 00 00 00 00 ldc.i4 0 6C conv.r8 28 02 00 00 0A call class [ScriptTypes]LindenLab.SecondLife.Vector class [LslUserScript]LindenLab.SecondLife.LslUserScript::'CreateVector'(float32, float32, float32) 26 pop // <0xffffffff, 0xffffffff, 0>; 20 FF FF FF FF ldc.i4 -1 6C conv.r8 20 FF FF FF FF ldc.i4 -1 6C conv.r8 20 00 00 00 00 ldc.i4 0 6C conv.r8 28 02 00 00 0A call class [ScriptTypes]LindenLab.SecondLife.Vector class [LslUserScript]LindenLab.SecondLife.LslUserScript::'CreateVector'(float32, float32, float32) 26 pop // v + v; 11 05 ldloc.s 5 11 05 ldloc.s 5 28 0B 00 00 0A call class [ScriptTypes]LindenLab.SecondLife.Vector class [LslUserScript]LindenLab.SecondLife.LslUserScript::'Add'(class [ScriptTypes]LindenLab.SecondLife.Vector, class [ScriptTypes]LindenLab.SecondLife.Vector) 26 pop // v - v; 11 05 ldloc.s 5 11 05 ldloc.s 5 28 0C 00 00 0A call class [ScriptTypes]LindenLab.SecondLife.Vector class [LslUserScript]LindenLab.SecondLife.LslUserScript::'Subtract'(class [ScriptTypes]LindenLab.SecondLife.Vector, class [ScriptTypes]LindenLab.SecondLife.Vector) 26 pop // v * v; 11 05 ldloc.s 5 11 05 ldloc.s 5 28 0D 00 00 0A call float32 class [LslUserScript]LindenLab.SecondLife.LslUserScript::'Multiply'(class [ScriptTypes]LindenLab.SecondLife.Vector, class [ScriptTypes]LindenLab.SecondLife.Vector) 26 pop // v % v; 11 05 ldloc.s 5 11 05 ldloc.s 5 28 0E 00 00 0A call class [ScriptTypes]LindenLab.SecondLife.Vector class [LslUserScript]LindenLab.SecondLife.LslUserScript::'Modulo'(class [ScriptTypes]LindenLab.SecondLife.Vector, class [ScriptTypes]LindenLab.SecondLife.Vector) 26 pop // []; 28 03 00 00 0A call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::CreateList() 26 pop // a = []; 28 03 00 00 0A call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::CreateList() 25 dup 13 06 stloc.s 6 26 pop // a + [x]; 11 00 ldloc.s 0 8C 01 00 00 1B box [mscorlib]System.Int32 28 03 00 00 0A call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::CreateList() 28 0F 00 00 0A call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::Prepend(object, class [mscorlib]System.Collections.ArrayList) 11 06 ldloc.s 6 28 10 00 00 0A call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::Append(class [mscorlib]System.Collections.ArrayList, class [mscorlib]System.Collections.ArrayList) 26 pop // a + x; 11 00 ldloc.s 0 11 06 ldloc.s 6 28 11 00 00 0A call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::Append(int32, class [mscorlib]System.Collections.ArrayList) 26 pop // [x] + a; 11 06 ldloc.s 6 11 00 ldloc.s 0 8C 01 00 00 1B box [mscorlib]System.Int32 28 03 00 00 0A call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::CreateList() 28 0F 00 00 0A call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::Prepend(object, class [mscorlib]System.Collections.ArrayList) 28 10 00 00 0A call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::Append(class [mscorlib]System.Collections.ArrayList, class [mscorlib]System.Collections.ArrayList) 26 pop // x + a; 11 06 ldloc.s 6 11 00 ldloc.s 0 8C 01 00 00 1B box [mscorlib]System.Int32 28 12 00 00 0A call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::Prepend(class [mscorlib]System.Collections.ArrayList, object) 26 pop // [x]; 11 00 ldloc.s 0 8C 01 00 00 1B box [mscorlib]System.Int32 28 03 00 00 0A call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::CreateList() 28 0F 00 00 0A call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::Prepend(object, class [mscorlib]System.Collections.ArrayList) 26 pop // []+x; 11 00 ldloc.s 0 28 03 00 00 0A call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::CreateList() 28 11 00 00 0A call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::Append(int32, class [mscorlib]System.Collections.ArrayList) 26 pop // (list)x; 11 00 ldloc.s 0 8C 01 00 00 1B box [mscorlib]System.Int32 28 13 00 00 0A call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::CreateList(object) 26 pop // [x, y]; 11 00 ldloc.s 0 8C 01 00 00 1B box [mscorlib]System.Int32 11 01 ldloc.s 1 8C 01 00 00 1B box [mscorlib]System.Int32 28 03 00 00 0A call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::CreateList() 28 0F 00 00 0A call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::Prepend(object, class [mscorlib]System.Collections.ArrayList) 28 0F 00 00 0A call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::Prepend(object, class [mscorlib]System.Collections.ArrayList) 26 pop // []+x+y; 11 01 ldloc.s 1 11 00 ldloc.s 0 28 03 00 00 0A call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::CreateList() 28 11 00 00 0A call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::Append(int32, class [mscorlib]System.Collections.ArrayList) 28 11 00 00 0A call class [mscorlib]System.Collections.ArrayList class [LslUserScript]LindenLab.SecondLife.LslUserScript::Append(int32, class [mscorlib]System.Collections.ArrayList) 26 pop // (string)a; 11 06 ldloc.s 6 28 14 00 00 0A call string [LslLibrary]LindenLab.SecondLife.LslRunTime::ListToString(class [mscorlib]System.Collections.ArrayList) 26 pop // i; 02 ldarg.0 7B 01 00 00 04 ldfld int32 LSL_y::'i' 26 pop // u(); 02 ldarg.0 28 02 00 00 06 call instance void class LSL_y::'gu'() // end of event 2A 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 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 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 in which 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 in a single function or event causes wraparound, making the 257th be an alias to the 1st, and so on. If they aren't the same type, the script crashes at runtime with an uncaught exception. That's a consequence of using
ldloc.s
/stloc.s
without switching to the long version (ldloc
/stloc
) when the argument is greater than 255.
Additional memory usage notes:
- Global variable, function, and function parameter names do take code memory from the script (as part of some symbol table). Fortunately they take 1 byte per character only, as opposed to Mono strings, which take at least 2 bytes per character (they are UTF-16). That extra code is only taken once per variable, regardless of how many times it is used.
- In addition to the state code and state change command code, the state names themselves take code memory from the script, as follows:
- The state name by itself takes no code memory, but internally, each event name includes the state name. The internal name for the event is e.g.
edefaultstate_entry
(for statedefault
, eventstate_entry
),eblahtimer
(for state blah, eventtimer
). These names take 1 byte per character. - If a state switch statement appears in the code, the state name takes additionally 2 bytes per character. (But these strings are reused, so multiple state switch statements don't take additional space for the strings.)
- The state name by itself takes no code memory, but internally, each event name includes the state name. The internal name for the event is e.g.
Although not mentioned above, every single-byte string needs an additional terminating zero byte, and every UTF-16 string needs an additional length prefix byte (or more if longer than 127 bytes, i.e. 63 characters if in the ASCII range) plus an additional terminating zero byte.