Difference between revisions of "User:Pedro Oval/Mono code memory usage/CIL"
Jump to navigation
Jump to search
Pedro Oval (talk | contribs) (Created page. More additions coming.) |
Pedro Oval (talk | contribs) (All at once) |
||
Line 1: | Line 1: | ||
Here's the CIL code generated by | 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. | ||
| | 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: | |||
<pre> | |||
.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 | |||
} | |||
} | |||
</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 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. | ||
* 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 much more bytes than what the CIL result above suggests. Forward jumps, however, seem predictable enough. | |||
* Global variable and function names do take code memory. | |||
Revision as of 16:35, 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. Assembly was done using ilasm
from the Mono suite.
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 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.
- 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 much more bytes than what the CIL result above suggests. Forward jumps, however, seem predictable enough.
- Global variable and function names do take code memory.