16
16
17
17
package vm
18
18
19
+ const (
20
+ set2BitsMask = uint16 (0b1100_0000_0000_0000 )
21
+ set3BitsMask = uint16 (0b1110_0000_0000_0000 )
22
+ set4BitsMask = uint16 (0b1111_0000_0000_0000 )
23
+ set5BitsMask = uint16 (0b1111_1000_0000_0000 )
24
+ set6BitsMask = uint16 (0b1111_1100_0000_0000 )
25
+ set7BitsMask = uint16 (0b1111_1110_0000_0000 )
26
+ )
27
+
19
28
// bitvec is a bit vector which maps bytes in a program.
20
29
// An unset bit means the byte is an opcode, a set bit means
21
30
// it's data (i.e. argument of PUSHxx).
22
31
type bitvec []byte
23
32
24
- func (bits * bitvec ) set (pos uint64 ) {
25
- (* bits )[pos / 8 ] |= 0x80 >> (pos % 8 )
33
+ var lookup = [8 ]byte {
34
+ 0x80 , 0x40 , 0x20 , 0x10 , 0x8 , 0x4 , 0x2 , 0x1 ,
35
+ }
36
+
37
+ func (bits bitvec ) set1 (pos uint64 ) {
38
+ bits [pos / 8 ] |= lookup [pos % 8 ]
39
+ }
40
+
41
+ func (bits bitvec ) setN (flag uint16 , pos uint64 ) {
42
+ a := flag >> (pos % 8 )
43
+ bits [pos / 8 ] |= byte (a >> 8 )
44
+ if b := byte (a ); b != 0 {
45
+ // If the bit-setting affects the neighbouring byte, we can assign - no need to OR it,
46
+ // since it's the first write to that byte
47
+ bits [pos / 8 + 1 ] = b
48
+ }
49
+ }
50
+
51
+ func (bits bitvec ) set8 (pos uint64 ) {
52
+ a := byte (0xFF >> (pos % 8 ))
53
+ bits [pos / 8 ] |= a
54
+ bits [pos / 8 + 1 ] = ^ a
26
55
}
27
- func (bits * bitvec ) set8 (pos uint64 ) {
28
- (* bits )[pos / 8 ] |= 0xFF >> (pos % 8 )
29
- (* bits )[pos / 8 + 1 ] |= ^ (0xFF >> (pos % 8 ))
56
+
57
+ func (bits bitvec ) set16 (pos uint64 ) {
58
+ a := byte (0xFF >> (pos % 8 ))
59
+ bits [pos / 8 ] |= a
60
+ bits [pos / 8 + 1 ] = 0xFF
61
+ bits [pos / 8 + 2 ] = ^ a
30
62
}
31
63
32
64
// codeSegment checks if the position is in a code segment.
@@ -40,22 +72,52 @@ func codeBitmap(code []byte) bitvec {
40
72
// ends with a PUSH32, the algorithm will push zeroes onto the
41
73
// bitvector outside the bounds of the actual code.
42
74
bits := make (bitvec , len (code )/ 8 + 1 + 4 )
75
+ return codeBitmapInternal (code , bits )
76
+ }
77
+
78
+ // codeBitmapInternal is the internal implementation of codeBitmap.
79
+ // It exists for the purpose of being able to run benchmark tests
80
+ // without dynamic allocations affecting the results.
81
+ func codeBitmapInternal (code , bits bitvec ) bitvec {
43
82
for pc := uint64 (0 ); pc < uint64 (len (code )); {
44
83
op := OpCode (code [pc ])
45
-
46
- if op >= PUSH1 && op <= PUSH32 {
47
- numbits := op - PUSH1 + 1
48
- pc ++
84
+ pc ++
85
+ if op < PUSH1 || op > PUSH32 {
86
+ continue
87
+ }
88
+ numbits := op - PUSH1 + 1
89
+ if numbits >= 8 {
90
+ for ; numbits >= 16 ; numbits -= 16 {
91
+ bits .set16 (pc )
92
+ pc += 16
93
+ }
49
94
for ; numbits >= 8 ; numbits -= 8 {
50
- bits .set8 (pc ) // 8
95
+ bits .set8 (pc )
51
96
pc += 8
52
97
}
53
- for ; numbits > 0 ; numbits -- {
54
- bits .set (pc )
55
- pc ++
56
- }
57
- } else {
58
- pc ++
98
+ }
99
+ switch numbits {
100
+ case 1 :
101
+ bits .set1 (pc )
102
+ pc += 1
103
+ case 2 :
104
+ bits .setN (set2BitsMask , pc )
105
+ pc += 2
106
+ case 3 :
107
+ bits .setN (set3BitsMask , pc )
108
+ pc += 3
109
+ case 4 :
110
+ bits .setN (set4BitsMask , pc )
111
+ pc += 4
112
+ case 5 :
113
+ bits .setN (set5BitsMask , pc )
114
+ pc += 5
115
+ case 6 :
116
+ bits .setN (set6BitsMask , pc )
117
+ pc += 6
118
+ case 7 :
119
+ bits .setN (set7BitsMask , pc )
120
+ pc += 7
59
121
}
60
122
}
61
123
return bits
0 commit comments