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 
  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 
  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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 226   public void visitLDC(LDC i) {
 227     createConstant(i.getValue(_cp));
 228   }
 229 
 230   public void visitLDC2_W(LDC2_W i) {
 231     createConstant(i.getValue(_cp));
 232   }
 233 
 234   public void visitConstantPushInstruction(ConstantPushInstruction i) {
 235     createConstant(i.getValue());
 236   }
 237 
 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 
 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 
 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 
 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 
 318   public void visitRET(RET i) {
 319     _out.println("il.append(new RET(" + i.getIndex() + ")));");
 320   }
 321 
 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 
 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 }