View Javadoc
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  package org.apache.bcel.util;
19  
20  import java.io.PrintWriter;
21  import java.util.ArrayList;
22  import java.util.HashMap;
23  import java.util.List;
24  import java.util.Locale;
25  import java.util.Map;
26  
27  import org.apache.bcel.Constants;
28  import org.apache.bcel.classfile.Utility;
29  import org.apache.bcel.generic.AllocationInstruction;
30  import org.apache.bcel.generic.ArrayInstruction;
31  import org.apache.bcel.generic.ArrayType;
32  import org.apache.bcel.generic.BranchHandle;
33  import org.apache.bcel.generic.BranchInstruction;
34  import org.apache.bcel.generic.CHECKCAST;
35  import org.apache.bcel.generic.CPInstruction;
36  import org.apache.bcel.generic.CodeExceptionGen;
37  import org.apache.bcel.generic.ConstantPoolGen;
38  import org.apache.bcel.generic.ConstantPushInstruction;
39  import org.apache.bcel.generic.EmptyVisitor;
40  import org.apache.bcel.generic.FieldInstruction;
41  import org.apache.bcel.generic.IINC;
42  import org.apache.bcel.generic.INSTANCEOF;
43  import org.apache.bcel.generic.Instruction;
44  import org.apache.bcel.generic.InstructionConstants;
45  import org.apache.bcel.generic.InstructionHandle;
46  import org.apache.bcel.generic.InvokeInstruction;
47  import org.apache.bcel.generic.LDC;
48  import org.apache.bcel.generic.LDC2_W;
49  import org.apache.bcel.generic.LocalVariableInstruction;
50  import org.apache.bcel.generic.MULTIANEWARRAY;
51  import org.apache.bcel.generic.MethodGen;
52  import org.apache.bcel.generic.NEWARRAY;
53  import org.apache.bcel.generic.ObjectType;
54  import org.apache.bcel.generic.RET;
55  import org.apache.bcel.generic.ReturnInstruction;
56  import org.apache.bcel.generic.Select;
57  import org.apache.bcel.generic.Type;
58  
59  /**
60   * Factory creates il.append() statements, and sets instruction targets.
61   * A helper class for BCELifier.
62   *
63   * @see BCELifier
64   * @version $Id: BCELFactory.html 898356 2014-02-18 05:44:40Z ggregory $
65   * @author  <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
66   */
67  class BCELFactory extends EmptyVisitor {
68  
69      private final MethodGen _mg;
70      private final PrintWriter _out;
71      private final ConstantPoolGen _cp;
72  
73  
74      BCELFactory(MethodGen mg, PrintWriter out) {
75          _mg = mg;
76          _cp = mg.getConstantPool();
77          _out = out;
78      }
79  
80      private final Map<Instruction, InstructionHandle> branch_map = new HashMap<Instruction, InstructionHandle>();
81  
82  
83      public void start() {
84          if (!_mg.isAbstract() && !_mg.isNative()) {
85              for (InstructionHandle ih = _mg.getInstructionList().getStart(); ih != null; ih = ih
86                      .getNext()) {
87                  Instruction i = ih.getInstruction();
88                  if (i instanceof BranchInstruction) {
89                      branch_map.put(i, ih); // memorize container
90                  }
91                  if (ih.hasTargeters()) {
92                      if (i instanceof BranchInstruction) {
93                          _out.println("    InstructionHandle ih_" + ih.getPosition() + ";");
94                      } else {
95                          _out.print("    InstructionHandle ih_" + ih.getPosition() + " = ");
96                      }
97                  } else {
98                      _out.print("    ");
99                  }
100                 if (!visitInstruction(i)) {
101                     i.accept(this);
102                 }
103             }
104             updateBranchTargets();
105             updateExceptionHandlers();
106         }
107     }
108 
109 
110     private boolean visitInstruction( Instruction i ) {
111         short opcode = i.getOpcode();
112         if ((InstructionConstants.INSTRUCTIONS[opcode] != null)
113                 && !(i instanceof ConstantPushInstruction) && !(i instanceof ReturnInstruction)) { // Handled below
114             _out.println("il.append(InstructionConstants."
115                     + i.getName().toUpperCase(Locale.ENGLISH) + ");");
116             return true;
117         }
118         return false;
119     }
120 
121 
122     @Override
123     public void visitLocalVariableInstruction( LocalVariableInstruction i ) {
124         short opcode = i.getOpcode();
125         Type type = i.getType(_cp);
126         if (opcode == Constants.IINC) {
127             _out.println("il.append(new IINC(" + i.getIndex() + ", " + ((IINC) i).getIncrement()
128                     + "));");
129         } else {
130             String kind = (opcode < Constants.ISTORE) ? "Load" : "Store";
131             _out.println("il.append(_factory.create" + kind + "(" + BCELifier.printType(type)
132                     + ", " + i.getIndex() + "));");
133         }
134     }
135 
136 
137     @Override
138     public void visitArrayInstruction( ArrayInstruction i ) {
139         short opcode = i.getOpcode();
140         Type type = i.getType(_cp);
141         String kind = (opcode < Constants.IASTORE) ? "Load" : "Store";
142         _out.println("il.append(_factory.createArray" + kind + "(" + BCELifier.printType(type)
143                 + "));");
144     }
145 
146 
147     @Override
148     public void visitFieldInstruction( FieldInstruction i ) {
149         short opcode = i.getOpcode();
150         String class_name = i.getClassName(_cp);
151         String field_name = i.getFieldName(_cp);
152         Type type = i.getFieldType(_cp);
153         _out.println("il.append(_factory.createFieldAccess(\"" + class_name + "\", \"" + field_name
154                 + "\", " + BCELifier.printType(type) + ", " + "Constants."
155                 + Constants.OPCODE_NAMES[opcode].toUpperCase(Locale.ENGLISH) + "));");
156     }
157 
158 
159     @Override
160     public void visitInvokeInstruction( InvokeInstruction i ) {
161         short opcode = i.getOpcode();
162         String class_name = i.getClassName(_cp);
163         String method_name = i.getMethodName(_cp);
164         Type type = i.getReturnType(_cp);
165         Type[] arg_types = i.getArgumentTypes(_cp);
166         _out.println("il.append(_factory.createInvoke(\"" + class_name + "\", \"" + method_name
167                 + "\", " + BCELifier.printType(type) + ", "
168                 + BCELifier.printArgumentTypes(arg_types) + ", " + "Constants."
169                 + Constants.OPCODE_NAMES[opcode].toUpperCase(Locale.ENGLISH) + "));");
170     }
171 
172 
173     @Override
174     public void visitAllocationInstruction( AllocationInstruction i ) {
175         Type type;
176         if (i instanceof CPInstruction) {
177             type = ((CPInstruction) i).getType(_cp);
178         } else {
179             type = ((NEWARRAY) i).getType();
180         }
181         short opcode = ((Instruction) i).getOpcode();
182         int dim = 1;
183         switch (opcode) {
184             case Constants.NEW:
185                 _out.println("il.append(_factory.createNew(\"" + ((ObjectType) type).getClassName()
186                         + "\"));");
187                 break;
188             case Constants.MULTIANEWARRAY:
189                 dim = ((MULTIANEWARRAY) i).getDimensions();
190                 //$FALL-THROUGH$
191             case Constants.ANEWARRAY:
192             case Constants.NEWARRAY:
193                 if (type instanceof ArrayType) {
194                     type = ((ArrayType) type).getBasicType();
195                 }
196                 _out.println("il.append(_factory.createNewArray(" + BCELifier.printType(type)
197                         + ", (short) " + dim + "));");
198                 break;
199             default:
200                 throw new RuntimeException("Oops: " + opcode);
201         }
202     }
203 
204 
205     private void createConstant( Object value ) {
206         String embed = value.toString();
207         if (value instanceof String) {
208             embed = '"' + Utility.convertString(embed) + '"';
209         } else if (value instanceof Character) {
210             embed = "(char)0x" + Integer.toHexString(((Character) value).charValue());
211         } else if (value instanceof Float) {
212             embed += "f";
213         } else if (value instanceof Long) {
214             embed += "L";
215         } else if (value instanceof ObjectType){
216             ObjectType ot = (ObjectType) value;
217             embed = "new ObjectType(\""+ot.getClassName()+"\")";
218         }
219 
220         _out.println("il.append(new PUSH(_cp, " + embed + "));");
221     }
222 
223 
224     @Override
225     public void visitLDC( LDC i ) {
226         createConstant(i.getValue(_cp));
227     }
228 
229 
230     @Override
231     public void visitLDC2_W( LDC2_W i ) {
232         createConstant(i.getValue(_cp));
233     }
234 
235 
236     @Override
237     public void visitConstantPushInstruction( ConstantPushInstruction i ) {
238         createConstant(i.getValue());
239     }
240 
241 
242     @Override
243     public void visitINSTANCEOF( INSTANCEOF i ) {
244         Type type = i.getType(_cp);
245         _out.println("il.append(new INSTANCEOF(_cp.addClass(" + BCELifier.printType(type) + ")));");
246     }
247 
248 
249     @Override
250     public void visitCHECKCAST( CHECKCAST i ) {
251         Type type = i.getType(_cp);
252         _out.println("il.append(_factory.createCheckCast(" + BCELifier.printType(type) + "));");
253     }
254 
255 
256     @Override
257     public void visitReturnInstruction( ReturnInstruction i ) {
258         Type type = i.getType(_cp);
259         _out.println("il.append(_factory.createReturn(" + BCELifier.printType(type) + "));");
260     }
261 
262     // Memorize BranchInstructions that need an update
263     private final List<BranchInstruction> branches = new ArrayList<BranchInstruction>();
264 
265 
266     @Override
267     public void visitBranchInstruction( BranchInstruction bi ) {
268         BranchHandle bh = (BranchHandle) branch_map.get(bi);
269         int pos = bh.getPosition();
270         String name = bi.getName() + "_" + pos;
271         if (bi instanceof Select) {
272             Select s = (Select) bi;
273             branches.add(bi);
274             StringBuffer args = new StringBuffer("new int[] { ");
275             int[] matchs = s.getMatchs();
276             for (int i = 0; i < matchs.length; i++) {
277                 args.append(matchs[i]);
278                 if (i < matchs.length - 1) {
279                     args.append(", ");
280                 }
281             }
282             args.append(" }");
283             _out.print("Select " + name + " = new " + bi.getName().toUpperCase(Locale.ENGLISH)
284                     + "(" + args + ", new InstructionHandle[] { ");
285             for (int i = 0; i < matchs.length; i++) {
286                 _out.print("null");
287                 if (i < matchs.length - 1) {
288                     _out.print(", ");
289                 }
290             }
291             _out.println(" }, null);");
292         } else {
293             int t_pos = bh.getTarget().getPosition();
294             String target;
295             if (pos > t_pos) {
296                 target = "ih_" + t_pos;
297             } else {
298                 branches.add(bi);
299                 target = "null";
300             }
301             _out.println("    BranchInstruction " + name + " = _factory.createBranchInstruction("
302                     + "Constants." + bi.getName().toUpperCase(Locale.ENGLISH) + ", " + target
303                     + ");");
304         }
305         if (bh.hasTargeters()) {
306             _out.println("    ih_" + pos + " = il.append(" + name + ");");
307         } else {
308             _out.println("    il.append(" + name + ");");
309         }
310     }
311 
312 
313     @Override
314     public void visitRET( RET i ) {
315         _out.println("il.append(new RET(" + i.getIndex() + ")));");
316     }
317 
318 
319     private void updateBranchTargets() {
320         for (BranchInstruction bi : branches) {
321             BranchHandle bh = (BranchHandle) branch_map.get(bi);
322             int pos = bh.getPosition();
323             String name = bi.getName() + "_" + pos;
324             int t_pos = bh.getTarget().getPosition();
325             _out.println("    " + name + ".setTarget(ih_" + t_pos + ");");
326             if (bi instanceof Select) {
327                 InstructionHandle[] ihs = ((Select) bi).getTargets();
328                 for (int j = 0; j < ihs.length; j++) {
329                     t_pos = ihs[j].getPosition();
330                     _out.println("    " + name + ".setTarget(" + j + ", ih_" + t_pos + ");");
331                 }
332             }
333         }
334     }
335 
336 
337     private void updateExceptionHandlers() {
338         CodeExceptionGen[] handlers = _mg.getExceptionHandlers();
339         for (CodeExceptionGen h : handlers) {
340             String type = (h.getCatchType() == null) ? "null" : BCELifier.printType(h
341                     .getCatchType());
342             _out.println("    method.addExceptionHandler(" + "ih_" + h.getStartPC().getPosition()
343                     + ", " + "ih_" + h.getEndPC().getPosition() + ", " + "ih_"
344                     + h.getHandlerPC().getPosition() + ", " + type + ");");
345         }
346     }
347 }