My limited understanding of the stack/heap is that reference types are put onto the heap (dynamically allocated), and value types are put on the stack.
Theoretically (as in a theoretical machine, compiler, programming language), is the stack a necessity? Couldn't all memory be placed onto the heap?
In theory, you could do that. In practice, it would be a huge performance killer.
In "Hackers", Steven Levy tells the tale. At MIT, decades ago, before hardware stacks, writing a "decimal print" routine in under 50 instructions was the Holy Grail of hacking. Someone finally got there. Not too long after that, a new machine showed up, with a similar instruction set, except that it included a new instruction, PUSHJ, Push Return Address and Jump. PUSHJ pushed the return address onto a stack, instead of storing it at an absolute memory location (or in a register: same same - you have to store the register SOMEWHERE if you need to call something else). With PUSHJ, the decimal print could be written in 10 instructions.
Modern RISC theory eschews stack instructions in favor of registers, and forces programmers (or, more likely, compilers) to implement PUSHJ in software on every call. This is a performance hit, any way you cut it, because you WILL pay the added cost of manipulating the stack pointer in software (instruction fetches, register juggles, register increment/decrement).