9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package jdk.internal.classfile.impl;
27
28 import java.lang.classfile.BufWriter;
29 import java.lang.classfile.ClassReader;
30 import java.lang.classfile.Label;
31 import java.lang.classfile.MethodModel;
32 import java.lang.classfile.attribute.StackMapFrameInfo;
33 import java.lang.classfile.attribute.StackMapFrameInfo.ObjectVerificationTypeInfo;
34 import java.lang.classfile.attribute.StackMapFrameInfo.SimpleVerificationTypeInfo;
35 import java.lang.classfile.attribute.StackMapFrameInfo.UninitializedVerificationTypeInfo;
36 import java.lang.classfile.attribute.StackMapFrameInfo.VerificationTypeInfo;
37 import java.lang.classfile.constantpool.ClassEntry;
38 import java.lang.constant.ConstantDescs;
39 import java.lang.constant.MethodTypeDesc;
40 import java.lang.reflect.AccessFlag;
41 import java.util.Arrays;
42 import java.util.Comparator;
43 import java.util.List;
44 import java.util.Objects;
45
46 import static java.lang.classfile.ClassFile.ACC_STATIC;
47 import static java.util.Objects.requireNonNull;
48 import static jdk.internal.classfile.impl.StackMapGenerator.*;
49
50 public class StackMapDecoder {
51
52 private static final StackMapFrameInfo[] NO_STACK_FRAME_INFOS = {};
53
54 private final ClassReader classReader;
55 private final int pos;
56 private final LabelContext ctx;
57 private final List<VerificationTypeInfo> initFrameLocals;
58 private int p;
59
60 StackMapDecoder(ClassReader classReader, int pos, LabelContext ctx, List<VerificationTypeInfo> initFrameLocals) {
61 this.classReader = classReader;
62 this.pos = pos;
63 this.ctx = ctx;
64 this.initFrameLocals = initFrameLocals;
65 }
66
67 static List<VerificationTypeInfo> initFrameLocals(MethodModel method) {
68 return initFrameLocals(method.parent().orElseThrow().thisClass(),
69 method.methodName().stringValue(),
70 method.methodTypeSymbol(),
71 method.flags().has(AccessFlag.STATIC));
72 }
73
74 public static List<VerificationTypeInfo> initFrameLocals(ClassEntry thisClass, String methodName, MethodTypeDesc methodType, boolean isStatic) {
75 VerificationTypeInfo vtis[];
76 int i = 0;
77 if (!isStatic) {
78 vtis = new VerificationTypeInfo[methodType.parameterCount() + 1];
79 if ("<init>".equals(methodName) && !ConstantDescs.CD_Object.equals(thisClass.asSymbol())) {
80 vtis[i++] = SimpleVerificationTypeInfo.UNINITIALIZED_THIS;
81 } else {
82 vtis[i++] = new StackMapDecoder.ObjectVerificationTypeInfoImpl(thisClass);
83 }
84 } else {
85 vtis = new VerificationTypeInfo[methodType.parameterCount()];
86 }
87 for (int pi = 0; pi < methodType.parameterCount(); pi++) {
88 var arg = methodType.parameterType(pi);
89 vtis[i++] = switch (arg.descriptorString().charAt(0)) {
90 case 'I', 'S', 'C' ,'B', 'Z' -> SimpleVerificationTypeInfo.INTEGER;
91 case 'J' -> SimpleVerificationTypeInfo.LONG;
92 case 'F' -> SimpleVerificationTypeInfo.FLOAT;
93 case 'D' -> SimpleVerificationTypeInfo.DOUBLE;
94 case 'V' -> throw new IllegalArgumentException("Illegal method argument type: " + arg);
95 default -> new StackMapDecoder.ObjectVerificationTypeInfoImpl(TemporaryConstantPool.INSTANCE.classEntry(arg));
96 };
97 }
98 return List.of(vtis);
99 }
100
101 public static void writeFrames(BufWriter b, List<StackMapFrameInfo> entries) {
102 var buf = (BufWriterImpl)b;
103 var dcb = (DirectCodeBuilder)buf.labelContext();
104 var mi = dcb.methodInfo();
105 var prevLocals = StackMapDecoder.initFrameLocals(buf.thisClass(),
106 mi.methodName().stringValue(),
107 mi.methodTypeSymbol(),
108 (mi.methodFlags() & ACC_STATIC) != 0);
109 int prevOffset = -1;
110 // avoid using method handles due to early bootstrap
111 StackMapFrameInfo[] infos = entries.toArray(NO_STACK_FRAME_INFOS);
112 //sort by resolved label offsets first to allow unordered entries
113 Arrays.sort(infos, new Comparator<StackMapFrameInfo>() {
114 public int compare(final StackMapFrameInfo o1, final StackMapFrameInfo o2) {
115 return Integer.compare(dcb.labelToBci(o1.target()), dcb.labelToBci(o2.target()));
116 }
117 });
118 b.writeU2(infos.length);
119 for (var fr : infos) {
120 int offset = dcb.labelToBci(fr.target());
121 if (offset == prevOffset) {
122 throw new IllegalArgumentException("Duplicated stack frame bytecode index: " + offset);
123 }
124 writeFrame(buf, offset - prevOffset - 1, prevLocals, fr);
125 prevOffset = offset;
126 prevLocals = fr.locals();
127 }
128 }
129
130 private static void writeFrame(BufWriterImpl out, int offsetDelta, List<VerificationTypeInfo> prevLocals, StackMapFrameInfo fr) {
131 if (offsetDelta < 0) throw new IllegalArgumentException("Invalid stack map frames order");
132 if (fr.stack().isEmpty()) {
133 int commonLocalsSize = Math.min(prevLocals.size(), fr.locals().size());
134 int diffLocalsSize = fr.locals().size() - prevLocals.size();
135 if (-3 <= diffLocalsSize && diffLocalsSize <= 3 && equals(fr.locals(), prevLocals, commonLocalsSize)) {
136 if (diffLocalsSize == 0 && offsetDelta <= SAME_FRAME_END) { //same frame
137 out.writeU1(offsetDelta);
138 } else { //chop, same extended or append frame
139 out.writeU1U2(SAME_FRAME_EXTENDED + diffLocalsSize, offsetDelta);
140 for (int i=commonLocalsSize; i<fr.locals().size(); i++) writeTypeInfo(out, fr.locals().get(i));
141 }
142 return;
143 }
144 } else if (fr.stack().size() == 1 && fr.locals().equals(prevLocals)) {
145 if (offsetDelta <= SAME_LOCALS_1_STACK_ITEM_FRAME_END - SAME_LOCALS_1_STACK_ITEM_FRAME_START) { //same locals 1 stack item frame
146 out.writeU1(SAME_LOCALS_1_STACK_ITEM_FRAME_START + offsetDelta);
147 } else { //same locals 1 stack item extended frame
148 out.writeU1U2(SAME_LOCALS_1_STACK_ITEM_EXTENDED, offsetDelta);
149 }
150 writeTypeInfo(out, fr.stack().get(0));
151 return;
161 for (int i = 0; i < compareSize; i++) {
162 if (!l1.get(i).equals(l2.get(i))) return false;
163 }
164 return true;
165 }
166
167 private static void writeTypeInfo(BufWriterImpl bw, VerificationTypeInfo vti) {
168 int tag = vti.tag();
169 switch (tag) {
170 case ITEM_TOP, ITEM_INTEGER, ITEM_FLOAT, ITEM_DOUBLE, ITEM_LONG, ITEM_NULL,
171 ITEM_UNINITIALIZED_THIS ->
172 bw.writeU1(tag);
173 case ITEM_OBJECT ->
174 bw.writeU1U2(tag, bw.cpIndex(((ObjectVerificationTypeInfo)vti).className()));
175 case ITEM_UNINITIALIZED ->
176 bw.writeU1U2(tag, bw.labelContext().labelToBci(((UninitializedVerificationTypeInfo)vti).newTarget()));
177 default -> throw new IllegalArgumentException("Invalid verification type tag: " + vti.tag());
178 }
179 }
180
181 List<StackMapFrameInfo> entries() {
182 p = pos;
183 List<VerificationTypeInfo> locals = initFrameLocals, stack = List.of();
184 int bci = -1;
185 var entries = new StackMapFrameInfo[u2()];
186 for (int ei = 0; ei < entries.length; ei++) {
187 int frameType = classReader.readU1(p++);
188 if (frameType <= SAME_FRAME_END) {
189 bci += frameType + 1;
190 stack = List.of();
191 } else if (frameType <= SAME_LOCALS_1_STACK_ITEM_FRAME_END) {
192 bci += frameType - SAME_LOCALS_1_STACK_ITEM_FRAME_START + 1;
193 stack = List.of(readVerificationTypeInfo());
194 } else {
195 if (frameType < SAME_LOCALS_1_STACK_ITEM_EXTENDED)
196 throw new IllegalArgumentException("Invalid stackmap frame type: " + frameType);
197 bci += u2() + 1;
198 if (frameType == SAME_LOCALS_1_STACK_ITEM_EXTENDED) {
199 stack = List.of(readVerificationTypeInfo());
200 } else if (frameType < SAME_FRAME_EXTENDED) {
201 locals = locals.subList(0, locals.size() + frameType - SAME_FRAME_EXTENDED);
202 stack = List.of();
203 } else if (frameType == SAME_FRAME_EXTENDED) {
204 stack = List.of();
205 } else if (frameType <= APPEND_FRAME_END) {
206 int actSize = locals.size();
207 var newLocals = locals.toArray(new VerificationTypeInfo[actSize + frameType - SAME_FRAME_EXTENDED]);
208 for (int i = actSize; i < newLocals.length; i++)
209 newLocals[i] = readVerificationTypeInfo();
210 locals = List.of(newLocals);
211 stack = List.of();
212 } else {
213 var newLocals = new VerificationTypeInfo[u2()];
214 for (int i=0; i<newLocals.length; i++)
215 newLocals[i] = readVerificationTypeInfo();
216 var newStack = new VerificationTypeInfo[u2()];
217 for (int i=0; i<newStack.length; i++)
218 newStack[i] = readVerificationTypeInfo();
219 locals = List.of(newLocals);
220 stack = List.of(newStack);
221 }
222 }
223 entries[ei] = new StackMapFrameImpl(frameType,
224 ctx.getLabel(bci),
225 locals,
226 stack);
227 }
228 return List.of(entries);
229 }
230
231 private VerificationTypeInfo readVerificationTypeInfo() {
232 int tag = classReader.readU1(p++);
233 return switch (tag) {
234 case ITEM_TOP -> SimpleVerificationTypeInfo.TOP;
235 case ITEM_INTEGER -> SimpleVerificationTypeInfo.INTEGER;
236 case ITEM_FLOAT -> SimpleVerificationTypeInfo.FLOAT;
237 case ITEM_DOUBLE -> SimpleVerificationTypeInfo.DOUBLE;
238 case ITEM_LONG -> SimpleVerificationTypeInfo.LONG;
239 case ITEM_NULL -> SimpleVerificationTypeInfo.NULL;
240 case ITEM_UNINITIALIZED_THIS -> SimpleVerificationTypeInfo.UNINITIALIZED_THIS;
241 case ITEM_OBJECT -> new ObjectVerificationTypeInfoImpl(classReader.entryByIndex(u2(), ClassEntry.class));
242 case ITEM_UNINITIALIZED -> new UninitializedVerificationTypeInfoImpl(ctx.getLabel(u2()));
243 default -> throw new IllegalArgumentException("Invalid verification type tag: " + tag);
244 };
245 }
246
279 }
280
281 @Override
282 public int tag() { return ITEM_UNINITIALIZED; }
283
284 @Override
285 public String toString() {
286 return "UNINIT(" + newTarget +")";
287 }
288 }
289
290 private int u2() {
291 int v = classReader.readU2(p);
292 p += 2;
293 return v;
294 }
295
296 public static record StackMapFrameImpl(int frameType,
297 Label target,
298 List<VerificationTypeInfo> locals,
299 List<VerificationTypeInfo> stack)
300 implements StackMapFrameInfo {
301 public StackMapFrameImpl {
302 requireNonNull(target);
303 locals = Util.sanitizeU2List(locals);
304 stack = Util.sanitizeU2List(stack);
305 }
306 }
307 }
|
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package jdk.internal.classfile.impl;
27
28 import java.lang.classfile.BufWriter;
29 import java.lang.classfile.ClassModel;
30 import java.lang.classfile.ClassReader;
31 import java.lang.classfile.Label;
32 import java.lang.classfile.MethodModel;
33 import java.lang.classfile.attribute.StackMapFrameInfo;
34 import java.lang.classfile.attribute.StackMapFrameInfo.ObjectVerificationTypeInfo;
35 import java.lang.classfile.attribute.StackMapFrameInfo.SimpleVerificationTypeInfo;
36 import java.lang.classfile.attribute.StackMapFrameInfo.UninitializedVerificationTypeInfo;
37 import java.lang.classfile.attribute.StackMapFrameInfo.VerificationTypeInfo;
38 import java.lang.classfile.constantpool.ClassEntry;
39 import java.lang.classfile.constantpool.NameAndTypeEntry;
40 import java.lang.classfile.constantpool.PoolEntry;
41 import java.lang.classfile.constantpool.Utf8Entry;
42 import java.lang.constant.ConstantDescs;
43 import java.lang.constant.MethodTypeDesc;
44 import java.lang.reflect.AccessFlag;
45 import java.util.ArrayList;
46 import java.util.Arrays;
47 import java.util.Comparator;
48 import java.util.List;
49 import java.util.Objects;
50
51 import jdk.internal.access.SharedSecrets;
52
53 import static java.lang.classfile.ClassFile.*;
54 import static java.util.Objects.requireNonNull;
55 import static jdk.internal.classfile.impl.StackMapGenerator.*;
56
57 public class StackMapDecoder {
58
59 private static final StackMapFrameInfo[] NO_STACK_FRAME_INFOS = {};
60
61 private final ClassReader classReader;
62 private final int pos;
63 private final LabelContext ctx;
64 private final List<VerificationTypeInfo> initFrameLocals;
65 private final List<NameAndTypeEntry> initFrameUnsets;
66 private int p;
67
68 StackMapDecoder(ClassReader classReader, int pos, LabelContext ctx, List<VerificationTypeInfo> initFrameLocals,
69 List<NameAndTypeEntry> initFrameUnsets) {
70 this.classReader = classReader;
71 this.pos = pos;
72 this.ctx = ctx;
73 this.initFrameLocals = initFrameLocals;
74 this.initFrameUnsets = initFrameUnsets;
75 }
76
77 static List<VerificationTypeInfo> initFrameLocals(MethodModel method) {
78 return initFrameLocals(method.parent().orElseThrow().thisClass(),
79 method.methodName().stringValue(),
80 method.methodTypeSymbol(),
81 method.flags().has(AccessFlag.STATIC));
82 }
83
84 public static List<VerificationTypeInfo> initFrameLocals(ClassEntry thisClass, String methodName, MethodTypeDesc methodType, boolean isStatic) {
85 VerificationTypeInfo vtis[];
86 int i = 0;
87 if (!isStatic) {
88 vtis = new VerificationTypeInfo[methodType.parameterCount() + 1];
89 if ("<init>".equals(methodName) && !ConstantDescs.CD_Object.equals(thisClass.asSymbol())) {
90 vtis[i++] = SimpleVerificationTypeInfo.UNINITIALIZED_THIS;
91 } else {
92 vtis[i++] = new StackMapDecoder.ObjectVerificationTypeInfoImpl(thisClass);
93 }
94 } else {
95 vtis = new VerificationTypeInfo[methodType.parameterCount()];
96 }
97 for (int pi = 0; pi < methodType.parameterCount(); pi++) {
98 var arg = methodType.parameterType(pi);
99 vtis[i++] = switch (arg.descriptorString().charAt(0)) {
100 case 'I', 'S', 'C' ,'B', 'Z' -> SimpleVerificationTypeInfo.INTEGER;
101 case 'J' -> SimpleVerificationTypeInfo.LONG;
102 case 'F' -> SimpleVerificationTypeInfo.FLOAT;
103 case 'D' -> SimpleVerificationTypeInfo.DOUBLE;
104 case 'V' -> throw new IllegalArgumentException("Illegal method argument type: " + arg);
105 default -> new StackMapDecoder.ObjectVerificationTypeInfoImpl(TemporaryConstantPool.INSTANCE.classEntry(arg));
106 };
107 }
108 return List.of(vtis);
109 }
110
111 static List<NameAndTypeEntry> initFrameUnsets(MethodModel method) {
112 return initFrameUnsets(method.parent().orElseThrow(),
113 method.methodName());
114 }
115
116 private static List<NameAndTypeEntry> initFrameUnsets(ClassModel clazz, Utf8Entry methodName) {
117 if (!methodName.equalsString(ConstantDescs.INIT_NAME))
118 return List.of();
119 if (clazz.minorVersion() != PREVIEW_MINOR_VERSION || clazz.majorVersion() < Util.VALUE_OBJECTS_MAJOR)
120 return List.of();
121 var l = new ArrayList<NameAndTypeEntry>(clazz.fields().size());
122 for (var field : clazz.fields()) {
123 if ((field.flags().flagsMask() & (ACC_STATIC | ACC_STRICT_INIT)) == ACC_STRICT_INIT) { // instance strict
124 l.add(TemporaryConstantPool.INSTANCE.nameAndTypeEntry(field.fieldName(), field.fieldType()));
125 }
126 }
127 return List.copyOf(l);
128 }
129
130 private static List<NameAndTypeEntry> initFrameUnsets(MethodInfo mi, WritableField.UnsetField[] unsets) {
131 if (!mi.methodName().equalsString(ConstantDescs.INIT_NAME))
132 return List.of();
133 var l = new ArrayList<NameAndTypeEntry>(unsets.length);
134 for (var field : unsets) {
135 l.add(TemporaryConstantPool.INSTANCE.nameAndTypeEntry(field.name(), field.type()));
136 }
137 return List.copyOf(l);
138 }
139
140 public static void writeFrames(BufWriter b, List<StackMapFrameInfo> entries) {
141 var buf = (BufWriterImpl)b;
142 var dcb = (DirectCodeBuilder)buf.labelContext();
143 var mi = dcb.methodInfo();
144 var prevLocals = StackMapDecoder.initFrameLocals(buf.thisClass(),
145 mi.methodName().stringValue(),
146 mi.methodTypeSymbol(),
147 (mi.methodFlags() & ACC_STATIC) != 0);
148 var prevUnsets = initFrameUnsets(mi, buf.getStrictInstanceFields());
149 int prevOffset = -1;
150 // avoid using method handles due to early bootstrap
151 StackMapFrameInfo[] infos = entries.toArray(NO_STACK_FRAME_INFOS);
152 //sort by resolved label offsets first to allow unordered entries
153 Arrays.sort(infos, new Comparator<StackMapFrameInfo>() {
154 public int compare(final StackMapFrameInfo o1, final StackMapFrameInfo o2) {
155 return Integer.compare(dcb.labelToBci(o1.target()), dcb.labelToBci(o2.target()));
156 }
157 });
158 b.writeU2(infos.length);
159 for (var fr : infos) {
160 int offset = dcb.labelToBci(fr.target());
161 if (offset == prevOffset) {
162 throw new IllegalArgumentException("Duplicated stack frame bytecode index: " + offset);
163 }
164 writeFrame(buf, offset - prevOffset - 1, prevLocals, prevUnsets, fr);
165 prevOffset = offset;
166 prevLocals = fr.locals();
167 prevUnsets = fr.unsetFields();
168 }
169 }
170
171 // In sync with StackMapGenerator::needsLarvalFrame
172 private static boolean needsLarvalFrameForTransition(List<NameAndTypeEntry> prevUnsets, StackMapFrameInfo fr) {
173 if (prevUnsets.equals(fr.unsetFields()))
174 return false;
175 if (!fr.locals().contains(SimpleVerificationTypeInfo.UNINITIALIZED_THIS)) {
176 assert fr.unsetFields().isEmpty() : fr; // should be checked in StackMapFrameInfo constructor
177 return false;
178 }
179 return true;
180 }
181
182 private static void writeFrame(BufWriterImpl out, int offsetDelta, List<VerificationTypeInfo> prevLocals, List<NameAndTypeEntry> prevUnsets, StackMapFrameInfo fr) {
183 if (offsetDelta < 0) throw new IllegalArgumentException("Invalid stack map frames order");
184 // enclosing frames
185 if (needsLarvalFrameForTransition(prevUnsets, fr)) {
186 out.writeU1(EARLY_LARVAL);
187 Util.writeListIndices(out, fr.unsetFields());
188 }
189 // base frame
190 if (fr.stack().isEmpty()) {
191 int commonLocalsSize = Math.min(prevLocals.size(), fr.locals().size());
192 int diffLocalsSize = fr.locals().size() - prevLocals.size();
193 if (-3 <= diffLocalsSize && diffLocalsSize <= 3 && equals(fr.locals(), prevLocals, commonLocalsSize)) {
194 if (diffLocalsSize == 0 && offsetDelta <= SAME_FRAME_END) { //same frame
195 out.writeU1(offsetDelta);
196 } else { //chop, same extended or append frame
197 out.writeU1U2(SAME_FRAME_EXTENDED + diffLocalsSize, offsetDelta);
198 for (int i=commonLocalsSize; i<fr.locals().size(); i++) writeTypeInfo(out, fr.locals().get(i));
199 }
200 return;
201 }
202 } else if (fr.stack().size() == 1 && fr.locals().equals(prevLocals)) {
203 if (offsetDelta <= SAME_LOCALS_1_STACK_ITEM_FRAME_END - SAME_LOCALS_1_STACK_ITEM_FRAME_START) { //same locals 1 stack item frame
204 out.writeU1(SAME_LOCALS_1_STACK_ITEM_FRAME_START + offsetDelta);
205 } else { //same locals 1 stack item extended frame
206 out.writeU1U2(SAME_LOCALS_1_STACK_ITEM_EXTENDED, offsetDelta);
207 }
208 writeTypeInfo(out, fr.stack().get(0));
209 return;
219 for (int i = 0; i < compareSize; i++) {
220 if (!l1.get(i).equals(l2.get(i))) return false;
221 }
222 return true;
223 }
224
225 private static void writeTypeInfo(BufWriterImpl bw, VerificationTypeInfo vti) {
226 int tag = vti.tag();
227 switch (tag) {
228 case ITEM_TOP, ITEM_INTEGER, ITEM_FLOAT, ITEM_DOUBLE, ITEM_LONG, ITEM_NULL,
229 ITEM_UNINITIALIZED_THIS ->
230 bw.writeU1(tag);
231 case ITEM_OBJECT ->
232 bw.writeU1U2(tag, bw.cpIndex(((ObjectVerificationTypeInfo)vti).className()));
233 case ITEM_UNINITIALIZED ->
234 bw.writeU1U2(tag, bw.labelContext().labelToBci(((UninitializedVerificationTypeInfo)vti).newTarget()));
235 default -> throw new IllegalArgumentException("Invalid verification type tag: " + vti.tag());
236 }
237 }
238
239 // Copied from BoundAttribute
240 <E extends PoolEntry> List<E> readEntryList(int p, Class<E> type) {
241 int cnt = classReader.readU2(p);
242 p += 2;
243 var entries = new Object[cnt];
244 int end = p + (cnt * 2);
245 for (int i = 0; p < end; i++, p += 2) {
246 entries[i] = classReader.readEntry(p, type);
247 }
248 return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(entries);
249 }
250
251 List<StackMapFrameInfo> entries() {
252 p = pos;
253 List<VerificationTypeInfo> locals = initFrameLocals, stack = List.of();
254 List<NameAndTypeEntry> unsetFields = initFrameUnsets;
255 int bci = -1;
256 var entries = new StackMapFrameInfo[u2()];
257 for (int ei = 0; ei < entries.length; ei++) {
258 int actualFrameType = classReader.readU1(p++);
259 int frameType = actualFrameType; // effective frame type for parsing
260 // enclosing frames handling
261 if (frameType == EARLY_LARVAL) {
262 unsetFields = readEntryList(p, NameAndTypeEntry.class);
263 p += 2 + unsetFields.size() * 2;
264 frameType = classReader.readU1(p++);
265 }
266 // base frame handling
267 if (frameType <= SAME_FRAME_END) {
268 bci += frameType + 1;
269 stack = List.of();
270 } else if (frameType <= SAME_LOCALS_1_STACK_ITEM_FRAME_END) {
271 bci += frameType - SAME_LOCALS_1_STACK_ITEM_FRAME_START + 1;
272 stack = List.of(readVerificationTypeInfo());
273 } else {
274 if (frameType < SAME_LOCALS_1_STACK_ITEM_EXTENDED)
275 throw new IllegalArgumentException("Invalid base frame type: " + frameType);
276 bci += u2() + 1;
277 if (frameType == SAME_LOCALS_1_STACK_ITEM_EXTENDED) {
278 stack = List.of(readVerificationTypeInfo());
279 } else if (frameType < SAME_FRAME_EXTENDED) {
280 locals = locals.subList(0, locals.size() + frameType - SAME_FRAME_EXTENDED);
281 stack = List.of();
282 } else if (frameType == SAME_FRAME_EXTENDED) {
283 stack = List.of();
284 } else if (frameType <= APPEND_FRAME_END) {
285 int actSize = locals.size();
286 var newLocals = locals.toArray(new VerificationTypeInfo[actSize + frameType - SAME_FRAME_EXTENDED]);
287 for (int i = actSize; i < newLocals.length; i++)
288 newLocals[i] = readVerificationTypeInfo();
289 locals = List.of(newLocals);
290 stack = List.of();
291 } else {
292 var newLocals = new VerificationTypeInfo[u2()];
293 for (int i=0; i<newLocals.length; i++)
294 newLocals[i] = readVerificationTypeInfo();
295 var newStack = new VerificationTypeInfo[u2()];
296 for (int i=0; i<newStack.length; i++)
297 newStack[i] = readVerificationTypeInfo();
298 locals = List.of(newLocals);
299 stack = List.of(newStack);
300 }
301 }
302 if (actualFrameType != EARLY_LARVAL && !unsetFields.isEmpty() && !locals.contains(SimpleVerificationTypeInfo.UNINITIALIZED_THIS)) {
303 // clear unsets post larval
304 unsetFields = List.of();
305 }
306 entries[ei] = new StackMapFrameImpl(actualFrameType,
307 ctx.getLabel(bci),
308 locals,
309 stack,
310 unsetFields);
311 }
312 return List.of(entries);
313 }
314
315 private VerificationTypeInfo readVerificationTypeInfo() {
316 int tag = classReader.readU1(p++);
317 return switch (tag) {
318 case ITEM_TOP -> SimpleVerificationTypeInfo.TOP;
319 case ITEM_INTEGER -> SimpleVerificationTypeInfo.INTEGER;
320 case ITEM_FLOAT -> SimpleVerificationTypeInfo.FLOAT;
321 case ITEM_DOUBLE -> SimpleVerificationTypeInfo.DOUBLE;
322 case ITEM_LONG -> SimpleVerificationTypeInfo.LONG;
323 case ITEM_NULL -> SimpleVerificationTypeInfo.NULL;
324 case ITEM_UNINITIALIZED_THIS -> SimpleVerificationTypeInfo.UNINITIALIZED_THIS;
325 case ITEM_OBJECT -> new ObjectVerificationTypeInfoImpl(classReader.entryByIndex(u2(), ClassEntry.class));
326 case ITEM_UNINITIALIZED -> new UninitializedVerificationTypeInfoImpl(ctx.getLabel(u2()));
327 default -> throw new IllegalArgumentException("Invalid verification type tag: " + tag);
328 };
329 }
330
363 }
364
365 @Override
366 public int tag() { return ITEM_UNINITIALIZED; }
367
368 @Override
369 public String toString() {
370 return "UNINIT(" + newTarget +")";
371 }
372 }
373
374 private int u2() {
375 int v = classReader.readU2(p);
376 p += 2;
377 return v;
378 }
379
380 public static record StackMapFrameImpl(int frameType,
381 Label target,
382 List<VerificationTypeInfo> locals,
383 List<VerificationTypeInfo> stack,
384 List<NameAndTypeEntry> unsetFields)
385 implements StackMapFrameInfo {
386 public StackMapFrameImpl {
387 requireNonNull(target);
388 locals = Util.sanitizeU2List(locals);
389 stack = Util.sanitizeU2List(stack);
390 unsetFields = Util.sanitizeU2List(unsetFields);
391
392 uninitializedThisCheck:
393 if (!unsetFields.isEmpty()) {
394 for (var local : locals) {
395 if (local == SimpleVerificationTypeInfo.UNINITIALIZED_THIS) {
396 break uninitializedThisCheck;
397 }
398 }
399 throw new IllegalArgumentException("unset fields requires uninitializedThis in locals");
400 }
401 }
402
403 public StackMapFrameImpl(int frameType,
404 Label target,
405 List<VerificationTypeInfo> locals,
406 List<VerificationTypeInfo> stack) {
407 this(frameType, target, locals, stack, List.of());
408 }
409 }
410 }
|