User:Pedro Oval/Mono code memory usage/CIL: Difference between revisions
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.