View Javadoc
1   /*
2    * MIT License
3    * Copyright (c) 2006-2025 JMockit developers
4    * See LICENSE file for full license text.
5    */
6   package mockit.asm.methods;
7   
8   import edu.umd.cs.findbugs.annotations.NonNull;
9   import edu.umd.cs.findbugs.annotations.Nullable;
10  
11  import mockit.asm.constantPool.AttributeWriter;
12  import mockit.asm.constantPool.ConstantPoolGeneration;
13  import mockit.asm.controlFlow.Label;
14  import mockit.asm.util.ByteVector;
15  
16  import org.checkerframework.checker.index.qual.NonNegative;
17  
18  /**
19   * Writes the bytecode for the "LocalVariableTable" and "LocalVariableTypeTable" method code attributes.
20   */
21  final class LocalVariableTableWriter extends AttributeWriter {
22      /**
23       * Number of entries in the LocalVariableTable attribute.
24       */
25      @NonNegative
26      private int localVarCount;
27  
28      /**
29       * The LocalVariableTable attribute.
30       */
31      @Nullable
32      private ByteVector localVarTable;
33  
34      @NonNegative
35      private int localVarTypeAttributeIndex;
36  
37      /**
38       * Number of entries in the LocalVariableTypeTable attribute.
39       */
40      @NonNegative
41      private int localVarTypeCount;
42  
43      /**
44       * The LocalVariableTypeTable attribute.
45       */
46      @Nullable
47      private ByteVector localVarTypeTable;
48  
49      LocalVariableTableWriter(@NonNull ConstantPoolGeneration cp) {
50          super(cp);
51      }
52  
53      @NonNegative
54      int addLocalVariable(@NonNull String name, @NonNull String desc, @Nullable String signature, @NonNull Label start,
55              @NonNull Label end, @NonNegative int index) {
56          if (signature != null) {
57              if (localVarTypeTable == null) {
58                  localVarTypeAttributeIndex = cp.newUTF8("LocalVariableTypeTable");
59                  localVarTypeTable = new ByteVector();
60              }
61  
62              addAttribute(localVarTypeTable, name, signature, start, end, index);
63              localVarTypeCount++;
64          }
65  
66          if (localVarTable == null) {
67              setAttribute("LocalVariableTable");
68              localVarTable = new ByteVector();
69          }
70  
71          addAttribute(localVarTable, name, desc, start, end, index);
72          localVarCount++;
73  
74          char c = desc.charAt(0);
75          return index + (c == 'J' || c == 'D' ? 2 : 1);
76      }
77  
78      private void addAttribute(@NonNull ByteVector attribute, @NonNull String name, @NonNull String desc,
79              @NonNull Label start, @NonNull Label end, @NonNegative int index) {
80          attribute.putShort(start.position).putShort(end.position - start.position).putShort(cp.newUTF8(name))
81                  .putShort(cp.newUTF8(desc)).putShort(index);
82      }
83  
84      @NonNegative
85      @Override
86      public int getSize() {
87          return getSize(localVarTable) + getSize(localVarTypeTable);
88      }
89  
90      @NonNegative
91      private static int getSize(@Nullable ByteVector attribute) {
92          return attribute == null ? 0 : 8 + attribute.getLength();
93      }
94  
95      @NonNegative
96      int getAttributeCount() {
97          return (localVarTable == null ? 0 : 1) + (localVarTypeTable == null ? 0 : 1);
98      }
99  
100     @Override
101     public void put(@NonNull ByteVector out) {
102         put(out, localVarTable, localVarCount);
103         attributeIndex = localVarTypeAttributeIndex;
104         put(out, localVarTypeTable, localVarTypeCount);
105     }
106 
107     private void put(@NonNull ByteVector out, @Nullable ByteVector attribute, @NonNegative int numEntries) {
108         if (attribute != null) {
109             put(out, 2 + attribute.getLength());
110             out.putShort(numEntries);
111             out.putByteVector(attribute);
112         }
113     }
114 }