1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.bcel.generic;
20
21 import org.apache.bcel.Const;
22
23
24
25
26
27
28
29
30
31
32
33 public class InstructionFactory implements InstructionConstants {
34
35 private static final class MethodObject {
36
37 final Type[] argTypes;
38 final Type resultType;
39 final String className;
40 final String name;
41
42 MethodObject(final String c, final String n, final Type r, final Type[] a) {
43 this.className = c;
44 this.name = n;
45 this.resultType = r;
46 this.argTypes = a;
47 }
48 }
49
50 private static final String APPEND = "append";
51
52 private static final String FQCN_STRING_BUFFER = "java.lang.StringBuffer";
53
54
55
56
57 private static final String[] SHORT_NAMES = {"C", "F", "D", "B", "S", "I", "L"};
58
59 private static final MethodObject[] APPEND_METHOD_OBJECTS = {
60 new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[] { Type.STRING }),
61 new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[] { Type.OBJECT }), null, null,
62 new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[] { Type.BOOLEAN }),
63 new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[] { Type.CHAR }),
64 new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[] { Type.FLOAT }),
65 new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[] { Type.DOUBLE }),
66 new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[] { Type.INT }),
67 new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[] { Type.INT }),
68 new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[] { Type.INT }),
69 new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[] { Type.LONG })};
70
71
72
73
74 public static ArrayInstruction createArrayLoad(final Type type) {
75 switch (type.getType()) {
76 case Const.T_BOOLEAN:
77 case Const.T_BYTE:
78 return InstructionConst.BALOAD;
79 case Const.T_CHAR:
80 return InstructionConst.CALOAD;
81 case Const.T_SHORT:
82 return InstructionConst.SALOAD;
83 case Const.T_INT:
84 return InstructionConst.IALOAD;
85 case Const.T_FLOAT:
86 return InstructionConst.FALOAD;
87 case Const.T_DOUBLE:
88 return InstructionConst.DALOAD;
89 case Const.T_LONG:
90 return InstructionConst.LALOAD;
91 case Const.T_ARRAY:
92 case Const.T_OBJECT:
93 return InstructionConst.AALOAD;
94 default:
95 throw new IllegalArgumentException("Invalid type " + type);
96 }
97 }
98
99
100
101
102 public static ArrayInstruction createArrayStore(final Type type) {
103 switch (type.getType()) {
104 case Const.T_BOOLEAN:
105 case Const.T_BYTE:
106 return InstructionConst.BASTORE;
107 case Const.T_CHAR:
108 return InstructionConst.CASTORE;
109 case Const.T_SHORT:
110 return InstructionConst.SASTORE;
111 case Const.T_INT:
112 return InstructionConst.IASTORE;
113 case Const.T_FLOAT:
114 return InstructionConst.FASTORE;
115 case Const.T_DOUBLE:
116 return InstructionConst.DASTORE;
117 case Const.T_LONG:
118 return InstructionConst.LASTORE;
119 case Const.T_ARRAY:
120 case Const.T_OBJECT:
121 return InstructionConst.AASTORE;
122 default:
123 throw new IllegalArgumentException("Invalid type " + type);
124 }
125 }
126
127 private static ArithmeticInstruction createBinaryDoubleOp(final char op) {
128 switch (op) {
129 case '-':
130 return InstructionConst.DSUB;
131 case '+':
132 return InstructionConst.DADD;
133 case '*':
134 return InstructionConst.DMUL;
135 case '/':
136 return InstructionConst.DDIV;
137 case '%':
138 return InstructionConst.DREM;
139 default:
140 throw new IllegalArgumentException("Invalid operand " + op);
141 }
142 }
143
144 private static ArithmeticInstruction createBinaryFloatOp(final char op) {
145 switch (op) {
146 case '-':
147 return InstructionConst.FSUB;
148 case '+':
149 return InstructionConst.FADD;
150 case '*':
151 return InstructionConst.FMUL;
152 case '/':
153 return InstructionConst.FDIV;
154 case '%':
155 return InstructionConst.FREM;
156 default:
157 throw new IllegalArgumentException("Invalid operand " + op);
158 }
159 }
160
161 private static ArithmeticInstruction createBinaryIntOp(final char first, final String op) {
162 switch (first) {
163 case '-':
164 return InstructionConst.ISUB;
165 case '+':
166 return InstructionConst.IADD;
167 case '%':
168 return InstructionConst.IREM;
169 case '*':
170 return InstructionConst.IMUL;
171 case '/':
172 return InstructionConst.IDIV;
173 case '&':
174 return InstructionConst.IAND;
175 case '|':
176 return InstructionConst.IOR;
177 case '^':
178 return InstructionConst.IXOR;
179 case '<':
180 return InstructionConst.ISHL;
181 case '>':
182 return op.equals(">>>") ? InstructionConst.IUSHR : InstructionConst.ISHR;
183 default:
184 throw new IllegalArgumentException("Invalid operand " + op);
185 }
186 }
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208 private static ArithmeticInstruction createBinaryLongOp(final char first, final String op) {
209 switch (first) {
210 case '-':
211 return InstructionConst.LSUB;
212 case '+':
213 return InstructionConst.LADD;
214 case '%':
215 return InstructionConst.LREM;
216 case '*':
217 return InstructionConst.LMUL;
218 case '/':
219 return InstructionConst.LDIV;
220 case '&':
221 return InstructionConst.LAND;
222 case '|':
223 return InstructionConst.LOR;
224 case '^':
225 return InstructionConst.LXOR;
226 case '<':
227 return InstructionConst.LSHL;
228 case '>':
229 return op.equals(">>>") ? InstructionConst.LUSHR : InstructionConst.LSHR;
230 default:
231 throw new IllegalArgumentException("Invalid operand " + op);
232 }
233 }
234
235
236
237
238
239
240 public static ArithmeticInstruction createBinaryOperation(final String op, final Type type) {
241 final char first = op.charAt(0);
242 switch (type.getType()) {
243 case Const.T_BYTE:
244 case Const.T_SHORT:
245 case Const.T_INT:
246 case Const.T_CHAR:
247 return createBinaryIntOp(first, op);
248 case Const.T_LONG:
249 return createBinaryLongOp(first, op);
250 case Const.T_FLOAT:
251 return createBinaryFloatOp(first);
252 case Const.T_DOUBLE:
253 return createBinaryDoubleOp(first);
254 default:
255 throw new IllegalArgumentException("Invalid type " + type);
256 }
257 }
258
259
260
261
262
263 public static BranchInstruction createBranchInstruction(final short opcode, final InstructionHandle target) {
264 switch (opcode) {
265 case Const.IFEQ:
266 return new IFEQ(target);
267 case Const.IFNE:
268 return new IFNE(target);
269 case Const.IFLT:
270 return new IFLT(target);
271 case Const.IFGE:
272 return new IFGE(target);
273 case Const.IFGT:
274 return new IFGT(target);
275 case Const.IFLE:
276 return new IFLE(target);
277 case Const.IF_ICMPEQ:
278 return new IF_ICMPEQ(target);
279 case Const.IF_ICMPNE:
280 return new IF_ICMPNE(target);
281 case Const.IF_ICMPLT:
282 return new IF_ICMPLT(target);
283 case Const.IF_ICMPGE:
284 return new IF_ICMPGE(target);
285 case Const.IF_ICMPGT:
286 return new IF_ICMPGT(target);
287 case Const.IF_ICMPLE:
288 return new IF_ICMPLE(target);
289 case Const.IF_ACMPEQ:
290 return new IF_ACMPEQ(target);
291 case Const.IF_ACMPNE:
292 return new IF_ACMPNE(target);
293 case Const.GOTO:
294 return new GOTO(target);
295 case Const.JSR:
296 return new JSR(target);
297 case Const.IFNULL:
298 return new IFNULL(target);
299 case Const.IFNONNULL:
300 return new IFNONNULL(target);
301 case Const.GOTO_W:
302 return new GOTO_W(target);
303 case Const.JSR_W:
304 return new JSR_W(target);
305 default:
306 throw new IllegalArgumentException("Invalid opcode: " + opcode);
307 }
308 }
309
310
311
312
313 public static StackInstruction createDup(final int size) {
314 return size == 2 ? InstructionConst.DUP2 : InstructionConst.DUP;
315 }
316
317
318
319
320 public static StackInstruction createDup_1(final int size) {
321 return size == 2 ? InstructionConst.DUP2_X1 : InstructionConst.DUP_X1;
322 }
323
324
325
326
327 public static StackInstruction createDup_2(final int size) {
328 return size == 2 ? InstructionConst.DUP2_X2 : InstructionConst.DUP_X2;
329 }
330
331
332
333
334 public static LocalVariableInstruction createLoad(final Type type, final int index) {
335 switch (type.getType()) {
336 case Const.T_BOOLEAN:
337 case Const.T_CHAR:
338 case Const.T_BYTE:
339 case Const.T_SHORT:
340 case Const.T_INT:
341 return new ILOAD(index);
342 case Const.T_FLOAT:
343 return new FLOAD(index);
344 case Const.T_DOUBLE:
345 return new DLOAD(index);
346 case Const.T_LONG:
347 return new LLOAD(index);
348 case Const.T_ARRAY:
349 case Const.T_OBJECT:
350 return new ALOAD(index);
351 default:
352 throw new IllegalArgumentException("Invalid type " + type);
353 }
354 }
355
356
357
358
359 public static Instruction createNull(final Type type) {
360 switch (type.getType()) {
361 case Const.T_ARRAY:
362 case Const.T_OBJECT:
363 return InstructionConst.ACONST_NULL;
364 case Const.T_INT:
365 case Const.T_SHORT:
366 case Const.T_BOOLEAN:
367 case Const.T_CHAR:
368 case Const.T_BYTE:
369 return InstructionConst.ICONST_0;
370 case Const.T_FLOAT:
371 return InstructionConst.FCONST_0;
372 case Const.T_DOUBLE:
373 return InstructionConst.DCONST_0;
374 case Const.T_LONG:
375 return InstructionConst.LCONST_0;
376 case Const.T_VOID:
377 return InstructionConst.NOP;
378 default:
379 throw new IllegalArgumentException("Invalid type: " + type);
380 }
381 }
382
383
384
385
386 public static StackInstruction createPop(final int size) {
387 return size == 2 ? InstructionConst.POP2 : InstructionConst.POP;
388 }
389
390
391
392
393 public static ReturnInstruction createReturn(final Type type) {
394 switch (type.getType()) {
395 case Const.T_ARRAY:
396 case Const.T_OBJECT:
397 return InstructionConst.ARETURN;
398 case Const.T_INT:
399 case Const.T_SHORT:
400 case Const.T_BOOLEAN:
401 case Const.T_CHAR:
402 case Const.T_BYTE:
403 return InstructionConst.IRETURN;
404 case Const.T_FLOAT:
405 return InstructionConst.FRETURN;
406 case Const.T_DOUBLE:
407 return InstructionConst.DRETURN;
408 case Const.T_LONG:
409 return InstructionConst.LRETURN;
410 case Const.T_VOID:
411 return InstructionConst.RETURN;
412 default:
413 throw new IllegalArgumentException("Invalid type: " + type);
414 }
415 }
416
417
418
419
420 public static LocalVariableInstruction createStore(final Type type, final int index) {
421 switch (type.getType()) {
422 case Const.T_BOOLEAN:
423 case Const.T_CHAR:
424 case Const.T_BYTE:
425 case Const.T_SHORT:
426 case Const.T_INT:
427 return new ISTORE(index);
428 case Const.T_FLOAT:
429 return new FSTORE(index);
430 case Const.T_DOUBLE:
431 return new DSTORE(index);
432 case Const.T_LONG:
433 return new LSTORE(index);
434 case Const.T_ARRAY:
435 case Const.T_OBJECT:
436 return new ASTORE(index);
437 default:
438 throw new IllegalArgumentException("Invalid type " + type);
439 }
440 }
441
442
443
444
445 public static Instruction createThis() {
446 return new ALOAD(0);
447 }
448
449 private static boolean isString(final Type type) {
450 return type instanceof ObjectType && ((ObjectType) type).getClassName().equals("java.lang.String");
451 }
452
453
454
455
456 @Deprecated
457 protected ClassGen cg;
458
459
460
461
462 @Deprecated
463 protected ConstantPoolGen cp;
464
465
466
467
468 public InstructionFactory(final ClassGen cg) {
469 this(cg, cg.getConstantPool());
470 }
471
472 public InstructionFactory(final ClassGen cg, final ConstantPoolGen cp) {
473 this.cg = cg;
474 this.cp = cp;
475 }
476
477
478
479
480 public InstructionFactory(final ConstantPoolGen cp) {
481 this(null, cp);
482 }
483
484 public Instruction createAppend(final Type type) {
485 final byte t = type.getType();
486 if (isString(type)) {
487 return createInvoke(APPEND_METHOD_OBJECTS[0], Const.INVOKEVIRTUAL);
488 }
489 switch (t) {
490 case Const.T_BOOLEAN:
491 case Const.T_CHAR:
492 case Const.T_FLOAT:
493 case Const.T_DOUBLE:
494 case Const.T_BYTE:
495 case Const.T_SHORT:
496 case Const.T_INT:
497 case Const.T_LONG:
498 return createInvoke(APPEND_METHOD_OBJECTS[t], Const.INVOKEVIRTUAL);
499 case Const.T_ARRAY:
500 case Const.T_OBJECT:
501 return createInvoke(APPEND_METHOD_OBJECTS[1], Const.INVOKEVIRTUAL);
502 default:
503 throw new IllegalArgumentException("No append for this type? " + type);
504 }
505 }
506
507
508
509
510
511 public Instruction createCast(final Type srcType, final Type destType) {
512 if (srcType instanceof BasicType && destType instanceof BasicType) {
513 final byte dest = destType.getType();
514 byte src = srcType.getType();
515 if (dest == Const.T_LONG && (src == Const.T_CHAR || src == Const.T_BYTE || src == Const.T_SHORT)) {
516 src = Const.T_INT;
517 }
518 final String name = "org.apache.bcel.generic." + SHORT_NAMES[src - Const.T_CHAR] + "2" + SHORT_NAMES[dest - Const.T_CHAR];
519 Instruction i = null;
520 try {
521 i = (Instruction) Class.forName(name).getConstructor().newInstance();
522 } catch (final Exception e) {
523 throw new IllegalArgumentException("Could not find instruction: " + name, e);
524 }
525 return i;
526 }
527 if (!(srcType instanceof ReferenceType) || !(destType instanceof ReferenceType)) {
528 throw new IllegalArgumentException("Cannot cast " + srcType + " to " + destType);
529 }
530 if (destType instanceof ArrayType) {
531 return new CHECKCAST(cp.addArrayClass((ArrayType) destType));
532 }
533 return new CHECKCAST(cp.addClass(((ObjectType) destType).getClassName()));
534 }
535
536 public CHECKCAST createCheckCast(final ReferenceType t) {
537 if (t instanceof ArrayType) {
538 return new CHECKCAST(cp.addArrayClass((ArrayType) t));
539 }
540 return new CHECKCAST(cp.addClass((ObjectType) t));
541 }
542
543
544
545
546
547
548 public Instruction createConstant(final Object value) {
549 final PUSH push;
550 if (value instanceof Number) {
551 push = new PUSH(cp, (Number) value);
552 } else if (value instanceof String) {
553 push = new PUSH(cp, (String) value);
554 } else if (value instanceof Boolean) {
555 push = new PUSH(cp, (Boolean) value);
556 } else if (value instanceof Character) {
557 push = new PUSH(cp, (Character) value);
558 } else {
559 throw new ClassGenException("Illegal type: " + value.getClass());
560 }
561 return push.getInstruction();
562 }
563
564
565
566
567
568
569
570
571
572
573 public FieldInstruction createFieldAccess(final String className, final String name, final Type type, final short kind) {
574 final String signature = type.getSignature();
575 final int index = cp.addFieldref(className, name, signature);
576 switch (kind) {
577 case Const.GETFIELD:
578 return new GETFIELD(index);
579 case Const.PUTFIELD:
580 return new PUTFIELD(index);
581 case Const.GETSTATIC:
582 return new GETSTATIC(index);
583 case Const.PUTSTATIC:
584 return new PUTSTATIC(index);
585 default:
586 throw new IllegalArgumentException("Unknown getfield kind:" + kind);
587 }
588 }
589
590 public GETFIELD createGetField(final String className, final String name, final Type t) {
591 return new GETFIELD(cp.addFieldref(className, name, t.getSignature()));
592 }
593
594 public GETSTATIC createGetStatic(final String className, final String name, final Type t) {
595 return new GETSTATIC(cp.addFieldref(className, name, t.getSignature()));
596 }
597
598 public INSTANCEOF createInstanceOf(final ReferenceType t) {
599 if (t instanceof ArrayType) {
600 return new INSTANCEOF(cp.addArrayClass((ArrayType) t));
601 }
602 return new INSTANCEOF(cp.addClass((ObjectType) t));
603 }
604
605 private InvokeInstruction createInvoke(final MethodObject m, final short kind) {
606 return createInvoke(m.className, m.name, m.resultType, m.argTypes, kind);
607 }
608
609
610
611
612
613
614
615
616
617
618
619 public InvokeInstruction createInvoke(final String className, final String name, final Type retType, final Type[] argTypes, final short kind) {
620 return createInvoke(className, name, retType, argTypes, kind, kind == Const.INVOKEINTERFACE);
621 }
622
623
624
625
626
627
628
629
630
631
632
633
634
635 public InvokeInstruction createInvoke(final String className, final String name, final Type retType, final Type[] argTypes, final short kind,
636 final boolean useInterface) {
637 if (kind != Const.INVOKESPECIAL && kind != Const.INVOKEVIRTUAL && kind != Const.INVOKESTATIC && kind != Const.INVOKEINTERFACE
638 && kind != Const.INVOKEDYNAMIC) {
639 throw new IllegalArgumentException("Unknown invoke kind: " + kind);
640 }
641 final int index;
642 int nargs = 0;
643 final String signature = Type.getMethodSignature(retType, argTypes);
644 if (argTypes != null) {
645 for (final Type argType : argTypes) {
646 nargs += argType.getSize();
647 }
648 }
649 if (useInterface) {
650 index = cp.addInterfaceMethodref(className, name, signature);
651 } else {
652 index = cp.addMethodref(className, name, signature);
653 }
654 switch (kind) {
655 case Const.INVOKESPECIAL:
656 return new INVOKESPECIAL(index);
657 case Const.INVOKEVIRTUAL:
658 return new INVOKEVIRTUAL(index);
659 case Const.INVOKESTATIC:
660 return new INVOKESTATIC(index);
661 case Const.INVOKEINTERFACE:
662 return new INVOKEINTERFACE(index, nargs + 1);
663 case Const.INVOKEDYNAMIC:
664 return new INVOKEDYNAMIC(index);
665 default:
666
667 throw new IllegalStateException("Unknown invoke kind: " + kind);
668 }
669 }
670
671 public NEW createNew(final ObjectType t) {
672 return new NEW(cp.addClass(t));
673 }
674
675 public NEW createNew(final String s) {
676 return createNew(ObjectType.getInstance(s));
677 }
678
679
680
681
682
683
684 public Instruction createNewArray(final Type t, final short dim) {
685 if (dim == 1) {
686 if (t instanceof ObjectType) {
687 return new ANEWARRAY(cp.addClass((ObjectType) t));
688 }
689 if (t instanceof ArrayType) {
690 return new ANEWARRAY(cp.addArrayClass((ArrayType) t));
691 }
692 return new NEWARRAY(t.getType());
693 }
694 final ArrayType at;
695 if (t instanceof ArrayType) {
696 at = (ArrayType) t;
697 } else {
698 at = new ArrayType(t, dim);
699 }
700 return new MULTIANEWARRAY(cp.addArrayClass(at), dim);
701 }
702
703
704
705
706
707
708 public InstructionList createPrintln(final String s) {
709 final InstructionList il = new InstructionList();
710 il.append(createGetStatic("java.lang.System", "out", Type.getType("Ljava/io/PrintStream;")));
711 il.append(new PUSH(cp, s));
712 final MethodObject methodObject = new MethodObject("java.io.PrintStream", "println", Type.VOID, new Type[] { Type.getType("Ljava/lang/String;") });
713 il.append(createInvoke(methodObject, Const.INVOKEVIRTUAL));
714 return il;
715 }
716
717 public PUTFIELD createPutField(final String className, final String name, final Type t) {
718 return new PUTFIELD(cp.addFieldref(className, name, t.getSignature()));
719 }
720
721 public PUTSTATIC createPutStatic(final String className, final String name, final Type t) {
722 return new PUTSTATIC(cp.addFieldref(className, name, t.getSignature()));
723 }
724
725 public ClassGen getClassGen() {
726 return cg;
727 }
728
729 public ConstantPoolGen getConstantPool() {
730 return cp;
731 }
732
733 public void setClassGen(final ClassGen c) {
734 cg = c;
735 }
736
737 public void setConstantPool(final ConstantPoolGen c) {
738 cp = c;
739 }
740 }