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