View Javadoc

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