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