0

I was researching call vs callvirt opcodes with all of the gotchas along the way.

You can read the description online, but when you encounter this

The callvirt instruction calls a late-bound method on an object. That is, the method is chosen based on the runtime type of obj rather than the compile-time class visible in the method pointer.

you know it's not the full story since callvirt is emitted for virtually everything by the C# compiler and that the implementation details make up for all the difference.

I think what the callvirt internally does is check the metadata token from the method table for whether it's virtual or not and if not virtual, doesn't really bother with the object's vtables. But how do I know?

Can somebody explain how the runtime code is structured with regard to handling of the opcodes (I guess the JITter) so I can more easily browse the source code and understand the implementation details.

6
  • Do you really care about how it is implemented? You don't need to know this unless you are building your own CLR implementation. In any case, there are multiple implementations of the CLR out there. Please make your question more focused to target one particular implementation. Commented Mar 25, 2024 at 3:31
  • @Sweeper, enough to post on stackoverflow, I guess. Commented Mar 25, 2024 at 6:01
  • 1
    If you want to dig into the guts of the JIT for this, probably start at Guarded Devirtualization. I think that contains enough hints and rabbit holes to go down. Commented Mar 25, 2024 at 6:18
  • @Damien_The_Unbeliever thanks. Closer to what I want, although callvirt for a non-virtual instance method shouldn't fall under "Guarded Devirtualization" one would think. Commented Mar 25, 2024 at 7:32
  • @tinmanjk - yes but there are some mentions in the intro to the non-guarded cases and it also makes reference to stub dispatch which is also important to know because vtables aren't the only option. I.e. it's complicated and you need to understand how many of the moving parts work together to get an idea of how it will work. Commented Mar 25, 2024 at 9:02

2 Answers 2

0

We can handle this in 2-3 different ways... 1)OpCodes Class: The OpCodes class in the System.Reflection.Emit namespace provides field representations of the Microsoft Intermediate Language (MSIL) instructions for emission by the ILGenerator class members. This class is used when you want to emit IL instructions dynamically in your .NET code.

  1. Use CodeDOM to build and compile a code tree. Build an Expression tree and compile it. Generate code one IL instruction after another. Adding a New Bytecode Instruction to the CLR: If you want to add a new bytecode instruction to the CLR, you would need to make changes in opcode.def
Sign up to request clarification or add additional context in comments.

2 Comments

My question is focused more to what happens AFTER the IL has been generated (by the compiler or by us). How is the opcode callvirt handled by CLR's logic to sometimes use vtables/sometimes use just use direct address.
Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.
0
public class Base {
    public virtual void A(){}
    public void B(){}
    
    public void Test(){
        this.A();
        this.B();
    }
}
public class Derived : Base{
    public override void A(){}
}

If the compiler can't know which method will be called at compile time, the runtime uses callvirt to find the method implementation based on the type of the variable. This is true for any virtual method, or any method called via an interface.

The runtime may optimise these calls and de-virtualise them where appropriate.

it's not the full story since callvirt is emitted for virtually everything by the C# compiler

Only because so many methods are virtual or accessed via an interface.

1 Comment

not true, it will be all instance methods which are not proven by the compiler that the instance is not null. I am looking at the portion of the runtime code that handles the callvirt JITting.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.