using System;
namespace Generic
{
class MainClass
{
public interface VectorProperties<T>
{
T Length
{ get; }
}
public struct Vec2 : VectorProperties<double>
{
public double X;
public double Y;
public double Length
{
get { return Math.Sqrt(X*X + Y*Y); }
}
}
public struct Vec3 : VectorProperties<double>
{
public double X;
public double Y;
public double Z;
public double Length
{
get { return Math.Sqrt(X*X + Y*Y + Z*Z); }
}
}
public static double VectorsLengthA(VectorProperties<double> vec1, VectorProperties<double> vec2)
{
return (vec1.Length + vec2.Length);
}
public static double VectorsLengthB<V1,V2>(V1 vec1, V2 vec2)
where V1 : VectorProperties<double>
where V2 : VectorProperties<double>
{
return (vec1.Length + vec2.Length);
}
public static void Main (string[] args)
{
var a = new Vec2 { X = Convert.ToDouble(args[0]), Y = Convert.ToDouble(args[1]) };
var b = new Vec3 { X = Convert.ToDouble(args[0]), Y = Convert.ToDouble(args[1]), Z = Convert.ToDouble(args[2]) };
Console.WriteLine("Length a = {0}", a.Length);
Console.WriteLine("Length b = {0}", b.Length);
Console.WriteLine("1: Length a,b = {0}", VectorsLengthA(a, b));
Console.WriteLine("2: Length a,b = {0}", VectorsLengthB(a, b));
}
}
}
See the CIL for VectorsLengthA and VectorsLengthB. Notice the way both those methods is called.
namespace Generic
{
class MainClass
{
public interface VectorProperties<T>
{
T Length
{ get; }
}
public struct Vec2 : VectorProperties<double>
{
public double X;
public double Y;
public double Length
{
get { return Math.Sqrt(X*X + Y*Y); }
}
}
public struct Vec3 : VectorProperties<double>
{
public double X;
public double Y;
public double Z;
public double Length
{
get { return Math.Sqrt(X*X + Y*Y + Z*Z); }
}
}
public static double VectorsLengthA(VectorProperties<double> vec1, VectorProperties<double> vec2)
{
return (vec1.Length + vec2.Length);
}
public static double VectorsLengthB<V1,V2>(V1 vec1, V2 vec2)
where V1 : VectorProperties<double>
where V2 : VectorProperties<double>
{
return (vec1.Length + vec2.Length);
}
public static void Main (string[] args)
{
var a = new Vec2 { X = Convert.ToDouble(args[0]), Y = Convert.ToDouble(args[1]) };
var b = new Vec3 { X = Convert.ToDouble(args[0]), Y = Convert.ToDouble(args[1]), Z = Convert.ToDouble(args[2]) };
Console.WriteLine("Length a = {0}", a.Length);
Console.WriteLine("Length b = {0}", b.Length);
Console.WriteLine("1: Length a,b = {0}", VectorsLengthA(a, b));
Console.WriteLine("2: Length a,b = {0}", VectorsLengthB(a, b));
}
}
}
// ...
.namespace Generic
{
.class private auto ansi beforefieldinit MainClass
extends [mscorlib]System.Object
{
// ...
// method line 2
.method public static hidebysig
default float64 VectorsLengthA (class Generic.MainClass/VectorProperties`1<float64> vec1, class Generic.MainClass/VectorProperties`1<float64> vec2) cil managed
{
// Method begins at RVA 0x20f4
// Code size 14 (0xe)
.maxstack 8
IL_0000: ldarg.0
IL_0001: callvirt instance !0 class Generic.MainClass/VectorProperties`1<float64>::get_Length()
IL_0006: ldarg.1
IL_0007: callvirt instance !0 class Generic.MainClass/VectorProperties`1<float64>::get_Length()
IL_000c: add
IL_000d: ret
} // end of method MainClass::VectorsLengthA
// method line 3
.method public static hidebysig
default float64 VectorsLengthB<(class Generic.MainClass/VectorProperties`1<float64>) V1,(class Generic.MainClass/VectorProperties`1<float64>) V2> (!!V1 vec1, !!V2 vec2) cil managed
{
// Method begins at RVA 0x2104
// Code size 28 (0x1c)
.maxstack 8
IL_0000: ldarga.s 0
IL_0002: constrained. !!0
IL_0008: callvirt instance !0 class Generic.MainClass/VectorProperties`1<float64>::get_Length()
IL_000d: ldarga.s 1
IL_000f: constrained. !!1
IL_0015: callvirt instance !0 class Generic.MainClass/VectorProperties`1<float64>::get_Length()
IL_001a: add
IL_001b: ret
} // end of method MainClass::VectorsLengthB
// method line 4
.method public static hidebysig
default void Main (string[] args) cil managed
{
// Method begins at RVA 0x2124
.entrypoint
// Code size 198 (0xc6)
.maxstack 17
.locals init (
valuetype Generic.MainClass/Vec2 V_0,
valuetype Generic.MainClass/Vec3 V_1,
valuetype Generic.MainClass/Vec2 V_2,
valuetype Generic.MainClass/Vec3 V_3)
// ...
IL_0062: stloc.1
IL_0063: ldstr "Length a = {0}"
IL_0068: ldloca.s 0
IL_006a: call instance float64 valuetype Generic.MainClass/Vec2::get_Length()
IL_006f: box [mscorlib]System.Double
IL_0074: call void class [mscorlib]System.Console::WriteLine(string, object)
IL_0079: ldstr "Length b = {0}"
IL_007e: ldloca.s 1
IL_0080: call instance float64 valuetype Generic.MainClass/Vec3::get_Length()
IL_0085: box [mscorlib]System.Double
IL_008a: call void class [mscorlib]System.Console::WriteLine(string, object)
IL_008f: ldstr "1: Length a,b = {0}"
IL_0094: ldloc.0
IL_0095: box Generic.MainClass/Vec2
IL_009a: ldloc.1
IL_009b: box Generic.MainClass/Vec3
IL_00a0: call float64 class Generic.MainClass::VectorsLengthA(class Generic.MainClass/VectorProperties`1<float64>, class Generic.MainClass/VectorProperties`1<float64>)
IL_00a5: box [mscorlib]System.Double
IL_00aa: call void class [mscorlib]System.Console::WriteLine(string, object)
IL_00af: ldstr "2: Length a,b = {0}"
IL_00b4: ldloc.0
IL_00b5: ldloc.1
IL_00b6: call float64 class Generic.MainClass::VectorsLengthB<valuetype Generic.MainClass/Vec2, valuetype Generic.MainClass/Vec3> (!!0, !!1)
IL_00bb: box [mscorlib]System.Double
IL_00c0: call void class [mscorlib]System.Console::WriteLine(string, object)
IL_00c5: ret
} // end of method MainClass::Main
// ...
} // end of class Generic.MainClass
}
// ex:filetype=ilasm
After JIT it becomes:
.namespace Generic
{
.class private auto ansi beforefieldinit MainClass
extends [mscorlib]System.Object
{
// ...
// method line 2
.method public static hidebysig
default float64 VectorsLengthA (class Generic.MainClass/VectorProperties`1<float64> vec1, class Generic.MainClass/VectorProperties`1<float64> vec2) cil managed
{
// Method begins at RVA 0x20f4
// Code size 14 (0xe)
.maxstack 8
IL_0000: ldarg.0
IL_0001: callvirt instance !0 class Generic.MainClass/VectorProperties`1<float64>::get_Length()
IL_0006: ldarg.1
IL_0007: callvirt instance !0 class Generic.MainClass/VectorProperties`1<float64>::get_Length()
IL_000c: add
IL_000d: ret
} // end of method MainClass::VectorsLengthA
// method line 3
.method public static hidebysig
default float64 VectorsLengthB<(class Generic.MainClass/VectorProperties`1<float64>) V1,(class Generic.MainClass/VectorProperties`1<float64>) V2> (!!V1 vec1, !!V2 vec2) cil managed
{
// Method begins at RVA 0x2104
// Code size 28 (0x1c)
.maxstack 8
IL_0000: ldarga.s 0
IL_0002: constrained. !!0
IL_0008: callvirt instance !0 class Generic.MainClass/VectorProperties`1<float64>::get_Length()
IL_000d: ldarga.s 1
IL_000f: constrained. !!1
IL_0015: callvirt instance !0 class Generic.MainClass/VectorProperties`1<float64>::get_Length()
IL_001a: add
IL_001b: ret
} // end of method MainClass::VectorsLengthB
// method line 4
.method public static hidebysig
default void Main (string[] args) cil managed
{
// Method begins at RVA 0x2124
.entrypoint
// Code size 198 (0xc6)
.maxstack 17
.locals init (
valuetype Generic.MainClass/Vec2 V_0,
valuetype Generic.MainClass/Vec3 V_1,
valuetype Generic.MainClass/Vec2 V_2,
valuetype Generic.MainClass/Vec3 V_3)
// ...
IL_0062: stloc.1
IL_0063: ldstr "Length a = {0}"
IL_0068: ldloca.s 0
IL_006a: call instance float64 valuetype Generic.MainClass/Vec2::get_Length()
IL_006f: box [mscorlib]System.Double
IL_0074: call void class [mscorlib]System.Console::WriteLine(string, object)
IL_0079: ldstr "Length b = {0}"
IL_007e: ldloca.s 1
IL_0080: call instance float64 valuetype Generic.MainClass/Vec3::get_Length()
IL_0085: box [mscorlib]System.Double
IL_008a: call void class [mscorlib]System.Console::WriteLine(string, object)
IL_008f: ldstr "1: Length a,b = {0}"
IL_0094: ldloc.0
IL_0095: box Generic.MainClass/Vec2
IL_009a: ldloc.1
IL_009b: box Generic.MainClass/Vec3
IL_00a0: call float64 class Generic.MainClass::VectorsLengthA(class Generic.MainClass/VectorProperties`1<float64>, class Generic.MainClass/VectorProperties`1<float64>)
IL_00a5: box [mscorlib]System.Double
IL_00aa: call void class [mscorlib]System.Console::WriteLine(string, object)
IL_00af: ldstr "2: Length a,b = {0}"
IL_00b4: ldloc.0
IL_00b5: ldloc.1
IL_00b6: call float64 class Generic.MainClass::VectorsLengthB<valuetype Generic.MainClass/Vec2, valuetype Generic.MainClass/Vec3> (!!0, !!1)
IL_00bb: box [mscorlib]System.Double
IL_00c0: call void class [mscorlib]System.Console::WriteLine(string, object)
IL_00c5: ret
} // end of method MainClass::Main
// ...
} // end of class Generic.MainClass
}
// ex:filetype=ilasm
Generic.exe.so: file format elf64-x86-64
Disassembly of section .text:
0000000000001000 <methods>:
...
0000000000001010 <Generic_MainClass__ctor>:
; Ehmm.... Setting ZF from %rsp? What for? And why in that way?
1010: 48 83 ec 08 sub $0x8,%rsp
1014: 48 83 c4 08 add $0x8,%rsp
1018: c3 retq
1019: 00 00 add %al,(%rax)
101b: 00 00 add %al,(%rax)
101d: 00 00 add %al,(%rax)
...
; interface-based VectorsLengthA
0000000000001020 <Generic_MainClass_VectorsLengthA_Generic_MainClass_VectorProperties_1_double_Generic_MainClass_VectorProperties_1_double>:
1020: 48 83 ec 18 sub $0x18,%rsp ; 3 words
1024: 48 89 3c 24 mov %rdi,(%rsp) ; vecA
1028: 48 89 74 24 08 mov %rsi,0x8(%rsp) ; vecB
102d: 48 8b c7 mov %rdi,%rax
1030: 48 8b 00 mov (%rax),%rax
1033: 4d 8b 15 de 24 00 00 mov 0x24de(%rip),%r10 # 3518 <__bss_start+0x18>
103a: ff 90 70 ff ff ff callq *-0x90(%rax)
1040: f2 0f 11 44 24 10 movsd %xmm0,0x10(%rsp) ; temp var for sum
1046: 48 8b 7c 24 08 mov 0x8(%rsp),%rdi
104b: 48 8b c7 mov %rdi,%rax
104e: 48 8b 00 mov (%rax),%rax
1051: 4d 8b 15 c0 24 00 00 mov 0x24c0(%rip),%r10 # 3518 <__bss_start+0x18>
1058: ff 90 70 ff ff ff callq *-0x90(%rax)
; ???
105e: f2 0f 10 c8 movsd %xmm0,%xmm1
1062: f2 0f 10 44 24 10 movsd 0x10(%rsp),%xmm0
1068: f2 0f 58 c1 addsd %xmm1,%xmm0
106c: 48 83 c4 18 add $0x18,%rsp
1070: c3 retq
...
; generic-based VectorsLengthB (so we can work with any generic)
; not so much difference from VectorsLengthA
; except of storing r10 on stack
0000000000001080 <Generic_MainClass_VectorsLengthB_V1_V2_V1_V2>:
1080: 48 83 ec 28 sub $0x28,%rsp ; 4 words
1084: 4c 89 14 24 mov %r10,(%rsp) ; unknown
1088: 48 89 7c 24 08 mov %rdi,0x8(%rsp) ; vecA
108d: 48 89 74 24 10 mov %rsi,0x10(%rsp)
1092: 48 8b c7 mov %rdi,%rax ; vecA
1095: 48 8b f8 mov %rax,%rdi ; what a???...
1098: 48 8b 00 mov (%rax),%rax ; vecA
109b: 4d 8b 15 76 24 00 00 mov 0x2476(%rip),%r10 # 3518 <__bss_start+0x18>
10a2: ff 90 70 ff ff ff callq *-0x90(%rax)
10a8: f2 0f 11 44 24 18 movsd %xmm0,0x18(%rsp) ; temp var for sum
10ae: 48 8b 44 24 10 mov 0x10(%rsp),%rax ; vecB
10b3: 48 8b f8 mov %rax,%rdi
10b6: 48 8b 00 mov (%rax),%rax
10b9: 4d 8b 15 58 24 00 00 mov 0x2458(%rip),%r10 # 3518 <__bss_start+0x18>
10c0: ff 90 70 ff ff ff callq *-0x90(%rax)
10c6: f2 0f 10 c8 movsd %xmm0,%xmm1
10ca: f2 0f 10 44 24 18 movsd 0x18(%rsp),%xmm0
10d0: f2 0f 58 c1 addsd %xmm1,%xmm0
10d4: 48 83 c4 28 add $0x28,%rsp
10d8: c3 retq
10d9: 00 00 add %al,(%rax)
10db: 00 00 add %al,(%rax)
10dd: 00 00 add %al,(%rax)
...
00000000000010e0 <Generic_MainClass_Main_string__>:
10e0: 55 push %rbp
10e1: 48 8b ec mov %rsp,%rbp
10e4: 41 57 push %r15
10e6: 48 81 ec 08 01 00 00 sub $0x108,%rsp
10ed: 4c 8b ff mov %rdi,%r15
10f0: 33 c0 xor %eax,%eax
10f2: 48 89 85 58 ff ff ff mov %rax,-0xa8(%rbp)
; ...
1130: 48 89 85 60 ff ff ff mov %rax,-0xa0(%rbp)
; ...
; direct call to interface implementation
1218: 48 8b 45 90 mov -0x70(%rbp),%rax
121c: 48 89 85 68 ff ff ff mov %rax,-0x98(%rbp)
1223: 48 8b 45 98 mov -0x68(%rbp),%rax
1227: 48 89 85 70 ff ff ff mov %rax,-0x90(%rbp)
122e: 48 8b 45 a0 mov -0x60(%rbp),%rax
1232: 48 89 85 78 ff ff ff mov %rax,-0x88(%rbp)
1239: 49 8b 05 e0 22 00 00 mov 0x22e0(%rip),%rax # 3520 <__bss_start+0x20>
1240: 48 89 85 18 ff ff ff mov %rax,-0xe8(%rbp)
1247: 48 8b fd mov %rbp,%rdi
124a: 48 81 c7 58 ff ff ff add $0xffffffffffffff58,%rdi
1251: e8 2a 02 00 00 callq 1480 <Generic_MainClass_Vec2_get_Length>
1256: f2 0f 11 85 10 ff ff movsd %xmm0,-0xf0(%rbp)
125d: ff
; indirect call with boxing
125e: 49 8b 3d c3 22 00 00 mov 0x22c3(%rip),%rdi # 3528 <__bss_start+0x28>
1265: e8 1a 03 00 00 callq 1584 <plt_wrapper_alloc_object_AllocSmall_intptr>
126a: 48 8b f0 mov %rax,%rsi
126d: 48 8b bd 18 ff ff ff mov -0xe8(%rbp),%rdi
1274: f2 0f 10 85 10 ff ff movsd -0xf0(%rbp),%xmm0
127b: ff
127c: f2 0f 11 46 10 movsd %xmm0,0x10(%rsi)
1281: e8 08 03 00 00 callq 158e <plt_System_Console_WriteLine_string_object>
; ...
; indirect call to local function with boxing
12d3: 49 8b 05 5e 22 00 00 mov 0x225e(%rip),%rax # 3538 <__bss_start+0x38>
12da: 48 89 85 40 ff ff ff mov %rax,-0xc0(%rbp)
12e1: 48 8b 85 58 ff ff ff mov -0xa8(%rbp),%rax
12e8: 48 89 45 a8 mov %rax,-0x58(%rbp)
12ec: 48 8b 85 60 ff ff ff mov -0xa0(%rbp),%rax
12f3: 48 89 45 b0 mov %rax,-0x50(%rbp)
12f7: 49 8b 3d 42 22 00 00 mov 0x2242(%rip),%rdi # 3540 <__bss_start+0x40>
12fe: e8 81 02 00 00 callq 1584 <plt_wrapper_alloc_object_AllocSmall_intptr>
1303: 48 89 85 30 ff ff ff mov %rax,-0xd0(%rbp)
130a: 48 83 c0 10 add $0x10,%rax
130e: 48 8b 4d a8 mov -0x58(%rbp),%rcx
1312: 48 89 08 mov %rcx,(%rax)
1315: 48 8b 4d b0 mov -0x50(%rbp),%rcx
1319: 48 89 48 08 mov %rcx,0x8(%rax)
131d: 48 8b 85 68 ff ff ff mov -0x98(%rbp),%rax
1324: 48 89 45 b8 mov %rax,-0x48(%rbp)
1328: 48 8b 85 70 ff ff ff mov -0x90(%rbp),%rax
132f: 48 89 45 c0 mov %rax,-0x40(%rbp)
1333: 48 8b 85 78 ff ff ff mov -0x88(%rbp),%rax
133a: 48 89 45 c8 mov %rax,-0x38(%rbp)
133e: 49 8b 3d 03 22 00 00 mov 0x2203(%rip),%rdi # 3548 <__bss_start+0x48>
1345: e8 3a 02 00 00 callq 1584 <plt_wrapper_alloc_object_AllocSmall_intptr>
134a: 48 8b f0 mov %rax,%rsi
134d: 48 8b bd 30 ff ff ff mov -0xd0(%rbp),%rdi
1354: 48 8b c6 mov %rsi,%rax
1357: 48 83 c0 10 add $0x10,%rax
135b: 48 8b 4d b8 mov -0x48(%rbp),%rcx
135f: 48 89 08 mov %rcx,(%rax)
1362: 48 8b 4d c0 mov -0x40(%rbp),%rcx
1366: 48 89 48 08 mov %rcx,0x8(%rax)
136a: 48 8b 4d c8 mov -0x38(%rbp),%rcx
136e: 48 89 48 10 mov %rcx,0x10(%rax)
1372: e8 21 02 00 00 callq 1598 <plt_Generic_MainClass_VectorsLengthA_Generic_MainClass_VectorProperties_1_double_Generic_MainClass_VectorProperties_1_double>
1377: f2 0f 11 85 38 ff ff movsd %xmm0,-0xc8(%rbp)
137e: ff
; ...
; direct call to generic
13a7: 49 8b 05 a2 21 00 00 mov 0x21a2(%rip),%rax # 3550 <__bss_start+0x50>
13ae: 48 89 85 50 ff ff ff mov %rax,-0xb0(%rbp)
13b5: 48 8b 85 58 ff ff ff mov -0xa8(%rbp),%rax
13bc: 48 89 45 d0 mov %rax,-0x30(%rbp)
13c0: 48 8b 85 60 ff ff ff mov -0xa0(%rbp),%rax
13c7: 48 89 45 d8 mov %rax,-0x28(%rbp)
13cb: 48 8b 85 68 ff ff ff mov -0x98(%rbp),%rax
13d2: 48 89 45 e0 mov %rax,-0x20(%rbp)
13d6: 48 8b 85 70 ff ff ff mov -0x90(%rbp),%rax
13dd: 48 89 45 e8 mov %rax,-0x18(%rbp)
13e1: 48 8b 85 78 ff ff ff mov -0x88(%rbp),%rax
13e8: 48 89 45 f0 mov %rax,-0x10(%rbp)
13ec: 48 8b 45 e0 mov -0x20(%rbp),%rax
13f0: 48 89 04 24 mov %rax,(%rsp)
13f4: 48 8b 45 e8 mov -0x18(%rbp),%rax
13f8: 48 89 44 24 08 mov %rax,0x8(%rsp)
13fd: 48 8b 45 f0 mov -0x10(%rbp),%rax
1401: 48 89 44 24 10 mov %rax,0x10(%rsp)
1406: 48 8b 7d d0 mov -0x30(%rbp),%rdi
140a: 48 8b 75 d8 mov -0x28(%rbp),%rsi
140e: e8 1d 01 00 00 callq 1530 <Generic_MainClass_VectorsLengthB_Generic_MainClass_Vec2_Generic_MainClass_Vec3_Generic_MainClass_Vec2_Generic_MainClass_Vec3>
1413: f2 0f 11 85 48 ff ff movsd %xmm0,-0xb8(%rbp)
141a: ff
; ...
...
; ...
; Specialization of VectorsLengthB<Vec2,Vec3>
0000000000001530 <Generic_MainClass_VectorsLengthB_Generic_MainClass_Vec2_Generic_MainClass_Vec3_Generic_MainClass_Vec2_Generic_MainClass_Vec3>:
1530: 55 push %rbp
1531: 48 8b ec mov %rsp,%rbp
1534: 48 83 ec 20 sub $0x20,%rsp
1538: 48 89 7d f0 mov %rdi,-0x10(%rbp)
153c: 48 89 75 f8 mov %rsi,-0x8(%rbp)
1540: 48 8b fd mov %rbp,%rdi
1543: 48 83 c7 f0 add $0xfffffffffffffff0,%rdi
1547: e8 34 ff ff ff callq 1480 <Generic_MainClass_Vec2_get_Length>
154c: f2 0f 11 45 e8 movsd %xmm0,-0x18(%rbp)
1551: 48 8d 7d 10 lea 0x10(%rbp),%rdi
1555: e8 76 ff ff ff callq 14d0 <Generic_MainClass_Vec3_get_Length>
155a: f2 0f 10 c8 movsd %xmm0,%xmm1
155e: f2 0f 10 45 e8 movsd -0x18(%rbp),%xmm0
1563: f2 0f 58 c1 addsd %xmm1,%xmm0
1567: c9 leaveq
1568: c3 retq
; ...
...
; ... plt ...
No comments:
Post a Comment