I reply here to some of the detailed points made by @AlexeyAkhunov at Proposal to remove EIP-2315 (simple subroutines) from Berlin · Issue #263 · ethereum/pm · GitHub
I think from what @lightclient posted above (great work, BTW), it is clear that there were 2 points of contention with regards to the properties of the subroutines:
- Whether the
JUMPSUB
uses jump location from the stack, or from the immediate as a part of the opcode. Eventually the stack solution was used, and I agree with Chris (after my own analysis) that this effectively made this variant of subroutines non beneficial for one of initially stated goals - ease of static analysis due to lack of dynamic jumps. It actually makes that stated goal harder to achieve because to do so, JUMPSUB
opcode will need to be deprecated as well as JUMP
and JUMPI
.
Ease of static analysis was never a stated goal of EIP-2315. The goal was to make “almost the smallest change that provides native subroutines without breaking backwards compatibility.”
More on deprecation below.
- Whether the jumping from the middle of one subroutine into the middle of another subroutine is allowed. Eventually this was allowed, I believe to simplify the implementation and therefore expedite the acceptance of EIP. I believe (after my own analysis) that this decision has unfortunately mostly eroded another stated benefit of the subroutines - strict “first in/first out” behaviour of subroutines calling each other (as we are used as programmers). As a result, simple emulation of the implemented behaviour by using combination of
PUSH
and JUMP
opcodes seems to suffice.
Again, this was never a stated benefit of EIP-2315.
EIP-615 imposed syntax on the bytecode to enforce safety.
EIP-2315 is pure mechanism – the core mechanism of EIP-615.
(I don’t think “jumping in and out” is the real issue anyway. It’s whether the stack is always aligned at the JUMPs, and the JUMPSUBs and RETURNSUBs balance.)
There were other observations made after my analysis:
- The claim (now apparently retracted) by the EIP author that subroutines are present in every modern virtual machine
My claim was, “These are provided in some form by most all physical and virtual machines going back at least 50 years.” I stand by it, though “some form”, and “most all” leaves room for disagreement.
I chose a simple form for EIP-2315 – I state that, “Our design is modeled on the original Forth two-stack machine of 1970. The data stack is supplemented with a return stack to provide simple support for subroutines, as specified below.”
There are of course other models, both more simple and more complex. These include the JVM method invocation and Wasm function table models.
EIP-2315 is also compatible with Nick Johnson’s EIP-3337: Frame pointer support for memory load and store operations. Together they can be used to provide a richer model of subroutine more similar to EIP-615 and to Vax, Intel, and other CPUs.
Much of the rest of your critique seems to be details of your disagreement as to what should count as a subroutine.
- … I find the argument for still using subroutines in the current EIP-2315 form (without cross-jump restriction) as a safety feature, much weaker and perhaps non-existent.
Again, such safety was not a goal or a promise.
The only safety directly provided by EIP-2315 is that it is impossible to overwrite the return address for a subroutine call.
Future EIPs might impose stricter requirements, but by now I do not think that deprecating opcodes is an option – too many years have passed, and backwards-compatibility is too important.
At best we can restrict the JUMP* opcodes to constant arguments or some form of restricted arguments, such as loading them from a data table. (per EIP-2327: BEGINDATA opcode)
- Reference implementation of the currently proposed form of this EIP was done in go-ethererum. After the review of the implementation, I concluded that it does not incur extra performance overhead on other opcodes. However, in evmone implementation, EIP-2315 seems to be introducing overhead to all the execution …
… this issue has not been flagged until the evmone implementation was benchmarked.
I have not seen a full report of this testing. My impression was that the performance hit was small, that some of it was just the increased code size of adding any new opcodes at all, and that work was still underway to see whether it could be reduced. It’s unfortunate that the evmone implementation was so delayed
I don’t know whether a slight performance hit in one implementation is a showstopper for this proposal.