are all subclasses virtual (use vtables?)

Z

ZenRhapsody

Are ALL methods in subclasses implemented in C# with vtables and virtual
functions?

I know I could test this myself, but I'm still using Express edition of 2.0,
so I cannot view the optimized disassembly.

I know that you must use vtables for all virtual functions (and interfaces),
but if there are non-virtual functions, does the compiler use a vtable for
everything anyway?

For example, if I have a base class like this:

class baseClass
{ protected variables list......
public void A(){}
public void B(){}
public abstract void C(){}
}
class sub1 : baseClass
{ public override void C(){}
public void D(){}
}

class sub2 : baseClass
{ public override void C(){}
public void E(){}
}

Will the compiler create a full vtable for all of sub2's methods (including
inherited ones)? Or, will it compile in direct addresses (and allow inline
compile for short methods) for functions A(), B(), E() ? (and it could
possibly do C() also). IMO, the only real vtable required would be if you
access sub2 through a variable of type baseClass.

I'm just trying to fully understand this compiler - any insight is
appreciated.
 
H

Helge Jensen

ZenRhapsody said:
Are ALL methods in subclasses implemented in C# with vtables and virtual
functions?

Methods are not virtual by default in C#, so my guess would be no.
I know I could test this myself, but I'm still using Express edition of 2.0,
so I cannot view the optimized disassembly.

I was under the impression that the express edition of the compiler is
exactly the same as the non-express one.
I'm just trying to fully understand this compiler - any insight is
appreciated.

May I ask why this is of such intense interest to you? if you are
thinking about performance you will probably be much better off using a
profiler.

Don't draw too many conclusions based on the compiler output, the JIT
can change the playing field and your hard work analyzing will, at best,
be wasted and at worst misguiding.
 
Z

ZenRhapsody

Thx for the response.

Since I have the Express edition, I cannot view the disassembly in debug
mode. In 1.0 Prefessional (only have that at work, and not a lot of time to
experiment with this issue), I can view the actually assembly code after it
has been JIT'd by attaching the debugger to a running EXE. This has been
educational, for example, for seeing how the JIT compiler inline compiles
functions, how it optimizes long switch statements, and how it optimizes
local variables into register variables.

My interest now is purely academic. I am always interested in performance,
but realize that the additional indirect address call of a virtual function
is usally trivial compared to the function's actual calculation time.
However, with short functions that could be in-lined by the compiler, it
would make a difference (assuming, of course, the function is called enough
times to be significant).
 
J

