< prev index next >

src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java

Print this page

  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 }
< prev index next >