Question

Quoted from CLR via C#, it reads to me as if call would search for the method that is defined by a base type at runtime via CLR.

Then call IL instruction is used to call an instance or virtual method, you must specify a variable that refers to an object. The type of the variable itself indicates which type defines the method that the CLR should call. If the variable's type doesn't define the method, base types are checked for a matching method.

and

When calling a non-virtual instance method, JIT locates the type object that corresponds to the type of the variable being used to make the call. If the type didn't defined the method being called, JIT walks down the class hierarchy toward Object looking for this method. It can do this because each type object has a field in it that refers to its base type. Then, JIT locates the entry in the type object's method table that refers to the method being called.

However, based on the following example it seems the method inheritance is checked on compile time:

class A
{
    public void Foo() {}
}
class B : A {}
void Main()
{
    new B().Foo();
}
IL_0000:  newobj      UserQuery+B..ctor
IL_0005:  call        UserQuery+A.Foo // Not B.Foo, resolved by C# complier.

Am I correct?

Even if I do this:

void Main()
{
    B x = new B();
    x.Foo();
}
IL_0000:  newobj      UserQuery+B..ctor
IL_0005:  stloc.0     // x
IL_0006:  ldloc.0     // x
IL_0007:  callvirt    UserQuery+A.Foo // Not B.Foo, resolved by C# complier.

Update:

Now I understand that the resolution is static.

And I believe that the variable type that the JIT needs is actually the class specified by the metadata token.

Duplicate Alert

Actually it is a duplicate to Is Richter mistaken when describing the internals of a non-virtual method call?

Glad that there is another person who had the same question as me.

Was it helpful?

Solution

The quote speaks of the type of the variable, not of the type of the object instance the variable refers to. The variable type is statically known so all decisions are static.

The C# compiler resolves the exact method to call and encodes it into the IL. If the referenced assemblies do not change, the JIT does not have to do any method resolution by itself. The C# compiler does that because it wants to apply C# semantics, not CLR semantics.

To answer your edited-in questions:

  1. The JIT cannot look at any object reference because it needs to decide statically. It looks at the type that the element on the stack has, wherever that element came from. In verifiable code this is unambiguous. The variable type does not influence method binding though (IOW your question 1 is irrelevant).
  2. Yes, a method is referenced by assembly+type+method name and signature incl. return type. Very precise.

OTHER TIPS

Richter described jitter behavior. A compiler doesn't have an obligation to rely on it. The C# compiler certainly may make the jitter's job easier if it has enough type info available to reliably specify the base class method. And it does so.

The C# compiler in fact must do this to implement the base keyword. A base.Foo() call must use the base class if the Foo() method is virtual. There's no reliable way for the jitter to figure this out, all it has available is the method table for the derived class. But a Foo() override replaces the method address of the Foo() method in the base class. Notably a problem with the dynamic keyword.

Indeed, non virtual methods are resolved at compile time because you are sure about which method will be called. The same apply for static method.

On the contrary, virtual method can't be resolve until runtime

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top