< prev index next >

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

Print this page
*** 1,7 ***
  /*
!  * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   *
   * This code is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License version 2 only, as
   * published by the Free Software Foundation.  Oracle designates this
--- 1,7 ---
  /*
!  * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved.
   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   *
   * This code is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License version 2 only, as
   * published by the Free Software Foundation.  Oracle designates this

*** 33,27 ***
  import java.lang.classfile.attribute.StackMapFrameInfo.ObjectVerificationTypeInfo;
  import java.lang.classfile.attribute.StackMapFrameInfo.SimpleVerificationTypeInfo;
  import java.lang.classfile.attribute.StackMapFrameInfo.UninitializedVerificationTypeInfo;
  import java.lang.classfile.attribute.StackMapFrameInfo.VerificationTypeInfo;
  import java.lang.classfile.constantpool.ClassEntry;
  import java.lang.constant.ConstantDescs;
  import java.lang.constant.MethodTypeDesc;
  import java.lang.reflect.AccessFlag;
  import java.util.Arrays;
  import java.util.Comparator;
  import java.util.List;
  import java.util.Objects;
  
  import static java.lang.classfile.ClassFile.ACC_STATIC;
  import static java.lang.classfile.attribute.StackMapFrameInfo.VerificationTypeInfo.*;
  import static java.util.Objects.requireNonNull;
  
  public class StackMapDecoder {
  
!     private static final int
                      SAME_LOCALS_1_STACK_ITEM_EXTENDED = 247,
                      SAME_EXTENDED = 251;
      private static final StackMapFrameInfo[] NO_STACK_FRAME_INFOS = {};
  
      private final ClassReader classReader;
      private final int pos;
      private final LabelContext ctx;
--- 33,34 ---
  import java.lang.classfile.attribute.StackMapFrameInfo.ObjectVerificationTypeInfo;
  import java.lang.classfile.attribute.StackMapFrameInfo.SimpleVerificationTypeInfo;
  import java.lang.classfile.attribute.StackMapFrameInfo.UninitializedVerificationTypeInfo;
  import java.lang.classfile.attribute.StackMapFrameInfo.VerificationTypeInfo;
  import java.lang.classfile.constantpool.ClassEntry;
+ import java.lang.classfile.constantpool.NameAndTypeEntry;
+ import java.lang.classfile.constantpool.PoolEntry;
  import java.lang.constant.ConstantDescs;
  import java.lang.constant.MethodTypeDesc;
  import java.lang.reflect.AccessFlag;
+ import java.util.ArrayList;
  import java.util.Arrays;
  import java.util.Comparator;
  import java.util.List;
  import java.util.Objects;
  
+ import jdk.internal.access.SharedSecrets;
+ 
  import static java.lang.classfile.ClassFile.ACC_STATIC;
  import static java.lang.classfile.attribute.StackMapFrameInfo.VerificationTypeInfo.*;
  import static java.util.Objects.requireNonNull;
  
  public class StackMapDecoder {
  
!     static final int
+                     ASSERT_UNSET_FIELDS = 246,
                      SAME_LOCALS_1_STACK_ITEM_EXTENDED = 247,
                      SAME_EXTENDED = 251;
+     private static final int RESERVED_TAGS_UPPER_LIMIT = ASSERT_UNSET_FIELDS; // not inclusive
      private static final StackMapFrameInfo[] NO_STACK_FRAME_INFOS = {};
  
      private final ClassReader classReader;
      private final int pos;
      private final LabelContext ctx;

*** 179,26 ***
                  bw.writeU1U2(tag, bw.labelContext().labelToBci(((UninitializedVerificationTypeInfo)vti).newTarget()));
              default -> throw new IllegalArgumentException("Invalid verification type tag: " + vti.tag());
          }
      }
  
      List<StackMapFrameInfo> entries() {
          p = pos;
          List<VerificationTypeInfo> locals = initFrameLocals, stack = List.of();
          int bci = -1;
!         var entries = new StackMapFrameInfo[u2()];
!         for (int ei = 0; ei < entries.length; ei++) {
              int frameType = classReader.readU1(p++);
              if (frameType < 64) {
                  bci += frameType + 1;
                  stack = List.of();
              } else if (frameType < 128) {
                  bci += frameType - 63;
                  stack = List.of(readVerificationTypeInfo());
              } else {
!                 if (frameType < SAME_LOCALS_1_STACK_ITEM_EXTENDED)
                      throw new IllegalArgumentException("Invalid stackmap frame type: " + frameType);
                  bci += u2() + 1;
                  if (frameType == SAME_LOCALS_1_STACK_ITEM_EXTENDED) {
                      stack = List.of(readVerificationTypeInfo());
                  } else if (frameType < SAME_EXTENDED) {
                      locals = locals.subList(0, locals.size() + frameType - SAME_EXTENDED);
--- 186,49 ---
                  bw.writeU1U2(tag, bw.labelContext().labelToBci(((UninitializedVerificationTypeInfo)vti).newTarget()));
              default -> throw new IllegalArgumentException("Invalid verification type tag: " + vti.tag());
          }
      }
  
+     // Copied from BoundAttribute
+     <E extends PoolEntry> List<E> readEntryList(int p, Class<E> type) {
+         int cnt = classReader.readU2(p);
+         p += 2;
+         var entries = new Object[cnt];
+         int end = p + (cnt * 2);
+         for (int i = 0; p < end; i++, p += 2) {
+             entries[i] = classReader.readEntry(p, type);
+         }
+         return SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(entries);
+     }
+ 
      List<StackMapFrameInfo> entries() {
          p = pos;
          List<VerificationTypeInfo> locals = initFrameLocals, stack = List.of();
+         List<NameAndTypeEntry> unsetFields = List.of();
          int bci = -1;
!         int len = u2();
!         var entries = new ArrayList<StackMapFrameInfo>(len);
+         List<List<NameAndTypeEntry>> deferredUnsetFields = new ArrayList<>();
+         for (int ei = 0; ei < len; ei++) {
+             var oldLocals = locals;
+             var oldStack = stack;
              int frameType = classReader.readU1(p++);
              if (frameType < 64) {
                  bci += frameType + 1;
                  stack = List.of();
              } else if (frameType < 128) {
                  bci += frameType - 63;
                  stack = List.of(readVerificationTypeInfo());
              } else {
!                 if (frameType < RESERVED_TAGS_UPPER_LIMIT)
                      throw new IllegalArgumentException("Invalid stackmap frame type: " + frameType);
+                 if (frameType == ASSERT_UNSET_FIELDS) {
+                     unsetFields = readEntryList(p, NameAndTypeEntry.class);
+                     p += 2 + unsetFields.size() * 2;
+                     deferredUnsetFields.add(unsetFields);
+                     continue; // defer entry until we can get the bci
+                 }
                  bci += u2() + 1;
                  if (frameType == SAME_LOCALS_1_STACK_ITEM_EXTENDED) {
                      stack = List.of(readVerificationTypeInfo());
                  } else if (frameType < SAME_EXTENDED) {
                      locals = locals.subList(0, locals.size() + frameType - SAME_EXTENDED);

*** 221,16 ***
                          newStack[i] = readVerificationTypeInfo();
                      locals = List.of(newLocals);
                      stack = List.of(newStack);
                  }
              }
!             entries[ei] = new StackMapFrameImpl(frameType,
!                         ctx.getLabel(bci),
                          locals,
!                         stack);
          }
!         return List.of(entries);
      }
  
      private VerificationTypeInfo readVerificationTypeInfo() {
          int tag = classReader.readU1(p++);
          return switch (tag) {
--- 251,26 ---
                          newStack[i] = readVerificationTypeInfo();
                      locals = List.of(newLocals);
                      stack = List.of(newStack);
                  }
              }
!             Label label = ctx.getLabel(bci);
!             if (!deferredUnsetFields.isEmpty()) {
+                 // technically we only have one assert at once, just in case
+                 // of duplicate asserts...
+                 for (var deferredList : deferredUnsetFields) {
+                     entries.add(new StackMapFrameImpl(ASSERT_UNSET_FIELDS,
+                                 label, oldLocals, oldStack, deferredList));
+                 }
+                 deferredUnsetFields.clear();
+             }
+             entries.add(new StackMapFrameImpl(frameType,
+                         label,
                          locals,
!                         stack));
          }
!         return List.copyOf(entries);
      }
  
      private VerificationTypeInfo readVerificationTypeInfo() {
          int tag = classReader.readU1(p++);
          return switch (tag) {

*** 297,14 ***
      }
  
      public static record StackMapFrameImpl(int frameType,
                                             Label target,
                                             List<VerificationTypeInfo> locals,
!                                            List<VerificationTypeInfo> stack)
              implements StackMapFrameInfo {
          public StackMapFrameImpl {
              requireNonNull(target);
              locals = List.copyOf(locals);
              stack = List.copyOf(stack);
          }
      }
  }
--- 337,23 ---
      }
  
      public static record StackMapFrameImpl(int frameType,
                                             Label target,
                                             List<VerificationTypeInfo> locals,
!                                            List<VerificationTypeInfo> stack,
+                                            List<NameAndTypeEntry> unsetFields)
              implements StackMapFrameInfo {
          public StackMapFrameImpl {
              requireNonNull(target);
              locals = List.copyOf(locals);
              stack = List.copyOf(stack);
+             unsetFields = List.copyOf(unsetFields);
+         }
+ 
+         public StackMapFrameImpl(int frameType,
+                                  Label target,
+                                  List<VerificationTypeInfo> locals,
+                                  List<VerificationTypeInfo> stack) {
+             this(frameType, target, locals, stack, List.of());
          }
      }
  }
< prev index next >