1
2
3
4
5
6 package mockit.asm.classes;
7
8 import static mockit.asm.jvmConstants.ConstantPoolTypes.INVOKE_DYNAMIC;
9
10 import edu.umd.cs.findbugs.annotations.NonNull;
11
12 import mockit.asm.constantPool.AttributeWriter;
13 import mockit.asm.constantPool.BootstrapMethodItem;
14 import mockit.asm.constantPool.ConstantPoolGeneration;
15 import mockit.asm.constantPool.DynamicItem;
16 import mockit.asm.constantPool.Item;
17 import mockit.asm.constantPool.MethodHandleItem;
18 import mockit.asm.util.ByteVector;
19 import mockit.asm.util.MethodHandle;
20
21 import org.checkerframework.checker.index.qual.NonNegative;
22
23
24
25
26 final class BootstrapMethodsWriter extends AttributeWriter {
27 @NonNull
28 private final ByteVector bootstrapMethods;
29 @NonNegative
30 private final int bootstrapMethodsCount;
31 @NonNegative
32 private final int bsmStartCodeIndex;
33
34 BootstrapMethodsWriter(@NonNull ConstantPoolGeneration cp, @NonNull ClassReader cr) {
35 super(cp);
36
37 int attrSize = cr.readInt();
38 bootstrapMethods = new ByteVector(attrSize + 62);
39 bootstrapMethodsCount = cr.readUnsignedShort();
40
41 bsmStartCodeIndex = cr.codeIndex;
42 bootstrapMethods.putByteArray(cr.code, bsmStartCodeIndex, attrSize - 2);
43 }
44
45
46
47
48 void copyBootstrapMethods(@NonNull ClassReader cr, @NonNull Item[] items) {
49 int previousCodeIndex = cr.codeIndex;
50 cr.codeIndex = bsmStartCodeIndex;
51
52 for (int bsmIndex = 0, bsmCount = bootstrapMethodsCount; bsmIndex < bsmCount; bsmIndex++) {
53 copyBootstrapMethod(cr, items, bsmIndex);
54 }
55
56 cr.codeIndex = previousCodeIndex;
57 }
58
59 private void copyBootstrapMethod(@NonNull ClassReader cr, @NonNull Item[] items, @NonNegative int bsmIndex) {
60 int position = cr.codeIndex - bsmStartCodeIndex;
61 MethodHandle bsm = cr.readMethodHandle();
62 int hashCode = bsm.hashCode();
63
64 for (int bsmArgCount = cr.readUnsignedShort(); bsmArgCount > 0; bsmArgCount--) {
65 Object bsmArg = cr.readConstItem();
66 hashCode ^= bsmArg.hashCode();
67 }
68
69 BootstrapMethodItem item = new BootstrapMethodItem(bsmIndex, position, hashCode);
70 item.setNext(items);
71 }
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88 @NonNull
89 DynamicItem addInvokeDynamicReference(@NonNull String name, @NonNull String desc, @NonNull MethodHandle bsm,
90 @NonNull Object... bsmArgs) {
91 ByteVector methods = bootstrapMethods;
92 int position = methods.getLength();
93
94 MethodHandleItem methodHandleItem = cp.newMethodHandleItem(bsm);
95 methods.putShort(methodHandleItem.index);
96
97 int argsLength = bsmArgs.length;
98 methods.putShort(argsLength);
99
100 int hashCode = bsm.hashCode();
101 hashCode = putBSMArgs(hashCode, bsmArgs);
102 hashCode &= 0x7FFFFFFF;
103
104 methods.setLength(position);
105
106 BootstrapMethodItem bsmItem = getBSMItem(hashCode);
107 return cp.createDynamicItem(INVOKE_DYNAMIC, name, desc, bsmItem.index);
108 }
109
110 private int putBSMArgs(int hashCode, @NonNull Object[] bsmArgs) {
111 for (Object bsmArg : bsmArgs) {
112 hashCode ^= bsmArg.hashCode();
113
114 Item constItem = cp.newConstItem(bsmArg);
115 bootstrapMethods.putShort(constItem.index);
116 }
117
118 return hashCode;
119 }
120
121 @NonNull
122 private BootstrapMethodItem getBSMItem(@NonNegative int hashCode) {
123 Item item = cp.getItem(hashCode);
124
125 while (item != null) {
126 if (item instanceof BootstrapMethodItem && item.getHashCode() == hashCode) {
127 return (BootstrapMethodItem) item;
128 }
129
130 item = item.getNext();
131 }
132
133 throw new IllegalStateException("BootstrapMethodItem not found for hash code " + hashCode);
134 }
135
136 @NonNegative
137 @Override
138 public int getSize() {
139 return 8 + bootstrapMethods.getLength();
140 }
141
142 @Override
143 public void put(@NonNull ByteVector out) {
144 setAttribute("BootstrapMethods");
145 put(out, 2 + bootstrapMethods.getLength());
146 out.putShort(bootstrapMethodsCount);
147 out.putByteVector(bootstrapMethods);
148 }
149 }