1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.bcel.util;
19
20 import java.util.ArrayList;
21 import java.util.HashMap;
22 import java.util.Iterator;
23 import java.util.List;
24 import java.util.Locale;
25 import java.util.Map;
26 import java.util.regex.Matcher;
27 import java.util.regex.Pattern;
28
29 import org.apache.bcel.Constants;
30 import org.apache.bcel.generic.ClassGenException;
31 import org.apache.bcel.generic.Instruction;
32 import org.apache.bcel.generic.InstructionHandle;
33 import org.apache.bcel.generic.InstructionList;
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69 public class InstructionFinder {
70
71 private static final int OFFSET = 32767;
72
73
74 private static final int NO_OPCODES = 256;
75
76 private static final Map<String, String> map = new HashMap<String, String>();
77 private InstructionList il;
78 private String il_string;
79
80 private InstructionHandle[] handles;
81
82
83
84
85
86
87
88 public InstructionFinder(InstructionList il) {
89 this.il = il;
90 reread();
91 }
92
93
94
95
96
97
98 public final void reread() {
99 int size = il.getLength();
100 char[] buf = new char[size];
101
102 handles = il.getInstructionHandles();
103
104 for (int i = 0; i < size; i++) {
105 buf[i] = makeChar(handles[i].getInstruction().getOpcode());
106 }
107 il_string = new String(buf);
108 }
109
110
111
112
113
114
115
116
117
118 private static final String mapName( String pattern ) {
119 String result = map.get(pattern);
120 if (result != null) {
121 return result;
122 }
123 for (short i = 0; i < NO_OPCODES; i++) {
124 if (pattern.equals(Constants.OPCODE_NAMES[i])) {
125 return "" + makeChar(i);
126 }
127 }
128 throw new RuntimeException("Instruction unknown: " + pattern);
129 }
130
131
132
133
134
135
136
137
138
139
140
141 private static final String compilePattern( String pattern ) {
142
143 String lower = pattern.toLowerCase(Locale.ENGLISH);
144 StringBuilder buf = new StringBuilder();
145 int size = pattern.length();
146 for (int i = 0; i < size; i++) {
147 char ch = lower.charAt(i);
148 if (Character.isLetterOrDigit(ch)) {
149 StringBuilder name = new StringBuilder();
150 while ((Character.isLetterOrDigit(ch) || ch == '_') && i < size) {
151 name.append(ch);
152 if (++i < size) {
153 ch = lower.charAt(i);
154 } else {
155 break;
156 }
157 }
158 i--;
159 buf.append(mapName(name.toString()));
160 } else if (!Character.isWhitespace(ch)) {
161 buf.append(ch);
162 }
163 }
164 return buf.toString();
165 }
166
167
168
169
170
171 private InstructionHandle[] getMatch( int matched_from, int match_length ) {
172 InstructionHandle[] match = new InstructionHandle[match_length];
173 System.arraycopy(handles, matched_from, match, 0, match_length);
174 return match;
175 }
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213 public final Iterator<InstructionHandle[]> search( String pattern, InstructionHandle from, CodeConstraint constraint ) {
214 String search = compilePattern(pattern);
215 int start = -1;
216 for (int i = 0; i < handles.length; i++) {
217 if (handles[i] == from) {
218 start = i;
219 break;
220 }
221 }
222 if (start == -1) {
223 throw new ClassGenException("Instruction handle " + from
224 + " not found in instruction list.");
225 }
226 Pattern regex = Pattern.compile(search);
227 List<InstructionHandle[]> matches = new ArrayList<InstructionHandle[]>();
228 Matcher matcher = regex.matcher(il_string);
229 while (start < il_string.length() && matcher.find(start)) {
230 int startExpr = matcher.start();
231 int endExpr = matcher.end();
232 int lenExpr = (endExpr - startExpr);
233 InstructionHandle[] match = getMatch(startExpr, lenExpr);
234 if ((constraint == null) || constraint.checkCode(match)) {
235 matches.add(match);
236 }
237 start = endExpr;
238 }
239 return matches.iterator();
240 }
241
242
243
244
245
246
247
248
249
250
251 public final Iterator<InstructionHandle[]> search( String pattern ) {
252 return search(pattern, il.getStart(), null);
253 }
254
255
256
257
258
259
260
261
262
263
264
265
266 public final Iterator<InstructionHandle[]> search( String pattern, InstructionHandle from ) {
267 return search(pattern, from, null);
268 }
269
270
271
272
273
274
275
276
277
278
279
280
281 public final Iterator<InstructionHandle[]> search( String pattern, CodeConstraint constraint ) {
282 return search(pattern, il.getStart(), constraint);
283 }
284
285
286
287
288
289 private static final char makeChar( short opcode ) {
290 return (char) (opcode + OFFSET);
291 }
292
293
294
295
296
297 public final InstructionList getInstructionList() {
298 return il;
299 }
300
301
302
303
304
305
306
307 public static interface CodeConstraint {
308
309
310
311
312
313
314 public boolean checkCode( InstructionHandle[] match );
315 }
316
317
318 static {
319 map.put("arithmeticinstruction","(irem|lrem|iand|ior|ineg|isub|lneg|fneg|fmul|ldiv|fadd|lxor|frem|idiv|land|ixor|ishr|fsub|lshl|fdiv|iadd|lor|dmul|lsub|ishl|imul|lmul|lushr|dneg|iushr|lshr|ddiv|drem|dadd|ladd|dsub)");
320 map.put("invokeinstruction", "(invokevirtual|invokeinterface|invokestatic|invokespecial)");
321 map.put("arrayinstruction", "(baload|aastore|saload|caload|fastore|lastore|iaload|castore|iastore|aaload|bastore|sastore|faload|laload|daload|dastore)");
322 map.put("gotoinstruction", "(goto|goto_w)");
323 map.put("conversioninstruction", "(d2l|l2d|i2s|d2i|l2i|i2b|l2f|d2f|f2i|i2d|i2l|f2d|i2c|f2l|i2f)");
324 map.put("localvariableinstruction","(fstore|iinc|lload|dstore|dload|iload|aload|astore|istore|fload|lstore)");
325 map.put("loadinstruction", "(fload|dload|lload|iload|aload)");
326 map.put("fieldinstruction", "(getfield|putstatic|getstatic|putfield)");
327 map.put("cpinstruction", "(ldc2_w|invokeinterface|multianewarray|putstatic|instanceof|getstatic|checkcast|getfield|invokespecial|ldc_w|invokestatic|invokevirtual|putfield|ldc|new|anewarray)");
328 map.put("stackinstruction", "(dup2|swap|dup2_x2|pop|pop2|dup|dup2_x1|dup_x2|dup_x1)");
329 map.put("branchinstruction", "(ifle|if_acmpne|if_icmpeq|if_acmpeq|ifnonnull|goto_w|iflt|ifnull|if_icmpne|tableswitch|if_icmple|ifeq|if_icmplt|jsr_w|if_icmpgt|ifgt|jsr|goto|ifne|ifge|lookupswitch|if_icmpge)");
330 map.put("returninstruction", "(lreturn|ireturn|freturn|dreturn|areturn|return)");
331 map.put("storeinstruction", "(istore|fstore|dstore|astore|lstore)");
332 map.put("select", "(tableswitch|lookupswitch)");
333 map.put("ifinstruction", "(ifeq|ifgt|if_icmpne|if_icmpeq|ifge|ifnull|ifne|if_icmple|if_icmpge|if_acmpeq|if_icmplt|if_acmpne|ifnonnull|iflt|if_icmpgt|ifle)");
334 map.put("jsrinstruction", "(jsr|jsr_w)");
335 map.put("variablelengthinstruction", "(tableswitch|jsr|goto|lookupswitch)");
336 map.put("unconditionalbranch", "(goto|jsr|jsr_w|athrow|goto_w)");
337 map.put("constantpushinstruction", "(dconst|bipush|sipush|fconst|iconst|lconst)");
338 map.put("typedinstruction", "(imul|lsub|aload|fload|lor|new|aaload|fcmpg|iand|iaload|lrem|idiv|d2l|isub|dcmpg|dastore|ret|f2d|f2i|drem|iinc|i2c|checkcast|frem|lreturn|astore|lushr|daload|dneg|fastore|istore|lshl|ldiv|lstore|areturn|ishr|ldc_w|invokeinterface|aastore|lxor|ishl|l2d|i2f|return|faload|sipush|iushr|caload|instanceof|invokespecial|putfield|fmul|ireturn|laload|d2f|lneg|ixor|i2l|fdiv|lastore|multianewarray|i2b|getstatic|i2d|putstatic|fcmpl|saload|ladd|irem|dload|jsr_w|dconst|dcmpl|fsub|freturn|ldc|aconst_null|castore|lmul|ldc2_w|dadd|iconst|f2l|ddiv|dstore|land|jsr|anewarray|dmul|bipush|dsub|sastore|d2i|i2s|lshr|iadd|l2i|lload|bastore|fstore|fneg|iload|fadd|baload|fconst|ior|ineg|dreturn|l2f|lconst|getfield|invokevirtual|invokestatic|iastore)");
339 map.put("popinstruction", "(fstore|dstore|pop|pop2|astore|putstatic|istore|lstore)");
340 map.put("allocationinstruction", "(multianewarray|new|anewarray|newarray)");
341 map.put("indexedinstruction", "(lload|lstore|fload|ldc2_w|invokeinterface|multianewarray|astore|dload|putstatic|instanceof|getstatic|checkcast|getfield|invokespecial|dstore|istore|iinc|ldc_w|ret|fstore|invokestatic|iload|putfield|invokevirtual|ldc|new|aload|anewarray)");
342 map.put("pushinstruction", "(dup|lload|dup2|bipush|fload|ldc2_w|sipush|lconst|fconst|dload|getstatic|ldc_w|aconst_null|dconst|iload|ldc|iconst|aload)");
343 map.put("stackproducer", "(imul|lsub|aload|fload|lor|new|aaload|fcmpg|iand|iaload|lrem|idiv|d2l|isub|dcmpg|dup|f2d|f2i|drem|i2c|checkcast|frem|lushr|daload|dneg|lshl|ldiv|ishr|ldc_w|invokeinterface|lxor|ishl|l2d|i2f|faload|sipush|iushr|caload|instanceof|invokespecial|fmul|laload|d2f|lneg|ixor|i2l|fdiv|getstatic|i2b|swap|i2d|dup2|fcmpl|saload|ladd|irem|dload|jsr_w|dconst|dcmpl|fsub|ldc|arraylength|aconst_null|tableswitch|lmul|ldc2_w|iconst|dadd|f2l|ddiv|land|jsr|anewarray|dmul|bipush|dsub|d2i|newarray|i2s|lshr|iadd|lload|l2i|fneg|iload|fadd|baload|fconst|lookupswitch|ior|ineg|lconst|l2f|getfield|invokevirtual|invokestatic)");
344 map.put("stackconsumer", "(imul|lsub|lor|iflt|fcmpg|if_icmpgt|iand|ifeq|if_icmplt|lrem|ifnonnull|idiv|d2l|isub|dcmpg|dastore|if_icmpeq|f2d|f2i|drem|i2c|checkcast|frem|lreturn|astore|lushr|pop2|monitorexit|dneg|fastore|istore|lshl|ldiv|lstore|areturn|if_icmpge|ishr|monitorenter|invokeinterface|aastore|lxor|ishl|l2d|i2f|return|iushr|instanceof|invokespecial|fmul|ireturn|d2f|lneg|ixor|pop|i2l|ifnull|fdiv|lastore|i2b|if_acmpeq|ifge|swap|i2d|putstatic|fcmpl|ladd|irem|dcmpl|fsub|freturn|ifgt|castore|lmul|dadd|f2l|ddiv|dstore|land|if_icmpne|if_acmpne|dmul|dsub|sastore|ifle|d2i|i2s|lshr|iadd|l2i|bastore|fstore|fneg|fadd|ior|ineg|ifne|dreturn|l2f|if_icmple|getfield|invokevirtual|invokestatic|iastore)");
345 map.put("exceptionthrower","(irem|lrem|laload|putstatic|baload|dastore|areturn|getstatic|ldiv|anewarray|iastore|castore|idiv|saload|lastore|fastore|putfield|lreturn|caload|getfield|return|aastore|freturn|newarray|instanceof|multianewarray|athrow|faload|iaload|aaload|dreturn|monitorenter|checkcast|bastore|arraylength|new|invokevirtual|sastore|ldc_w|ireturn|invokespecial|monitorexit|invokeinterface|ldc|invokestatic|daload)");
346 map.put("loadclass", "(multianewarray|invokeinterface|instanceof|invokespecial|putfield|checkcast|putstatic|invokevirtual|new|getstatic|invokestatic|getfield|anewarray)");
347 map.put("instructiontargeter", "(ifle|if_acmpne|if_icmpeq|if_acmpeq|ifnonnull|goto_w|iflt|ifnull|if_icmpne|tableswitch|if_icmple|ifeq|if_icmplt|jsr_w|if_icmpgt|ifgt|jsr|goto|ifne|ifge|lookupswitch|if_icmpge)");
348
349 map.put("if_icmp", "(if_icmpne|if_icmpeq|if_icmple|if_icmpge|if_icmplt|if_icmpgt)");
350 map.put("if_acmp", "(if_acmpeq|if_acmpne)");
351 map.put("if", "(ifeq|ifne|iflt|ifge|ifgt|ifle)");
352
353 map.put("iconst", precompile(Constants.ICONST_0, Constants.ICONST_5, Constants.ICONST_M1));
354 map.put("lconst", new String(new char[] { '(', makeChar(Constants.LCONST_0), '|', makeChar(Constants.LCONST_1), ')' }));
355 map.put("dconst", new String(new char[] { '(', makeChar(Constants.DCONST_0), '|', makeChar(Constants.DCONST_1), ')' }));
356 map.put("fconst", new String(new char[] { '(', makeChar(Constants.FCONST_0), '|', makeChar(Constants.FCONST_1), ')' }));
357 map.put("iload", precompile(Constants.ILOAD_0, Constants.ILOAD_3, Constants.ILOAD));
358 map.put("dload", precompile(Constants.DLOAD_0, Constants.DLOAD_3, Constants.DLOAD));
359 map.put("fload", precompile(Constants.FLOAD_0, Constants.FLOAD_3, Constants.FLOAD));
360 map.put("aload", precompile(Constants.ALOAD_0, Constants.ALOAD_3, Constants.ALOAD));
361 map.put("istore", precompile(Constants.ISTORE_0, Constants.ISTORE_3, Constants.ISTORE));
362 map.put("dstore", precompile(Constants.DSTORE_0, Constants.DSTORE_3, Constants.DSTORE));
363 map.put("fstore", precompile(Constants.FSTORE_0, Constants.FSTORE_3, Constants.FSTORE));
364 map.put("astore", precompile(Constants.ASTORE_0, Constants.ASTORE_3, Constants.ASTORE));
365
366 for (String key : map.keySet()) {
367 String value = map.get(key);
368 char ch = value.charAt(1);
369 if (ch < OFFSET) {
370 map.put(key, compilePattern(value));
371
372 }
373 }
374
375 StringBuilder buf = new StringBuilder("(");
376 for (short i = 0; i < NO_OPCODES; i++) {
377 if (Constants.NO_OF_OPERANDS[i] != Constants.UNDEFINED) {
378
379
380
381 buf.append(makeChar(i));
382 if (i < NO_OPCODES - 1) {
383 buf.append('|');
384 }
385 }
386 }
387 buf.append(')');
388 map.put("instruction", buf.toString());
389 }
390
391
392 private static String precompile( short from, short to, short extra ) {
393 StringBuilder buf = new StringBuilder("(");
394 for (short i = from; i <= to; i++) {
395 buf.append(makeChar(i));
396 buf.append('|');
397 }
398 buf.append(makeChar(extra));
399 buf.append(")");
400 return buf.toString();
401 }
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428 }