I am currently trying to teach myself MSIL by playing about with translating C# into MSIL commands.
Where I believe I have stumbled, however, is making the assumption that the "evaluation stack" on to which values are pushed and then popped and stored in the local variable list is just another way of referring to the stack which is assigned to a thread at runtime.
Reading Eric Lippert's answer on the purpose of the evaluation stack makes it clear that they are not the same thing:
I assume you mean the evaluation stack of the MSIL language, and not the actual per-thread stack at runtime.
My question is: what is the precise difference between these two stacks? And how are they related?
No, there's just one stack. There are some languages that distinguish between an eval stack and a return stack. The Forth language jumps to mind as the primary example, fairly influential in the early days of micro-processors. And exceedingly stack-based down to the language syntax, pretty unfriendly to program. Easy to implement however, it didn't take more than 2 kilobytes of code. Roughly what your Linq query comprehension takes :)
But no, MSIL is not one of them. The VM (virtual machine) defines just one stack for a method. It is entirely type-agnostic, it can store an int or a double or an object reference or a method return address with equal aplomb. Pushing and popping a value to/from the stack is just a logical operation, not modeling the actual data transfer at all.
It is the job of the jitter to turn that into machine code that deals with real data. Not actually that hard, a processor has a stack as well, just like the VM. And it can also store all kinds of different data types, but without being able to ignore the data size of course. And above all, eliminating that kind of pushing and popping and take advantage of the registry bank of the processor, entirely not modeled in MSIL. Not a coincidence either, different processors have very different registry bank capabilities. Very important to make code fast.
And yes, every thread has its own stack. Absolutely essential, the stack stores method return addresses and threads can execute different code. Both in MSIL and in machine code.
Basically, the evaluation stack of CIL is what you're manipulating using CIL instructions, the actual per-thread runtime stack is what you're manipulating by machine code (assembly) instructions.
The CIL stack doesn't really exist at runtime, because it's part of the virtual machine defined by the CLI specification.
What the CLR JIT compiler does is to take CIL code that uses the CIL stack and transforms it into machine code (specific to your architecture, like x86 or ARM) that uses the actual runtime stack.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With