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