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