From 188fcf68ed60ef7f229495280f5a92615074164b Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Wed, 11 Aug 2021 12:09:31 +0200 Subject: [PATCH 01/11] core/vm: more detailed benchmark for jumpdest analysis --- core/vm/analysis_test.go | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/core/vm/analysis_test.go b/core/vm/analysis_test.go index fd2d744d87f4..29dd19a13f63 100644 --- a/core/vm/analysis_test.go +++ b/core/vm/analysis_test.go @@ -73,3 +73,22 @@ func BenchmarkJumpdestHashing_1200k(bench *testing.B) { } bench.StopTimer() } + +func BenchmarkJumpdestOpAnalysis(bench *testing.B) { + var op OpCode + bencher := func(b *testing.B) { + code := make([]byte, 32*b.N) + for i := range code { + code[i] = byte(op) + } + b.ResetTimer() + codeBitmap(code) + } + for op = PUSH1; op <= PUSH32; op++ { + bench.Run(op.String(), bencher) + } + op = JUMPDEST + bench.Run(op.String(), bencher) + op = STOP + bench.Run(op.String(), bencher) +} From c8c19a0c80eea4cd31831353374e2b743c10dae8 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Sun, 15 Aug 2021 20:43:37 +0200 Subject: [PATCH 02/11] core/vm: make jd analysis benchmark alloc free --- core/vm/analysis.go | 7 +++++++ core/vm/analysis_test.go | 3 ++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/core/vm/analysis.go b/core/vm/analysis.go index 0ccf47b97903..2c813ecb240b 100644 --- a/core/vm/analysis.go +++ b/core/vm/analysis.go @@ -40,6 +40,13 @@ func codeBitmap(code []byte) bitvec { // ends with a PUSH32, the algorithm will push zeroes onto 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]) diff --git a/core/vm/analysis_test.go b/core/vm/analysis_test.go index 29dd19a13f63..61e508744275 100644 --- a/core/vm/analysis_test.go +++ b/core/vm/analysis_test.go @@ -81,8 +81,9 @@ func BenchmarkJumpdestOpAnalysis(bench *testing.B) { for i := range code { code[i] = byte(op) } + bits := make(bitvec, len(code)/8+1+4) b.ResetTimer() - codeBitmap(code) + codeBitmapInternal(code, bits) } for op = PUSH1; op <= PUSH32; op++ { bench.Run(op.String(), bencher) From 14e80e0be576a176b93c6d8e5903623bd51c3ff6 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Wed, 11 Aug 2021 13:46:34 +0200 Subject: [PATCH 03/11] core/vm: improve jumpdest analysis --- core/vm/analysis.go | 80 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 64 insertions(+), 16 deletions(-) diff --git a/core/vm/analysis.go b/core/vm/analysis.go index 2c813ecb240b..477c65a83f18 100644 --- a/core/vm/analysis.go +++ b/core/vm/analysis.go @@ -21,12 +21,48 @@ package vm // it's data (i.e. argument of PUSHxx). type bitvec []byte +var lookup = [8]byte{ + 0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1, +} + func (bits *bitvec) set(pos uint64) { - (*bits)[pos/8] |= 0x80 >> (pos % 8) + //(*bits)[pos/8] |= 0x80 >> (pos % 8) + (*bits)[pos/8] |= lookup[pos%8] +} + +func (bits *bitvec) set2(pos uint64) { + (*bits)[pos/8+1] |= 0b1100_0000 << (8 - pos%8) + (*bits)[pos/8] |= 0b1100_0000 >> (pos % 8) +} + +func (bits *bitvec) set3(pos uint64) { + (*bits)[pos/8+1] |= 0b1110_0000 << (8 - pos%8) + (*bits)[pos/8] |= 0b1110_0000 >> (pos % 8) +} + +func (bits *bitvec) set4(pos uint64) { + (*bits)[pos/8+1] |= 0b1111_0000 << (8 - pos%8) + (*bits)[pos/8] |= 0b1111_0000 >> (pos % 8) +} + +func (bits *bitvec) set5(pos uint64) { + (*bits)[pos/8+1] |= 0b1111_1000 << (8 - pos%8) + (*bits)[pos/8] |= 0b1111_1000 >> (pos % 8) } + +func (bits *bitvec) set6(pos uint64) { + (*bits)[pos/8+1] |= 0b1111_1100 << (8 - pos%8) + (*bits)[pos/8] |= 0b1111_1100 >> (pos % 8) +} + +func (bits *bitvec) set7(pos uint64) { + (*bits)[pos/8+1] |= 0b1111_1110 << (8 - pos%8) + (*bits)[pos/8] |= 0b1111_1110 >> (pos % 8) +} + func (bits *bitvec) set8(pos uint64) { - (*bits)[pos/8] |= 0xFF >> (pos % 8) (*bits)[pos/8+1] |= ^(0xFF >> (pos % 8)) + (*bits)[pos/8] |= 0xFF >> (pos % 8) } // codeSegment checks if the position is in a code segment. @@ -49,21 +85,33 @@ func codeBitmap(code []byte) bitvec { func codeBitmapInternal(code, bits bitvec) bitvec { for pc := uint64(0); pc < uint64(len(code)); { op := OpCode(code[pc]) - - if op >= PUSH1 && op <= PUSH32 { - numbits := op - PUSH1 + 1 - pc++ - for ; numbits >= 8; numbits -= 8 { - bits.set8(pc) // 8 - pc += 8 - } - for ; numbits > 0; numbits-- { - bits.set(pc) - pc++ - } - } else { - pc++ + pc++ + if op < PUSH1 || op > PUSH32 { + continue + } + numbits := op - PUSH1 + 1 + for ; numbits >= 8; numbits -= 8 { + bits.set8(pc) // 8 + pc += 8 + } + // numbits now max 7 + switch numbits { + case 1: + bits.set(pc) + case 2: + bits.set2(pc) + case 3: + bits.set3(pc) + case 4: + bits.set4(pc) + case 5: + bits.set5(pc) + case 6: + bits.set6(pc) + case 7: + bits.set7(pc) } + pc += uint64(numbits) } return bits } From ee5b02609466550ed23940a68af87fe79da4d112 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Wed, 11 Aug 2021 14:23:18 +0200 Subject: [PATCH 04/11] core/vm: improve worst-case --- core/vm/analysis.go | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/core/vm/analysis.go b/core/vm/analysis.go index 477c65a83f18..ae00d0569c35 100644 --- a/core/vm/analysis.go +++ b/core/vm/analysis.go @@ -89,6 +89,32 @@ func codeBitmapInternal(code, bits bitvec) bitvec { if op < PUSH1 || op > PUSH32 { continue } + if op < PUSH8 { + switch op { + case PUSH1: + bits.set(pc) + pc += 1 + case PUSH2: + bits.set2(pc) + pc += 2 + case PUSH3: + bits.set3(pc) + pc += 3 + case PUSH4: + bits.set4(pc) + pc += 4 + case PUSH5: + bits.set5(pc) + pc += 5 + case PUSH6: + bits.set6(pc) + pc += 6 + case PUSH7: + bits.set7(pc) + pc += 7 + } + continue + } numbits := op - PUSH1 + 1 for ; numbits >= 8; numbits -= 8 { bits.set8(pc) // 8 From 5c06f270b5a6d2d4b6f7ca5cc8655d7e02b3f690 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Sat, 14 Aug 2021 21:41:45 +0200 Subject: [PATCH 05/11] core/vm: further improvements in analysis --- core/vm/analysis.go | 88 ++++++++++++++++++++-------------------- core/vm/analysis_test.go | 4 +- 2 files changed, 47 insertions(+), 45 deletions(-) diff --git a/core/vm/analysis.go b/core/vm/analysis.go index ae00d0569c35..f04352583fa7 100644 --- a/core/vm/analysis.go +++ b/core/vm/analysis.go @@ -31,38 +31,61 @@ func (bits *bitvec) set(pos uint64) { } func (bits *bitvec) set2(pos uint64) { - (*bits)[pos/8+1] |= 0b1100_0000 << (8 - pos%8) - (*bits)[pos/8] |= 0b1100_0000 >> (pos % 8) + a := uint16(0b1100_0000_0000_0000) >> (pos % 8) + (*bits)[pos/8] |= byte(a >> 8) + if b := byte(a); b != 0 { + // If the bit-setting affects the neigbouring byte, we can assign - no need to OR it, + // since it's the first write to that byte + (*bits)[pos/8+1] = b + } } func (bits *bitvec) set3(pos uint64) { - (*bits)[pos/8+1] |= 0b1110_0000 << (8 - pos%8) - (*bits)[pos/8] |= 0b1110_0000 >> (pos % 8) + a := uint16(0b1110_0000_0000_0000) >> (pos % 8) + (*bits)[pos/8] |= byte(a >> 8) + if b := byte(a); b != 0 { + (*bits)[pos/8+1] = b + } } func (bits *bitvec) set4(pos uint64) { - (*bits)[pos/8+1] |= 0b1111_0000 << (8 - pos%8) - (*bits)[pos/8] |= 0b1111_0000 >> (pos % 8) + a := uint16(0b1111_0000_0000_0000) >> (pos % 8) + (*bits)[pos/8] |= byte(a >> 8) + if b := byte(a); b != 0 { + (*bits)[pos/8+1] = b + } } func (bits *bitvec) set5(pos uint64) { - (*bits)[pos/8+1] |= 0b1111_1000 << (8 - pos%8) - (*bits)[pos/8] |= 0b1111_1000 >> (pos % 8) + a := uint16(0b1111_1000_0000_0000) >> (pos % 8) + (*bits)[pos/8] |= byte(a >> 8) + if b := byte(a); b != 0 { + (*bits)[pos/8+1] = b + } } func (bits *bitvec) set6(pos uint64) { - (*bits)[pos/8+1] |= 0b1111_1100 << (8 - pos%8) - (*bits)[pos/8] |= 0b1111_1100 >> (pos % 8) + a := uint16(0b1111_1100_0000_0000) >> (pos % 8) + (*bits)[pos/8] |= byte(a >> 8) + if b := byte(a); b != 0 { + (*bits)[pos/8+1] = b + } } func (bits *bitvec) set7(pos uint64) { - (*bits)[pos/8+1] |= 0b1111_1110 << (8 - pos%8) - (*bits)[pos/8] |= 0b1111_1110 >> (pos % 8) + a := uint16(0b1111_1110_0000_0000) >> (pos % 8) + (*bits)[pos/8] |= byte(a >> 8) + if b := byte(a); b != 0 { + (*bits)[pos/8+1] = b + } } func (bits *bitvec) set8(pos uint64) { - (*bits)[pos/8+1] |= ^(0xFF >> (pos % 8)) - (*bits)[pos/8] |= 0xFF >> (pos % 8) + a := byte(0xFF >> (pos % 8)) + (*bits)[pos/8] |= a + if ^a != 0{ + (*bits)[pos/8+1] = ^a + } } // codeSegment checks if the position is in a code segment. @@ -89,55 +112,34 @@ func codeBitmapInternal(code, bits bitvec) bitvec { if op < PUSH1 || op > PUSH32 { continue } - if op < PUSH8 { - switch op { - case PUSH1: - bits.set(pc) - pc += 1 - case PUSH2: - bits.set2(pc) - pc += 2 - case PUSH3: - bits.set3(pc) - pc += 3 - case PUSH4: - bits.set4(pc) - pc += 4 - case PUSH5: - bits.set5(pc) - pc += 5 - case PUSH6: - bits.set6(pc) - pc += 6 - case PUSH7: - bits.set7(pc) - pc += 7 - } - continue - } numbits := op - PUSH1 + 1 for ; numbits >= 8; numbits -= 8 { - bits.set8(pc) // 8 + bits.set8(pc) pc += 8 } - // numbits now max 7 switch numbits { case 1: bits.set(pc) + pc += 1 case 2: bits.set2(pc) + pc += 2 case 3: bits.set3(pc) + pc += 3 case 4: bits.set4(pc) + pc += 4 case 5: bits.set5(pc) + pc += 5 case 6: bits.set6(pc) + pc += 6 case 7: bits.set7(pc) + pc += 7 } - pc += uint64(numbits) } return bits } diff --git a/core/vm/analysis_test.go b/core/vm/analysis_test.go index 61e508744275..585bb3097f44 100644 --- a/core/vm/analysis_test.go +++ b/core/vm/analysis_test.go @@ -47,10 +47,10 @@ func TestJumpDestAnalysis(t *testing.T) { {[]byte{byte(PUSH32)}, 0xFF, 1}, {[]byte{byte(PUSH32)}, 0xFF, 2}, } - for _, test := range tests { + for i, test := range tests { ret := codeBitmap(test.code) if ret[test.which] != test.exp { - t.Fatalf("expected %x, got %02x", test.exp, ret[test.which]) + t.Fatalf("test %d: expected %x, got %02x", i, test.exp, ret[test.which]) } } } From ac834652475d11480113816a4a4ee8efb7582879 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Sat, 14 Aug 2021 23:01:36 +0200 Subject: [PATCH 06/11] core/vm: improve jumpdest analysis >PUSH15 --- core/vm/analysis.go | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/core/vm/analysis.go b/core/vm/analysis.go index f04352583fa7..eb82904af26a 100644 --- a/core/vm/analysis.go +++ b/core/vm/analysis.go @@ -83,11 +83,20 @@ func (bits *bitvec) set7(pos uint64) { func (bits *bitvec) set8(pos uint64) { a := byte(0xFF >> (pos % 8)) (*bits)[pos/8] |= a - if ^a != 0{ + if ^a != 0 { (*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 + if ^a != 0 { + (*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] & (0x80 >> (pos % 8))) == 0 @@ -113,9 +122,15 @@ func codeBitmapInternal(code, bits bitvec) bitvec { continue } numbits := op - PUSH1 + 1 - for ; numbits >= 8; numbits -= 8 { - bits.set8(pc) - pc += 8 + 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: From 3f60d8ba311a3b6a16bc582c06013eee09dbe66c Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Sun, 15 Aug 2021 20:44:28 +0200 Subject: [PATCH 07/11] core/vm: make jd analysis ref by value --- core/vm/analysis.go | 54 ++++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/core/vm/analysis.go b/core/vm/analysis.go index eb82904af26a..3ef085184865 100644 --- a/core/vm/analysis.go +++ b/core/vm/analysis.go @@ -25,75 +25,75 @@ var lookup = [8]byte{ 0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1, } -func (bits *bitvec) set(pos uint64) { +func (bits bitvec) set(pos uint64) { //(*bits)[pos/8] |= 0x80 >> (pos % 8) - (*bits)[pos/8] |= lookup[pos%8] + bits[pos/8] |= lookup[pos%8] } -func (bits *bitvec) set2(pos uint64) { +func (bits bitvec) set2(pos uint64) { a := uint16(0b1100_0000_0000_0000) >> (pos % 8) - (*bits)[pos/8] |= byte(a >> 8) + bits[pos/8] |= byte(a >> 8) if b := byte(a); b != 0 { // If the bit-setting affects the neigbouring byte, we can assign - no need to OR it, // since it's the first write to that byte - (*bits)[pos/8+1] = b + bits[pos/8+1] = b } } -func (bits *bitvec) set3(pos uint64) { +func (bits bitvec) set3(pos uint64) { a := uint16(0b1110_0000_0000_0000) >> (pos % 8) - (*bits)[pos/8] |= byte(a >> 8) + bits[pos/8] |= byte(a >> 8) if b := byte(a); b != 0 { - (*bits)[pos/8+1] = b + bits[pos/8+1] = b } } -func (bits *bitvec) set4(pos uint64) { +func (bits bitvec) set4(pos uint64) { a := uint16(0b1111_0000_0000_0000) >> (pos % 8) - (*bits)[pos/8] |= byte(a >> 8) + bits[pos/8] |= byte(a >> 8) if b := byte(a); b != 0 { - (*bits)[pos/8+1] = b + bits[pos/8+1] = b } } -func (bits *bitvec) set5(pos uint64) { +func (bits bitvec) set5(pos uint64) { a := uint16(0b1111_1000_0000_0000) >> (pos % 8) - (*bits)[pos/8] |= byte(a >> 8) + bits[pos/8] |= byte(a >> 8) if b := byte(a); b != 0 { - (*bits)[pos/8+1] = b + bits[pos/8+1] = b } } -func (bits *bitvec) set6(pos uint64) { +func (bits bitvec) set6(pos uint64) { a := uint16(0b1111_1100_0000_0000) >> (pos % 8) - (*bits)[pos/8] |= byte(a >> 8) + bits[pos/8] |= byte(a >> 8) if b := byte(a); b != 0 { - (*bits)[pos/8+1] = b + bits[pos/8+1] = b } } -func (bits *bitvec) set7(pos uint64) { +func (bits bitvec) set7(pos uint64) { a := uint16(0b1111_1110_0000_0000) >> (pos % 8) - (*bits)[pos/8] |= byte(a >> 8) + bits[pos/8] |= byte(a >> 8) if b := byte(a); b != 0 { - (*bits)[pos/8+1] = b + bits[pos/8+1] = b } } -func (bits *bitvec) set8(pos uint64) { +func (bits bitvec) set8(pos uint64) { a := byte(0xFF >> (pos % 8)) - (*bits)[pos/8] |= a + bits[pos/8] |= a if ^a != 0 { - (*bits)[pos/8+1] = ^a + bits[pos/8+1] = ^a } } -func (bits *bitvec) set16(pos uint64) { +func (bits bitvec) set16(pos uint64) { a := byte(0xFF >> (pos % 8)) - (*bits)[pos/8] |= a - (*bits)[pos/8+1] = 0xFF + bits[pos/8] |= a + bits[pos/8+1] = 0xFF if ^a != 0 { - (*bits)[pos/8+2] = ^a + bits[pos/8+2] = ^a } } From 0cb16d8521bae9785ca05ad069d39549357cf71d Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Mon, 16 Aug 2021 08:37:36 +0200 Subject: [PATCH 08/11] core/vm: fix misspell --- core/vm/analysis.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/vm/analysis.go b/core/vm/analysis.go index 3ef085184865..812aa1e4833d 100644 --- a/core/vm/analysis.go +++ b/core/vm/analysis.go @@ -34,7 +34,7 @@ func (bits bitvec) set2(pos uint64) { a := uint16(0b1100_0000_0000_0000) >> (pos % 8) bits[pos/8] |= byte(a >> 8) if b := byte(a); b != 0 { - // If the bit-setting affects the neigbouring byte, we can assign - no need to OR it, + // If the bit-setting affects the neighbouring byte, we can assign - no need to OR it, // since it's the first write to that byte bits[pos/8+1] = b } From e3e0ce00e3cff868b578577686b10e956af89364 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Wed, 18 Aug 2021 13:38:49 +0200 Subject: [PATCH 09/11] core/vm: improve set8 and set16 a bit --- core/vm/analysis.go | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/core/vm/analysis.go b/core/vm/analysis.go index 812aa1e4833d..0434e5092ee0 100644 --- a/core/vm/analysis.go +++ b/core/vm/analysis.go @@ -83,18 +83,14 @@ func (bits bitvec) set7(pos uint64) { func (bits bitvec) set8(pos uint64) { a := byte(0xFF >> (pos % 8)) bits[pos/8] |= a - if ^a != 0 { - bits[pos/8+1] = ^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 - if ^a != 0 { - bits[pos/8+2] = ^a - } + bits[pos/8+2] = ^a } // codeSegment checks if the position is in a code segment. From 8e05e089c189d3f1e7c585801e107d402972dff8 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Wed, 18 Aug 2021 14:22:56 +0200 Subject: [PATCH 10/11] core/vm: reduce amount of code --- core/vm/analysis.go | 70 ++++++++++++--------------------------------- 1 file changed, 19 insertions(+), 51 deletions(-) diff --git a/core/vm/analysis.go b/core/vm/analysis.go index 0434e5092ee0..449cded2a896 100644 --- a/core/vm/analysis.go +++ b/core/vm/analysis.go @@ -16,6 +16,15 @@ package vm +const ( + set2BitsMask = uint16(0b1100_0000_0000_0000) + set3BitsMask = uint16(0b1110_0000_0000_0000) + set4BitsMask = uint16(0b1111_0000_0000_0000) + set5BitsMask = uint16(0b1111_1000_0000_0000) + set6BitsMask = uint16(0b1111_1100_0000_0000) + set7BitsMask = uint16(0b1111_1110_0000_0000) +) + // 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). @@ -25,13 +34,12 @@ var lookup = [8]byte{ 0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1, } -func (bits bitvec) set(pos uint64) { - //(*bits)[pos/8] |= 0x80 >> (pos % 8) +func (bits bitvec) set1(pos uint64) { bits[pos/8] |= lookup[pos%8] } -func (bits bitvec) set2(pos uint64) { - a := uint16(0b1100_0000_0000_0000) >> (pos % 8) +func (bits bitvec) setN(flag uint16, pos uint64) { + a := flag >> (pos % 8) bits[pos/8] |= byte(a >> 8) if b := byte(a); b != 0 { // If the bit-setting affects the neighbouring byte, we can assign - no need to OR it, @@ -40,46 +48,6 @@ func (bits bitvec) set2(pos uint64) { } } -func (bits bitvec) set3(pos uint64) { - a := uint16(0b1110_0000_0000_0000) >> (pos % 8) - bits[pos/8] |= byte(a >> 8) - if b := byte(a); b != 0 { - bits[pos/8+1] = b - } -} - -func (bits bitvec) set4(pos uint64) { - a := uint16(0b1111_0000_0000_0000) >> (pos % 8) - bits[pos/8] |= byte(a >> 8) - if b := byte(a); b != 0 { - bits[pos/8+1] = b - } -} - -func (bits bitvec) set5(pos uint64) { - a := uint16(0b1111_1000_0000_0000) >> (pos % 8) - bits[pos/8] |= byte(a >> 8) - if b := byte(a); b != 0 { - bits[pos/8+1] = b - } -} - -func (bits bitvec) set6(pos uint64) { - a := uint16(0b1111_1100_0000_0000) >> (pos % 8) - bits[pos/8] |= byte(a >> 8) - if b := byte(a); b != 0 { - bits[pos/8+1] = b - } -} - -func (bits bitvec) set7(pos uint64) { - a := uint16(0b1111_1110_0000_0000) >> (pos % 8) - bits[pos/8] |= byte(a >> 8) - if b := byte(a); b != 0 { - bits[pos/8+1] = b - } -} - func (bits bitvec) set8(pos uint64) { a := byte(0xFF >> (pos % 8)) bits[pos/8] |= a @@ -130,25 +98,25 @@ func codeBitmapInternal(code, bits bitvec) bitvec { } switch numbits { case 1: - bits.set(pc) + bits.set1(pc) pc += 1 case 2: - bits.set2(pc) + bits.setN(set2BitsMask, pc) pc += 2 case 3: - bits.set3(pc) + bits.setN(set3BitsMask, pc) pc += 3 case 4: - bits.set4(pc) + bits.setN(set4BitsMask, pc) pc += 4 case 5: - bits.set5(pc) + bits.setN(set5BitsMask, pc) pc += 5 case 6: - bits.set6(pc) + bits.setN(set6BitsMask, pc) pc += 6 case 7: - bits.set7(pc) + bits.setN(set7BitsMask, pc) pc += 7 } } From 4d4879cafd1b3c906fc184a8c4a357137465128f Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Wed, 18 Aug 2021 13:34:52 +0200 Subject: [PATCH 11/11] core/vm: optimize byte copying --- core/vm/instructions.go | 4 ++++ core/vm/interpreter.go | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/core/vm/instructions.go b/core/vm/instructions.go index f7ef2f900e20..6c8c6e6e6fa1 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -669,6 +669,7 @@ func opCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byt } stack.push(&temp) if err == nil || err == ErrExecutionReverted { + ret = common.CopyBytes(ret) scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } scope.Contract.Gas += returnGas @@ -703,6 +704,7 @@ func opCallCode(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([ } stack.push(&temp) if err == nil || err == ErrExecutionReverted { + ret = common.CopyBytes(ret) scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } scope.Contract.Gas += returnGas @@ -730,6 +732,7 @@ func opDelegateCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext } stack.push(&temp) if err == nil || err == ErrExecutionReverted { + ret = common.CopyBytes(ret) scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } scope.Contract.Gas += returnGas @@ -757,6 +760,7 @@ func opStaticCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) } stack.push(&temp) if err == nil || err == ErrExecutionReverted { + ret = common.CopyBytes(ret) scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } scope.Contract.Gas += returnGas diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 9cf0c4e2c1e0..9fb83799c98c 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -262,7 +262,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( // if the operation clears the return data (e.g. it has returning data) // set the last return to the result of the operation. if operation.returns { - in.returnData = common.CopyBytes(res) + in.returnData = res } switch {