/Users/lyon/j4p/src/javassist/CtClassType.java

1    /* 
2     * Javassist, a Java-bytecode translator toolkit. 
3     * Copyright (C) 1999-2003 Shigeru Chiba. All Rights Reserved. 
4     * 
5     * The contents of this file are subject to the Mozilla Public License Version 
6     * 1.1 (the "License"); you may not use this file except in compliance with 
7     * the License.  Alternatively, the contents of this file may be used under 
8     * the terms of the GNU Lesser General Public License Version 2.1 or later. 
9     * 
10    * Software distributed under the License is distributed on an "AS IS" basis, 
11    * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 
12    * for the specific language governing rights and limitations under the 
13    * License. 
14    */ 
15    
16   package javassist; 
17    
18   import javassist.bytecode.*; 
19   import javassist.compiler.CompileError; 
20   import javassist.compiler.Javac; 
21   import javassist.expr.ExprEditor; 
22    
23   import java.io.*; 
24   import java.util.ArrayList; 
25   import java.util.HashMap; 
26   import java.util.Hashtable; 
27   import java.util.List; 
28    
29   /** 
30    * Class types. 
31    */ 
32   class CtClassType extends CtClass { 
33       protected ClassPool classPool; 
34       protected boolean wasChanged; 
35       protected boolean wasFrozen; 
36       protected ClassFile classfile; 
37    
38       private CtField fieldsCache; 
39       private CtConstructor constructorsCache; 
40       private CtConstructor classInitializerCache; 
41       private CtMethod methodsCache; 
42    
43       private FieldInitLink fieldInitializers; 
44       private Hashtable hiddenMethods;    // must be synchronous 
45       private int uniqueNumberSeed; 
46    
47       CtClassType(String name, ClassPool cp) { 
48           super(name); 
49           classPool = cp; 
50           wasChanged = wasFrozen = false; 
51           classfile = null; 
52           fieldInitializers = null; 
53           hiddenMethods = null; 
54           uniqueNumberSeed = 0; 
55           eraseCache(); 
56       } 
57    
58       CtClassType(InputStream ins, ClassPool cp) throws IOException { 
59           this((String) null, cp); 
60           classfile = new ClassFile(new DataInputStream(ins)); 
61           qualifiedName = classfile.getName(); 
62       } 
63    
64       protected void eraseCache() { 
65           fieldsCache = null; 
66           constructorsCache = null; 
67           classInitializerCache = null; 
68           methodsCache = null; 
69       } 
70    
71       public ClassFile getClassFile2() { 
72           if (classfile != null) 
73               return classfile; 
74    
75           try { 
76               byte[] b = classPool.readSource(getName()); 
77               DataInputStream dis 
78                       = new DataInputStream(new ByteArrayInputStream(b)); 
79               return (classfile = new ClassFile(dis)); 
80           } catch (NotFoundException e) { 
81               throw new RuntimeException(e.toString()); 
82           } catch (IOException e) { 
83               throw new RuntimeException(e.toString()); 
84           } catch (CannotCompileException e) { 
85               throw new RuntimeException(e.toString()); 
86           } 
87       } 
88    
89       public ClassPool getClassPool() { 
90           return classPool; 
91       } 
92    
93       public boolean isModified() { 
94           return wasChanged; 
95       } 
96    
97       public boolean isFrozen() { 
98           return wasFrozen; 
99       } 
100   
101      void freeze() { 
102          wasFrozen = true; 
103      } 
104   
105      void checkModify() throws RuntimeException { 
106          super.checkModify(); 
107          wasChanged = true; 
108      } 
109   
110      public void defrost() { 
111          wasFrozen = false; 
112      } 
113   
114      public boolean subtypeOf(CtClass clazz) throws NotFoundException { 
115          int i; 
116          String cname = clazz.getName(); 
117          if (this == clazz || getName().equals(cname)) 
118              return true; 
119   
120          ClassFile file = getClassFile2(); 
121          String supername = file.getSuperclass(); 
122          if (supername != null && supername.equals(cname)) 
123              return true; 
124   
125          String[] ifs = file.getInterfaces(); 
126          int num = ifs.length; 
127          for (i = 0; i < num; ++i) 
128              if (ifs[i].equals(cname)) 
129                  return true; 
130   
131          if (supername != null && classPool.get(supername).subtypeOf(clazz)) 
132              return true; 
133   
134          for (i = 0; i < num; ++i) 
135              if (classPool.get(ifs[i]).subtypeOf(clazz)) 
136                  return true; 
137   
138          return false; 
139      } 
140   
141      public void setName(String name) throws RuntimeException { 
142          String oldname = getName(); 
143          if (name.equals(oldname)) 
144              return; 
145   
146          classPool.checkNotFrozen(name, 
147                  "the class with the new name is frozen"); 
148          ClassFile cf = getClassFile2(); 
149          super.setName(name); 
150          cf.setName(name); 
151          eraseCache(); 
152          classPool.classNameChanged(oldname, this); 
153      } 
154   
155      public void replaceClassName(ClassMap classnames) 
156              throws RuntimeException { 
157          String oldClassName = getName(); 
158          String newClassName 
159                  = (String) classnames.get(Descriptor.toJvmName(oldClassName)); 
160          if (newClassName != null) { 
161              newClassName = Descriptor.toJavaName(newClassName); 
162              classPool.checkNotFrozen(newClassName, 
163                      "the class " + newClassName + " is frozen"); 
164          } 
165   
166          super.replaceClassName(classnames); 
167          ClassFile cf = getClassFile2(); 
168          cf.renameClass(classnames); 
169          eraseCache(); 
170   
171          if (newClassName != null) { 
172              super.setName(newClassName); 
173              classPool.classNameChanged(oldClassName, this); 
174          } 
175      } 
176   
177      public void replaceClassName(String oldname, String newname) 
178              throws RuntimeException { 
179          String thisname = getName(); 
180          if (thisname.equals(oldname)) 
181              setName(newname); 
182          else { 
183              super.replaceClassName(oldname, newname); 
184              getClassFile2().renameClass(oldname, newname); 
185              eraseCache(); 
186          } 
187      } 
188   
189      public boolean isInterface() { 
190          return Modifier.isInterface(getModifiers()); 
191      } 
192   
193      public int getModifiers() { 
194          int acc = getClassFile2().getAccessFlags(); 
195          acc = AccessFlag.clear(acc, AccessFlag.SUPER); 
196          return AccessFlag.toModifier(acc); 
197      } 
198   
199      public void setModifiers(int mod) { 
200          checkModify(); 
201          int acc = AccessFlag.of(mod) | AccessFlag.SUPER; 
202          getClassFile2().setAccessFlags(acc); 
203      } 
204   
205      public boolean subclassOf(CtClass superclass) { 
206          if (superclass == null) 
207              return false; 
208   
209          String superName = superclass.getName(); 
210          CtClass curr = this; 
211          try { 
212              while (curr != null) { 
213                  if (curr.getName().equals(superName)) 
214                      return true; 
215   
216                  curr = curr.getSuperclass(); 
217              } 
218          } catch (Exception ignored) { 
219          } 
220          return false; 
221      } 
222   
223      public CtClass getSuperclass() throws NotFoundException { 
224          String supername = getClassFile2().getSuperclass(); 
225          if (supername == null) 
226              return null; 
227          else 
228              return classPool.get(supername); 
229      } 
230   
231      public void setSuperclass(CtClass clazz) throws CannotCompileException { 
232          checkModify(); 
233          getClassFile2().setSuperclass(clazz.getName()); 
234      } 
235   
236      public CtClass[] getInterfaces() throws NotFoundException { 
237          String[] ifs = getClassFile2().getInterfaces(); 
238          int num = ifs.length; 
239          CtClass[] ifc = new CtClass[num]; 
240          for (int i = 0; i < num; ++i) 
241              ifc[i] = classPool.get(ifs[i]); 
242   
243          return ifc; 
244      } 
245   
246      public void setInterfaces(CtClass[] list) { 
247          checkModify(); 
248          String[] ifs; 
249          if (list == null) 
250              ifs = new String[0]; 
251          else { 
252              int num = list.length; 
253              ifs = new String[num]; 
254              for (int i = 0; i < num; ++i) 
255                  ifs[i] = list[i].getName(); 
256          } 
257   
258          getClassFile2().setInterfaces(ifs); 
259      } 
260   
261      public void addInterface(CtClass anInterface) { 
262          checkModify(); 
263          if (anInterface != null) 
264              getClassFile2().addInterface(anInterface.getName()); 
265      } 
266   
267      public CtField[] getFields() { 
268          ArrayList alist = new ArrayList(); 
269          getFields(alist, this); 
270          return (CtField[]) alist.toArray(new CtField[alist.size()]); 
271      } 
272   
273      private static void getFields(ArrayList alist, CtClass cc) { 
274          int i, num; 
275          if (cc == null) 
276              return; 
277   
278          try { 
279              getFields(alist, cc.getSuperclass()); 
280          } catch (NotFoundException e) { 
281          } 
282   
283          try { 
284              CtClass[] ifs = cc.getInterfaces(); 
285              num = ifs.length; 
286              for (i = 0; i < num; ++i) 
287                  getFields(alist, ifs[i]); 
288          } catch (NotFoundException e) { 
289          } 
290   
291          CtField cf = ((CtClassType) cc).getFieldsCache(); 
292          while (cf != null) { 
293              if (Modifier.isPublic(cf.getModifiers())) 
294                  alist.add(cf); 
295   
296              cf = cf.next; 
297          } 
298      } 
299   
300      public CtField getField(String name) throws NotFoundException { 
301          try { 
302              return getDeclaredField(name); 
303          } catch (NotFoundException e) { 
304          } 
305   
306          try { 
307              CtClass[] ifs = getInterfaces(); 
308              int num = ifs.length; 
309              for (int i = 0; i < num; ++i) 
310                  try { 
311                      return ifs[i].getField(name); 
312                  } catch (NotFoundException e) { 
313                  } 
314          } catch (NotFoundException e) { 
315          } 
316   
317          try { 
318              CtClass s = getSuperclass(); 
319              if (s != null) 
320                  return s.getField(name); 
321          } catch (NotFoundException e) { 
322          } 
323   
324          throw new NotFoundException(name); 
325      } 
326   
327      public CtField[] getDeclaredFields() { 
328          CtField cf = getFieldsCache(); 
329          int num = CtField.count(cf); 
330          CtField[] cfs = new CtField[num]; 
331          int i = 0; 
332          while (cf != null) { 
333              cfs[i++] = cf; 
334              cf = cf.next; 
335          } 
336   
337          return cfs; 
338      } 
339   
340      protected CtField getFieldsCache() { 
341          if (fieldsCache == null) { 
342              List list = getClassFile2().getFields(); 
343              int n = list.size(); 
344              for (int i = 0; i < n; ++i) { 
345                  FieldInfo finfo = (FieldInfo) list.get(i); 
346                  fieldsCache = CtField.append(fieldsCache, 
347                          new CtField(finfo, this)); 
348              } 
349          } 
350   
351          return fieldsCache; 
352      } 
353   
354      public CtField getDeclaredField(String name) throws NotFoundException { 
355          CtField cf = getFieldsCache(); 
356          while (cf != null) { 
357              if (cf.getName().equals(name)) 
358                  return cf; 
359   
360              cf = cf.next; 
361          } 
362   
363          throw new NotFoundException(name); 
364      } 
365   
366      public CtBehavior[] getDeclaredBehaviors() { 
367          CtConstructor cc = getConstructorsCache(); 
368          CtMethod cm = getMethodsCache(); 
369          int num = CtMethod.count(cm) + CtConstructor.count(cc); 
370          CtBehavior[] cb = new CtBehavior[num]; 
371          int i = 0; 
372          while (cc != null) { 
373              cb[i++] = cc; 
374              cc = cc.next; 
375          } 
376   
377          while (cm != null) { 
378              cb[i++] = cm; 
379              cm = cm.next; 
380          } 
381   
382          return cb; 
383      } 
384   
385      public CtConstructor[] getConstructors() { 
386          CtConstructor[] cons = getDeclaredConstructors(); 
387          if (cons.length == 0) 
388              return cons; 
389   
390          int n = 0; 
391          int i = cons.length; 
392          while (--i >= 0) 
393              if (Modifier.isPublic(cons[i].getModifiers())) 
394                  ++n; 
395   
396          CtConstructor[] result = new CtConstructor[n]; 
397          n = 0; 
398          i = cons.length; 
399          while (--i >= 0) { 
400              CtConstructor c = cons[i]; 
401              if (Modifier.isPublic(c.getModifiers())) 
402                  result[n++] = c; 
403          } 
404   
405          return result; 
406      } 
407   
408      public CtConstructor getConstructor(String desc) 
409              throws NotFoundException { 
410          CtConstructor cc = getConstructorsCache(); 
411          while (cc != null) { 
412              if (cc.getMethodInfo2().getDescriptor().equals(desc)) 
413                  return cc; 
414   
415              cc = cc.next; 
416          } 
417   
418          return super.getConstructor(desc); 
419      } 
420   
421      public CtConstructor[] getDeclaredConstructors() { 
422          CtConstructor cc = getConstructorsCache(); 
423          int num = CtConstructor.count(cc); 
424          CtConstructor[] ccs = new CtConstructor[num]; 
425          int i = 0; 
426          while (cc != null) { 
427              ccs[i++] = cc; 
428              cc = cc.next; 
429          } 
430   
431          return ccs; 
432      } 
433   
434      protected CtConstructor getConstructorsCache() { 
435          if (constructorsCache == null) { 
436              List list = getClassFile2().getMethods(); 
437              int n = list.size(); 
438              for (int i = 0; i < n; ++i) { 
439                  MethodInfo minfo = (MethodInfo) list.get(i); 
440                  if (minfo.isConstructor()) 
441                      constructorsCache 
442                              = CtConstructor.append(constructorsCache, 
443                                      new CtConstructor(minfo, this)); 
444              } 
445          } 
446   
447          return constructorsCache; 
448      } 
449   
450      public CtConstructor getClassInitializer() { 
451          if (classInitializerCache == null) { 
452              MethodInfo minfo = getClassFile2().getStaticInitializer(); 
453              if (minfo != null) 
454                  classInitializerCache = new CtConstructor(minfo, this); 
455          } 
456   
457          return classInitializerCache; 
458      } 
459   
460      public CtMethod[] getMethods() { 
461          HashMap h = new HashMap(); 
462          getMethods0(h, this); 
463          return (CtMethod[]) h.values().toArray(new CtMethod[0]); 
464      } 
465   
466      private static void getMethods0(HashMap h, CtClass cc) { 
467          try { 
468              CtClass[] ifs = cc.getInterfaces(); 
469              int size = ifs.length; 
470              for (int i = 0; i < size; ++i) 
471                  getMethods0(h, ifs[i]); 
472          } catch (NotFoundException e) { 
473          } 
474   
475          try { 
476              CtClass s = cc.getSuperclass(); 
477              if (s != null) 
478                  getMethods0(h, s); 
479          } catch (NotFoundException e) { 
480          } 
481   
482          if (cc instanceof CtClassType) { 
483              CtMethod cm = ((CtClassType) cc).getMethodsCache(); 
484              while (cm != null) { 
485                  if (Modifier.isPublic(cm.getModifiers())) 
486                      h.put(cm, cm); 
487   
488                  cm = cm.next; 
489              } 
490          } 
491      } 
492   
493      public CtMethod getMethod(String name, String desc) 
494              throws NotFoundException { 
495          CtMethod m = getMethod0(this, name, desc); 
496          if (m != null) 
497              return m; 
498          else 
499              throw new NotFoundException(name + "(..) is not found in " 
500                      + getName()); 
501      } 
502   
503      private static CtMethod getMethod0(CtClass cc, 
504                                         String name, String desc) { 
505          if (cc instanceof CtClassType) { 
506              CtMethod cm = ((CtClassType) cc).getMethodsCache(); 
507              while (cm != null) { 
508                  if (cm.getName().equals(name) 
509                          && cm.getMethodInfo2().getDescriptor().equals(desc)) 
510                      return cm; 
511   
512                  cm = cm.next; 
513              } 
514          } 
515   
516          try { 
517              CtClass s = cc.getSuperclass(); 
518              if (s != null) { 
519                  CtMethod m = getMethod0(s, name, desc); 
520                  if (m != null) 
521                      return m; 
522              } 
523          } catch (NotFoundException e) { 
524          } 
525   
526          try { 
527              CtClass[] ifs = cc.getInterfaces(); 
528              int size = ifs.length; 
529              for (int i = 0; i < size; ++i) { 
530                  CtMethod m = getMethod0(ifs[i], name, desc); 
531                  if (m != null) 
532                      return m; 
533              } 
534          } catch (NotFoundException e) { 
535          } 
536          return null; 
537      } 
538   
539      public CtMethod[] getDeclaredMethods() { 
540          CtMethod cm = getMethodsCache(); 
541          int num = CtMethod.count(cm); 
542          CtMethod[] cms = new CtMethod[num]; 
543          int i = 0; 
544          while (cm != null) { 
545              cms[i++] = cm; 
546              cm = cm.next; 
547          } 
548   
549          return cms; 
550      } 
551   
552      public CtMethod getDeclaredMethod(String name) throws NotFoundException { 
553          CtMethod m = getMethodsCache(); 
554          while (m != null) { 
555              if (m.getName().equals(name)) 
556                  return m; 
557   
558              m = m.next; 
559          } 
560   
561          throw new NotFoundException(name + "(..) is not found in " 
562                  + getName()); 
563      } 
564   
565      public CtMethod getDeclaredMethod(String name, CtClass[] params) 
566              throws NotFoundException { 
567          String desc = Descriptor.ofParameters(params); 
568          CtMethod m = getMethodsCache(); 
569          while (m != null) { 
570              if (m.getName().equals(name) 
571                      && m.getMethodInfo2().getDescriptor().startsWith(desc)) 
572                  return m; 
573   
574              m = m.next; 
575          } 
576   
577          throw new NotFoundException(name + "(..) is not found in " 
578                  + getName()); 
579      } 
580   
581      protected CtMethod getMethodsCache() { 
582          if (methodsCache == null) { 
583              List list = getClassFile2().getMethods(); 
584              int n = list.size(); 
585              for (int i = 0; i < n; ++i) { 
586                  MethodInfo minfo = (MethodInfo) list.get(i); 
587                  if (minfo.isMethod()) 
588                      methodsCache = CtMethod.append(methodsCache, 
589                              new CtMethod(minfo, this)); 
590              } 
591          } 
592   
593          return methodsCache; 
594      } 
595   
596      public void addField(CtField f, String init) 
597              throws CannotCompileException { 
598          addField(f, CtField.Initializer.byExpr(init)); 
599      } 
600   
601      public void addField(CtField f, CtField.Initializer init) 
602              throws CannotCompileException { 
603          checkModify(); 
604          if (f.getDeclaringClass() != this) 
605              throw new CannotCompileException("cannot add"); 
606   
607          if (init == null) 
608              init = f.getInit(); 
609   
610          getFieldsCache(); 
611          fieldsCache = CtField.append(fieldsCache, f); 
612          getClassFile2().addField(f.getFieldInfo2()); 
613   
614          if (init != null) { 
615              FieldInitLink fil = new FieldInitLink(f, init); 
616              FieldInitLink link = fieldInitializers; 
617              if (link == null) 
618                  fieldInitializers = fil; 
619              else { 
620                  while (link.next != null) 
621                      link = link.next; 
622   
623                  link.next = fil; 
624              } 
625          } 
626      } 
627   
628      public CtConstructor makeClassInitializer() 
629              throws CannotCompileException { 
630          CtConstructor clinit = getClassInitializer(); 
631          if (clinit != null) 
632              return clinit; 
633   
634          checkModify(); 
635          ClassFile cf = getClassFile2(); 
636          Bytecode code = new Bytecode(cf.getConstPool(), 0, 0); 
637          modifyClassConstructor(cf, code, 0, 0); 
638          return getClassInitializer(); 
639      } 
640   
641      public void addConstructor(CtConstructor c) 
642              throws CannotCompileException { 
643          checkModify(); 
644          if (c.getDeclaringClass() != this) 
645              throw new CannotCompileException("cannot add"); 
646   
647          getConstructorsCache(); 
648          constructorsCache = CtConstructor.append(constructorsCache, c); 
649          getClassFile2().addMethod(c.getMethodInfo2()); 
650      } 
651   
652      public void addMethod(CtMethod m) throws CannotCompileException { 
653          checkModify(); 
654          if (m.getDeclaringClass() != this) 
655              throw new CannotCompileException("cannot add"); 
656   
657          getMethodsCache(); 
658          methodsCache = CtMethod.append(methodsCache, m); 
659          getClassFile2().addMethod(m.getMethodInfo2()); 
660          if ((m.getModifiers() & Modifier.ABSTRACT) != 0) 
661              setModifiers(getModifiers() | Modifier.ABSTRACT); 
662      } 
663   
664      public byte[] getAttribute(String name) { 
665          AttributeInfo ai = getClassFile2().getAttribute(name); 
666          if (ai == null) 
667              return null; 
668          else 
669              return ai.get(); 
670      } 
671   
672      public void setAttribute(String name, byte[] data) { 
673          checkModify(); 
674          ClassFile cf = getClassFile2(); 
675          cf.addAttribute(new AttributeInfo(cf.getConstPool(), name, data)); 
676      } 
677   
678      public void instrument(CodeConverter converter) 
679              throws CannotCompileException { 
680          checkModify(); 
681          ClassFile cf = getClassFile2(); 
682          ConstPool cp = cf.getConstPool(); 
683          List list = cf.getMethods(); 
684          int n = list.size(); 
685          for (int i = 0; i < n; ++i) { 
686              MethodInfo minfo = (MethodInfo) list.get(i); 
687              converter.doit(this, minfo, cp); 
688          } 
689      } 
690   
691      public void instrument(ExprEditor editor) 
692              throws CannotCompileException { 
693          checkModify(); 
694          ClassFile cf = getClassFile2(); 
695          List list = cf.getMethods(); 
696          int n = list.size(); 
697          for (int i = 0; i < n; ++i) { 
698              MethodInfo minfo = (MethodInfo) list.get(i); 
699              editor.doit(this, minfo); 
700          } 
701      } 
702   
703      void toBytecode(DataOutputStream out) 
704              throws CannotCompileException, IOException { 
705          ClassFile cf = getClassFile2(); 
706          try { 
707              modifyClassConstructor(cf); 
708              modifyConstructors(cf); 
709          } catch (NotFoundException e) { 
710              throw new CannotCompileException(e); 
711          } 
712   
713          wasFrozen = true; 
714          try { 
715              cf.write(out); 
716              out.flush(); 
717          } catch (IOException e) { 
718              throw new CannotCompileException(e); 
719          } 
720      } 
721   
722      protected void modifyClassConstructor(ClassFile cf) 
723              throws CannotCompileException, NotFoundException { 
724          Bytecode code = new Bytecode(cf.getConstPool(), 0, 0); 
725          Javac jv = new Javac(code, this); 
726          int stacksize = 0; 
727          boolean doInit = false; 
728          for (FieldInitLink fi = fieldInitializers; fi != null; fi = fi.next) { 
729              CtField f = fi.field; 
730              if (Modifier.isStatic(f.getModifiers())) { 
731                  doInit = true; 
732                  int s = fi.init.compileIfStatic(f.getType(), f.getName(), 
733                          code, jv); 
734                  if (stacksize < s) 
735                      stacksize = s; 
736              } 
737          } 
738   
739          if (doInit)    // need an initializer for static fileds. 
740              modifyClassConstructor(cf, code, stacksize, 0); 
741      } 
742   
743      private void modifyClassConstructor(ClassFile cf, Bytecode code, 
744                                          int stacksize, int localsize) 
745              throws CannotCompileException { 
746          MethodInfo m = cf.getStaticInitializer(); 
747          if (m == null) { 
748              code.add(Bytecode.RETURN); 
749              code.setMaxStack(stacksize); 
750              code.setMaxLocals(localsize); 
751              m = new MethodInfo(cf.getConstPool(), "<clinit>", "()V"); 
752              m.setAccessFlags(AccessFlag.STATIC); 
753              m.setCodeAttribute(code.toCodeAttribute()); 
754              cf.addMethod(m); 
755          } else { 
756              CodeAttribute codeAttr = m.getCodeAttribute(); 
757              if (codeAttr == null) 
758                  throw new CannotCompileException("empty <clinit>"); 
759   
760              try { 
761                  CodeIterator it = codeAttr.iterator(); 
762                  int pos = it.insertEx(code.get()); 
763                  it.insert(code.getExceptionTable(), pos); 
764                  int maxstack = codeAttr.getMaxStack(); 
765                  if (maxstack < stacksize) 
766                      codeAttr.setMaxStack(stacksize); 
767   
768                  int maxlocals = codeAttr.getMaxLocals(); 
769                  if (maxlocals < localsize) 
770                      codeAttr.setMaxLocals(localsize); 
771              } catch (BadBytecode e) { 
772                  throw new CannotCompileException(e); 
773              } 
774          } 
775      } 
776   
777      protected void modifyConstructors(ClassFile cf) 
778              throws CannotCompileException, NotFoundException { 
779          if (fieldInitializers == null) 
780              return; 
781   
782          ConstPool cp = cf.getConstPool(); 
783          List list = cf.getMethods(); 
784          int n = list.size(); 
785          for (int i = 0; i < n; ++i) { 
786              MethodInfo minfo = (MethodInfo) list.get(i); 
787              if (minfo.isConstructor()) { 
788                  CodeAttribute codeAttr = minfo.getCodeAttribute(); 
789                  if (codeAttr != null) 
790                      try { 
791                          Bytecode init = new Bytecode(cp, 0, 
792                                  codeAttr.getMaxLocals()); 
793                          CtClass[] params 
794                                  = Descriptor.getParameterTypes( 
795                                          minfo.getDescriptor(), 
796                                          classPool); 
797                          int stacksize = makeFieldInitializer(init, params); 
798                          insertAuxInitializer(codeAttr, init, stacksize); 
799                      } catch (BadBytecode e) { 
800                          throw new CannotCompileException(e); 
801                      } 
802              } 
803          } 
804      } 
805   
806      private static void insertAuxInitializer(CodeAttribute codeAttr, 
807                                               Bytecode initializer, 
808                                               int stacksize) 
809              throws BadBytecode { 
810          CodeIterator it = codeAttr.iterator(); 
811          int index = it.skipSuperConstructor(); 
812          if (index < 0) { 
813              index = it.skipThisConstructor(); 
814              if (index >= 0) 
815                  return;         // this() is called. 
816   
817              // Neither this() or super() is called. 
818          } 
819   
820          int pos = it.insertEx(initializer.get()); 
821          it.insert(initializer.getExceptionTable(), pos); 
822          int maxstack = codeAttr.getMaxStack(); 
823          if (maxstack < stacksize) 
824              codeAttr.setMaxStack(stacksize); 
825      } 
826   
827      private int makeFieldInitializer(Bytecode code, CtClass[] parameters) 
828              throws CannotCompileException, NotFoundException { 
829          int stacksize = 0; 
830          Javac jv = new Javac(code, this); 
831          try { 
832              jv.recordParams(parameters, false); 
833          } catch (CompileError e) { 
834              throw new CannotCompileException(e); 
835          } 
836   
837          for (FieldInitLink fi = fieldInitializers; fi != null; fi = fi.next) { 
838              CtField f = fi.field; 
839              if (!Modifier.isStatic(f.getModifiers())) { 
840                  int s = fi.init.compile(f.getType(), f.getName(), code, 
841                          parameters, jv); 
842                  if (stacksize < s) 
843                      stacksize = s; 
844              } 
845          } 
846   
847          return stacksize; 
848      } 
849   
850      // Methods used by CtNewWrappedMethod 
851   
852      Hashtable getHiddenMethods() { 
853          if (hiddenMethods == null) 
854              hiddenMethods = new Hashtable(); 
855   
856          return hiddenMethods; 
857      } 
858   
859      int getUniqueNumber() { 
860          return uniqueNumberSeed++; 
861      } 
862  } 
863   
864  class FieldInitLink { 
865      FieldInitLink next; 
866      CtField field; 
867      CtField.Initializer init; 
868   
869      FieldInitLink(CtField f, CtField.Initializer i) { 
870          next = null; 
871          field = f; 
872          init = i; 
873      } 
874  } 
875