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