Jon Skeet [C# MVP]

ZenRhapsody said:
Since I have the Express edition, I cannot view the disassembly in debug
mode. In 1.0 Prefessional (only have that at work, and not a lot of time to
experiment with this issue), I can view the actually assembly code after it
has been JIT'd by attaching the debugger to a running EXE. This has been
educational, for example, for seeing how the JIT compiler inline compiles
functions, how it optimizes long switch statements, and how it optimizes
local variables into register variables.

My interest now is purely academic. I am always interested in performance,
but realize that the additional indirect address call of a virtual function
is usally trivial compared to the function's actual calculation time.
However, with short functions that could be in-lined by the compiler, it
would make a difference (assuming, of course, the function is called enough
times to be significant).

Do you have cordbg installed? You can use that to debug through the
optimised code to find out what's going on. However, you should be
aware that inlining is done by the JIT, not the compiler.

Jon
 
W

Willy Denoyette [MVP]

The only way to debug at that level without interfering with the JIT (which
will turn of inlining whenever a managed debugger is attached) is by using
an unmanaged debugger like cdb or windbg. These debuggers are freely
downloadable from
http://www.microsoft.com/whdc/devtools/debugging/installx86.mspx

Willy.

| Thx for the response.
|
| Since I have the Express edition, I cannot view the disassembly in debug
| mode. In 1.0 Prefessional (only have that at work, and not a lot of time
to
| experiment with this issue), I can view the actually assembly code after
it
| has been JIT'd by attaching the debugger to a running EXE. This has been
| educational, for example, for seeing how the JIT compiler inline compiles
| functions, how it optimizes long switch statements, and how it optimizes
| local variables into register variables.
|
| My interest now is purely academic. I am always interested in
performance,
| but realize that the additional indirect address call of a virtual
function
| is usally trivial compared to the function's actual calculation time.
| However, with short functions that could be in-lined by the compiler, it
| would make a difference (assuming, of course, the function is called
enough
| times to be significant).
|
|
| | > ZenRhapsody wrote:
| >
| >> Are ALL methods in subclasses implemented in C# with vtables and
virtual
| >> functions?
| >
| > Methods are not virtual by default in C#, so my guess would be no.
| >
| >> I know I could test this myself, but I'm still using Express edition of
| >> 2.0,
| >> so I cannot view the optimized disassembly.
| >
| > I was under the impression that the express edition of the compiler is
| > exactly the same as the non-express one.
| >
| >> I'm just trying to fully understand this compiler - any insight is
| >> appreciated.
| >
| > May I ask why this is of such intense interest to you? if you are
| > thinking about performance you will probably be much better off using a
| > profiler.
| >
| > Don't draw too many conclusions based on the compiler output, the JIT
| > can change the playing field and your hard work analyzing will, at best,
| > be wasted and at worst misguiding.
| >
| > --
| > Helge Jensen
| > mailto:[email protected]
| > sip:[email protected]
| > -=> Sebastian cover-music: http://ungdomshus.nu <=-
|
|
 
J

Jon Skeet [C# MVP]

Willy Denoyette said:
The only way to debug at that level without interfering with the JIT (which
will turn of inlining whenever a managed debugger is attached) is by using
an unmanaged debugger like cdb or windbg. These debuggers are freely
downloadable from
http://www.microsoft.com/whdc/devtools/debugging/installx86.mspx

cordbg allows you to keep JIT optimizations, including inlining - type
m JitOptimizations 1
to set this.

For example, here's some sample C# code:
using System;

class Program
{
static void Main()
{
for (int i=0; i < 10; i++)
{
Console.WriteLine (Square(i));
}
}

static int Square (int x)
{
return x*x;
}
}


Here's the disassembly of Main with optimization off:
[0000] push ebp
[0001] mov ebp,esp
[0003] push eax
[0004] push edi
[0005] push esi
[0006] xor esi,esi
*[0008] xor esi,esi
[000a] nop
[000b] jmp 00000015
[000d] mov ecx,esi
[000f] call dword ptr ds:[00A150E4h]
[0015] mov edi,eax
[0017] mov ecx,edi
[0019] call dword ptr ds:[79C56664h]
[001f] inc esi
[0020] cmp esi,0Ah
[0023] jl FFFFFFEA
[0025] nop
[0026] pop esi
[0027] pop edi
[0028] mov esp,ebp
[002a] pop ebp
[002b] ret


And here it is with optimization on:

(cordbg) dis 20
[0000] push esi
*[0001] xor esi,esi
[0003] mov eax,esi
[0005] imul eax,esi
[0008] mov edx,eax
[000a] mov ecx,dword ptr ds:[01C42030h]
[0010] mov eax,dword ptr [ecx]
[0012] call dword ptr [eax+000000BCh]
[0018] inc esi
[0019] cmp esi,0Ah
[001c] jl FFFFFFE7
[001e] pop esi
[001f] ret

Note the inlining of the multiplication in the second version.
 
W

Willy Denoyette [MVP]

| > The only way to debug at that level without interfering with the JIT
(which
| > will turn of inlining whenever a managed debugger is attached) is by
using
| > an unmanaged debugger like cdb or windbg. These debuggers are freely
| > downloadable from
| > http://www.microsoft.com/whdc/devtools/debugging/installx86.mspx
|
| cordbg allows you to keep JIT optimizations, including inlining - type
| m JitOptimizations 1
| to set this.
|
| For example, here's some sample C# code:
| using System;
|
| class Program
| {
| static void Main()
| {
| for (int i=0; i < 10; i++)
| {
| Console.WriteLine (Square(i));
| }
| }
|
| static int Square (int x)
| {
| return x*x;
| }
| }
|
|
| Here's the disassembly of Main with optimization off:
| [0000] push ebp
| [0001] mov ebp,esp
| [0003] push eax
| [0004] push edi
| [0005] push esi
| [0006] xor esi,esi
| *[0008] xor esi,esi
| [000a] nop
| [000b] jmp 00000015
| [000d] mov ecx,esi
| [000f] call dword ptr ds:[00A150E4h]
| [0015] mov edi,eax
| [0017] mov ecx,edi
| [0019] call dword ptr ds:[79C56664h]
| [001f] inc esi
| [0020] cmp esi,0Ah
| [0023] jl FFFFFFEA
| [0025] nop
| [0026] pop esi
| [0027] pop edi
| [0028] mov esp,ebp
| [002a] pop ebp
| [002b] ret
|
|
| And here it is with optimization on:
|
| (cordbg) dis 20
| [0000] push esi
| *[0001] xor esi,esi
| [0003] mov eax,esi
| [0005] imul eax,esi
| [0008] mov edx,eax
| [000a] mov ecx,dword ptr ds:[01C42030h]
| [0010] mov eax,dword ptr [ecx]
| [0012] call dword ptr [eax+000000BCh]
| [0018] inc esi
| [0019] cmp esi,0Ah
| [001c] jl FFFFFFE7
| [001e] pop esi
| [001f] ret
|
| Note the inlining of the multiplication in the second version.
|

You are right that the call to Square is inlined, but that's normal, the CLR
tests the "IsDebugger" atached flag at the first hit of a (managed)
breakpoint in your code, that is after Main is JIT compiled, so, after the
inlining has been done (in optimized build).
subsequent JIT compiles are not guaranteed to be optimized, unless you have
set the "JitOptimizations" mode flag, but the result is not pretty, it's
quite hard to debug with this flag set and the disassembly output cannot be
trusted.

Here is the VS debugger output, which includes the actual address and code
bytes, note that you ran this on V1.1, so I've included the V2. code here
[1] so you can watch the differences between v1 and V2, which may be quite
interesting.

02D1005F 33 F6 xor esi,esi
02D10061 8B D6 mov edx,esi
02D10063 0F AF D6 imul edx,esi
02D10066 8B 0D 30 20 B4 01 mov ecx,dword ptr ds:[1B42030h]
02D1006C 8B 01 mov eax,dword ptr [ecx]
02D1006E FF 90 BC 00 00 00 call dword ptr [eax+0BCh]
02D10074 46 inc esi
02D10075 83 FE 0A cmp esi,0Ah
02D10078 7C E7 jl 02D10061
02D1007A 5E pop esi
02D1007B C3 ret

Here is the same but running under V2.

00CB0077 33 F6 xor esi,esi
00CB0079 EB 2D jmp 00CB00A8
00CB007B 8B C6 mov eax,esi
00CB007D 0F AF C6 imul eax,esi
00CB0080 8B F8 mov edi,eax
00CB0082 83 3D 84 10 27 02 00 cmp dword ptr ds:[2271084h],0
00CB0089 75 0A jne 00CB0095
00CB008B B9 01 00 00 00 mov ecx,1
00CB0090 E8 77 D7 69 78 call 7934D80C
00CB0095 8B 0D 84 10 27 02 mov ecx,dword ptr ds:[2271084h]
00CB009B 8B D7 mov edx,edi
00CB009D 8B 01 mov eax,dword ptr [ecx]
00CB009F FF 90 BC 00 00 00 call dword ptr [eax+0BCh]
00CB00A5 83 C6 01 add esi,1
00CB00A8 83 FE 0A cmp esi,0Ah
00CB00AB 0F 9C C0 setl al
00CB00AE 0F B6 C0 movzx eax,al
00CB00B1 85 C0 test eax,eax
00CB00B3 75 C6 jne 00CB007B
00CB00B5 5E pop esi
00CB00B6 5F pop edi
00CB00B7 C3 ret

Noticed the main differences?

Willy.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top