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