--- eip: 2315 title: Simple Subroutines for the EVM status: Draft type: Standards Track category: Core author: Greg Colvin (greg@colvin.org) discussions-to: https://ethereum-magicians.org/t/eip-2315-simple-subroutines-for-the-evm/3941 created: 2019-10-17 --- ## Abstract This proposal introduces two opcodes to support subroutines: `JUMPSUB` and `RETURNSUB`. ## Motivation The EVM does not provide subroutines as a primitive. Instead, calls must be synthesized by fetching and pushing the current program counter on the data stack and jumping to the subroutine address; returns must be synthesized by getting the return address to the top of stack and jumping back to it. ## Specification ##### `JUMPSUB` Jumps to the address on top of the stack, which must be the offset of a `JUMPDEST`. ##### `RETURNSUB` Returns to the most recently executed `JUMPSUB` and advances to the following instruction. A program may `JUMPSUB` at most 1023 times without an intervening `RETURNSUB`. A program which executes `RETURNSUB` without no prior `BEGINSUB` will `STOP`. ## Rationale This is the smallest possible change that provides native subroutines without breaking backwards compatibility. ## Backwards Compatibility These changes do not affect the semantics of existing EVM code. ## Test Cases ``` offset step op stack 0 0 PUSH1 3 [] 1 1 JUMPSUB [3] 2 4 STOP [] 3 2 JUMPDEST [] 4 3 RETURNSUB [] ``` This code should terminate after 4 steps with an empty stack. ``` offset step op stack 0 0 PUSH1 2 [] 1 1 JUMPSUB [2] 2 2 JUMPDEST [] 3 3 RETURNSUB [] ``` This code should terminate after 4 steps with an empty stack. ``` offset step op stack 0 0 PUSH1 2 [] 1 1 JUMPSUB [3] 2 8 STOP [] 3 2 JUMPDEST [] 4 3 PUSH1 7 [] 5 4 JUMPSUB [7] 6 7 RETURNSUB [] 7 5 JUMPDEST [] 8 6 RETURNSUB [] ``` This code should terminate after 8 steps with an empty stack. ## Implementations No clients have implemented this proposal as of yet. The new operators proposed here are implemented by the following pseudocode, which in eight lines adds a return stack and cases for `JUMPSUB` and `RETURNSUB` to a simple loop-and-switch interpreter. ``` bytecode[code_size] data_stack[1024] return_stack[1024] push(return_stack, code_size) PC = 0 while PC < code_size { opcode = bytecode[PC] switch opcode { ... case JUMPSUB: push(return_stack, PC) PC = pop(data_stack) continue case RETURNSUB: PC = pop(return_stack) } ++PC } ``` Execution of EVM bytecode begins with one value on the return stackā€”the size of the bytecode. The virtual byte of 0 at this offset is the EVM `STOP` opcode, so executing a `RETURNSUB` with no prior `JUMPSUB` executes a `STOP`. A `STOP` or `RETURN` ends the execution of the subroutine and the program. ### Costs and Codes We suggest the cost of `JUMPSUB` should be _low_, and `RETURNSUB` should be _verylow_. Measurement will tell. We suggest the following opcodes: ``` 0xb3 JUMPSUB 0xb7 RETURNSUB ``` ## Security Considerations Program flow analysis frameworks will need to be updated to allow for a new type of branch -`JUMPSUB` - and new type of branching - `RETURNSUB` - which will cause a jump to a destination which is a `JUMPSUB`, not a `JUMPDEST`. **Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).**