1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 19 import java.util.Iterator; 20 21 import org.apache.bcel.Repository; 22 import org.apache.bcel.classfile.JavaClass; 23 import org.apache.bcel.classfile.Method; 24 import org.apache.bcel.generic.ConstantPoolGen; 25 import org.apache.bcel.generic.InstructionHandle; 26 import org.apache.bcel.generic.InstructionList; 27 import org.apache.bcel.generic.InstructionTargeter; 28 import org.apache.bcel.generic.MethodGen; 29 import org.apache.bcel.generic.TargetLostException; 30 import org.apache.bcel.util.InstructionFinder; 31 32 /** 33 * Remove NOPs from given class 34 * 35 * @version $Id$ 36 */ 37 public class Peephole { 38 main(String[] argv)39 public static void main(String[] argv) { 40 try { 41 // Load the class from CLASSPATH. 42 JavaClass clazz = Repository.lookupClass(argv[0]); 43 Method[] methods = clazz.getMethods(); 44 ConstantPoolGen cp = new ConstantPoolGen(clazz.getConstantPool()); 45 46 for (int i = 0; i < methods.length; i++) { 47 if (!(methods[i].isAbstract() || methods[i].isNative())) { 48 MethodGen mg = new MethodGen(methods[i], clazz.getClassName(), cp); 49 Method stripped = removeNOPs(mg); 50 51 if (stripped != null) { 52 methods[i] = stripped; // Overwrite with stripped method 53 } 54 } 55 } 56 57 // Dump the class to <class name>_.class 58 clazz.setConstantPool(cp.getFinalConstantPool()); 59 clazz.dump(clazz.getClassName() + "_.class"); 60 } catch (Exception e) { 61 e.printStackTrace(); 62 } 63 } 64 removeNOPs(MethodGen mg)65 private static Method removeNOPs(MethodGen mg) { 66 InstructionList il = mg.getInstructionList(); 67 InstructionFinder f = new InstructionFinder(il); 68 String pat = "NOP+"; // Find at least one NOP 69 InstructionHandle next = null; 70 int count = 0; 71 72 for (Iterator<InstructionHandle[]> e = f.search(pat); e.hasNext(); ) { 73 InstructionHandle[] match = e.next(); 74 InstructionHandle first = match[0]; 75 InstructionHandle last = match[match.length - 1]; 76 77 // Some nasty Java compilers may add NOP at end of method. 78 if ((next = last.getNext()) == null) { 79 break; 80 } 81 82 count += match.length; 83 84 // Delete NOPs and redirect any references to them to the following (non-nop) instruction. 85 try { 86 il.delete(first, last); 87 } catch (TargetLostException e2) { 88 for (InstructionHandle target : e2.getTargets()) { 89 for (InstructionTargeter targeter : target.getTargeters()) { 90 targeter.updateTarget(target, next); 91 } 92 } 93 } 94 } 95 96 Method m = null; 97 98 if (count > 0) { 99 System.out.println("Removed " + count + " NOP instructions from method " + mg.getName()); 100 m = mg.getMethod(); 101 } 102 103 il.dispose(); // Reuse instruction handles 104 return m; 105 } 106 } 107