Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

remove appendix #3316

Merged
merged 2 commits into from
Mar 3, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 2 additions & 75 deletions EIPS/eip-2315.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,13 @@ This proposal introduces three opcodes to support subroutines: `BEGINSUB`, `JUMP

## Motivation

The EVM does not provide subroutines as a primitive. Instead, calls can be synthesized by fetching and pushing the current program counter on the data stack and jumping to the subroutine address; returns can be synthesized by contriving to get the return address back to the top of stack and jumping back to it. Complex calling conventions are then needed to use the same stack for computation and control flow. Memory allows for simpler conventions but still costs gas. Eschewing subroutines in user code is the least costly -- but also the most failure-prone.
The EVM does not provide subroutines as a primitive. Instead, calls can be synthesized by fetching and pushing the current program counter on the data stack and jumping to the subroutine address; returns can be synthesized by contriving to get the return address back to the top of stack and jumping back to it. Sometimes complex calling conventions are then needed to use the same stack for computation and control flow. Memory allows for simpler conventions but still costs gas. Eschewing subroutines in user code is the least costly -- but also the most failure-prone.

Over the course of 30 years the computer industry struggled with this complexity and cost
and settled in on opcodes to directly support subroutines. These are provided in some form by most all physical and virtual machines going back at least 50 years.

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.

In the Appendix we show example solc output for a simple program that uses over three times as much gas just calling and returning from subroutines as comparable code using these opcodes. Actual differences in run-time efficiency will of course vary widely.

## Specification

We introduce one more stack into the EVM in addition to the existing `data stack` which we call the `return stack`. The `return stack` is limited to `1023` items.
Expand Down Expand Up @@ -62,7 +60,7 @@ _Note 3: The description above lays out the semantics of this feature in terms o

## Rationale

This is the is a small change that provides native subroutines without breaking backwards compatibility.
This is almost the smallest change that provides native subroutines without breaking backwards compatibility.

## Backwards Compatibility

Expand Down Expand Up @@ -203,75 +201,4 @@ We suggest the following opcodes:
These changes do introduce new flow control instructions, so any software which does static/dynamic analysis of evm-code
needs to be modified accordingly. The `JUMPSUB` semantics are similar to `JUMP` (but jumping to a `BEGINSUB`), whereas the `RETURNSUB` instruction is different, since it can 'land' on any opcode (but the possible destinations can be statically inferred).


## Appendix: Comparative costs.

```
contract fun {
function test(uint x, uint y) public returns (uint) {
return test_mul(2,3);
}
function test_mul(uint x, uint y) public returns (uint) {
return multiply(x,y);
}
function multiply(uint x, uint y) public returns (uint) {
return x * y;
}
}

```
Here is solc 0.6.3 assembly code with labeled destinations.
```
TEST:
jumpdest
0x00
RTN
0x02
0x03
TEST_MUL
jump
TEST_MUL:
jumpdest
0x00
RTN
dup4
dup4
MULTIPLY
jump
RTN:
jumpdest
swap4
swap3
pop
pop
pop
jump
MULTIPLY:
jumpdest
mul
swap1
jump
```
solc does a good job with the multiply() function, which is a leaf. Non-leaf functions are more awkward to get out of. Calling `fun.test()` will cost _118 gas_, plus 5 for the `mul`.

This is the same code written using `jumpsub` and `returnsub`. Calling `fun.test()` will cost _32 gas_ plus 5 for the `mul`.
```
TEST:
beginsub
0x02
0x03
TEST_MUL
jumpsub
returnsub
TEST_MUL:
beginsub
MULTIPLY
jumpsub
returnsub
MULTIPLY:
beginsub
mul
returnsub
```

**Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).**