View Javadoc
1 /* MethodTransformer.java */ 2 package org.quilt.cl; 3 4 import java.util.Hashtable; 5 import java.util.List; 6 7 import org.apache.bcel.classfile.*; 8 import org.apache.bcel.Constants; 9 import org.apache.bcel.generic.*; 10 import org.quilt.graph.*; 11 12 /*** 13 * Optionally preprocesses a method, optionally transforms 14 * its control flow graph, optionally postprocesses it. The list of 15 * preprocessors is applied in forward order before graph transformation. 16 * The corresponding list of postprocessors is applied in reverse order 17 * after graph transformation. 18 * 19 * @author <a href="jddixon@users.sourceforge.net">Jim Dixon</a> 20 */ 21 public class MethodTransformer { 22 23 /*** For passing application-specific data. XXX Not used, probably 24 * best dropped. */ 25 private Hashtable methodHash = new Hashtable(); 26 27 /*** Ordered list of method pre- and post-processors.*/ 28 private List mxf; 29 30 /*** Graph processors. */ 31 private List gxf; 32 33 /*** Main graph processor. */ 34 private GraphTransformer xformer; 35 36 /*** 37 * Sets up method transformer, saving MethodXformer vector here 38 * and passing GraphXformer vector to that transformer. 39 */ 40 public MethodTransformer( List mxf, List gxf) { 41 this.mxf = mxf; 42 this.gxf = gxf; 43 xformer = new GraphTransformer (gxf); 44 } 45 46 /*** 47 * Get a reference to the hash used to share data between this 48 * and other transformers. 49 */ 50 public Hashtable getMethodHash() { 51 return methodHash; 52 } 53 /*** 54 * Zero out a badly-behaved method Xformer. 55 * @param mxf The tranformer being killed. 56 * @param e The exception responsible. 57 */ 58 private void zapMethodXformer ( MethodXformer mxf, Exception e) { 59 System.err.println("WARNING: exception in " 60 + mxf.getName() + ": transformation will not be applied" ); 61 e.printStackTrace(); 62 mxf = null; 63 } 64 /*** 65 * <p>Transform a specific method, first applying preprocessors, 66 * then transforming the graph, then applying method postprocessors.</p> 67 * 68 * @param clazz The class to which the method belongs 69 * @param method The MethodGen being transformed. 70 */ 71 public MethodGen xform ( ClassGen clazz, Method orig ) { 72 if (orig == null) { 73 throw new IllegalArgumentException("null method"); 74 } 75 MethodGen method = new MethodGen (orig, clazz.getClassName(), 76 clazz.getConstantPool()); 77 // New instances of the MethodXformers. 78 MethodXformer [] xf = new MethodXformer[ mxf.size() ]; 79 80 // apply preprocessors in order 81 for (int i = 0; i < xf.length; i++) { 82 try { 83 xf[i] = (MethodXformer) ( 84 (mxf.get(i)).getClass().newInstance() ); 85 } catch (IllegalAccessException e) { 86 zapMethodXformer (xf[i], e); 87 } catch (InstantiationException e) { 88 zapMethodXformer (xf[i], e); 89 } 90 if (xf[i] != null && method != null) { 91 xf[i].preGraph (clazz, method); 92 } 93 } 94 // transform the graph 95 if (gxf.size() > 0 && method != null) { 96 InstructionList ilist = xformer.xform (clazz, method); 97 if (ilist == null) { 98 System.out.println("MethodTransformer.xformer: WARNING: " 99 + "xformer returned null instruction list"); 100 return null; 101 } 102 // Quilt 0.5 approach, turns out to be unnecessary; the 103 // exception handlers are based on instruction handles, 104 // which in turn contain references to the method's instructions, 105 // which remain valid while the graph is being transformed. 106 // 107 // XXX But we may want to allow handlers to be added or changed. 108 109 method.removeExceptionHandlers(); // new ones come from graph 110 111 //checkAndSetPos(ilist); 112 ilist.setPositions(true); 113 method.setInstructionList (ilist); 114 115 CodeExceptionGen [] cgs = xformer.getExceptionHandlers(); 116 for (int i = 0; i < cgs.length; i++) { 117 // DEBUG 118 System.out.println("adding exception " + i 119 + " to method " + method.getName() 120 + ": [" + cgs[i].getStartPC().getPosition() 121 + ".." + cgs[i].getEndPC().getPosition() 122 + "] --> " + cgs[i].getHandlerPC().getPosition() 123 ); 124 // END 125 126 method.addExceptionHandler ( 127 cgs[i].getStartPC(), cgs[i].getEndPC(), 128 cgs[i].getHandlerPC(), cgs[i].getCatchType() ); 129 } 130 method.removeNOPs(); 131 method.update(); // to be called after editing MethodGen 132 // during development, exceptions were thrown in setMaxStack 133 try { 134 method.setMaxStack(); 135 method.setMaxLocals(); 136 // method.stripAttributes(true); // Quilt 0.5 legacy 137 } catch (RuntimeException e) { 138 e.printStackTrace(); 139 System.out.println("GraphTransformer.xformer:\n" 140 + " EXCEPTION finishing method " + e); 141 throw e; 142 } 143 // // DEBUG ONLY /////////////////////////////////////////// 144 // dumpIList (method, "after fixups"); 145 // cgs = method.getExceptionHandlers(); 146 // dumpExceptionHandlers(method, "after fixups", cgs.length); 147 // ///////////////////////////////////////////////////////// 148 } 149 150 // apply postprocessors in reverse order 151 for (int i = xf.length-1; i >= 0; i--) { 152 if (xf[i] != null && method != null) { 153 xf[i].postGraph (clazz, method); 154 } 155 } 156 // IF THERE HAVE BEEN ANY FATAL ERRORS, SHOULD RETURN NULL 157 return method; 158 } 159 // UTILITY METHODS ////////////////////////////////////////////// 160 void dumpExceptionHandlers (MethodGen method, String where, int len) { 161 CodeExceptionGen handlers[] = method.getExceptionHandlers(); 162 if (handlers.length != len) { 163 System.out.println("EXPECTED " + len 164 + " exception handlers, found " + handlers.length); 165 } 166 if (handlers.length > 0) { 167 System.out.println("Exception handlers for method " 168 + method.getName() + " " + where + ":"); 169 170 for (int j = 0; j < handlers.length; j++) { 171 System.out.println(" " + j 172 + ": [" + handlers[j].getStartPC().getPosition() 173 + ".." + handlers[j].getEndPC().getPosition() 174 + "] --> " + handlers[j].getHandlerPC().getPosition() 175 ); 176 } 177 } 178 } 179 void dumpIList(MethodGen method, String where) { 180 InstructionList myList = method.getInstructionList(); 181 System.out.println( 182 "MethodTransformer: instruction list " + where + ":"); 183 int i = 0; 184 for (InstructionHandle ih = myList.getStart(); ih != null; 185 ih = ih.getNext() ) { 186 System.out.println( " " + (i++) + " " + ih); 187 } 188 } 189 }

This page was automatically generated by Maven