Is callvirt faster than call ?

D

Doker

I've made some small examples in VB and C# thay were doing this:
private void Form1_Load(object sender, System.EventArgs e){

int b = 9966;

Doh (b); }

and that

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load

Dim b As Int32 = 9966

Doh(b)

End Sub

Public Sub Doh(ByRef a As Integer)

End Sub

i've compiled tham and decompiled using Salamander
(http://www.remotesoft.com/salamander/index.html)

My intention was to see how do pointer work in C# with regards to VB.net
byref.
What i've seen was a big difference that may cause big speed decrease in vb.
I just don't know why because reference are in practice safe way of
transfering variables' addresses.


look



.maxstack 2 //same
.locals (int32) //same

IL_0000: ldc.i4 9966 //same
IL_0005: stloc.0 //same
IL_0006: ldarg.0 //same
IL_0007: ldloca.s 0 //same
IL_0009: call instance void
WindowsApplication5.Form1::Doh(int32*)
IL_000e: ret

vs. (VB)

.maxstack 2 //same
.locals (int32) //same

IL_0000: nop //WHAT FOR!
IL_0001: ldc.i4 9966
IL_0006: stloc.0 //same
IL_0007: ldarg.0 //same
IL_0008: ldloca.s 0 //same
IL_000a: callvirt instance void
WindowsApplication4.Form1::Doh(int32&) // differs with virt and "&"
IL_000f: nop //WHAT FOR!
IL_0010: nop //WHAT FOR!
IL_0011: ret //same

So:
Is callvirt faster than call ?

why can't ref int be called using using call and int32* ? Whas it to
difficult, or is it faster?

What the hell are those NOOPS for? To make VB slower?

I'm shocked!

Can you explain it in any way?
 
A

Alejandro Lapeyre

I am not shure but, I think that in c# you have to call it Doh(&b);
Excuse me if I am wrong.

Best Regards,
Alejandro Lapeyre
 
D

Doker

nop.
but thats not the question.
the questions are what is the difference between pointers and ref.
whats is faster, for real (not what C++ programmers say)
why there are so many nops in VB.net code.
 
H

Helge Jensen

Doker said:
nop.
but thats not the question.

I can see that you are calling 2 different Form1.Doh's. I don't know
about VB, maybe "Sub"'s are virtual by default? that would explain the
virtual-call in the generated IL.

Virtual vs. non-virtual call-overhead is not related to the types of
arguments at all.

Virtual-calls cannot be cheaper than non-virtual calls but the compiler
and/or .NET-runtime may (JIT-)compile a virtual call to a non-virtual
under certain conditions, or even inline the code from the called function.
the questions are what is the difference between pointers and ref.
whats is faster, for real (not what C++ programmers say)
why there are so many nops in VB.net code.

You do realize that pointers are to memory and ref's are to objects?

Pointers in C# can be obtained using "fixed", which fixes the object in
memory so the garbage-collector cannot move it. That operation is
probably rather expensive, but if you do relative indexing the JIT may
be able to do something faster in loops when it is guaranteed that the
GC cannot move the array around? write a test...

In your specific example, I would guess the C#-compiler has better
optimization, since int is a struct-type and therefore on the stack it
can use a pointer instead of a ref, without fixing it fist.

Try something like this: (uncompiled code ahead :)

class Thing { public Thing Value; }
class A { public virtual f(ref Thing t) { t.Value = t; } }
class B: A { public override f(ref Thing t) { t.Value = null; } }
public class Test {
public static int Main(string[] args) {
Thing t = new Thing();
A a;
// Make sure compiler cannot see which .f is called:
if ( args.Length > 1 )
a = new A();
else
a = new B();
a.f(ref t);
// Make sure t.Value is used
// so compiler cannot optimize a.f(ref t) away
if ( t.Value == null )
return 0;
else
return 1;
}
}
 
D

Daniel O'Connell [C# MVP]

Doker said:
I've made some small examples in VB and C# thay were doing this:
private void Form1_Load(object sender, System.EventArgs e){

int b = 9966;

Doh (b); }
Could you provide the definition of Doh() for the C# code? That IL doesn't
look right at all...
 
M

Mattias Sjögren

Is callvirt faster than call ?

Most likely not.

why can't ref int be called using using call

It can, but C# often use callvirt for instance method calls even when
call would have worked, because callvirt will throw if called with a
null this reference, which is the behavior specified by the language.

What the hell are those NOOPS for? To make VB slower?

No, to make it debuggable. You should probably look at an optimized
release build instead.



Mattias
 
O

Olaf Baeyens

What the hell are those NOOPS for? To make VB slower?
NOP's are instructions that does nothing. You could regard them as space
filler.

NOP's are normally used to synchronize your next assembler instruction to be
on a memory boundary to speed up executing.
For example, if you have a 32 bits data bus, then adding NOP so that your
next assembler instruction starts at a 4 byte boundary, then it speeds up
loading the instruction in one pass or else the processor must first read
the lower part and then in a next phase read the upper part which would be a
2 pass instruction load, slowing down the processor instruction.

The problem this is IL and I know that IL gets translated to real assembler
by the CLR, so I have no idea if the NOP's will still be there or even if
they have meaning.
 
O

Olaf Baeyens

What the hell are those NOOPS for? To make VB slower?
No, to make it debuggable. You should probably look at an optimized
release build instead.
That could also be a reason.

A debug built is almost a one to on translation of every function.
A release built is a very optimize assembler instruction set and can change
the order of the instructions that are ordered in such a way that is
executes faster, but have almost no relationship with the original source
code, so very hard to put breakpoints.

For example, a loop is always slower since the processor has to jump back
and thus must flush the already preloaded instructions of the code after the
loop, it loses time to reload the previous code. So a release code could
expand the loop if the loop is small, lets say 2-4 loops max, and thus avoid
the jump back. But ofcourse this means that that there is no debug
information possible to put a breakpoint.
 

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