001    /*
002     * The JastAdd Extensible Java Compiler (http://jastadd.org) is covered
003     * by the modified BSD License. You should have received a copy of the
004     * modified BSD license with this compiler.
005     * 
006     * Copyright (c) 2005-2008, Torbjorn Ekman
007     * All rights reserved.
008     */
009    
010    import java.util.*;
011    import java.io.*;
012    
013    aspect ConstantPool {
014      syn lazy ConstantPool TypeDecl.constantPool() = new ConstantPool(this);
015    
016      syn lazy String TypeDecl.constantPoolName() {
017        if(!isNestedType()) {
018          String packageName = packageName();
019          if(!packageName.equals("")) {
020            packageName = packageName.replace('.', '/') + "/";
021          }
022          return packageName + name();
023        }
024        else {
025          String prefix = enclosingType().constantPoolName();
026          if(isAnonymous()) {
027            return prefix + "$" + uniqueIndex();
028          }
029          else if(isLocalClass()) {
030            return prefix + "$" + uniqueIndex() + name();
031          }
032          return prefix + "$" + name();
033        }
034      }
035    
036      syn lazy String ArrayDecl.constantPoolName() = typeDescriptor();
037    
038      public class ConstantPool {
039        public TypeDecl typeDecl;
040        public ConstantPool(TypeDecl typeDecl) {
041          this.typeDecl = typeDecl;
042          //if(!typeDecl.isFinal)
043          //  System.out.println("Warning: trying to create constant pool for non final type decl " + typeDecl.fullName());
044        }
045        
046        public static final byte CONSTANT_Class              = 7;
047        public static final byte CONSTANT_Fieldref           = 9;
048        public static final byte CONSTANT_Methodref          = 10;
049        public static final byte CONSTANT_InterfaceMethodref = 11;
050        public static final byte CONSTANT_String             = 8;
051        public static final byte CONSTANT_Integer            = 3;
052        public static final byte CONSTANT_Float              = 4;
053        public static final byte CONSTANT_Long               = 5;
054        public static final byte CONSTANT_Double             = 6;
055        public static final byte CONSTANT_NameAndType        = 12;
056        public static final byte CONSTANT_Utf8               = 1;
057     
058        private int posCounter = 1;
059     
060        private ArrayList list = new ArrayList();
061        private void addCPInfo(CPInfo info) {
062          list.add(info);
063        }
064     
065        // for debugging purposes
066        public int numElements() {
067          return list.size();
068        }
069        public String toString() {
070          StringBuffer s = new StringBuffer();
071          for(Iterator iter = list.iterator(); iter.hasNext(); ) {
072            s.append(iter.next().toString());
073            s.append("\n");
074          }
075          return s.toString();
076        }
077     
078        public void emit(DataOutputStream out) throws IOException {
079          out.writeChar(posCounter);
080          for(Iterator iter = list.iterator(); iter.hasNext(); ) {
081            CPInfo info = (CPInfo)iter.next();
082            info.emit(out);
083          }
084        }
085    
086        private int labelCounter = 1;
087        public int newLabel() {
088          return labelCounter++;
089        }
090     
091        private HashMap classConstants = new HashMap();
092        public int addClass(String name) {
093          Map map = classConstants;
094          Object key = name;
095          if(!map.containsKey(key)) {
096            CPInfo info = new ConstantClass(addUtf8(name.replace('.', '/')));
097            info.pos = posCounter; posCounter += info.size();
098            addCPInfo(info);
099            map.put(key, info);
100            String s = info.toString();
101            return info.pos;
102          }
103          CPInfo info = (CPInfo)map.get(key);
104          return info.pos;
105        }
106     
107        private HashMap fieldrefConstants = new HashMap();
108        public int addFieldref(String classname, String name, String type) {
109          Map map = fieldrefConstants;
110          Object key = classname + name + type;
111          if(!map.containsKey(key)) {
112            CPInfo info = new ConstantFieldref(addClass(classname), addNameAndType(name, type));
113            info.pos = posCounter; posCounter += info.size();
114            addCPInfo(info);
115            map.put(key, info);
116            String s = info.toString();
117            return info.pos;
118          }
119          CPInfo info = (CPInfo)map.get(key);
120          return info.pos;
121        }
122     
123        private HashMap methodrefConstants = new HashMap();
124        public int addMethodref(String classname, String name, String desc) {
125          Map map = methodrefConstants;
126          Object key = classname + name + desc;
127          if(!map.containsKey(key)) {
128            CPInfo info = new ConstantMethodref(addClass(classname), addNameAndType(name, desc));
129            info.pos = posCounter; posCounter += info.size();
130            addCPInfo(info);
131            map.put(key, info);
132            String s = info.toString();
133            return info.pos;
134          }
135          CPInfo info = (CPInfo)map.get(key);
136          return info.pos;
137        }
138     
139        private HashMap interfaceMethodrefConstants = new HashMap();
140        public int addInterfaceMethodref(String classname, String name, String desc) {
141          Map map = interfaceMethodrefConstants;
142          Object key = classname + name + desc;
143          if(!map.containsKey(key)) {
144            CPInfo info = new ConstantInterfaceMethodref(addClass(classname), addNameAndType(name, desc));
145            info.pos = posCounter; posCounter += info.size();
146            addCPInfo(info);
147            map.put(key, info);
148            String s = info.toString();
149            return info.pos;
150          }
151          CPInfo info = (CPInfo)map.get(key);
152          return info.pos;
153        }
154     
155        private HashMap nameAndTypeConstants = new HashMap();
156        public int addNameAndType(String name, String type) {
157          Map map = nameAndTypeConstants;
158          Object key = name + type;
159          if(!map.containsKey(key)) {
160            CPInfo info = new ConstantNameAndType(addUtf8(name), addUtf8(type));
161            info.pos = posCounter; posCounter += info.size();
162            addCPInfo(info);
163            map.put(key, info);
164            String s = info.toString();
165            return info.pos;
166          }
167          CPInfo info = (CPInfo)map.get(key);
168          return info.pos;
169        }
170     
171        private HashMap utf8Constants = new HashMap();
172        public int addUtf8(String name) {
173          Map map = utf8Constants;
174          Object key = name;
175          if(!map.containsKey(key)) {
176            CPInfo info = new ConstantUtf8(name);
177            info.pos = posCounter; posCounter += info.size();
178            addCPInfo(info);
179            map.put(key, info);
180            String s = info.toString();
181            return info.pos;
182          }
183          CPInfo info = (CPInfo)map.get(key);
184          return info.pos;
185        }
186     
187        private HashMap stringConstants = new HashMap();
188        public int addConstant(String val) {
189          Map map = stringConstants;
190          Object key = val;
191          if(!map.containsKey(key)) {
192            CPInfo info = new ConstantString(addUtf8(val));
193            info.pos = posCounter; posCounter += info.size();
194            addCPInfo(info);
195            map.put(key, info);
196            String s = info.toString();
197            return info.pos;
198          }
199          CPInfo info = (CPInfo)map.get(key);
200          return info.pos;
201        }
202     
203        private HashMap intConstants = new HashMap();
204        public int addConstant(int val) {
205          Map map = intConstants;
206          Object key = new Integer(val);
207          if(!map.containsKey(key)) {
208            CPInfo info = new ConstantInteger(val);
209            info.pos = posCounter; posCounter += info.size();
210            addCPInfo(info);
211            map.put(key, info);
212            return info.pos;
213          }
214          CPInfo info = (CPInfo)map.get(key);
215          return info.pos;
216        }
217     
218        private HashMap floatConstants = new HashMap();
219        public int addConstant(float val) {
220          Map map = floatConstants;
221          Object key = new Float(val);
222          if(!map.containsKey(key)) {
223            CPInfo info = new ConstantFloat(val);
224            info.pos = posCounter; posCounter += info.size();
225            addCPInfo(info);
226            map.put(key, info);
227            return info.pos;
228          }
229          CPInfo info = (CPInfo)map.get(key);
230          return info.pos;
231        }
232     
233        private HashMap longConstants = new HashMap();
234        public int addConstant(long val) {
235          Map map = longConstants;
236          Object key = new Long(val);
237          if(!map.containsKey(key)) {
238            CPInfo info = new ConstantLong(val);
239            info.pos = posCounter; posCounter += info.size();
240            addCPInfo(info);
241            map.put(key, info);
242            return info.pos;
243          }
244          CPInfo info = (CPInfo)map.get(key);
245          return info.pos;
246        }
247     
248        private HashMap doubleConstants = new HashMap();
249        public int addConstant(double val) {
250          Map map = doubleConstants;
251          Object key = new Double(val);
252          if(!map.containsKey(key)) {
253            CPInfo info = new ConstantDouble(val);
254            info.pos = posCounter; posCounter += info.size();
255            addCPInfo(info);
256            map.put(key, info);
257            return info.pos;
258          }
259          CPInfo info = (CPInfo)map.get(key);
260          return info.pos;
261        }
262      }
263    
264      public class CPInfo {
265        public void emit(DataOutputStream out) throws IOException {
266        }
267        public int size() {
268          return  1;
269        }
270        public int pos;
271      }
272    
273      public class ConstantClass extends CPInfo {
274        private int name;
275        public ConstantClass(int name) {
276          this.name = name;
277        }
278        public void emit(DataOutputStream out) throws IOException {
279          out.writeByte(ConstantPool.CONSTANT_Class);
280          out.writeChar(name);
281        }
282        public String toString() {
283          return pos + " ConstantClass: tag " + ConstantPool.CONSTANT_Class + ", name_index: " + name;
284        }
285      }
286    
287      public class ConstantFieldref extends CPInfo {
288        private int classname;
289        private int nameandtype;
290        public ConstantFieldref(int classname, int nameandtype) {
291          this.classname = classname;
292          this.nameandtype = nameandtype;
293        }
294        public void emit(DataOutputStream out) throws IOException {
295          out.writeByte(ConstantPool.CONSTANT_Fieldref);
296          out.writeChar(classname);
297          out.writeChar(nameandtype);
298        }
299        public String toString() {
300          return pos + " ConstantFieldref: tag " + ConstantPool.CONSTANT_Fieldref + ", class_index: " + classname + ", name_and_type_index: " + nameandtype;
301        }
302      }
303      
304      public class ConstantMethodref extends CPInfo {
305        private int classname;
306        private int nameandtype;
307        public ConstantMethodref(int classname, int nameandtype) {
308          this.classname = classname;
309          this.nameandtype = nameandtype;
310        }
311    
312        public void emit(DataOutputStream out) throws IOException {
313          out.writeByte(ConstantPool.CONSTANT_Methodref);
314          out.writeChar(classname);
315          out.writeChar(nameandtype);
316        }
317        public String toString() {
318          return pos + " ConstantMethodref: tag " + ConstantPool.CONSTANT_Methodref + ", class_index: " + classname + ", name_and_type_index: " + nameandtype;
319        }
320      }
321      
322      public class ConstantInterfaceMethodref extends CPInfo {
323        private int classname;
324        private int nameandtype;
325        public ConstantInterfaceMethodref(int classname, int nameandtype) {
326          this.classname = classname;
327          this.nameandtype = nameandtype;
328        }
329        public void emit(DataOutputStream out) throws IOException {
330          out.writeByte(ConstantPool.CONSTANT_InterfaceMethodref);
331          out.writeChar(classname);
332          out.writeChar(nameandtype);
333        }
334        public String toString() {
335          return pos + " ConstantInterfaceMethodref: tag " + ConstantPool.CONSTANT_InterfaceMethodref + ", class_index: " + classname + ", name_and_type_index: " + nameandtype;
336        }
337      }
338    
339      public class ConstantNameAndType extends CPInfo {
340        private int name;
341        private int type;
342        public ConstantNameAndType(int name, int type) {
343          this.name = name;
344          this.type = type;
345        }
346        public void emit(DataOutputStream out) throws IOException {
347          out.writeByte(ConstantPool.CONSTANT_NameAndType);
348          out.writeChar(name);
349          out.writeChar(type);
350        }
351        public String toString() {
352          return pos + " NameAndType: tag " + ConstantPool.CONSTANT_NameAndType + ", name_index: " + name + ", descriptor_index: " + type;
353        }
354      }
355    
356      public class ConstantUtf8 extends CPInfo {
357        private String name;
358        public ConstantUtf8(String name) {
359          this.name = name;
360        }
361        public void emit(DataOutputStream out) throws IOException {
362          out.writeByte(ConstantPool.CONSTANT_Utf8);
363          out.writeUTF(name);
364        }
365        public String toString() {
366          return pos + " ConstantUtf8: tag " + ConstantPool.CONSTANT_Utf8 + ", length: " + name.length() + ", bytes: " + name;
367        }
368      }
369    
370      public class ConstantString extends CPInfo {
371        private int name;
372        public ConstantString(int name) {
373          this.name = name;
374        }
375        public void emit(DataOutputStream out) throws IOException {
376          out.writeByte(ConstantPool.CONSTANT_String);
377          out.writeChar(name);
378        }
379        public String toString() {
380          return pos + " ConstantString: tag " + ConstantPool.CONSTANT_String + ", string_index: " + name;
381        }
382      }
383    
384      public class ConstantInteger extends CPInfo {
385        private int val;
386        public ConstantInteger(int val) {
387          this.val = val;
388        }
389        public void emit(DataOutputStream out) throws IOException {
390          out.writeByte(ConstantPool.CONSTANT_Integer);
391          out.writeInt(val);
392        }
393        public String toString() {
394          return pos + " ConstantInteger: tag " + ConstantPool.CONSTANT_Integer + ", bytes: " + val;
395        }
396      }
397    
398      public class ConstantFloat extends CPInfo {
399        private float val;
400        public ConstantFloat(float val) {
401          this.val = val;
402        }
403        public void emit(DataOutputStream out) throws IOException {
404          out.writeByte(ConstantPool.CONSTANT_Float);
405          out.writeFloat(val);
406        }
407        public String toString() {
408          return pos + " ConstantFloat: tag " + ConstantPool.CONSTANT_Float + ", bytes: " + val;
409        }
410      }
411    
412      public class ConstantLong extends CPInfo {
413        private long val;
414        public ConstantLong(long val) {
415          this.val = val;
416        }
417        public void emit(DataOutputStream out) throws IOException {
418          out.writeByte(ConstantPool.CONSTANT_Long);
419          out.writeLong(val);
420        }
421        public int size() {
422          return 2;
423        }
424        public String toString() {
425          return pos + " ConstantLong: tag " + ConstantPool.CONSTANT_Long + ", bytes: " + val;
426        }
427      }
428    
429      public class ConstantDouble extends CPInfo {
430        private double val;
431        public ConstantDouble(double val) {
432          this.val = val;
433        }
434        public void emit(DataOutputStream out) throws IOException {
435          out.writeByte(ConstantPool.CONSTANT_Double);
436          out.writeDouble(val);
437        }
438        public int size() {
439          return 2;
440        }
441        public String toString() {
442          return pos + " ConstantDouble: tag " + ConstantPool.CONSTANT_Double + ", bytes: " + val;
443        }
444      }
445    
446    }