-
Notifications
You must be signed in to change notification settings - Fork 5.3k
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
subroutines #2484
subroutines #2484
Changes from all commits
a7b7bcf
dab3d4a
de49e34
3a3e470
457abdf
99efd14
4ab57c4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
--- | ||
eip: 2315 | ||
title: Simple Subroutines for the EVM | ||
status: Draft | ||
type: Standards Track | ||
category: Core | ||
author: Greg Colvin | ||
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 `RETSUB`. | ||
|
||
## 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`. | ||
|
||
##### `RETSUB` | ||
Returns to the instruction after the most recently executed `JUMPSUB` instruction, which must be a `JUMPDEST` | ||
|
||
A program may jump at most 1024 times without returning. | ||
|
||
## 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 | ||
``` | ||
step op stack | ||
0 PUSH1 3 [] | ||
1 JUMPSUB [3] | ||
4 JUMPDEST [] | ||
5 STOP [] | ||
2 JUMPDEST [] | ||
3 RETSUB [] | ||
``` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is how I interpret it.
Trace:
I think I understood it now -- but I don't really like that you break an abstraction here -- previously, stack validation can be done without knowing exactly what the opcode is, only knowing how much it pops and how much it pushes. This EIP means that we'll have special handling on There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. see update There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, now I'm confused again. The There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just woke up. other duties. I might not be possible not to break something here. But then I doubt we have a list of every abstraction and assumption made by the current VM. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Three cups of coffee, @holiman. Getting closer?
Notes:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think what is confusing here is that in the typical implementation the ++PC is done at the end of the loop. So it's not exactly the case that JUMPSUB does that at step 4, although it is the case that RETSUB pops the return stack to PC at step3. It might be less confusing to say that RETSUB returns to 3 == PC = pop(return_stack) + 1, and adust the text and pseudocode to match. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Your The spec for
It does not mention any special casing of how empty stacks are handled, so IMO that means it errors out. The only time you mention a special casing is for the
Yes, if the intention is to continue after the 'current' For extra clarity, I'd suggest making the program maybe
IIUC, the trace would then go through PCs |
||
This code should terminate after 5 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 adds cases for `JUMPSUB` and `RETSUB` to a simple loop-and-switch interpreter. | ||
``` | ||
bytecode[code_size] | ||
data_stack[1024] | ||
return_stack[1024] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also add
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Right, thanks. |
||
push(return_stack, PC) | ||
PC = 0 | ||
while PC < code_size { | ||
opcode = bytecode[PC] | ||
... | ||
switch opcode { | ||
... | ||
case JUMPSUB: | ||
push(return_stack, PC + 1) | ||
PC = pop(data_stack) | ||
continue | ||
case RETSUB: | ||
PC = pop(return_stack) | ||
continue | ||
} | ||
++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 `RETSUB` with no prior `JUMPSUB` executes a `STOP`. A `STOP` or `RETURN` ends the execution of the subroutine and the program. | ||
|
||
We suggest the cost of `JUMPSUB` should be _low_, and `RETSUB` should be _verylow_. | ||
Measurement will tell. We suggest the following opcodes: | ||
``` | ||
0xbe JUMPSUB | ||
0xbf RETSUB | ||
``` | ||
## Security Considerations | ||
|
||
This proposal introduces no new security considerations to the EVM. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It kind of does, there are a couple of new things:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could consider introducing the requirement of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was considering that, and think it's a good idea. Will simplify things that cause a long, confusing discussion above. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I tried that, but am not so sure now that it's a good idea. Flow analysis frameworks will already have to change to allow for JUMPSUB, which is new kind of branching. And we still don't know statically where a RETSUB will go, except that it will for sure be the instruction after the most recent JUMPSUB. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That is, since you can't statically check the destination of a RETSUB anyway, it only figures as a basic-block terminator. So it doesn't seem like a big enough change to waste a byte after every JUMPSUB. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can't statically check jump destination currently, hence the reason for JUMPDEST which statically provides potential destinations. Following that logic, how is that bad for JUMPSUB? |
||
|
||
**Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).** |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't mention the return address (the instruction after this JUMPSUB) is stored in a call stack.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's an implementation detail, so long as RETSUB behaves as specified.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, not exactly if we specify a call stack limit, then that limit must be checked here.