Skip to content

Commit

Permalink
feat: EVM execution opcode level optimization
Browse files Browse the repository at this point in the history
several optimizations included:
- opcode fusion
- jumpdest calculation optimization
- SHA caching in interpreter

Co-authored-by: redhdx <[email protected]>
  • Loading branch information
sunny2022da and redhdx committed Mar 26, 2024
1 parent c18478a commit e5f1d94
Show file tree
Hide file tree
Showing 27 changed files with 1,682 additions and 94 deletions.
5 changes: 5 additions & 0 deletions cmd/evm/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,11 @@ var (
Usage: "enable return data output",
Category: flags.VMCategory,
}
VMOpcodeOptimizeFlag = &cli.BoolFlag{
Name: "vm.opcode.optimize",
Usage: "enable opcode optimization",
Value: true,
}
)

var stateTransitionCommand = &cli.Command{
Expand Down
8 changes: 7 additions & 1 deletion cmd/evm/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"bytes"
"encoding/json"
"fmt"
compiler2 "github.com/ethereum/go-ethereum/core/opcodeCompiler/compiler"
"io"
"math/big"
"os"
Expand Down Expand Up @@ -224,7 +225,8 @@ func runCmd(ctx *cli.Context) error {
BlobHashes: blobHashes,
BlobBaseFee: blobBaseFee,
EVMConfig: vm.Config{
Tracer: tracer,
Tracer: tracer,
EnableOpcodeOptimizations: ctx.Bool(VMOpcodeOptimizeFlag.Name),
},
}

Expand All @@ -234,6 +236,10 @@ func runCmd(ctx *cli.Context) error {
runtimeConfig.ChainConfig = params.AllEthashProtocolChanges
}

if runtimeConfig.EVMConfig.EnableOpcodeOptimizations {
compiler2.EnableOptimization()
}

var hexInput []byte
if inputFileFlag := ctx.String(InputFileFlag.Name); inputFileFlag != "" {
var err error
Expand Down
1 change: 1 addition & 0 deletions cmd/geth/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ var (
utils.RollupHaltOnIncompatibleProtocolVersionFlag,
utils.RollupSuperchainUpgradesFlag,
configFileFlag,
utils.VMOpcodeOptimizeFlag,
}, utils.NetworkFlags, utils.DatabaseFlags)

rpcFlags = []cli.Flag{
Expand Down
20 changes: 19 additions & 1 deletion cmd/utils/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"encoding/hex"
"errors"
"fmt"
"github.com/ethereum/go-ethereum/core/opcodeCompiler/compiler"
"math"
"math/big"
"net"
Expand Down Expand Up @@ -1050,6 +1051,13 @@ Please note that --` + MetricsHTTPFlag.Name + ` must be set to start the server.
Value: metrics.DefaultConfig.InfluxDBOrganization,
Category: flags.MetricsCategory,
}

VMOpcodeOptimizeFlag = &cli.BoolFlag{
Name: "vm.opcode.optimize",
Usage: "enable opcode optimization",
Value: true,
Category: flags.VMCategory,
}
)

var (
Expand Down Expand Up @@ -1901,6 +1909,12 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
cfg.EnablePreimageRecording = ctx.Bool(VMEnableDebugFlag.Name)
}

if ctx.IsSet(VMOpcodeOptimizeFlag.Name) {
// TODO(fjl): force-enable this in --dev mode
cfg.EnableOpcodeOptimizing = ctx.Bool(VMOpcodeOptimizeFlag.Name)
compiler.EnableOptimization()
}

