1 /* 2 * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. 3 */ 4 /* 5 * Licensed to the Apache Software Foundation (ASF) under one or more 6 * contributor license agreements. See the NOTICE file distributed with 7 * this work for additional information regarding copyright ownership. 8 * The ASF licenses this file to You under the Apache License, Version 2.0 9 * (the "License"); you may not use this file except in compliance with 10 * the License. You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, software 15 * distributed under the License is distributed on an "AS IS" BASIS, 16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 * See the License for the specific language governing permissions and 18 * limitations under the License. 19 */ 20 21 package com.sun.org.apache.bcel.internal.util; 22 23 import java.io.PrintWriter; 24 import java.util.ArrayList; 25 import java.util.HashMap; 26 import java.util.List; 27 import java.util.Locale; 28 import java.util.Map; 29 30 import com.sun.org.apache.bcel.internal.Const; 31 import com.sun.org.apache.bcel.internal.classfile.Utility; 32 import com.sun.org.apache.bcel.internal.generic.AllocationInstruction; 33 import com.sun.org.apache.bcel.internal.generic.ArrayInstruction; 34 import com.sun.org.apache.bcel.internal.generic.ArrayType; 35 import com.sun.org.apache.bcel.internal.generic.BranchHandle; 36 import com.sun.org.apache.bcel.internal.generic.BranchInstruction; 37 import com.sun.org.apache.bcel.internal.generic.CHECKCAST; 38 import com.sun.org.apache.bcel.internal.generic.CPInstruction; 39 import com.sun.org.apache.bcel.internal.generic.CodeExceptionGen; 40 import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen; 41 import com.sun.org.apache.bcel.internal.generic.ConstantPushInstruction; 42 import com.sun.org.apache.bcel.internal.generic.EmptyVisitor; 43 import com.sun.org.apache.bcel.internal.generic.FieldInstruction; 44 import com.sun.org.apache.bcel.internal.generic.IINC; 45 import com.sun.org.apache.bcel.internal.generic.INSTANCEOF; 46 import com.sun.org.apache.bcel.internal.generic.Instruction; 47 import com.sun.org.apache.bcel.internal.generic.InstructionConst; 48 import com.sun.org.apache.bcel.internal.generic.InstructionHandle; 49 import com.sun.org.apache.bcel.internal.generic.InvokeInstruction; 50 import com.sun.org.apache.bcel.internal.generic.LDC; 51 import com.sun.org.apache.bcel.internal.generic.LDC2_W; 52 import com.sun.org.apache.bcel.internal.generic.LocalVariableInstruction; 53 import com.sun.org.apache.bcel.internal.generic.MULTIANEWARRAY; 54 import com.sun.org.apache.bcel.internal.generic.MethodGen; 55 import com.sun.org.apache.bcel.internal.generic.NEWARRAY; 56 import com.sun.org.apache.bcel.internal.generic.ObjectType; 57 import com.sun.org.apache.bcel.internal.generic.RET; 58 import com.sun.org.apache.bcel.internal.generic.ReturnInstruction; 59 import com.sun.org.apache.bcel.internal.generic.Select; 60 import com.sun.org.apache.bcel.internal.generic.Type; 61 62 /** 63 * Factory creates il.append() statements, and sets instruction targets. 64 * A helper class for BCELifier. 65 * 66 * @see BCELifier 67 * @version $Id$ 68 * @LastModified: Jun 2019 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 BCELFactory(final MethodGen mg, final PrintWriter out)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 start()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 visitInstruction( final Instruction i )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 visitLocalVariableInstruction( final LocalVariableInstruction i )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 visitArrayInstruction( final ArrayInstruction i )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 visitFieldInstruction( final FieldInstruction i )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 visitInvokeInstruction( final InvokeInstruction i )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 visitAllocationInstruction( final AllocationInstruction i )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 createConstant( final Object value )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 visitLDC( final LDC i )230 public void visitLDC( final LDC i ) { 231 createConstant(i.getValue(_cp)); 232 } 233 234 235 @Override visitLDC2_W( final LDC2_W i )236 public void visitLDC2_W( final LDC2_W i ) { 237 createConstant(i.getValue(_cp)); 238 } 239 240 241 @Override visitConstantPushInstruction( final ConstantPushInstruction i )242 public void visitConstantPushInstruction( final ConstantPushInstruction i ) { 243 createConstant(i.getValue()); 244 } 245 246 247 @Override visitINSTANCEOF( final INSTANCEOF i )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 visitCHECKCAST( final CHECKCAST i )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 visitReturnInstruction( final ReturnInstruction i )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 visitBranchInstruction( final BranchInstruction bi )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 visitRET( final RET i )319 public void visitRET( final RET i ) { 320 _out.println("il.append(new RET(" + i.getIndex() + ")));"); 321 } 322 323 updateBranchTargets()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 updateExceptionHandlers()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 } 353