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