Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calling methods on value types

Stop me if I make a mistake here.

If I understand correctly, when I call a method on an instance of a class, the JIT compiler locates the type object corresponding to the type of the instance and then locates a reference therein to the actual method code.

My question is how does this work for value types? I was under the impression that value types did not have a type object pointer like reference types do. If this is the case, how does the CLR manage to navigate to the method code when one is called?

like image 984
Levi Botelho Avatar asked Aug 06 '13 08:08

Levi Botelho


People also ask

What are call methods?

Method Calls A method is a routine that applies to a particular class of objects. Once an object is declared, you can refer to it by its identifier when calling methods. The following example calls the SetActive method on the Find dialog box: Find.SetActive ()

What is the difference between value type and reference type?

There are two kinds of types in Visual Basic: reference types and value types. Variables of reference types store references to their data (objects), while variables of value types directly contain their data.

What is the difference between value type and reference type in C#?

A Value Type holds the data within its own memory allocation and a Reference Type contains a pointer to another memory location that holds the real data. Reference Type variables are stored in the heap while Value Type variables are stored in the stack.


1 Answers

Consider an example, suppose we have the following structure:

public struct Test
{
    public void TestMethod()
    {            
    }
}

Here's IL code for it:

.class public sequential ansi sealed beforefieldinit ConsoleApplication.Test
    extends [mscorlib]System.ValueType
{
    .pack 0
    .size 1

    .method public hidebysig 
        instance void TestMethod () cil managed 
    {
        // Method begins at RVA 0x21dc
        // Code size 1 (0x1)
        .maxstack 8

        IL_0000: ret
    } // end of method Test::TestMethod

}

Ok, now because the C# compiler statically knows the type of Test, it can do overload resolution and find the exact TestMethod being called. Then it emits MSIL to push the arguments onto the MSIL virtual stack, it expects a parameter of type pointer to Test, which the compiler handles without boxing and issues a call instruction containing a metadata reference to that particular method.

.locals init (
        [0] valuetype ConsoleApplication.Test test
    )

IL_0000: ldloca.s test
IL_0002: initobj ConsoleApplication.Test
IL_0008: ldloca.s test
IL_000a: call instance void ConsoleApplication.Test::TestMethod()

For ToString and GetHashCode the compiler uses the Constrained OpCode, because these methods can be overloaded.

IL_0002: initobj ConsoleApplication.Test
IL_0008: ldloca.s test
IL_000a: constrained. ConsoleApplication.Test
IL_0010: callvirt instance int32 [mscorlib]System.Object::GetHashCode()

The constrained opcode allows IL compilers to make a call to a virtual function in a uniform way independent of whether ptr is a value type or a reference type. Using the constrained prefix also avoids potential versioning problems with value types. If the constrained prefix is not used, different IL must be emitted depending on whether or not a value type overrides a method of System.Object. For example, if a value type V overrides the Object.ToString() method, a call V.ToString() instruction is emitted; if it does not, a box instruction and a callvirt Object.ToString() instruction are emitted. A versioning problem can arise in the former case if the override is later removed, and in the latter case if an override is later added.

For the GetType method requires boxing because it's non-virtual and defined in the Object type.

IL_0002: initobj ConsoleApplication.Test
IL_0008: ldloc.0
IL_0009: box ConsoleApplication.Test
IL_000e: call instance class [mscorlib]System.Type [mscorlib]System.Object::GetType()
like image 135
Vyacheslav Volkov Avatar answered Oct 26 '22 10:10

Vyacheslav Volkov