1   // Copyright 2012- Bill Campbell, Swami Iyer and Bahar Akbal-Delibas
2   
3   package jminusminus;
4   
5   import java.io.IOException;
6   import java.util.ArrayList;
7   
8   /**
9    * Representation of a class' constant pool.
10   */
11  class CLConstantPool {
12      // Index of the next item into the constant pool.
13      private int cpIndex;
14  
15      // List of constant pool items.
16      private ArrayList<CLCPInfo> cpItems;
17  
18      /**
19       * Constructs an empty constant pool.
20       */
21      public CLConstantPool() {
22          cpIndex = 1;
23          cpItems = new ArrayList<CLCPInfo>();
24      }
25  
26      /**
27       * Returns the size of the constant pool.
28       *
29       * @return the size of the constant pool.
30       */
31      public int size() {
32          return cpItems.size();
33      }
34  
35      /**
36       * Returns the index of the specified item in the constant pool or -1.
37       *
38       * @param cpInfo item to find.
39       * @return the index of the specified item in the constant pool or -1.
40       */
41      public int find(CLCPInfo cpInfo) {
42          int index = cpItems.indexOf(cpInfo);
43          return (index != -1) ? cpItems.get(index).cpIndex : index;
44      }
45  
46      /**
47       * Returns the constant pool item at the specified index or null.
48       *
49       * @param i constant pool index.
50       * @return the constant pool item at the specified index or null.
51       */
52      public CLCPInfo cpItem(int i) {
53          if (((i - 1) < 0) || ((i - 1) >= cpItems.size())) {
54              return null;
55          }
56          return cpItems.get(i - 1);
57      }
58  
59      /**
60       * Adds the specified (non-null) item to the constant pool and returns its index.
61       *
62       * @param cpInfo the item to add.
63       * @return constant pool index of the item.
64       */
65      public int addCPItem(CLCPInfo cpInfo) {
66          cpInfo.cpIndex = cpIndex++;
67          cpItems.add(cpInfo);
68  
69          // long and double, with their lower and higher words, are treated by JVM as two items in
70          // the constant pool. We have a single representation for each, so we add a null as
71          // a placeholder in the second slot.
72          if ((cpInfo instanceof CLConstantLongInfo) || (cpInfo instanceof CLConstantDoubleInfo)) {
73              cpIndex++;
74              cpItems.add(null);
75          }
76          return cpInfo.cpIndex;
77      }
78  
79      /**
80       * Writes the contents of the constant pool to the specified output stream.
81       *
82       * @param out output stream.
83       * @throws IOException if an error occurs while writing.
84       */
85      public void write(CLOutputStream out) throws IOException {
86          for (CLCPInfo cpInfo : cpItems) {
87              if (cpInfo != null) {
88                  cpInfo.write(out);
89              }
90          }
91      }
92  
93      /**
94       * Returns the constant pool index of a singleton instance of CLConstantClassInfo.
95       *
96       * @param className class or interface name in internal form.
97       * @return constant pool index.
98       */
99      public int constantClassInfo(String className) {
100         CLCPInfo c = new CLConstantClassInfo(constantUtf8Info(className));
101         return findOrAdd(c);
102     }
103 
104     /**
105      * Returns the constant pool index of a singleton instance of CLConstantFieldRefInfo.
106      *
107      * @param className class or interface name in internal form.
108      * @param name      name of the field.
109      * @param type      descriptor of the field.
110      * @return constant pool index.
111      */
112     public int constantFieldRefInfo(String className, String name, String type) {
113         CLCPInfo c = new CLConstantFieldRefInfo(constantClassInfo(className),
114                 constantNameAndTypeInfo(name, type));
115         return findOrAdd(c);
116     }
117 
118     /**
119      * Returns the constant pool index of a singleton instance of CLConstantMethodRefInfo.
120      *
121      * @param className class or interface name in internal form.
122      * @param name      name of the method.
123      * @param type      descriptor of the method.
124      * @return constant pool index.
125      */
126     public int constantMethodRefInfo(String className, String name, String type) {
127         CLCPInfo c = new CLConstantMethodRefInfo(constantClassInfo(className),
128                 constantNameAndTypeInfo(name, type));
129         return findOrAdd(c);
130     }
131 
132     /**
133      * Returns the constant pool index of a singleton instance of CLConstantInterfaceMethodRefInfo.
134      *
135      * @param className class or interface name in internal form.
136      * @param name      name of the method.
137      * @param type      descriptor of the method.
138      * @return constant pool index.
139      */
140     public int constantInterfaceMethodRefInfo(String className, String name, String type) {
141         CLCPInfo c = new CLConstantInterfaceMethodRefInfo(
142                 constantClassInfo(className), constantNameAndTypeInfo(name, type));
143         return findOrAdd(c);
144     }
145 
146     /**
147      * Returns the constant pool index of a singleton instance of CLConstantStringInfo.
148      *
149      * @param s the constant string value.
150      * @return constant pool index.
151      */
152     public int constantStringInfo(String s) {
153         CLCPInfo c = new CLConstantStringInfo(constantUtf8Info(s));
154         return findOrAdd(c);
155     }
156 
157     /**
158      * Returns the constant pool index of a singleton instance of CLConstantIntegerInfo.
159      *
160      * @param i the constant int value.
161      * @return constant pool index.
162      */
163     public int constantIntegerInfo(int i) {
164         CLCPInfo c = new CLConstantIntegerInfo(i);
165         return findOrAdd(c);
166     }
167 
168     /**
169      * Returns the constant pool index of a singleton instance of CLConstantFloatInfo.
170      *
171      * @param f the constant floating-point value.
172      * @return constant pool index.
173      */
174     public int constantFloatInfo(float f) {
175         CLCPInfo c = new CLConstantFloatInfo(f);
176         return findOrAdd(c);
177     }
178 
179     /**
180      * Returns the constant pool index of a singleton instance of CLConstantLongInfo.
181      *
182      * @param l the constant long value.
183      * @return constant pool index.
184      */
185     public int constantLongInfo(long l) {
186         CLCPInfo c = new CLConstantLongInfo(l);
187         return findOrAdd(c);
188     }
189 
190     /**
191      * Returns the constant pool index of a singleton instance of CLConstantDoubleInfo.
192      *
193      * @param d the constant double value.
194      * @return constant pool index.
195      */
196     public int constantDoubleInfo(double d) {
197         CLCPInfo c = new CLConstantDoubleInfo(d);
198         return findOrAdd(c);
199     }
200 
201     /**
202      * Returns the constant pool index of a singleton instance of CLConstantNameAndTypeInfo.
203      *
204      * @param name field or method name.
205      * @param type field or method type descriptor.
206      * @return constant pool index.
207      */
208     public int constantNameAndTypeInfo(String name, String type) {
209         CLCPInfo c = new CLConstantNameAndTypeInfo(constantUtf8Info(name), constantUtf8Info(type));
210         return findOrAdd(c);
211     }
212 
213     /**
214      * Returns the constant pool index of a singleton instance of CLConstantUtf8Info.
215      *
216      * @param s the constant string value.
217      * @return constant pool index.
218      */
219     public int constantUtf8Info(String s) {
220         CLCPInfo c = new CLConstantUtf8Info(s.getBytes());
221         return findOrAdd(c);
222     }
223 
224     // Returns the index of the specified item in the constant pool. If the item does not exist,
225     // adds the item to the pool and return its (new) index.
226     private int findOrAdd(CLCPInfo cpInfo) {
227         int index = find(cpInfo);
228         if (index == -1) {
229             index = addCPItem(cpInfo);
230         }
231         return index;
232     }
233 }
234