1 /*
2  * reserved comment block
3  * DO NOT REMOVE OR ALTER!
4  */
5 package com.sun.org.apache.bcel.internal.util;
6 
7 import com.sun.org.apache.bcel.internal.generic.*;
8 import com.sun.org.apache.bcel.internal.classfile.Utility;
9 import com.sun.org.apache.bcel.internal.Constants;
10 import java.io.PrintWriter;
11 import java.util.*;
12 
13 /* ====================================================================
14  * The Apache Software License, Version 1.1
15  *
16  * Copyright (c) 2002 The Apache Software Foundation.  All rights
17  * reserved.
18  *
19  * Redistribution and use in source and binary forms, with or without
20  * modification, are permitted provided that the following conditions
21  * are met:
22  *
23  * 1. Redistributions of source code must retain the above copyright
24  *    notice, this list of conditions and the following disclaimer.
25  *
26  * 2. Redistributions in binary form must reproduce the above copyright
27  *    notice, this list of conditions and the following disclaimer in
28  *    the documentation and/or other materials provided with the
29  *    distribution.
30  *
31  * 3. The end-user documentation included with the redistribution,
32  *    if any, must include the following acknowledgment:
33  *       "This product includes software developed by the
34  *        Apache Software Foundation (http://www.apache.org/)."
35  *    Alternately, this acknowledgment may appear in the software itself,
36  *    if and wherever such third-party acknowledgments normally appear.
37  *
38  * 4. The names "Apache" and "Apache Software Foundation" and
39  *    "Apache BCEL" must not be used to endorse or promote products
40  *    derived from this software without prior written permission. For
41  *    written permission, please contact apache@apache.org.
42  *
43  * 5. Products derived from this software may not be called "Apache",
44  *    "Apache BCEL", nor may "Apache" appear in their name, without
45  *    prior written permission of the Apache Software Foundation.
46  *
47  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
48  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
49  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
50  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
51  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
52  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
53  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
54  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
55  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
56  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
57  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58  * SUCH DAMAGE.
59  * ====================================================================
60  *
61  * This software consists of voluntary contributions made by many
62  * individuals on behalf of the Apache Software Foundation.  For more
63  * information on the Apache Software Foundation, please see
64  * <http://www.apache.org/>.
65  */
66 
67 /**
68  * Factory creates il.append() statements, and sets instruction targets.
69  * A helper class for BCELifier.
70  *
71  * @see BCELifier
72  * @author  <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
73  */
74 class BCELFactory extends EmptyVisitor {
75   private MethodGen       _mg;
76   private PrintWriter     _out;
77   private ConstantPoolGen _cp;
78 
BCELFactory(MethodGen mg, PrintWriter out)79   BCELFactory(MethodGen mg, PrintWriter out) {
80     _mg  = mg;
81     _cp  = mg.getConstantPool();
82     _out = out;
83   }
84 
85   private HashMap branch_map = new HashMap(); // Map<Instruction, InstructionHandle>
86 
start()87   public void start() {
88     if(!_mg.isAbstract() && !_mg.isNative()) {
89       for(InstructionHandle ih = _mg.getInstructionList().getStart();
90           ih != null; ih = ih.getNext()) {
91         Instruction i = ih.getInstruction();
92 
93         if(i instanceof BranchInstruction) {
94           branch_map.put(i, ih); // memorize container
95         }
96 
97         if(ih.hasTargeters()) {
98           if(i instanceof BranchInstruction) {
99             _out.println("    InstructionHandle ih_" + ih.getPosition() + ";");
100           } else {
101             _out.print("    InstructionHandle ih_" + ih.getPosition() + " = ");
102           }
103         } else {
104           _out.print("    ");
105         }
106 
107         if(!visitInstruction(i))
108           i.accept(this);
109       }
110 
111       updateBranchTargets();
112       updateExceptionHandlers();
113     }
114   }
115 
visitInstruction(Instruction i)116   private boolean visitInstruction(Instruction i) {
117     short opcode = i.getOpcode();
118 
119     if((InstructionConstants.INSTRUCTIONS[opcode] != null) &&
120        !(i instanceof ConstantPushInstruction) &&
121        !(i instanceof ReturnInstruction)) { // Handled below
122       _out.println("il.append(InstructionConstants." +
123                    i.getName().toUpperCase() + ");");
124       return true;
125     }
126 
127     return false;
128   }
129 
visitLocalVariableInstruction(LocalVariableInstruction i)130   public void visitLocalVariableInstruction(LocalVariableInstruction i) {
131     short  opcode = i.getOpcode();
132     Type   type   = i.getType(_cp);
133 
134     if(opcode == Constants.IINC) {
135       _out.println("il.append(new IINC(" + i.getIndex() + ", " +
136                    ((IINC)i).getIncrement() + "));");
137     } else {
138       String kind   = (opcode < Constants.ISTORE)? "Load" : "Store";
139       _out.println("il.append(_factory.create" + kind + "(" +
140                    BCELifier.printType(type) + ", " +
141                    i.getIndex() + "));");
142     }
143   }
144 
visitArrayInstruction(ArrayInstruction i)145   public void visitArrayInstruction(ArrayInstruction i) {
146     short  opcode = i.getOpcode();
147     Type   type   = i.getType(_cp);
148     String kind   = (opcode < Constants.IASTORE)? "Load" : "Store";
149 
150     _out.println("il.append(_factory.createArray" + kind + "(" +
151                  BCELifier.printType(type) + "));");
152   }
153 
visitFieldInstruction(FieldInstruction i)154   public void visitFieldInstruction(FieldInstruction i) {
155     short  opcode = i.getOpcode();
156 
157     String class_name = i.getClassName(_cp);
158     String field_name = i.getFieldName(_cp);
159     Type   type       = i.getFieldType(_cp);
160 
161     _out.println("il.append(_factory.createFieldAccess(\"" +
162                  class_name + "\", \"" + field_name + "\", " +
163                  BCELifier.printType(type) + ", " +
164                  "Constants." + Constants.OPCODE_NAMES[opcode].toUpperCase() +
165                  "));");
166   }
167 
visitInvokeInstruction(InvokeInstruction i)168   public void visitInvokeInstruction(InvokeInstruction i) {
169     short  opcode      = i.getOpcode();
170     String class_name  = i.getClassName(_cp);
171     String method_name = i.getMethodName(_cp);
172     Type   type        = i.getReturnType(_cp);
173     Type[] arg_types   = i.getArgumentTypes(_cp);
174 
175     _out.println("il.append(_factory.createInvoke(\"" +
176                  class_name + "\", \"" + method_name + "\", " +
177                  BCELifier.printType(type) + ", " +
178                  BCELifier.printArgumentTypes(arg_types) + ", " +
179                  "Constants." + Constants.OPCODE_NAMES[opcode].toUpperCase() +
180                  "));");
181   }
182 
visitAllocationInstruction(AllocationInstruction i)183   public void visitAllocationInstruction(AllocationInstruction i) {
184     Type type;
185 
186     if(i instanceof CPInstruction) {
187       type = ((CPInstruction)i).getType(_cp);
188     } else {
189       type = ((NEWARRAY)i).getType();
190     }
191 
192     short opcode = ((Instruction)i).getOpcode();
193     int   dim    = 1;
194 
195     switch(opcode) {
196     case Constants.NEW:
197       _out.println("il.append(_factory.createNew(\"" +
198                    ((ObjectType)type).getClassName() + "\"));");
199       break;
200 
201     case Constants.MULTIANEWARRAY:
202       dim = ((MULTIANEWARRAY)i).getDimensions();
203 
204     case Constants.ANEWARRAY:
205     case Constants.NEWARRAY:
206       _out.println("il.append(_factory.createNewArray(" +
207                    BCELifier.printType(type) + ", (short) " + dim + "));");
208       break;
209 
210     default:
211       throw new RuntimeException("Oops: " + opcode);
212     }
213   }
214 
createConstant(Object value)215   private void createConstant(Object value) {
216     String embed = value.toString();
217 
218     if(value instanceof String)
219       embed = '"' + Utility.convertString(value.toString()) + '"';
220     else if(value instanceof Character)
221       embed = "(char)0x" + Integer.toHexString(((Character)value).charValue());
222 
223     _out.println("il.append(new PUSH(_cp, " + embed + "));");
224   }
225 
visitLDC(LDC i)226   public void visitLDC(LDC i) {
227     createConstant(i.getValue(_cp));
228   }
229 
visitLDC2_W(LDC2_W i)230   public void visitLDC2_W(LDC2_W i) {
231     createConstant(i.getValue(_cp));
232   }
233 
visitConstantPushInstruction(ConstantPushInstruction i)234   public void visitConstantPushInstruction(ConstantPushInstruction i) {
235     createConstant(i.getValue());
236   }
237 
visitINSTANCEOF(INSTANCEOF i)238   public void visitINSTANCEOF(INSTANCEOF i) {
239     Type type = i.getType(_cp);
240 
241     _out.println("il.append(new INSTANCEOF(_cp.addClass(" +
242                  BCELifier.printType(type) + ")));");
243   }
244 
visitCHECKCAST(CHECKCAST i)245   public void visitCHECKCAST(CHECKCAST i) {
246     Type type = i.getType(_cp);
247 
248     _out.println("il.append(_factory.createCheckCast(" +
249                  BCELifier.printType(type) + "));");
250   }
251 
visitReturnInstruction(ReturnInstruction i)252   public void visitReturnInstruction(ReturnInstruction i) {
253     Type type = i.getType(_cp);
254 
255     _out.println("il.append(_factory.createReturn(" +
256                  BCELifier.printType(type) + "));");
257   }
258 
259   // Memorize BranchInstructions that need an update
260   private ArrayList branches = new ArrayList();
261 
visitBranchInstruction(BranchInstruction bi)262   public void visitBranchInstruction(BranchInstruction bi) {
263     BranchHandle bh   = (BranchHandle)branch_map.get(bi);
264     int          pos  = bh.getPosition();
265     String       name = bi.getName() + "_" + pos;
266 
267     if(bi instanceof Select) {
268       Select s = (Select)bi;
269       branches.add(bi);
270 
271       StringBuffer args   = new StringBuffer("new int[] { ");
272       int[]        matchs = s.getMatchs();
273 
274       for(int i=0; i < matchs.length; i++) {
275         args.append(matchs[i]);
276 
277         if(i < matchs.length - 1)
278           args.append(", ");
279       }
280 
281       args.append(" }");
282 
283       _out.print("    Select " + name + " = new " +
284                  bi.getName().toUpperCase() + "(" + args +
285                  ", new InstructionHandle[] { ");
286 
287       for(int i=0; i < matchs.length; i++) {
288         _out.print("null");
289 
290         if(i < matchs.length - 1)
291           _out.print(", ");
292       }
293 
294       _out.println(");");
295     } else {
296       int    t_pos  = bh.getTarget().getPosition();
297       String target;
298 
299       if(pos > t_pos) {
300         target = "ih_" + t_pos;
301       } else {
302         branches.add(bi);
303         target = "null";
304       }
305 
306       _out.println("    BranchInstruction " + name +
307                    " = _factory.createBranchInstruction(" +
308                    "Constants." + bi.getName().toUpperCase() + ", " +
309                    target + ");");
310     }
311 
312     if(bh.hasTargeters())
313       _out.println("    ih_" + pos + " = il.append(" + name + ");");
314     else
315       _out.println("    il.append(" + name + ");");
316   }
317 
visitRET(RET i)318   public void visitRET(RET i) {
319     _out.println("il.append(new RET(" + i.getIndex() + ")));");
320   }
321 
updateBranchTargets()322   private void updateBranchTargets() {
323     for(Iterator i = branches.iterator(); i.hasNext(); ) {
324       BranchInstruction bi    = (BranchInstruction)i.next();
325       BranchHandle      bh    = (BranchHandle)branch_map.get(bi);
326       int               pos   = bh.getPosition();
327       String            name  = bi.getName() + "_" + pos;
328       int               t_pos = bh.getTarget().getPosition();
329 
330       _out.println("    " + name + ".setTarget(ih_" + t_pos + ");");
331 
332       if(bi instanceof Select) {
333         InstructionHandle[] ihs = ((Select)bi).getTargets();
334 
335         for(int j = 0; j < ihs.length; j++) {
336           t_pos = ihs[j].getPosition();
337 
338           _out.println("    " + name + ".setTarget(" + j +
339                        ", ih_" + t_pos + ");");
340         }
341       }
342     }
343   }
344 
updateExceptionHandlers()345   private void updateExceptionHandlers() {
346     CodeExceptionGen[] handlers = _mg.getExceptionHandlers();
347 
348     for(int i=0; i < handlers.length; i++) {
349       CodeExceptionGen h    = handlers[i];
350       String           type = (h.getCatchType() == null)?
351         "null" : BCELifier.printType(h.getCatchType());
352 
353       _out.println("    method.addExceptionHandler(" +
354                    "ih_" + h.getStartPC().getPosition() + ", " +
355                    "ih_" + h.getEndPC().getPosition() + ", " +
356                    "ih_" + h.getHandlerPC().getPosition() + ", " +
357                    type + ");");
358     }
359   }
360 }
361