mirror of
https://github.com/status-im/EIPs.git
synced 2025-02-23 20:28:21 +00:00
Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing
109 lines
3.4 KiB
Markdown
109 lines
3.4 KiB
Markdown
---
|
|
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/).** |