Reserve register 0 for return and throw values
Summary
Method calls and throwing values uses different registers. Even when using a proper register allocator, different occurrences may use different registers. This complicates some parts of the VM, without introducing any benefits.
To solve this, for every execution context we should reserve register 0 for return and throw values. Since we can never have a successful return and throw at the same time, we can use the same register for both.
Implementation
Instructions used for running blocks should be modified to not take a target register. The compiler in turn has to be adjusted so that for calls and throws it also uses register 0 as the return register.
The Return instruction must be modified so that it just always write its value to register 0 of the parent context. The Throw instruction must be modified so that it doesn't consult catch tables to determine what register to write to, instead always writing to register 0. Catch tables in turn must be modified so they no longer store the register to write to.
All of this will make it (hopefully) also easier to write a JIT, as we can always use the same real register (e.g. EAX).