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.Const;
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.InstructionConst;
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 992795 2016-07-14 11:53:52Z britter $
65   */
66  class BCELFactory extends EmptyVisitor {
67  
68      private static final String CONSTANT_PREFIX = Const.class.getSimpleName()+".";
69      private final MethodGen _mg;
70      private final PrintWriter _out;
71      private final ConstantPoolGen _cp;
72  
73  
74      BCELFactory(final MethodGen mg, final PrintWriter out) {
75          _mg = mg;
76          _cp = mg.getConstantPool();
77          _out = out;
78      }
79  
80      private final Map<Instruction, InstructionHandle> branch_map = new HashMap<>();
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                  final 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( final Instruction i ) {
111         final short opcode = i.getOpcode();
112         if ((InstructionConst.getInstruction(opcode) != null)
113                 && !(i instanceof ConstantPushInstruction) && !(i instanceof ReturnInstruction)) { // Handled below
114             _out.println("il.append(InstructionConst."
115                     + i.getName().toUpperCase(Locale.ENGLISH) + ");");
116             return true;
117         }
118         return false;
119     }
120 
121 
122     @Override
123     public void visitLocalVariableInstruction( final LocalVariableInstruction i ) {
124         final short opcode = i.getOpcode();
125         final Type type = i.getType(_cp);
126         if (opcode == Const.IINC) {
127             _out.println("il.append(new IINC(" + i.getIndex() + ", " + ((IINC) i).getIncrement()
128                     + "));");
129         } else {
130             final String kind = (opcode < Const.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( final ArrayInstruction i ) {
139         final short opcode = i.getOpcode();
140         final Type type = i.getType(_cp);
141         final String kind = (opcode < Const.IASTORE) ? "Load" : "Store";
142         _out.println("il.append(_factory.createArray" + kind + "(" + BCELifier.printType(type)
143                 + "));");
144     }
145 
146 
147     @Override
148     public void visitFieldInstruction( final FieldInstruction i ) {
149         final short opcode = i.getOpcode();
150         final String class_name = i.getClassName(_cp);
151         final String field_name = i.getFieldName(_cp);
152         final Type type = i.getFieldType(_cp);
153         _out.println("il.append(_factory.createFieldAccess(\"" + class_name + "\", \"" + field_name
154                 + "\", " + BCELifier.printType(type) + ", " + CONSTANT_PREFIX
155                 + Const.getOpcodeName(opcode).toUpperCase(Locale.ENGLISH) + "));");
156     }
157 
158 
159     @Override
160     public void visitInvokeInstruction( final InvokeInstruction i ) {
161         final short opcode = i.getOpcode();
162         final String class_name = i.getClassName(_cp);
163         final String method_name = i.getMethodName(_cp);
164         final Type type = i.getReturnType(_cp);
165         final 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) + ", " + CONSTANT_PREFIX
169                 + Const.getOpcodeName(opcode).toUpperCase(Locale.ENGLISH) + "));");
170     }
171 
172 
173     @Override
174     public void visitAllocationInstruction( final 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         final short opcode = ((Instruction) i).getOpcode();
182         int dim = 1;
183         switch (opcode) {
184             case Const.NEW:
185                 _out.println("il.append(_factory.createNew(\"" + ((ObjectType) type).getClassName()
186                         + "\"));");
187                 break;
188             case Const.MULTIANEWARRAY:
189                 dim = ((MULTIANEWARRAY) i).getDimensions();
190                 //$FALL-THROUGH$
191             case Const.ANEWARRAY:
192             case Const.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( final 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             final 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( final LDC i ) {
226         createConstant(i.getValue(_cp));
227     }
228 
229 
230     @Override
231     public void visitLDC2_W( final LDC2_W i ) {
232         createConstant(i.getValue(_cp));
233     }
234 
235 
236     @Override
237     public void visitConstantPushInstruction( final ConstantPushInstruction i ) {
238         createConstant(i.getValue());
239     }
240 
241 
242     @Override
243     public void visitINSTANCEOF( final INSTANCEOF i ) {
244         final 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( final CHECKCAST i ) {
251         final Type type = i.getType(_cp);
252         _out.println("il.append(_factory.createCheckCast(" + BCELifier.printType(type) + "));");
253     }
254 
255 
256     @Override
257     public void visitReturnInstruction( final ReturnInstruction i ) {
258         final 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<>();
264 
265 
266     @Override
267     public void visitBranchInstruction( final BranchInstruction bi ) {
268         final BranchHandle bh = (BranchHandle) branch_map.get(bi);
269         final int pos = bh.getPosition();
270         final String name = bi.getName() + "_" + pos;
271         if (bi instanceof Select) {
272             final Select s = (Select) bi;
273             branches.add(bi);
274             final StringBuilder args = new StringBuilder("new int[] { ");
275             final 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             final 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                     + CONSTANT_PREFIX + 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( final RET i ) {
315         _out.println("il.append(new RET(" + i.getIndex() + ")));");
316     }
317 
318 
319     private void updateBranchTargets() {
320         for (final BranchInstruction bi : branches) {
321             final BranchHandle bh = (BranchHandle) branch_map.get(bi);
322             final int pos = bh.getPosition();
323             final 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                 final 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         final CodeExceptionGen[] handlers = _mg.getExceptionHandlers();
339         for (final CodeExceptionGen h : handlers) {
340             final 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 }