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