I offer not quite a standard survey on the .Net platform. Spoilers reveal the answers to the questions, but still I ask you first to answer the questionnaire yourself, then go and see the answers :)
When the static method is called, the JIT ...JIT compiles a call to a proxy method that makes an unconditional transition to the compiler necessary and replaces the address of the transition to the proxy with a new method body. This is done for several reasons.
Initially, when methods are compiled, all the call points of other methods indicate not a compiled body, but a piece of assembler code of fixed length and containing the same instructions for any method. As a matter of fact, only the address where jmp occurs changes. Before the method is compiled, the address points to the compiler of this method (therefore, the first call involves compilation). Further, when the compilation is complete, the argument of the jmp command changes from the address of the compiler to the address of the target, already compiled method. The advantages are obvious: proxy - contains the same instructions, the group of methods can be viewed as a table with two fields: Code and Address of the Transition on the one hand and not to change the addresses of the method call instruction - on the other.
What happens when casting to classType casting to base - nothing happens, casting to inherited - to start, the possibility of casting is checked and work with the object will follow the same virtual method table as before')
Type coercion is the syntactic sugar of a language that has almost nothing in common at the level of the structure of an object in memory. Since an object consists of the fields + SyncBlockIndex + MethodsTablePtr, where MethodsTablePtr is responsible for pointing the object type description, nothing happens when the pointer is placed in an object of another type (the object type does not change). Called additional check when casting up, because at the compilation stage it is not known in advance what is up, what types. Need to check. The check is performed by going to the table of methods and passing through the ParentClassMethodsTable pointer chain until either Object is encountered (then casting is not possible) or until a pointer is found that is equal to the one we are looking for. How the virtual method is called is well described here:
Wiki What happens when casting to an interface?In the type table, there is a link to the dictionary of interfaces and to check the possibility of casting it is necessary to bypass it all. According to the basic types do not go, because all of them are also present in the dictionary. If a match is found, the address of the table of virtual methods of the interface will be loaded into the register, and not the type of the object.
Since interfaces can appear in a type right in the middle of inheritance, both in one type and in another, for them a common scheme with virtual method tables will not work. Instead, in the virtual method table there is a link to the second table - the dictionary of interfaces. In essence, this is a list of references to the virtual method tables of each of them. When casting a type, the required table is searched for using the binary search method, since the search is performed according to the equality of the pointer to the required one (among the list we look for the presence of the pointer we need to the virtual methods table). If it is found, a pointer to this table is loaded into the register and then the method call goes through it (the table contains the addresses of the methods in the class. Therefore, for each interface implementation, the list of methods is present in the tables of all the classes that implement the interface, as well as all the descendants of the classes and interfaces)
What is the difference between Implicit and Explicit interfaces?Both are highlighted in the interface dictionary, but the Explicit methods are not in the class's virtual methods table, only in the interface dictionary.
Indeed, since the methods of implicit interfaces are part of the class inheritance hierarchy and can be called separately from the interface type, they must be present in the class's virtual methods table. However, there are also Explicit implementations when methods are separated from the class. Such methods are not present in the class's virtual methods table. However, for both cases we have the right to cast to the interface and work through it. This means that they will be present in the map of interfaces of both types, and with all the basic types - interfaces.
Streams in .Netare MS Windows platform threads, because the price of switching between threads is equal to the total price for Windows
Here, in general, without comment. GC cannot interfere with the overall process of servicing a multi-threaded code. .Net applications work like regular Windows applications.
Generic typesJIT creates unrelated classes for each type parameter.Since the JIT cannot know anything about the application logic, it cannot build the argument that
IEnumerable<object> a = new List<int>()
should somehow work. because implementation for each specific set of generic arguments is compiled into a separate code.
How instance methods are called - thisthis is the first parameter of the method that is not shown for the purposes of syntactic sugar.
If you imagine a method call, then at the processor level it will occur by fastcall notation: the first two parameters of the method go to registers, and the rest to the stack. if we don’t pass on anything in addition, we’ll get that inside the method we will not have a clue what object we were called for. To correct the situation, we always pass this as the first parameter, and in the programming language (for example, C #) we simply do not show it by entering the local variable this, which is always present, regardless of the programmer’s wishes. This is actually the first parameter of the method.
Value and Reference types. What is the difference?Value types are on the stack and on the heap, and Reference are only on the heap. They differ in that value is passed by value, and Reference by reference.
A huge percentage of developers at the interviews say the first answer. And in fact, it does not suit them, because if the Value type is a class field, its value cannot be in the working stack, because when exiting the method that created the frame, it containing it would cease to be valid with the correct data. The class field (even if it is the Value type) is always on the heap. The difference between Value and Ref types is that when copying from Ref types, the reference is copied, and in Value, the entire structure is copied. The second difference: the non-Value Value types lack the MethodsTable field and SyncBlockIndex.
Where are the static variables?They lie in the internal arrays and the reference goes to the link to the array + index
This is simply sacred knowledge. Just done and all.
How are virtual methods called?JIT creates a virtual method table for a type, through which the call goes with a pre-calculated indexIn the case of inheritance and the presence of virtual methods, it turns out that: from class to class, they can only be added in stock, without going anywhere. and in each subsequent class all methods of all basic will be guaranteed to be present. With one difference - at inheritance the method can be redefined. Therefore, when constructing a table of methods for a class, the methods of the base class must be located at the same indices as in the table of the base class. If the method is not overridden, then the address of the method body in the table will coincide with the address of this method in the table of the base class. If the method is overridden, the value will be different. After all the methods of the base classes will be the methods of the current class. And the call itself will occur like this:
- Load the address of the table of virt methods.
- Move to the beginning of the list of methods
- take the address of the method by index (for example) 1
- Call it.
Moreover, since the inheritance at this place will always contain the ToString () method, then even by overriding it in the heirs, the ToString () method will be called, but not of the base class, but of the heir.
