1 /* 2 * Copyright (c) 2017, 2020, 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 * @LastModified: Jan 2020 68 */ 69 class BCELFactory extends EmptyVisitor { 70 71 private static final String CONSTANT_PREFIX = Const.class.getSimpleName()+"."; 72 private final MethodGen _mg; 73 private final PrintWriter _out; 74 private final ConstantPoolGen _cp; 75 76 77 BCELFactory(final MethodGen mg, final PrintWriter out) { 78 _mg = mg; 79 _cp = mg.getConstantPool(); 80 _out = out; 81 } 82 83 private final Map<Instruction, InstructionHandle> branch_map = new HashMap<>(); 84 85 86 public void start() { 87 if (!_mg.isAbstract() && !_mg.isNative()) { 88 for (InstructionHandle ih = _mg.getInstructionList().getStart(); ih != null; ih = ih 89 .getNext()) { 90 final Instruction i = ih.getInstruction(); 91 if (i instanceof BranchInstruction) { 92 branch_map.put(i, ih); // memorize container 93 } 94 if (ih.hasTargeters()) { 95 if (i instanceof BranchInstruction) { 96 _out.println(" InstructionHandle ih_" + ih.getPosition() + ";"); 97 } else { 98 _out.print(" InstructionHandle ih_" + ih.getPosition() + " = "); 99 } 100 } else { 101 _out.print(" "); 102 } 103 if (!visitInstruction(i)) { 104 i.accept(this); 105 } 106 } 107 updateBranchTargets(); 108 updateExceptionHandlers(); 109 } 110 } 111 112 113 private boolean visitInstruction( final Instruction i ) { 114 final short opcode = i.getOpcode(); 115 if ((InstructionConst.getInstruction(opcode) != null) 116 && !(i instanceof ConstantPushInstruction) && !(i instanceof ReturnInstruction)) { // Handled below 117 _out.println("il.append(InstructionConst." 118 + i.getName().toUpperCase(Locale.ENGLISH) + ");"); 119 return true; 120 } 121 return false; 122 } 123 124 125 @Override 126 public void visitLocalVariableInstruction( final LocalVariableInstruction i ) { 127 final short opcode = i.getOpcode(); 128 final Type type = i.getType(_cp); 129 if (opcode == Const.IINC) { 130 _out.println("il.append(new IINC(" + i.getIndex() + ", " + ((IINC) i).getIncrement() 131 + "));"); 132 } else { 133 final String kind = (opcode < Const.ISTORE) ? "Load" : "Store"; 134 _out.println("il.append(_factory.create" + kind + "(" + BCELifier.printType(type) 135 + ", " + i.getIndex() + "));"); 136 } 137 } 138 139 140 @Override 141 public void visitArrayInstruction( final ArrayInstruction i ) { 142 final short opcode = i.getOpcode(); 143 final Type type = i.getType(_cp); 144 final String kind = (opcode < Const.IASTORE) ? "Load" : "Store"; 145 _out.println("il.append(_factory.createArray" + kind + "(" + BCELifier.printType(type) 146 + "));"); 147 } 148 149 150 @Override 151 public void visitFieldInstruction( final FieldInstruction i ) { 152 final short opcode = i.getOpcode(); 153 final String class_name = i.getReferenceType(_cp).getSignature(); 154 final String field_name = i.getFieldName(_cp); 155 final Type type = i.getFieldType(_cp); 156 _out.println("il.append(_factory.createFieldAccess(\"" + class_name + "\", \"" + field_name 157 + "\", " + BCELifier.printType(type) + ", " + CONSTANT_PREFIX 158 + Const.getOpcodeName(opcode).toUpperCase(Locale.ENGLISH) + "));"); 159 } 160 161 162 @Override 163 public void visitInvokeInstruction( final InvokeInstruction i ) { 164 final short opcode = i.getOpcode(); 165 final String class_name = i.getReferenceType(_cp).getSignature(); 166 final String method_name = i.getMethodName(_cp); 167 final Type type = i.getReturnType(_cp); 168 final Type[] arg_types = i.getArgumentTypes(_cp); 169 _out.println("il.append(_factory.createInvoke(\"" + class_name + "\", \"" + method_name 170 + "\", " + BCELifier.printType(type) + ", " 171 + BCELifier.printArgumentTypes(arg_types) + ", " + CONSTANT_PREFIX 172 + Const.getOpcodeName(opcode).toUpperCase(Locale.ENGLISH) + "));"); 173 } 174 175 176 @Override 177 @SuppressWarnings("fallthrough") // by design for case Const.ANEWARRAY 178 public void visitAllocationInstruction( final AllocationInstruction i ) { 179 Type type; 180 if (i instanceof CPInstruction) { 181 type = ((CPInstruction) i).getType(_cp); 182 } else { 183 type = ((NEWARRAY) i).getType(); 184 } 185 final short opcode = ((Instruction) i).getOpcode(); 186 int dim = 1; 187 switch (opcode) { 188 case Const.NEW: 189 _out.println("il.append(_factory.createNew(\"" + ((ObjectType) type).getClassName() 190 + "\"));"); 191 break; 192 case Const.MULTIANEWARRAY: 193 dim = ((MULTIANEWARRAY) i).getDimensions(); 194 //$FALL-THROUGH$ 195 case Const.ANEWARRAY: 196 case Const.NEWARRAY: 197 if (type instanceof ArrayType) { 198 type = ((ArrayType) type).getBasicType(); 199 } 200 _out.println("il.append(_factory.createNewArray(" + BCELifier.printType(type) 201 + ", (short) " + dim + "));"); 202 break; 203 default: 204 throw new RuntimeException("Oops: " + opcode); 205 } 206 } 207 208 209 private void createConstant( final Object value ) { 210 String embed = value.toString(); 211 if (value instanceof String) { 212 embed = '"' + Utility.convertString(embed) + '"'; 213 } else if (value instanceof Character) { 214 embed = "(char)0x" + Integer.toHexString(((Character) value).charValue()); 215 } else if (value instanceof Float) { 216 embed += "f"; 217 } else if (value instanceof Long) { 218 embed += "L"; 219 } else if (value instanceof ObjectType) { 220 final ObjectType ot = (ObjectType) value; 221 embed = "new ObjectType(\""+ot.getClassName()+"\")"; 222 } 223 224 _out.println("il.append(new PUSH(_cp, " + embed + "));"); 225 } 226 227 228 @Override 229 public void visitLDC( final LDC i ) { 230 createConstant(i.getValue(_cp)); 231 } 232 233 234 @Override 235 public void visitLDC2_W( final LDC2_W i ) { 236 createConstant(i.getValue(_cp)); 237 } 238 239 240 @Override 241 public void visitConstantPushInstruction( final ConstantPushInstruction i ) { 242 createConstant(i.getValue()); 243 } 244 245 246 @Override 247 public void visitINSTANCEOF( final INSTANCEOF i ) { 248 final Type type = i.getType(_cp); 249 _out.println("il.append(new INSTANCEOF(_cp.addClass(" + BCELifier.printType(type) + ")));"); 250 } 251 252 253 @Override 254 public void visitCHECKCAST( final CHECKCAST i ) { 255 final Type type = i.getType(_cp); 256 _out.println("il.append(_factory.createCheckCast(" + BCELifier.printType(type) + "));"); 257 } 258 259 260 @Override 261 public void visitReturnInstruction( final ReturnInstruction i ) { 262 final Type type = i.getType(_cp); 263 _out.println("il.append(_factory.createReturn(" + BCELifier.printType(type) + "));"); 264 } 265 266 // Memorize BranchInstructions that need an update 267 private final List<BranchInstruction> branches = new ArrayList<>(); 268 269 270 @Override 271 public void visitBranchInstruction( final BranchInstruction bi ) { 272 final BranchHandle bh = (BranchHandle) branch_map.get(bi); 273 final int pos = bh.getPosition(); 274 final String name = bi.getName() + "_" + pos; 275 if (bi instanceof Select) { 276 final Select s = (Select) bi; 277 branches.add(bi); 278 final StringBuilder args = new StringBuilder("new int[] { "); 279 final int[] matchs = s.getMatchs(); 280 for (int i = 0; i < matchs.length; i++) { 281 args.append(matchs[i]); 282 if (i < matchs.length - 1) { 283 args.append(", "); 284 } 285 } 286 args.append(" }"); 287 _out.print("Select " + name + " = new " + bi.getName().toUpperCase(Locale.ENGLISH) 288 + "(" + args + ", new InstructionHandle[] { "); 289 for (int i = 0; i < matchs.length; i++) { 290 _out.print("null"); 291 if (i < matchs.length - 1) { 292 _out.print(", "); 293 } 294 } 295 _out.println(" }, null);"); 296 } else { 297 final int t_pos = bh.getTarget().getPosition(); 298 String target; 299 if (pos > t_pos) { 300 target = "ih_" + t_pos; 301 } else { 302 branches.add(bi); 303 target = "null"; 304 } 305 _out.println(" BranchInstruction " + name + " = _factory.createBranchInstruction(" 306 + CONSTANT_PREFIX + bi.getName().toUpperCase(Locale.ENGLISH) + ", " + target 307 + ");"); 308 } 309 if (bh.hasTargeters()) { 310 _out.println(" ih_" + pos + " = il.append(" + name + ");"); 311 } else { 312 _out.println(" il.append(" + name + ");"); 313 } 314 } 315 316 317 @Override 318 public void visitRET( final RET i ) { 319 _out.println("il.append(new RET(" + i.getIndex() + ")));"); 320 } 321 322 323 private void updateBranchTargets() { 324 for (final BranchInstruction bi : branches) { 325 final BranchHandle bh = (BranchHandle) branch_map.get(bi); 326 final int pos = bh.getPosition(); 327 final String name = bi.getName() + "_" + pos; 328 int t_pos = bh.getTarget().getPosition(); 329 _out.println(" " + name + ".setTarget(ih_" + t_pos + ");"); 330 if (bi instanceof Select) { 331 final InstructionHandle[] ihs = ((Select) bi).getTargets(); 332 for (int j = 0; j < ihs.length; j++) { 333 t_pos = ihs[j].getPosition(); 334 _out.println(" " + name + ".setTarget(" + j + ", ih_" + t_pos + ");"); 335 } 336 } 337 } 338 } 339 340 341 private void updateExceptionHandlers() { 342 final CodeExceptionGen[] handlers = _mg.getExceptionHandlers(); 343 for (final CodeExceptionGen h : handlers) { 344 final String type = (h.getCatchType() == null) ? "null" : BCELifier.printType(h 345 .getCatchType()); 346 _out.println(" method.addExceptionHandler(" + "ih_" + h.getStartPC().getPosition() 347 + ", " + "ih_" + h.getEndPC().getPosition() + ", " + "ih_" 348 + h.getHandlerPC().getPosition() + ", " + type + ");"); 349 } 350 } 351 }