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