if ctx.IsSet(RPCGlobalGasCapFlag.Name) {
cfg.RPCGasCap = ctx.Uint64(RPCGlobalGasCapFlag.Name)
}
Expand Down Expand Up @@ -2387,8 +2401,12 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (*core.BlockCh
if ctx.IsSet(CacheFlag.Name) || ctx.IsSet(CacheGCFlag.Name) {
cache.TrieDirtyLimit = ctx.Int(CacheFlag.Name) * ctx.Int(CacheGCFlag.Name) / 100
}
vmcfg := vm.Config{EnablePreimageRecording: ctx.Bool(VMEnableDebugFlag.Name)}
vmcfg := vm.Config{EnablePreimageRecording: ctx.Bool(VMEnableDebugFlag.Name),
EnableOpcodeOptimizations: ctx.Bool(VMOpcodeOptimizeFlag.Name)}

if vmcfg.EnableOpcodeOptimizations {
compiler.EnableOptimization()
}
// Disable transaction indexing/unindexing by default.
chain, err := core.NewBlockChain(chainDb, cache, gspec, nil, engine, vmcfg, nil, nil)
if err != nil {
Expand Down
51 changes: 51 additions & 0 deletions core/opcodeCompiler/compiler/OpCodeCache.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package compiler

import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/lru"
)

type OpCodeCache struct {
optimizedCodeCache *lru.Cache[common.Hash, []byte]
bitvecCache *lru.Cache[common.Hash, []byte]
}

func (c *OpCodeCache) GetCachedBitvec(codeHash common.Hash) []byte {
bitvec, _ := c.bitvecCache.Get(codeHash)
return bitvec
}

func (c *OpCodeCache) AddBitvecCache(codeHash common.Hash, bitvec []byte) {
c.bitvecCache.Add(codeHash, bitvec)
}

func (c *OpCodeCache) RemoveCachedCode(hash common.Hash) {
c.optimizedCodeCache.Remove(hash)
}

func (c *OpCodeCache) GetCachedCode(hash common.Hash) []byte {
processedCode, _ := c.optimizedCodeCache.Get(hash)
return processedCode
}

func (c *OpCodeCache) AddCodeCache(hash common.Hash, optimizedCode []byte) {
c.optimizedCodeCache.Add(hash, optimizedCode)
}

var opcodeCache *OpCodeCache

const (
optimizedCodeCacheCap = 1024
bitvecCacheCap = 1024
)

func init() {
opcodeCache = &OpCodeCache{
optimizedCodeCache: lru.NewCache[common.Hash, []byte](optimizedCodeCacheCap),
bitvecCache: lru.NewCache[common.Hash, []byte](bitvecCacheCap),
}
}

func getOpCodeCacheInstance() *OpCodeCache {
return opcodeCache
}
225 changes: 225 additions & 0 deletions core/opcodeCompiler/compiler/evmByteCode.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
package compiler

// This is copied from vm/opcodes.go.

// ByteCode is an EVM ByteCode
type ByteCode byte

// 0x0 range - arithmetic ops.
const (
STOP ByteCode = 0x0
ADD ByteCode = 0x1
MUL ByteCode = 0x2
SUB ByteCode = 0x3
DIV ByteCode = 0x4
SDIV ByteCode = 0x5
MOD ByteCode = 0x6
SMOD ByteCode = 0x7
ADDMOD ByteCode = 0x8
MULMOD ByteCode = 0x9
EXP ByteCode = 0xa
SIGNEXTEND ByteCode = 0xb
)

// 0x10 range - comparison ops.
const (
LT ByteCode = 0x10
GT ByteCode = 0x11
SLT ByteCode = 0x12
SGT ByteCode = 0x13
EQ ByteCode = 0x14
ISZERO ByteCode = 0x15
AND ByteCode = 0x16
OR ByteCode = 0x17
XOR ByteCode = 0x18
NOT ByteCode = 0x19
BYTE ByteCode = 0x1a
SHL ByteCode = 0x1b
SHR ByteCode = 0x1c
SAR ByteCode = 0x1d
)

// 0x20 range - crypto.
const (
KECCAK256 ByteCode = 0x20
)

// 0x30 range - closure state.
const (
ADDRESS ByteCode = 0x30
BALANCE ByteCode = 0x31
ORIGIN ByteCode = 0x32
CALLER ByteCode = 0x33
CALLVALUE ByteCode = 0x34
CALLDATALOAD ByteCode = 0x35
CALLDATASIZE ByteCode = 0x36
CALLDATACOPY ByteCode = 0x37
CODESIZE ByteCode = 0x38
CODECOPY ByteCode = 0x39
GASPRICE ByteCode = 0x3a
EXTCODESIZE ByteCode = 0x3b
EXTCODECOPY ByteCode = 0x3c
RETURNDATASIZE ByteCode = 0x3d
RETURNDATACOPY ByteCode = 0x3e
EXTCODEHASH ByteCode = 0x3f
)

// 0x40 range - block operations.
const (
BLOCKHASH ByteCode = 0x40
COINBASE ByteCode = 0x41
TIMESTAMP ByteCode = 0x42
NUMBER ByteCode = 0x43
DIFFICULTY ByteCode = 0x44
RANDOM ByteCode = 0x44 // Same as DIFFICULTY
PREVRANDAO ByteCode = 0x44 // Same as DIFFICULTY
GASLIMIT ByteCode = 0x45
CHAINID ByteCode = 0x46
SELFBALANCE ByteCode = 0x47
BASEFEE ByteCode = 0x48
)

// 0x50 range - 'storage' and execution.
const (
POP ByteCode = 0x50
MLOAD ByteCode = 0x51
MSTORE ByteCode = 0x52
MSTORE8 ByteCode = 0x53
SLOAD ByteCode = 0x54
SSTORE ByteCode = 0x55
JUMP ByteCode = 0x56
JUMPI ByteCode = 0x57
PC ByteCode = 0x58
MSIZE ByteCode = 0x59
GAS ByteCode = 0x5a
JUMPDEST ByteCode = 0x5b
PUSH0 ByteCode = 0x5f
)

// 0x60 range - pushes.
const (
PUSH1 ByteCode = 0x60 + iota
PUSH2
PUSH3
PUSH4
PUSH5
PUSH6
PUSH7
PUSH8
PUSH9
PUSH10
PUSH11
PUSH12
PUSH13
PUSH14
PUSH15
PUSH16
PUSH17
PUSH18
PUSH19
PUSH20
PUSH21
PUSH22
PUSH23
PUSH24
PUSH25
PUSH26
PUSH27
PUSH28
PUSH29
PUSH30
PUSH31
PUSH32
)

// 0x80 range - dups.
const (
DUP1 = 0x80 + iota
DUP2
DUP3
DUP4
DUP5
DUP6
DUP7
DUP8
DUP9
DUP10
DUP11
DUP12
DUP13
DUP14
DUP15
DUP16
)

// 0x90 range - swaps.
const (
SWAP1 = 0x90 + iota
SWAP2
SWAP3
SWAP4
SWAP5
SWAP6
SWAP7
SWAP8
SWAP9
SWAP10
SWAP11
SWAP12
SWAP13
SWAP14
SWAP15
SWAP16
)

// 0xa0 range - logging ops.
const (
LOG0 ByteCode = 0xa0 + iota
LOG1
LOG2
LOG3
LOG4
)

// 0xd0 range - customized instructions.
const (
Nop ByteCode = 0xd0 + iota
AndSwap1PopSwap2Swap1
Swap2Swap1PopJump
Swap1PopSwap2Swap1
PopSwap2Swap1Pop
Push2Jump
Push2JumpI
Push1Push1
Push1Add
Push1Shl
Push1Dup1
Swap1Pop
PopJump
Pop2
Swap2Swap1
Swap2Pop
Dup2LT
JumpIfZero // 0xe2
)

// 0xf0 range - closures.
const (
CREATE ByteCode = 0xf0
CALL ByteCode = 0xf1
CALLCODE ByteCode = 0xf2
RETURN ByteCode = 0xf3
DELEGATECALL ByteCode = 0xf4
CREATE2 ByteCode = 0xf5

STATICCALL ByteCode = 0xfa
REVERT ByteCode = 0xfd
INVALID ByteCode = 0xfe
SELFDESTRUCT ByteCode = 0xff
)

// 0xb0 range.
const (
TLOAD ByteCode = 0xb3
TSTORE ByteCode = 0xb4
)
Loading

0 comments on commit e5f1d94

Please sign in to comment.