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