00001 package de.fub.bytecode.generic;
00002
00003 import de.fub.bytecode.Constants;
00004 import de.fub.bytecode.classfile.*;
00005 import gnu.regexp.*;
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 public class FindPattern {
00024 private static final int OFFSET = 32767;
00025 private static final int NO_OPCODES = 256;
00026
00027 private static final String[] patterns = {
00028 "instruction", "branchinstruction", "if_icmp__", "if__", "push",
00029 "iload__", "aload__", "fload__", "dload__", "lload__",
00030 "istore__", "astore__", "fstore__", "dstore__", "lstore__",
00031 "invokeinstruction", "returninstruction", "ifinstruction"
00032 };
00033
00034 private static String[] pattern_map;
00035
00036 private InstructionList il;
00037 private String il_string;
00038 private InstructionHandle[] handles;
00039 private int match_length;
00040 private int matched_from;
00041
00042
00043
00044 static {
00045
00046 String instruction_pattern, binstruction_pattern, if_icmp_pattern, if_pattern,
00047 push_pattern, iload_pattern, aload_pattern, fload_pattern,
00048 dload_pattern, lload_pattern, istore_pattern, astore_pattern,
00049 fstore_pattern, dstore_pattern, lstore_pattern, invoke_pattern, return_pattern,
00050 if_pattern2;
00051
00052 StringBuffer buf;
00053
00054
00055
00056 buf = new StringBuffer("(");
00057
00058 for(short i=0; i < NO_OPCODES; i++) {
00059 if(Constants.NO_OF_OPERANDS[i] != Constants.UNDEFINED) {
00060 buf.append(makeChar(i));
00061
00062 if(i < NO_OPCODES - 1)
00063 buf.append('|');
00064 }
00065 }
00066 buf.append(')');
00067
00068 instruction_pattern = buf.toString();
00069
00070
00071
00072 appendPatterns(buf = new StringBuffer("("), Constants.IFEQ, Constants.LOOKUPSWITCH);
00073 buf.append('|');
00074 appendPatterns(buf, Constants.IFNULL, Constants.JSR_W);
00075 buf.append(')');
00076 binstruction_pattern = buf.toString();
00077
00078
00079
00080 appendPatterns(buf = new StringBuffer("("), Constants.IF_ICMPEQ, Constants.IF_ICMPLE);
00081 buf.append(')');
00082 if_icmp_pattern = buf.toString();
00083
00084
00085
00086 appendPatterns(buf = new StringBuffer("("), Constants.IFEQ, Constants.IFLE);
00087 buf.append(')');
00088 if_pattern = buf.toString();
00089
00090
00091
00092 appendPatterns(buf = new StringBuffer("("), Constants.ACONST_NULL,Constants. LDC2_W);
00093 buf.append(')');
00094 push_pattern = buf.toString();
00095
00096
00097
00098 appendPatterns(buf = new StringBuffer("("), Constants.ILOAD_0, Constants.ILOAD_3);
00099 buf.append('|');
00100 buf.append(makeChar(Constants.ILOAD));
00101 buf.append(')');
00102 iload_pattern = buf.toString();
00103
00104
00105
00106 appendPatterns(buf = new StringBuffer("("), Constants.ALOAD_0, Constants.ALOAD_3);
00107 buf.append('|');
00108 buf.append(makeChar(Constants.ALOAD));
00109 buf.append(')');
00110 aload_pattern = buf.toString();
00111
00112
00113
00114 appendPatterns(buf = new StringBuffer("("), Constants.FLOAD_0, Constants.FLOAD_3);
00115 buf.append('|');
00116 buf.append(makeChar(Constants.FLOAD));
00117 buf.append(')');
00118 fload_pattern = buf.toString();
00119
00120
00121
00122 appendPatterns(buf = new StringBuffer("("), Constants.DLOAD_0, Constants.DLOAD_3);
00123 buf.append('|');
00124 buf.append(makeChar(Constants.DLOAD));
00125 buf.append(')');
00126 dload_pattern = buf.toString();
00127
00128
00129
00130 appendPatterns(buf = new StringBuffer("("), Constants.LLOAD_0, Constants.LLOAD_3);
00131 buf.append('|');
00132 buf.append(makeChar(Constants.LLOAD));
00133 buf.append(')');
00134 lload_pattern = buf.toString();
00135
00136
00137
00138 appendPatterns(buf = new StringBuffer("("), Constants.ISTORE_0, Constants.ISTORE_3);
00139 buf.append('|');
00140 buf.append(makeChar(Constants.ISTORE));
00141 buf.append(')');
00142 istore_pattern = buf.toString();
00143
00144
00145
00146 appendPatterns(buf = new StringBuffer("("), Constants.ASTORE_0, Constants.ASTORE_3);
00147 buf.append('|');
00148 buf.append(makeChar(Constants.ASTORE));
00149 buf.append(')');
00150 astore_pattern = buf.toString();
00151
00152
00153
00154 appendPatterns(buf = new StringBuffer("("), Constants.FSTORE_0, Constants.FSTORE_3);
00155 buf.append('|');
00156 buf.append(makeChar(Constants.FSTORE));
00157 buf.append(')');
00158 fstore_pattern = buf.toString();
00159
00160
00161
00162 appendPatterns(buf = new StringBuffer("("), Constants.DSTORE_0, Constants.DSTORE_3);
00163 buf.append('|');
00164 buf.append(makeChar(Constants.DSTORE));
00165 buf.append(')');
00166 dstore_pattern = buf.toString();
00167
00168
00169
00170 appendPatterns(buf = new StringBuffer("("), Constants.LSTORE_0, Constants.LSTORE_3);
00171 buf.append('|');
00172 buf.append(makeChar(Constants.LSTORE));
00173 buf.append(')');
00174 lstore_pattern = buf.toString();
00175
00176
00177
00178 appendPatterns(buf = new StringBuffer("("), Constants.INVOKEVIRTUAL, Constants.INVOKEINTERFACE);
00179 buf.append(')');
00180 invoke_pattern = buf.toString();
00181
00182
00183
00184 appendPatterns(buf = new StringBuffer("("), Constants.IRETURN, Constants.RETURN);
00185 buf.append(')');
00186 return_pattern = buf.toString();
00187
00188
00189
00190 appendPatterns(buf = new StringBuffer("("), Constants.IFEQ, Constants.IF_ACMPNE);
00191 buf.append('|');
00192 buf.append(makeChar(Constants.IFNULL));
00193 buf.append('|');
00194 buf.append(makeChar(Constants.IFNONNULL));
00195 buf.append(')');
00196 if_pattern2 = buf.toString();
00197
00198 pattern_map = new String[] {
00199 instruction_pattern, binstruction_pattern, if_icmp_pattern, if_pattern,
00200 push_pattern, iload_pattern, aload_pattern, fload_pattern,
00201 dload_pattern, lload_pattern, istore_pattern, astore_pattern,
00202 fstore_pattern, dstore_pattern, lstore_pattern, invoke_pattern, return_pattern,
00203 if_pattern2
00204 };
00205 }
00206
00207
00208
00209
00210 public FindPattern(InstructionList il) {
00211 this.il = il;
00212 reread();
00213 }
00214
00215
00216
00217 private final static void appendPatterns(StringBuffer buf, short from, short to) {
00218 for(short i=from; i <= to; i++) {
00219 buf.append(makeChar(i));
00220
00221 if(i < to)
00222 buf.append('|');
00223 }
00224 }
00225
00226
00227
00228 public final InstructionList getInstructionList() { return il; }
00229
00230
00231
00232 public final InstructionHandle[] getMatch() {
00233 if(match_length == -1)
00234 throw new ClassGenException("Nothing matched.");
00235
00236 InstructionHandle[] match = new InstructionHandle[match_length];
00237 System.arraycopy(handles, matched_from, match, 0, match_length);
00238
00239 return match;
00240 }
00241
00242
00243
00244 public final int getMatchLength() { return match_length; }
00245
00246
00247
00248
00249
00250
00251
00252 private static final String getPattern(String pattern) {
00253
00254 for(int i=0; i < patterns.length; i++) {
00255 if(pattern.equals(patterns[i]))
00256 return pattern_map[i];
00257 }
00258
00259
00260 for(short i=0; i < NO_OPCODES; i++)
00261 if(pattern.equals(Constants.OPCODE_NAMES[i]))
00262 return new String(new char[] { makeChar(i) });
00263
00264 return null;
00265 }
00266
00267
00268
00269 private static final char makeChar(short opcode) {
00270 return (char)(opcode + OFFSET);
00271 }
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281 private static final String makePattern(String pattern) {
00282 String lower = pattern.toLowerCase();
00283 StringBuffer buf = new StringBuffer();
00284 int size = pattern.length();
00285 boolean in_pattern = false;
00286 StringBuffer collect = null;
00287
00288 try {
00289 for(int i=0; i < size; i++) {
00290 char ch = lower.charAt(i);
00291
00292 switch(ch) {
00293 case '`':
00294 if(in_pattern)
00295 throw new ClassGenException("` within `' block.");
00296
00297 collect = new StringBuffer();
00298 in_pattern = true;
00299 break;
00300
00301 case '\'':
00302 if(!in_pattern)
00303 throw new ClassGenException("' without starting `.");
00304
00305 in_pattern = false;
00306 String str = collect.toString();
00307 String pat = getPattern(str);
00308
00309 if(pat == null)
00310 throw new ClassGenException("Unknown instruction pattern: \"" + str +
00311 "\"" + " at index " + i);
00312 buf.append(pat);
00313 break;
00314
00315 default:
00316 if(in_pattern)
00317 collect.append(ch);
00318 else
00319 buf.append(ch);
00320 }
00321 }
00322 } catch(StringIndexOutOfBoundsException e) {
00323 e.printStackTrace();
00324 }
00325
00326 return buf.toString();
00327 }
00328
00329
00330
00331 private static final String pattern2string(String pattern) {
00332 return pattern2string(pattern, true);
00333 }
00334 private static final String pattern2string(String pattern, boolean make_string) {
00335 StringBuffer buf = new StringBuffer();
00336
00337 for(int i=0; i < pattern.length(); i++) {
00338 char ch = pattern.charAt(i);
00339
00340 if(ch >= OFFSET) {
00341 if(make_string)
00342 buf.append(Constants.OPCODE_NAMES[ch - OFFSET]);
00343 else
00344 buf.append((int)(ch - OFFSET));
00345 }
00346 else
00347 buf.append(ch);
00348 }
00349
00350 return buf.toString();
00351 }
00352
00353
00354
00355 public final void reread() {
00356 int size = il.getLength();
00357 char[] buf = new char[size];
00358 handles = il.getInstructionHandles();
00359
00360 match_length = -1;
00361
00362
00363 for(int i=0; i < size; i++)
00364 buf[i] = makeChar(handles[i].getInstruction().getTag());
00365
00366 il_string = new String(buf);
00367 }
00368
00369
00370
00371
00372
00373
00374 public final InstructionHandle search(String pattern) {
00375 return search(pattern, il.getStart(), null);
00376 }
00377
00378
00379
00380
00381
00382
00383
00384
00385 public final InstructionHandle search(String pattern, CodeConstraint constraint) {
00386 return search(pattern, il.getStart(), constraint);
00387 }
00388
00389
00390
00391
00392
00393
00394
00395 public final InstructionHandle search(String pattern, InstructionHandle from) {
00396 return search(pattern, from, null);
00397 }
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432 public final InstructionHandle search(String pattern, InstructionHandle from,
00433 CodeConstraint constraint) {
00434 String search = makePattern(pattern);
00435 int start = -1;
00436
00437 match_length = matched_from = -1;
00438
00439 for(int i=0; i < handles.length; i++) {
00440 if(handles[i] == from) {
00441 start = i;
00442 break;
00443 }
00444 }
00445
00446 if(start == -1)
00447 throw new ClassGenException("Instruction handle " + from +
00448 " not found in instruction list.");
00449
00450 try {
00451 RE regex = new RE(search);
00452 REMatch r = regex.getMatch(il_string, start);
00453
00454 if(r != null) {
00455 matched_from = r.getStartIndex();
00456 match_length = (r.getEndIndex() - matched_from);
00457
00458 if((constraint == null) || constraint.checkCode(getMatch()))
00459 return handles[matched_from];
00460 }
00461 } catch(REException e) {
00462 System.err.println(e);
00463 }
00464
00465 return null;
00466 }
00467
00468
00469
00470
00471
00472
00473 public final void setInstructionList(InstructionList il) {
00474 this.il = il;
00475 reread();
00476 }
00477 }