mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 02:42:27 +00:00
dropped old code
This commit is contained in:
parent
36a4609150
commit
071bb70827
3 changed files with 93 additions and 258 deletions
|
|
@ -16,120 +16,26 @@
|
|||
|
||||
package vm
|
||||
|
||||
const (
|
||||
set2BitsMask = uint16(0b11)
|
||||
set3BitsMask = uint16(0b111)
|
||||
set4BitsMask = uint16(0b1111)
|
||||
set5BitsMask = uint16(0b1_1111)
|
||||
set6BitsMask = uint16(0b11_1111)
|
||||
set7BitsMask = uint16(0b111_1111)
|
||||
)
|
||||
|
||||
// bitvec is a bit vector which maps bytes in a program.
|
||||
// An unset bit means the byte is an opcode, a set bit means
|
||||
// it's data (i.e. argument of PUSHxx).
|
||||
type bitvec []byte
|
||||
type bitvec []uint32
|
||||
|
||||
func (bits bitvec) set1(pos uint64) {
|
||||
bits[pos/8] |= 1 << (pos % 8)
|
||||
func (bv bitvec) isCode(pc uint64) bool {
|
||||
return (bv[pc/32] & (1 << (pc % 32))) == 0
|
||||
}
|
||||
|
||||
func (bits bitvec) setN(flag uint16, pos uint64) {
|
||||
a := flag << (pos % 8)
|
||||
bits[pos/8] |= byte(a)
|
||||
if b := byte(a >> 8); b != 0 {
|
||||
bits[pos/8+1] = b
|
||||
}
|
||||
}
|
||||
|
||||
func (bits bitvec) set8(pos uint64) {
|
||||
a := byte(0xFF << (pos % 8))
|
||||
bits[pos/8] |= a
|
||||
bits[pos/8+1] = ^a
|
||||
}
|
||||
|
||||
func (bits bitvec) set16(pos uint64) {
|
||||
a := byte(0xFF << (pos % 8))
|
||||
bits[pos/8] |= a
|
||||
bits[pos/8+1] = 0xFF
|
||||
bits[pos/8+2] = ^a
|
||||
}
|
||||
|
||||
// codeSegment checks if the position is in a code segment.
|
||||
func (bits *bitvec) codeSegment(pos uint64) bool {
|
||||
return (((*bits)[pos/8] >> (pos % 8)) & 1) == 0
|
||||
}
|
||||
|
||||
// codeBitmap collects data locations in code.
|
||||
func codeBitmap(code []byte) bitvec {
|
||||
// The bitmap is 4 bytes longer than necessary, in case the code
|
||||
// ends with a PUSH32, the algorithm will set bits on the
|
||||
// bitvector outside the bounds of the actual code.
|
||||
bits := make(bitvec, len(code)/8+1+4)
|
||||
return codeBitmapInternal(code, bits)
|
||||
}
|
||||
|
||||
// codeBitmapInternal is the internal implementation of codeBitmap.
|
||||
// It exists for the purpose of being able to run benchmark tests
|
||||
// without dynamic allocations affecting the results.
|
||||
func codeBitmapInternal(code, bits bitvec) bitvec {
|
||||
for pc := uint64(0); pc < uint64(len(code)); {
|
||||
op := OpCode(code[pc])
|
||||
pc++
|
||||
if int8(op) < int8(PUSH1) { // If not PUSH (the int8(op) > int(PUSH32) is always false).
|
||||
continue
|
||||
}
|
||||
numbits := op - PUSH1 + 1
|
||||
if numbits >= 8 {
|
||||
for ; numbits >= 16; numbits -= 16 {
|
||||
bits.set16(pc)
|
||||
pc += 16
|
||||
}
|
||||
for ; numbits >= 8; numbits -= 8 {
|
||||
bits.set8(pc)
|
||||
pc += 8
|
||||
}
|
||||
}
|
||||
switch numbits {
|
||||
case 1:
|
||||
bits.set1(pc)
|
||||
pc += 1
|
||||
case 2:
|
||||
bits.setN(set2BitsMask, pc)
|
||||
pc += 2
|
||||
case 3:
|
||||
bits.setN(set3BitsMask, pc)
|
||||
pc += 3
|
||||
case 4:
|
||||
bits.setN(set4BitsMask, pc)
|
||||
pc += 4
|
||||
case 5:
|
||||
bits.setN(set5BitsMask, pc)
|
||||
pc += 5
|
||||
case 6:
|
||||
bits.setN(set6BitsMask, pc)
|
||||
pc += 6
|
||||
case 7:
|
||||
bits.setN(set7BitsMask, pc)
|
||||
pc += 7
|
||||
}
|
||||
}
|
||||
return bits
|
||||
}
|
||||
|
||||
type bitVec []uint32
|
||||
|
||||
func (b bitVec) isCode(pc uint64) bool {
|
||||
return (b[pc/32] & (1 << (pc % 32))) == 0
|
||||
}
|
||||
|
||||
func newCodeBitVec(code []byte) (bv bitVec) {
|
||||
bv = make(bitVec, len(code)/32+2)
|
||||
bv.codeBitVec(code)
|
||||
// newCodeBitVec collects data locations in code.
|
||||
func newCodeBitVec(code []byte) (bv bitvec) {
|
||||
bv = make(bitvec, len(code)/32+2)
|
||||
bv.codeBitvecInternal(code)
|
||||
return bv
|
||||
}
|
||||
|
||||
func (bv bitVec) codeBitVec(code []byte) bitVec {
|
||||
// codeBitvecInternal is the internal implementation of codeBitmap.
|
||||
// It exists for the purpose of being able to run benchmark tests
|
||||
// without dynamic allocations affecting the results.
|
||||
func (bv bitvec) codeBitvecInternal(code []byte) bitvec {
|
||||
var pc uint64
|
||||
for pc < uint64(len(code)) {
|
||||
op := code[pc]
|
||||
|
|
|
|||
|
|
@ -17,9 +17,9 @@
|
|||
package vm
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
_ "embed"
|
||||
"math/bits"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
|
|
@ -28,68 +28,67 @@ import (
|
|||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
func TestJumpDestAnalysis(t *testing.T) {
|
||||
tests := []struct {
|
||||
code []byte
|
||||
exp byte
|
||||
which int
|
||||
}{
|
||||
{[]byte{byte(PUSH1), 0x01, 0x01, 0x01}, 0b0000_0010, 0},
|
||||
{[]byte{byte(PUSH1), byte(PUSH1), byte(PUSH1), byte(PUSH1)}, 0b0000_1010, 0},
|
||||
{[]byte{0x00, byte(PUSH1), 0x00, byte(PUSH1), 0x00, byte(PUSH1), 0x00, byte(PUSH1)}, 0b0101_0100, 0},
|
||||
{[]byte{byte(PUSH8), byte(PUSH8), byte(PUSH8), byte(PUSH8), byte(PUSH8), byte(PUSH8), byte(PUSH8), byte(PUSH8), 0x01, 0x01, 0x01}, bits.Reverse8(0x7F), 0},
|
||||
{[]byte{byte(PUSH8), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0b0000_0001, 1},
|
||||
{[]byte{0x01, 0x01, 0x01, 0x01, 0x01, byte(PUSH2), byte(PUSH2), byte(PUSH2), 0x01, 0x01, 0x01}, 0b1100_0000, 0},
|
||||
{[]byte{0x01, 0x01, 0x01, 0x01, 0x01, byte(PUSH2), 0x01, 0x01, 0x01, 0x01, 0x01}, 0b0000_0000, 1},
|
||||
{[]byte{byte(PUSH3), 0x01, 0x01, 0x01, byte(PUSH1), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0b0010_1110, 0},
|
||||
{[]byte{byte(PUSH3), 0x01, 0x01, 0x01, byte(PUSH1), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0b0000_0000, 1},
|
||||
{[]byte{0x01, byte(PUSH8), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0b1111_1100, 0},
|
||||
{[]byte{0x01, byte(PUSH8), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0b0000_0011, 1},
|
||||
{[]byte{byte(PUSH16), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0b1111_1110, 0},
|
||||
{[]byte{byte(PUSH16), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0b1111_1111, 1},
|
||||
{[]byte{byte(PUSH16), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 0b0000_0001, 2},
|
||||
{[]byte{byte(PUSH8), 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, byte(PUSH1), 0x01}, 0b1111_1110, 0},
|
||||
{[]byte{byte(PUSH8), 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, byte(PUSH1), 0x01}, 0b0000_0101, 1},
|
||||
{[]byte{byte(PUSH32)}, 0b1111_1110, 0},
|
||||
{[]byte{byte(PUSH32)}, 0b1111_1111, 1},
|
||||
{[]byte{byte(PUSH32)}, 0b1111_1111, 2},
|
||||
{[]byte{byte(PUSH32)}, 0b1111_1111, 3},
|
||||
{[]byte{byte(PUSH32)}, 0b0000_0001, 4},
|
||||
}
|
||||
for i, test := range tests {
|
||||
ret := codeBitmap(test.code)
|
||||
if ret[test.which] != test.exp {
|
||||
t.Fatalf("test %d: expected %x, got %02x", i, test.exp, ret[test.which])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBitVec(t *testing.T) {
|
||||
func TestBitvec(t *testing.T) {
|
||||
tests := []struct {
|
||||
Code []byte
|
||||
Want bitVec
|
||||
Want bitvec
|
||||
}{
|
||||
{[]byte{}, bitVec{0, 0}},
|
||||
{[]byte{byte(PUSH1), 0xff, 0x00, 0x00}, bitVec{0b00000000_00000000_00000000_00000010, 0}},
|
||||
{[]byte{byte(PUSH2), 0xff, 0xff, 0x00}, bitVec{0b00000000_00000000_00000000_00000110, 0}},
|
||||
{Code: []byte{}, Want: bitvec{0, 0}},
|
||||
{Code: []byte{byte(PUSH1), 0x01, 0x01, 0x01}, Want: bitvec{0b00000000_00000000_00000000_00000010, 0}},
|
||||
{Code: []byte{byte(PUSH2), 0x01, 0x01, 0x01}, Want: bitvec{0b00000000_00000000_00000000_00000110, 0}},
|
||||
{
|
||||
[]byte{
|
||||
Code: []byte{byte(PUSH1), byte(PUSH1), byte(PUSH1), byte(PUSH1)},
|
||||
Want: bitvec{0b00000000_00000000_00000000_00001010, 0},
|
||||
},
|
||||
{
|
||||
Code: []byte{0x00, byte(PUSH1), 0x00, byte(PUSH1), 0x00, byte(PUSH1), 0x00, byte(PUSH1)},
|
||||
Want: bitvec{0b00000000_00000000_00000001_01010100, 0},
|
||||
},
|
||||
{
|
||||
Code: []byte{byte(PUSH8), byte(PUSH8), byte(PUSH8), byte(PUSH8), byte(PUSH8), byte(PUSH8), byte(PUSH8), byte(PUSH8), 0x01, 0x01, 0x01},
|
||||
Want: bitvec{0b00000000_00000000_00000001_11111110, 0},
|
||||
},
|
||||
{
|
||||
Code: []byte{0x01, 0x01, 0x01, 0x01, 0x01, byte(PUSH2), 0x01, 0x01, 0x01, 0x01, 0x01},
|
||||
Want: bitvec{0b00000000_00000000_00000000_11000000, 0},
|
||||
},
|
||||
|
||||
{
|
||||
Code: []byte{byte(PUSH3), 0x01, 0x01, 0x01, byte(PUSH1), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
|
||||
Want: bitvec{0b00000000_00000000_00000000_00101110, 0},
|
||||
},
|
||||
{
|
||||
Code: []byte{0x01, byte(PUSH8), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
|
||||
Want: bitvec{0b00000000_00000000_00000011_11111100, 0},
|
||||
},
|
||||
|
||||
{
|
||||
Code: []byte{byte(PUSH16), 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
|
||||
Want: bitvec{0b00000000_00000001_11111111_11111110, 0},
|
||||
},
|
||||
{
|
||||
Code: []byte{byte(PUSH8), 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, byte(PUSH1), 0x01},
|
||||
Want: bitvec{0b_00000000_00000000_00000101_11111110, 0},
|
||||
},
|
||||
{Code: []byte{byte(PUSH32)}, Want: bitvec{0b11111111_11111111_11111111_11111110, 0b00000000_00000000_00000000_00000001}},
|
||||
{
|
||||
Code: []byte{
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, byte(PUSH2), 0xff,
|
||||
0xff,
|
||||
},
|
||||
bitVec{0b10000000_00000000_00000000_00000000, 0b00000000_00000000_00000000_00000001, 0},
|
||||
Want: bitvec{0b10000000_00000000_00000000_00000000, 0b00000000_00000000_00000000_00000001, 0},
|
||||
},
|
||||
{
|
||||
[]byte{
|
||||
Code: []byte{
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, byte(PUSH32),
|
||||
},
|
||||
bitVec{0b00000000_00000000_00000000_00000000, 0b11111111_11111111_11111111_11111111, 0},
|
||||
Want: bitvec{0b00000000_00000000_00000000_00000000, 0b11111111_11111111_11111111_11111111, 0},
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -103,20 +102,6 @@ func TestBitVec(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func FuzzBitVec(f *testing.F) {
|
||||
f.Add([]byte{0x1})
|
||||
f.Fuzz(func(t *testing.T, code []byte) {
|
||||
newBitVec := newCodeBitVec(code)
|
||||
oldBitVec := codeBitmap(code)
|
||||
|
||||
for i := range code {
|
||||
if newBitVec.isCode(uint64(i)) != oldBitVec.codeSegment(uint64(i)) {
|
||||
t.Fatalf("mismatch at %d", i)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const analysisCodeSize = 1200 * 1024
|
||||
|
||||
func BenchmarkJumpdestAnalysis_1200k(bench *testing.B) {
|
||||
|
|
@ -125,34 +110,20 @@ func BenchmarkJumpdestAnalysis_1200k(bench *testing.B) {
|
|||
bench.SetBytes(analysisCodeSize)
|
||||
bench.ResetTimer()
|
||||
for i := 0; i < bench.N; i++ {
|
||||
codeBitmap(code)
|
||||
newCodeBitVec(code)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkJumpdestAnalysis_rand(b *testing.B) {
|
||||
b.Run("v=old", func(b *testing.B) {
|
||||
code := make([]byte, analysisCodeSize)
|
||||
rand.Read(code)
|
||||
code := make([]byte, analysisCodeSize)
|
||||
rand.Read(code)
|
||||
|
||||
bv := codeBitmap(code)
|
||||
b.SetBytes(int64(len(code)))
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
codeBitmapInternal(code, bv)
|
||||
}
|
||||
})
|
||||
|
||||
b.Run("v=new", func(b *testing.B) {
|
||||
code := make([]byte, analysisCodeSize)
|
||||
rand.Read(code)
|
||||
|
||||
bv := newCodeBitVec(code)
|
||||
b.SetBytes(int64(len(code)))
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
bv.codeBitVec(code)
|
||||
}
|
||||
})
|
||||
bv := newCodeBitVec(code)
|
||||
b.SetBytes(int64(len(code)))
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
bv.codeBitvecInternal(code)
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
|
|
@ -162,23 +133,12 @@ var (
|
|||
)
|
||||
|
||||
func BenchmarkJumpdestAnalysis_weth9(b *testing.B) {
|
||||
b.Run("v=old", func(b *testing.B) {
|
||||
bv := codeBitmap(codeWETH9)
|
||||
b.SetBytes(int64(len(codeWETH9)))
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
codeBitmapInternal(codeWETH9, bv)
|
||||
}
|
||||
})
|
||||
|
||||
b.Run("v=new", func(b *testing.B) {
|
||||
bv := newCodeBitVec(codeWETH9)
|
||||
b.SetBytes(int64(len(codeWETH9)))
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
bv.codeBitVec(codeWETH9)
|
||||
}
|
||||
})
|
||||
bv := newCodeBitVec(codeWETH9)
|
||||
b.SetBytes(int64(len(codeWETH9)))
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
bv.codeBitvecInternal(codeWETH9)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkJumpdestHashing_1200k(bench *testing.B) {
|
||||
|
|
@ -192,55 +152,24 @@ func BenchmarkJumpdestHashing_1200k(bench *testing.B) {
|
|||
}
|
||||
|
||||
func BenchmarkJumpdestOpAnalysis(b *testing.B) {
|
||||
b.Run("v=old", func(b *testing.B) {
|
||||
var op OpCode
|
||||
bencher := func(b *testing.B) {
|
||||
code := make([]byte, analysisCodeSize)
|
||||
b.SetBytes(analysisCodeSize)
|
||||
for i := range code {
|
||||
code[i] = byte(op)
|
||||
}
|
||||
bits := make(bitvec, len(code)/8+1+4)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
for j := range bits {
|
||||
bits[j] = 0
|
||||
}
|
||||
codeBitmapInternal(code, bits)
|
||||
var op OpCode
|
||||
bencher := func(b *testing.B) {
|
||||
code := bytes.Repeat([]byte{byte(op)}, analysisCodeSize)
|
||||
bv := newCodeBitVec(code)
|
||||
b.SetBytes(analysisCodeSize)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
for j := range bv {
|
||||
bv[j] = 0
|
||||
}
|
||||
bv.codeBitvecInternal(code)
|
||||
}
|
||||
for op = PUSH1; op <= PUSH32; op++ {
|
||||
b.Run(op.String(), bencher)
|
||||
}
|
||||
op = JUMPDEST
|
||||
}
|
||||
for op = PUSH1; op <= PUSH32; op++ {
|
||||
b.Run(op.String(), bencher)
|
||||
op = STOP
|
||||
b.Run(op.String(), bencher)
|
||||
})
|
||||
|
||||
b.Run("v=new", func(b *testing.B) {
|
||||
bencher := func(op OpCode) (string, func(b *testing.B)) {
|
||||
return op.String(), func(b *testing.B) {
|
||||
code := make([]byte, analysisCodeSize)
|
||||
b.SetBytes(analysisCodeSize)
|
||||
|
||||
for i := range code {
|
||||
code[i] = byte(op)
|
||||
}
|
||||
bv := newCodeBitVec(code)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
for j := range bv {
|
||||
bv[j] = 0
|
||||
}
|
||||
bv.codeBitVec(code)
|
||||
}
|
||||
}
|
||||
}
|
||||
for op := PUSH1; op <= PUSH32; op++ {
|
||||
b.Run(bencher(op))
|
||||
}
|
||||
b.Run(bencher(JUMPDEST))
|
||||
b.Run(bencher(STOP))
|
||||
})
|
||||
}
|
||||
op = JUMPDEST
|
||||
b.Run(op.String(), bencher)
|
||||
op = STOP
|
||||
b.Run(op.String(), bencher)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ func (c *Contract) validJumpdest(dest *uint256.Int) bool {
|
|||
func (c *Contract) isCode(udest uint64) bool {
|
||||
// Do we already have an analysis laying around?
|
||||
if c.analysis != nil {
|
||||
return c.analysis.codeSegment(udest)
|
||||
return c.analysis.isCode(udest)
|
||||
}
|
||||
// Do we have a contract hash already?
|
||||
// If we do have a hash, that means it's a 'regular' contract. For regular
|
||||
|
|
@ -110,21 +110,21 @@ func (c *Contract) isCode(udest uint64) bool {
|
|||
if !exist {
|
||||
// Do the analysis and save in parent context
|
||||
// We do not need to store it in c.analysis
|
||||
analysis = codeBitmap(c.Code)
|
||||
analysis = newCodeBitVec(c.Code)
|
||||
c.jumpdests[c.CodeHash] = analysis
|
||||
}
|
||||
// Also stash it in current contract for faster access
|
||||
c.analysis = analysis
|
||||
return analysis.codeSegment(udest)
|
||||
return analysis.isCode(udest)
|
||||
}
|
||||
// We don't have the code hash, most likely a piece of initcode not already
|
||||
// in state trie. In that case, we do an analysis, and save it locally, so
|
||||
// we don't have to recalculate it for every JUMP instruction in the execution
|
||||
// However, we don't save it within the parent context
|
||||
if c.analysis == nil {
|
||||
c.analysis = codeBitmap(c.Code)
|
||||
c.analysis = newCodeBitVec(c.Code)
|
||||
}
|
||||
return c.analysis.codeSegment(udest)
|
||||
return c.analysis.isCode(udest)
|
||||
}
|
||||
|
||||
// AsDelegate sets the contract to be a delegate call and returns the current
|
||||
|
|
|
|||
Loading…
Reference in a new issue