If you created a runtime virtual machine these days, I wouldn't use stacks or registers... address virtual/virtualized memory directly and let the CPU &| compiler || LLVM sort out register placement... registers are basically another layer in the storage hierarchy, from registers/L0 file all the way down to tape, or eww, hard copy.
Why not go all the way with this idea and pretend everything is a hard copy? Your program's statements would all be printing the result of something into paper, or scanning that paper. And then you just let the compiler and CPU figure out which pieces of paper can be put into registers.
The answer is that this is too cumbersome and hard to deal with. So is memory, in a smaller way - when things are in memory they can be affected by other threads, the outputs of different instructions can overlap, etc etc.