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 java.util.ArrayList;
20 import java.util.Arrays;
21 import java.util.Collections;
22 import java.util.Comparator;
23 import java.util.Hashtable;
24 import java.util.List;
25 import java.util.Objects;
26 import java.util.Stack;
27
28 import org.apache.bcel.Const;
29 import org.apache.bcel.classfile.AnnotationEntry;
30 import org.apache.bcel.classfile.Annotations;
31 import org.apache.bcel.classfile.Attribute;
32 import org.apache.bcel.classfile.Code;
33 import org.apache.bcel.classfile.CodeException;
34 import org.apache.bcel.classfile.ExceptionTable;
35 import org.apache.bcel.classfile.LineNumber;
36 import org.apache.bcel.classfile.LineNumberTable;
37 import org.apache.bcel.classfile.LocalVariable;
38 import org.apache.bcel.classfile.LocalVariableTable;
39 import org.apache.bcel.classfile.LocalVariableTypeTable;
40 import org.apache.bcel.classfile.Method;
41 import org.apache.bcel.classfile.ParameterAnnotationEntry;
42 import org.apache.bcel.classfile.ParameterAnnotations;
43 import org.apache.bcel.classfile.RuntimeVisibleParameterAnnotations;
44 import org.apache.bcel.classfile.Utility;
45 import org.apache.bcel.util.BCELComparator;
46 import org.apache.commons.lang3.ArrayUtils;
47
48
49
50
51
52
53
54
55
56
57
58
59 public class MethodGen extends FieldGenOrMethodGen {
60
61 static final class BranchStack {
62
63 private final Stack<BranchTarget> branchTargets = new Stack<>();
64 private final Hashtable<InstructionHandle, BranchTarget> visitedTargets = new Hashtable<>();
65
66 public BranchTarget pop() {
67 if (!branchTargets.empty()) {
68 return branchTargets.pop();
69 }
70 return null;
71 }
72
73 public void push(final InstructionHandle target, final int stackDepth) {
74 if (visited(target)) {
75 return;
76 }
77 branchTargets.push(visit(target, stackDepth));
78 }
79
80 private BranchTarget visit(final InstructionHandle target, final int stackDepth) {
81 final BranchTarget bt = new BranchTarget(target, stackDepth);
82 visitedTargets.put(target, bt);
83 return bt;
84 }
85
86 private boolean visited(final InstructionHandle target) {
87 return visitedTargets.get(target) != null;
88 }
89 }
90
91 static final class BranchTarget {
92
93 final InstructionHandle target;
94 final int stackDepth;
95
96 BranchTarget(final InstructionHandle target, final int stackDepth) {
97 this.target = target;
98 this.stackDepth = stackDepth;
99 }
100 }
101
102 private static BCELComparator<FieldGenOrMethodGen> bcelComparator = new BCELComparator<FieldGenOrMethodGen>() {
103
104 @Override
105 public boolean equals(final FieldGenOrMethodGen a, final FieldGenOrMethodGen b) {
106 return a == b || a != null && b != null && Objects.equals(a.getName(), b.getName()) && Objects.equals(a.getSignature(), b.getSignature());
107 }
108
109 @Override
110 public int hashCode(final FieldGenOrMethodGen o) {
111 return o != null ? Objects.hash(o.getSignature(), o.getName()) : 0;
112 }
113 };
114
115 private static byte[] getByteCodes(final Method method) {
116 final Code code = method.getCode();
117 if (code == null) {
118 throw new IllegalStateException(String.format("The method '%s' has no code.", method));
119 }
120 return code.getCode();
121 }
122
123
124
125
126 public static BCELComparator<FieldGenOrMethodGen> getComparator() {
127 return bcelComparator;
128 }
129
130
131
132
133
134
135 public static int getMaxStack(final ConstantPoolGen cp, final InstructionList il, final CodeExceptionGen[] et) {
136 final BranchStack branchTargets = new BranchStack();
137
138
139
140
141 for (final CodeExceptionGen element : et) {
142 final InstructionHandle handlerPc = element.getHandlerPC();
143 if (handlerPc != null) {
144 branchTargets.push(handlerPc, 1);
145 }
146 }
147 int stackDepth = 0;
148 int maxStackDepth = 0;
149 InstructionHandle ih = il.getStart();
150 while (ih != null) {
151 final Instruction instruction = ih.getInstruction();
152 final short opcode = instruction.getOpcode();
153 final int delta = instruction.produceStack(cp) - instruction.consumeStack(cp);
154 stackDepth += delta;
155 if (stackDepth > maxStackDepth) {
156 maxStackDepth = stackDepth;
157 }
158
159 if (instruction instanceof BranchInstruction) {
160 final BranchInstruction branch = (BranchInstruction) instruction;
161 if (instruction instanceof Select) {
162
163 final Select select = (Select) branch;
164 final InstructionHandle[] targets = select.getTargets();
165 for (final InstructionHandle target : targets) {
166 branchTargets.push(target, stackDepth);
167 }
168
169 ih = null;
170 } else if (!(branch instanceof IfInstruction)) {
171
172
173 if (opcode == Const.JSR || opcode == Const.JSR_W) {
174 branchTargets.push(ih.getNext(), stackDepth - 1);
175 }
176 ih = null;
177 }
178
179
180
181 branchTargets.push(branch.getTarget(), stackDepth);
182 } else
183 if (opcode == Const.ATHROW || opcode == Const.RET || opcode >= Const.IRETURN && opcode <= Const.RETURN) {
184 ih = null;
185 }
186
187 if (ih != null) {
188 ih = ih.getNext();
189 }
190
191 if (ih == null) {
192 final BranchTarget bt = branchTargets.pop();
193 if (bt != null) {
194 ih = bt.target;
195 stackDepth = bt.stackDepth;
196 }
197 }
198 }
199 return maxStackDepth;
200 }
201
202
203
204
205 public static void setComparator(final BCELComparator<FieldGenOrMethodGen> comparator) {
206 bcelComparator = comparator;
207 }
208
209 private String className;
210 private Type[] argTypes;
211 private String[] argNames;
212 private int maxLocals;
213 private int maxStack;
214 private InstructionList il;
215
216 private boolean stripAttributes;
217 private LocalVariableTypeTable localVariableTypeTable;
218 private final List<LocalVariableGen> variableList = new ArrayList<>();
219
220 private final List<LineNumberGen> lineNumberList = new ArrayList<>();
221
222 private final List<CodeExceptionGen> exceptionList = new ArrayList<>();
223
224 private final List<String> throwsList = new ArrayList<>();
225
226 private final List<Attribute> codeAttrsList = new ArrayList<>();
227
228 private List<AnnotationEntryGen>[] paramAnnotations;
229
230 private boolean hasParameterAnnotations;
231
232 private boolean haveUnpackedParameterAnnotations;
233
234 private List<MethodObserver> observers;
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253 public MethodGen(final int accessFlags, final Type returnType, final Type[] argTypes, String[] argNames, final String methodName, final String className,
254 final InstructionList il, final ConstantPoolGen cp) {
255 super(accessFlags);
256 setType(returnType);
257 setArgumentTypes(argTypes);
258 setArgumentNames(argNames);
259 setName(methodName);
260 setClassName(className);
261 setInstructionList(il);
262 setConstantPool(cp);
263 final boolean abstract_ = isAbstract() || isNative();
264 InstructionHandle start = null;
265 final InstructionHandle end = null;
266 if (!abstract_) {
267 start = il.getStart();
268
269
270
271
272 if (!isStatic() && className != null) {
273 addLocalVariable("this", ObjectType.getInstance(className), start, end);
274 }
275 }
276 if (argTypes != null) {
277 final int size = argTypes.length;
278 for (final Type argType : argTypes) {
279 if (Type.VOID == argType) {
280 throw new ClassGenException("'void' is an illegal argument type for a method");
281 }
282 }
283 if (argNames != null) {
284 if (size != argNames.length) {
285 throw new ClassGenException("Mismatch in argument array lengths: " + size + " vs. " + argNames.length);
286 }
287 } else {
288 argNames = new String[size];
289 for (int i = 0; i < size; i++) {
290 argNames[i] = "arg" + i;
291 }
292 setArgumentNames(argNames);
293 }
294 if (!abstract_) {
295 for (int i = 0; i < size; i++) {
296 addLocalVariable(argNames[i], argTypes[i], start, end);
297 }
298 }
299 }
300 }
301
302
303
304
305
306
307
308
309 public MethodGen(final Method method, final String className, final ConstantPoolGen cp) {
310 this(method.getAccessFlags(), Type.getReturnType(method.getSignature()), Type.getArgumentTypes(method.getSignature()),
311 null
312 , method.getName(), className,
313 (method.getAccessFlags() & (Const.ACC_ABSTRACT | Const.ACC_NATIVE)) == 0 ? new InstructionList(getByteCodes(method)) : null, cp);
314 final Attribute[] attributes = method.getAttributes();
315 for (final Attribute attribute : attributes) {
316 Attribute a = attribute;
317 if (a instanceof Code) {
318 final Code c = (Code) a;
319 setMaxStack(c.getMaxStack());
320 setMaxLocals(c.getMaxLocals());
321 final CodeException[] ces = c.getExceptionTable();
322 if (ces != null) {
323 for (final CodeException ce : ces) {
324 final int type = ce.getCatchType();
325 ObjectType cType = null;
326 if (type > 0) {
327 final String cen = method.getConstantPool().getConstantString(type, Const.CONSTANT_Class);
328 cType = ObjectType.getInstance(cen);
329 }
330 final int endPc = ce.getEndPC();
331 final int length = getByteCodes(method).length;
332 InstructionHandle end;
333 if (length == endPc) {
334 end = il.getEnd();
335 } else {
336 end = il.findHandle(endPc);
337 end = end.getPrev();
338 }
339 addExceptionHandler(il.findHandle(ce.getStartPC()), end, il.findHandle(ce.getHandlerPC()), cType);
340 }
341 }
342 final Attribute[] cAttributes = c.getAttributes();
343 for (final Attribute cAttribute : cAttributes) {
344 a = cAttribute;
345 if (a instanceof LineNumberTable) {
346 ((LineNumberTable) a).forEach(l -> {
347 final InstructionHandle ih = il.findHandle(l.getStartPC());
348 if (ih != null) {
349 addLineNumber(ih, l.getLineNumber());
350 }
351 });
352 } else if (a instanceof LocalVariableTable) {
353 updateLocalVariableTable((LocalVariableTable) a);
354 } else if (a instanceof LocalVariableTypeTable) {
355 this.localVariableTypeTable = (LocalVariableTypeTable) a.copy(cp.getConstantPool());
356 } else {
357 addCodeAttribute(a);
358 }
359 }
360 } else if (a instanceof ExceptionTable) {
361 Collections.addAll(throwsList, ((ExceptionTable) a).getExceptionNames());
362 } else if (a instanceof Annotations) {
363 final Annotations runtimeAnnotations = (Annotations) a;
364 runtimeAnnotations.forEach(element -> addAnnotationEntry(new AnnotationEntryGen(element, cp, false)));
365 } else {
366 addAttribute(a);
367 }
368 }
369 }
370
371
372
373
374 public void addAnnotationsAsAttribute(final ConstantPoolGen cp) {
375 addAll(AnnotationEntryGen.getAnnotationAttributes(cp, super.getAnnotationEntries()));
376 }
377
378
379
380
381
382
383
384
385 public void addCodeAttribute(final Attribute a) {
386 codeAttrsList.add(a);
387 }
388
389
390
391
392
393
394 public void addException(final String className) {
395 throwsList.add(className);
396 }
397
398
399
400
401
402
403
404
405
406
407
408 public CodeExceptionGen addExceptionHandler(final InstructionHandle startPc, final InstructionHandle endPc, final InstructionHandle handlerPc,
409 final ObjectType catchType) {
410 if (startPc == null || endPc == null || handlerPc == null) {
411 throw new ClassGenException("Exception handler target is null instruction");
412 }
413 final CodeExceptionGen c = new CodeExceptionGen(startPc, endPc, handlerPc, catchType);
414 exceptionList.add(c);
415 return c;
416 }
417
418
419
420
421
422
423
424
425 public LineNumberGen addLineNumber(final InstructionHandle ih, final int srcLine) {
426 final LineNumberGen l = new LineNumberGen(ih, srcLine);
427 lineNumberList.add(l);
428 return l;
429 }
430
431
432
433
434
435
436
437
438
439
440
441 public LocalVariableGen addLocalVariable(final String name, final Type type, final InstructionHandle start, final InstructionHandle end) {
442 return addLocalVariable(name, type, maxLocals, start, end);
443 }
444
445
446
447
448
449
450
451
452
453
454
455
456 public LocalVariableGen addLocalVariable(final String name, final Type type, final int slot, final InstructionHandle start, final InstructionHandle end) {
457 return addLocalVariable(name, type, slot, start, end, slot);
458 }
459
460
461
462
463
464
465
466
467
468
469
470
471
472 public LocalVariableGen addLocalVariable(final String name, final Type type, final int slot, final InstructionHandle start, final InstructionHandle end,
473 final int origIndex) {
474 final byte t = type.getType();
475 if (t != Const.T_ADDRESS) {
476 final int add = type.getSize();
477 if (slot + add > maxLocals) {
478 maxLocals = slot + add;
479 }
480 final LocalVariableGen l = new LocalVariableGen(slot, name, type, start, end, origIndex);
481 int i;
482 if ((i = variableList.indexOf(l)) >= 0) {
483 variableList.set(i, l);
484 } else {
485 variableList.add(l);
486 }
487 return l;
488 }
489 throw new IllegalArgumentException("Can not use " + type + " as type for local variable");
490 }
491
492
493
494
495 public void addObserver(final MethodObserver o) {
496 if (observers == null) {
497 observers = new ArrayList<>();
498 }
499 observers.add(o);
500 }
501
502 public void addParameterAnnotation(final int parameterIndex, final AnnotationEntryGen annotation) {
503 ensureExistingParameterAnnotationsUnpacked();
504 if (!hasParameterAnnotations) {
505 @SuppressWarnings("unchecked")
506 final List<AnnotationEntryGen>[] parmList = new List[argTypes.length];
507 paramAnnotations = parmList;
508 hasParameterAnnotations = true;
509 }
510 final List<AnnotationEntryGen> existingAnnotations = paramAnnotations[parameterIndex];
511 if (existingAnnotations != null) {
512 existingAnnotations.add(annotation);
513 } else {
514 final List<AnnotationEntryGen> l = new ArrayList<>();
515 l.add(annotation);
516 paramAnnotations[parameterIndex] = l;
517 }
518 }
519
520
521
522
523 public void addParameterAnnotationsAsAttribute(final ConstantPoolGen cp) {
524 if (!hasParameterAnnotations) {
525 return;
526 }
527 final Attribute[] attrs = AnnotationEntryGen.getParameterAnnotationAttributes(cp, paramAnnotations);
528 if (attrs != null) {
529 addAll(attrs);
530 }
531 }
532
533 private Attribute[] addRuntimeAnnotationsAsAttribute(final ConstantPoolGen cp) {
534 final Attribute[] attrs = AnnotationEntryGen.getAnnotationAttributes(cp, super.getAnnotationEntries());
535 addAll(attrs);
536 return attrs;
537 }
538
539 private Attribute[] addRuntimeParameterAnnotationsAsAttribute(final ConstantPoolGen cp) {
540 if (!hasParameterAnnotations) {
541 return Attribute.EMPTY_ARRAY;
542 }
543 final Attribute[] attrs = AnnotationEntryGen.getParameterAnnotationAttributes(cp, paramAnnotations);
544 addAll(attrs);
545 return attrs;
546 }
547
548 private void adjustLocalVariableTypeTable(final LocalVariableTable lvt) {
549 final LocalVariable[] lv = lvt.getLocalVariableTable();
550 for (final LocalVariable element : localVariableTypeTable.getLocalVariableTypeTable()) {
551 for (final LocalVariable l : lv) {
552 if (element.getName().equals(l.getName()) && element.getIndex() == l.getOrigIndex()) {
553 element.setLength(l.getLength());
554 element.setStartPC(l.getStartPC());
555 element.setIndex(l.getIndex());
556 break;
557 }
558 }
559 }
560 }
561
562
563
564
565 public MethodGen copy(final String className, final ConstantPoolGen cp) {
566 final Method m = ((MethodGen) clone()).getMethod();
567 final MethodGen mg = new MethodGen(m, className, super.getConstantPool());
568 if (super.getConstantPool() != cp) {
569 mg.setConstantPool(cp);
570 mg.getInstructionList().replaceConstantPool(super.getConstantPool(), cp);
571 }
572 return mg;
573 }
574
575
576
577
578
579
580
581 private void ensureExistingParameterAnnotationsUnpacked() {
582 if (haveUnpackedParameterAnnotations) {
583 return;
584 }
585
586 final Attribute[] attrs = getAttributes();
587 ParameterAnnotations paramAnnVisAttr = null;
588 ParameterAnnotations paramAnnInvisAttr = null;
589 for (final Attribute attribute : attrs) {
590 if (attribute instanceof ParameterAnnotations) {
591
592 if (!hasParameterAnnotations) {
593 @SuppressWarnings("unchecked")
594 final List<AnnotationEntryGen>[] parmList = new List[argTypes.length];
595 paramAnnotations = parmList;
596 Arrays.setAll(paramAnnotations, i -> new ArrayList<>());
597 }
598 hasParameterAnnotations = true;
599 final ParameterAnnotations rpa = (ParameterAnnotations) attribute;
600 if (rpa instanceof RuntimeVisibleParameterAnnotations) {
601 paramAnnVisAttr = rpa;
602 } else {
603 paramAnnInvisAttr = rpa;
604 }
605 final ParameterAnnotationEntry[] parameterAnnotationEntries = rpa.getParameterAnnotationEntries();
606 for (int j = 0; j < parameterAnnotationEntries.length; j++) {
607
608 final ParameterAnnotationEntry immutableArray = rpa.getParameterAnnotationEntries()[j];
609
610 final List<AnnotationEntryGen> mutable = makeMutableVersion(immutableArray.getAnnotationEntries());
611
612 paramAnnotations[j].addAll(mutable);
613 }
614 }
615 }
616 if (paramAnnVisAttr != null) {
617 removeAttribute(paramAnnVisAttr);
618 }
619 if (paramAnnInvisAttr != null) {
620 removeAttribute(paramAnnInvisAttr);
621 }
622 haveUnpackedParameterAnnotations = true;
623 }
624
625
626
627
628
629
630
631 @Override
632 public boolean equals(final Object obj) {
633 return obj instanceof FieldGenOrMethodGen && bcelComparator.equals(this, (FieldGenOrMethodGen) obj);
634 }
635
636
637
638
639
640
641
642
643 public List<AnnotationEntryGen> getAnnotationsOnParameter(final int i) {
644 ensureExistingParameterAnnotationsUnpacked();
645 if (!hasParameterAnnotations || i > argTypes.length) {
646 return null;
647 }
648 return paramAnnotations[i];
649 }
650
651 public String getArgumentName(final int i) {
652 return argNames[i];
653 }
654
655 public String[] getArgumentNames() {
656 return argNames.clone();
657 }
658
659 public Type getArgumentType(final int i) {
660 return argTypes[i];
661 }
662
663 public Type[] getArgumentTypes() {
664 return argTypes.clone();
665 }
666
667
668
669
670 public String getClassName() {
671 return className;
672 }
673
674
675
676
677 public Attribute[] getCodeAttributes() {
678 return codeAttrsList.toArray(Attribute.EMPTY_ARRAY);
679 }
680
681
682
683
684 private CodeException[] getCodeExceptions() {
685 final int size = exceptionList.size();
686 final CodeException[] cExc = new CodeException[size];
687 Arrays.setAll(cExc, i -> exceptionList.get(i).getCodeException(super.getConstantPool()));
688 return cExc;
689 }
690
691
692
693
694 public CodeExceptionGen[] getExceptionHandlers() {
695 return exceptionList.toArray(CodeExceptionGen.EMPTY_ARRAY);
696 }
697
698
699
700
701 public String[] getExceptions() {
702 return throwsList.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
703 }
704
705
706
707
708 private ExceptionTable getExceptionTable(final ConstantPoolGen cp) {
709 final int size = throwsList.size();
710 final int[] ex = new int[size];
711 Arrays.setAll(ex, i -> cp.addClass(throwsList.get(i)));
712 return new ExceptionTable(cp.addUtf8("Exceptions"), 2 + 2 * size, ex, cp.getConstantPool());
713 }
714
715 public InstructionList getInstructionList() {
716 return il;
717 }
718
719
720
721
722 public LineNumberGen[] getLineNumbers() {
723 return lineNumberList.toArray(LineNumberGen.EMPTY_ARRAY);
724 }
725
726
727
728
729 public LineNumberTable getLineNumberTable(final ConstantPoolGen cp) {
730 final int size = lineNumberList.size();
731 final LineNumber[] ln = new LineNumber[size];
732 Arrays.setAll(ln, i -> lineNumberList.get(i).getLineNumber());
733 return new LineNumberTable(cp.addUtf8("LineNumberTable"), 2 + ln.length * 4, ln, cp.getConstantPool());
734 }
735
736
737
738
739
740
741
742 public LocalVariableGen[] getLocalVariables() {
743 final int size = variableList.size();
744 final LocalVariableGen[] lg = new LocalVariableGen[size];
745 variableList.toArray(lg);
746 for (int i = 0; i < size; i++) {
747 if (lg[i].getStart() == null && il != null) {
748 lg[i].setStart(il.getStart());
749 }
750 if (lg[i].getEnd() == null && il != null) {
751 lg[i].setEnd(il.getEnd());
752 }
753 }
754 if (size > 1) {
755 Arrays.sort(lg, Comparator.comparingInt(LocalVariableGen::getIndex));
756 }
757 return lg;
758 }
759
760
761
762
763 public LocalVariableTable getLocalVariableTable(final ConstantPoolGen cp) {
764 final LocalVariableGen[] lg = getLocalVariables();
765 final int size = lg.length;
766 final LocalVariable[] lv = new LocalVariable[size];
767 Arrays.setAll(lv, i -> lg[i].getLocalVariable(cp));
768 return new LocalVariableTable(cp.addUtf8("LocalVariableTable"), 2 + lv.length * 10, lv, cp.getConstantPool());
769 }
770
771
772
773
774 public LocalVariableTypeTable getLocalVariableTypeTable() {
775 return localVariableTypeTable;
776 }
777
778 public int getMaxLocals() {
779 return maxLocals;
780 }
781
782 public int getMaxStack() {
783 return maxStack;
784 }
785
786
787
788
789
790
791
792 public Method getMethod() {
793 final String signature = getSignature();
794 final ConstantPoolGen cp = super.getConstantPool();
795 final int nameIndex = cp.addUtf8(super.getName());
796 final int signatureIndex = cp.addUtf8(signature);
797
798
799
800 final byte[] byteCode = il != null ? il.getByteCode() : null;
801 LineNumberTable lnt = null;
802 LocalVariableTable lvt = null;
803
804
805
806 if (!variableList.isEmpty() && !stripAttributes) {
807 updateLocalVariableTable(getLocalVariableTable(cp));
808 addCodeAttribute(lvt = getLocalVariableTable(cp));
809 }
810 if (localVariableTypeTable != null) {
811
812
813 if (lvt != null) {
814 adjustLocalVariableTypeTable(lvt);
815 }
816 addCodeAttribute(localVariableTypeTable);
817 }
818 if (!lineNumberList.isEmpty() && !stripAttributes) {
819 addCodeAttribute(lnt = getLineNumberTable(cp));
820 }
821 final Attribute[] codeAttrs = getCodeAttributes();
822
823
824
825 int attrsLen = 0;
826 for (final Attribute codeAttr : codeAttrs) {
827 attrsLen += codeAttr.getLength() + 6;
828 }
829 final CodeException[] cExc = getCodeExceptions();
830 final int excLen = cExc.length * 8;
831 Code code = null;
832 if (byteCode != null && !isAbstract() && !isNative()) {
833
834 final Attribute[] attributes = getAttributes();
835 for (final Attribute a : attributes) {
836 if (a instanceof Code) {
837 removeAttribute(a);
838 }
839 }
840 code = new Code(cp.addUtf8("Code"), 8 + byteCode.length +
841 2 + excLen +
842 2 + attrsLen,
843 maxStack, maxLocals, byteCode, cExc, codeAttrs, cp.getConstantPool());
844 addAttribute(code);
845 }
846 final Attribute[] annotations = addRuntimeAnnotationsAsAttribute(cp);
847 final Attribute[] parameterAnnotations = addRuntimeParameterAnnotationsAsAttribute(cp);
848 ExceptionTable et = null;
849 if (!throwsList.isEmpty()) {
850 addAttribute(et = getExceptionTable(cp));
851
852 }
853 final Method m = new Method(super.getAccessFlags(), nameIndex, signatureIndex, getAttributes(), cp.getConstantPool());
854
855 if (lvt != null) {
856 removeCodeAttribute(lvt);
857 }
858 if (localVariableTypeTable != null) {
859 removeCodeAttribute(localVariableTypeTable);
860 }
861 if (lnt != null) {
862 removeCodeAttribute(lnt);
863 }
864 if (code != null) {
865 removeAttribute(code);
866 }
867 if (et != null) {
868 removeAttribute(et);
869 }
870 removeRuntimeAttributes(annotations);
871 removeRuntimeAttributes(parameterAnnotations);
872 return m;
873 }
874
875 public Type getReturnType() {
876 return getType();
877 }
878
879 @Override
880 public String getSignature() {
881 return Type.getMethodSignature(super.getType(), argTypes);
882 }
883
884
885
886
887
888
889
890 @Override
891 public int hashCode() {
892 return bcelComparator.hashCode(this);
893 }
894
895 private List<AnnotationEntryGen> makeMutableVersion(final AnnotationEntry[] mutableArray) {
896 final List<AnnotationEntryGen> result = new ArrayList<>();
897 for (final AnnotationEntry element : mutableArray) {
898 result.add(new AnnotationEntryGen(element, getConstantPool(), false));
899 }
900 return result;
901 }
902
903
904
905
906 public void removeCodeAttribute(final Attribute a) {
907 codeAttrsList.remove(a);
908 }
909
910
911
912
913 public void removeCodeAttributes() {
914 localVariableTypeTable = null;
915 codeAttrsList.clear();
916 }
917
918
919
920
921 public void removeException(final String c) {
922 throwsList.remove(c);
923 }
924
925
926
927
928 public void removeExceptionHandler(final CodeExceptionGen c) {
929 exceptionList.remove(c);
930 }
931
932
933
934
935 public void removeExceptionHandlers() {
936 exceptionList.clear();
937 }
938
939
940
941
942 public void removeExceptions() {
943 throwsList.clear();
944 }
945
946
947
948
949 public void removeLineNumber(final LineNumberGen l) {
950 lineNumberList.remove(l);
951 }
952
953
954
955
956 public void removeLineNumbers() {
957 lineNumberList.clear();
958 }
959
960
961
962
963
964 public void removeLocalVariable(final LocalVariableGen l) {
965 l.dispose();
966 variableList.remove(l);
967 }
968
969
970
971
972 public void removeLocalVariables() {
973 variableList.forEach(LocalVariableGen::dispose);
974 variableList.clear();
975 }
976
977
978
979
980 public void removeLocalVariableTypeTable() {
981 localVariableTypeTable = null;
982 }
983
984
985
986
987
988 public void removeNOPs() {
989 if (il != null) {
990 InstructionHandle next;
991
992
993
994 for (InstructionHandle ih = il.getStart(); ih != null; ih = next) {
995 next = ih.getNext();
996 if (next != null && ih.getInstruction() instanceof NOP) {
997 try {
998 il.delete(ih);
999 } catch (final TargetLostException e) {
1000 for (final InstructionHandle target : e.getTargets()) {
1001 for (final InstructionTargeter targeter : target.getTargeters()) {
1002 targeter.updateTarget(target, next);
1003 }
1004 }
1005 }
1006 }
1007 }
1008 }
1009 }
1010
1011
1012
1013
1014 public void removeObserver(final MethodObserver o) {
1015 if (observers != null) {
1016 observers.remove(o);
1017 }
1018 }
1019
1020
1021
1022
1023
1024
1025
1026 public void removeRuntimeAttributes(final Attribute[] attrs) {
1027 for (final Attribute attr : attrs) {
1028 removeAttribute(attr);
1029 }
1030 }
1031
1032 public void setArgumentName(final int i, final String name) {
1033 argNames[i] = name;
1034 }
1035
1036 public void setArgumentNames(final String[] argNames) {
1037 this.argNames = argNames;
1038 }
1039
1040 public void setArgumentType(final int i, final Type type) {
1041 argTypes[i] = type;
1042 }
1043
1044 public void setArgumentTypes(final Type[] argTypes) {
1045 this.argTypes = argTypes;
1046 }
1047
1048 public void setClassName(final String className) {
1049 this.className = className;
1050 }
1051
1052 public void setInstructionList(final InstructionList il) {
1053 this.il = il;
1054 }
1055
1056
1057
1058
1059 public void setMaxLocals() {
1060 if (il != null) {
1061 int max = isStatic() ? 0 : 1;
1062 if (argTypes != null) {
1063 for (final Type argType : argTypes) {
1064 max += argType.getSize();
1065 }
1066 }
1067 for (InstructionHandle ih = il.getStart(); ih != null; ih = ih.getNext()) {
1068 final Instruction ins = ih.getInstruction();
1069 if (ins instanceof LocalVariableInstruction || ins instanceof RET || ins instanceof IINC) {
1070 final int index = ((IndexedInstruction) ins).getIndex() + ((TypedInstruction) ins).getType(super.getConstantPool()).getSize();
1071 if (index > max) {
1072 max = index;
1073 }
1074 }
1075 }
1076 maxLocals = max;
1077 } else {
1078 maxLocals = 0;
1079 }
1080 }
1081
1082
1083
1084
1085 public void setMaxLocals(final int m) {
1086 maxLocals = m;
1087 }
1088
1089
1090
1091
1092 public void setMaxStack() {
1093 if (il != null) {
1094 maxStack = getMaxStack(super.getConstantPool(), il, getExceptionHandlers());
1095 } else {
1096 maxStack = 0;
1097 }
1098 }
1099
1100
1101
1102
1103 public void setMaxStack(final int m) {
1104 maxStack = m;
1105 }
1106
1107 public void setReturnType(final Type returnType) {
1108 setType(returnType);
1109 }
1110
1111
1112
1113
1114 public void stripAttributes(final boolean flag) {
1115 stripAttributes = flag;
1116 }
1117
1118
1119
1120
1121
1122
1123
1124 @Override
1125 public final String toString() {
1126 final String access = Utility.accessToString(super.getAccessFlags());
1127 String signature = Type.getMethodSignature(super.getType(), argTypes);
1128 signature = Utility.methodSignatureToString(signature, super.getName(), access, true, getLocalVariableTable(super.getConstantPool()));
1129 final StringBuilder buf = new StringBuilder(signature);
1130 for (final Attribute a : getAttributes()) {
1131 if (!(a instanceof Code || a instanceof ExceptionTable)) {
1132 buf.append(" [").append(a).append("]");
1133 }
1134 }
1135
1136 if (!throwsList.isEmpty()) {
1137 for (final String throwsDescriptor : throwsList) {
1138 buf.append("\n\t\tthrows ").append(throwsDescriptor);
1139 }
1140 }
1141 return buf.toString();
1142 }
1143
1144
1145
1146
1147
1148 public void update() {
1149 if (observers != null) {
1150 for (final MethodObserver observer : observers) {
1151 observer.notify(this);
1152 }
1153 }
1154 }
1155
1156 private void updateLocalVariableTable(final LocalVariableTable a) {
1157 removeLocalVariables();
1158 for (final LocalVariable l : a.getLocalVariableTable()) {
1159 InstructionHandle start = il.findHandle(l.getStartPC());
1160 final InstructionHandle end = il.findHandle(l.getStartPC() + l.getLength());
1161
1162 if (null == start) {
1163 start = il.getStart();
1164 }
1165
1166
1167
1168 addLocalVariable(l.getName(), Type.getType(l.getSignature()), l.getIndex(), start, end, l.getOrigIndex());
1169 }
1170 }
1171 }