@@ -73,13 +73,95 @@ func (b *ByteCode) optimize(count int) (int, error) {
73
73
74
74
// Is there a branch INTO this pattern? If so, then it
75
75
// cannot be optimized.
76
- if branchTargetInPatter (b , idx , optimization , found ) {
76
+ for _ , i := range b .instructions {
77
+ if i .Operation > BranchInstructions {
78
+ destination := data .Int (i .Operand )
79
+ if destination >= idx && destination < idx + len (optimization .Pattern ) {
80
+ found = false
81
+
82
+ break
83
+ }
84
+ }
85
+ }
86
+
87
+ if ! found {
77
88
continue
78
89
}
79
90
80
91
// Search each instruction in the pattern to see if it matches
81
92
// with the instruction stream we are positioned at.
82
- found = doesPatternMatch (optimization , b , idx , found , operandValues , registers )
93
+ for sourceIdx , sourceInstruction := range optimization .Pattern {
94
+ if b .nextAddress <= idx + sourceIdx {
95
+ found = false
96
+
97
+ // This optimization can't fit because we're too near the end
98
+ // so go on to the next optimization.
99
+ break
100
+ }
101
+
102
+ i := b .instructions [idx + sourceIdx ]
103
+
104
+ // If the source instruction requires an empty operand and the operand isn't nil,
105
+ // then we skip this optimization.
106
+ if _ , isEmpty := sourceInstruction .Operand .(empty ); isEmpty && i .Operand != nil {
107
+ found = false
108
+
109
+ // This optimization didn't match; go to next optimization
110
+ break
111
+ }
112
+
113
+ if sourceInstruction .Operation != i .Operation {
114
+ found = false
115
+
116
+ // This optimization didn't match; go to next optimization
117
+ break
118
+ }
119
+
120
+ // Special type checks for specific operand patterns
121
+ if pattern , ok := sourceInstruction .Operand .(placeholder ); ok {
122
+ if pattern .MustBeString {
123
+ if _ , ok := i .Operand .(string ); ! ok {
124
+ found = false
125
+
126
+ break
127
+ }
128
+ }
129
+ }
130
+
131
+ // If the operands match between the instruction and the pattern,
132
+ // we're good and should keep going...
133
+ if reflect .DeepEqual (sourceInstruction .Operand , i .Operand ) {
134
+ continue
135
+ }
136
+
137
+ if token , ok := sourceInstruction .Operand .(placeholder ); ok {
138
+ value , inMap := operandValues [token .Name ]
139
+ if inMap {
140
+ if value .Value == i .Operand {
141
+ // no work to do
142
+ } else if i .Operand != sourceInstruction .Operand {
143
+ found = false
144
+
145
+ continue
146
+ }
147
+ } else {
148
+ switch token .Operation {
149
+ case OptCount :
150
+ increment := 1
151
+ if i .Operand != nil {
152
+ increment = data .Int (i .Operand )
153
+ }
154
+
155
+ registers [token .Register ] = data .Int (registers [token .Register ]) + increment
156
+
157
+ case optStore :
158
+ registers [token .Register ] = i .Operand
159
+ }
160
+
161
+ operandValues [token .Name ] = placeholder {Name : token .Name , Value : i .Operand }
162
+ }
163
+ }
164
+ }
83
165
84
166
// Does this optimization match?
85
167
if found {
@@ -159,97 +241,6 @@ func (b *ByteCode) optimize(count int) (int, error) {
159
241
return count , nil
160
242
}
161
243
162
- // Determine if the current operation is the start of this optimization pattern. Compares
163
- // the operation and operands, and ensures there is enough room to fit the pattern.
164
- func doesPatternMatch (optimization optimization , b * ByteCode , idx int , found bool , operandValues map [string ]placeholder , registers []interface {}) bool {
165
- for sourceIdx , sourceInstruction := range optimization .Pattern {
166
- // This optimization can't fit because we're too near the end
167
- // so go on to the next optimization.
168
- if b .nextAddress <= idx + sourceIdx {
169
- found = false
170
-
171
- break
172
- }
173
-
174
- i := b .instructions [idx + sourceIdx ]
175
-
176
- // If the source instruction requires an empty operand and the operand isn't nil,
177
- // then we skip this optimization.
178
- if _ , isEmpty := sourceInstruction .Operand .(empty ); isEmpty && i .Operand != nil {
179
- found = false
180
-
181
- break
182
- }
183
-
184
- // This optimization didn't match; go to next optimization
185
- if sourceInstruction .Operation != i .Operation {
186
- found = false
187
-
188
- break
189
- }
190
-
191
- // This optimization didn't match; go to next optimization
192
- if pattern , ok := sourceInstruction .Operand .(placeholder ); ok {
193
- if pattern .MustBeString {
194
- if _ , ok := i .Operand .(string ); ! ok {
195
- found = false
196
-
197
- break
198
- }
199
- }
200
- }
201
-
202
- if reflect .DeepEqual (sourceInstruction .Operand , i .Operand ) {
203
- continue
204
- }
205
-
206
- if token , ok := sourceInstruction .Operand .(placeholder ); ok {
207
- value , inMap := operandValues [token .Name ]
208
- if inMap {
209
- if value .Value == i .Operand {
210
-
211
- } else if i .Operand != sourceInstruction .Operand {
212
- found = false
213
-
214
- continue
215
- }
216
- } else {
217
- switch token .Operation {
218
- case OptCount :
219
- increment := 1
220
- if i .Operand != nil {
221
- increment = data .Int (i .Operand )
222
- }
223
-
224
- registers [token .Register ] = data .Int (registers [token .Register ]) + increment
225
-
226
- case optStore :
227
- registers [token .Register ] = i .Operand
228
- }
229
-
230
- operandValues [token .Name ] = placeholder {Name : token .Name , Value : i .Operand }
231
- }
232
- }
233
- }
234
-
235
- return found
236
- }
237
-
238
- func branchTargetInPatter (b * ByteCode , idx int , optimization optimization , found bool ) bool {
239
- for _ , i := range b .instructions {
240
- if i .Operation > BranchInstructions {
241
- destination := data .Int (i .Operand )
242
- if destination >= idx && destination < idx + len (optimization .Pattern ) {
243
- found = false
244
-
245
- break
246
- }
247
- }
248
- }
249
-
250
- return found
251
- }
252
-
253
244
func (b * ByteCode ) executeFragment (start , end int ) (interface {}, error ) {
254
245
fragment := New ("code fragment" )
255
246
0 commit comments