• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Javassist, a Java-bytecode translator toolkit.
3  * Copyright (C) 1999-2007 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 java.lang.ref.WeakReference;
19 import java.io.BufferedInputStream;
20 import java.io.ByteArrayOutputStream;
21 import java.io.ByteArrayInputStream;
22 import java.io.DataInputStream;
23 import java.io.DataOutputStream;
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.net.URL;
27 import java.util.ArrayList;
28 import java.util.HashMap;
29 import java.util.Hashtable;
30 import java.util.List;
31 import java.util.Set;
32 
33 import javassist.bytecode.AccessFlag;
34 import javassist.bytecode.AttributeInfo;
35 import javassist.bytecode.AnnotationsAttribute;
36 import javassist.bytecode.BadBytecode;
37 import javassist.bytecode.Bytecode;
38 import javassist.bytecode.ClassFile;
39 import javassist.bytecode.CodeAttribute;
40 import javassist.bytecode.ConstantAttribute;
41 import javassist.bytecode.CodeIterator;
42 import javassist.bytecode.ConstPool;
43 import javassist.bytecode.Descriptor;
44 import javassist.bytecode.EnclosingMethodAttribute;
45 import javassist.bytecode.FieldInfo;
46 import javassist.bytecode.InnerClassesAttribute;
47 import javassist.bytecode.MethodInfo;
48 import javassist.bytecode.ParameterAnnotationsAttribute;
49 import javassist.bytecode.annotation.Annotation;
50 import javassist.compiler.AccessorMaker;
51 import javassist.compiler.CompileError;
52 import javassist.compiler.Javac;
53 import javassist.expr.ExprEditor;
54 
55 /**
56  * Class types.
57  */
58 class CtClassType extends CtClass {
59     ClassPool classPool;
60     boolean wasChanged;
61     private boolean wasFrozen;
62     boolean wasPruned;
63     boolean gcConstPool;    // if true, the constant pool entries will be garbage collected.
64     ClassFile classfile;
65     byte[] rawClassfile;    // backup storage
66 
67     private WeakReference memberCache;
68     private AccessorMaker accessors;
69 
70     private FieldInitLink fieldInitializers;
71     private Hashtable hiddenMethods;    // must be synchronous
72     private int uniqueNumberSeed;
73 
74     private boolean doPruning = ClassPool.doPruning;
75     private int getCount;
76     private static final int GET_THRESHOLD = 2;     // see compress()
77 
CtClassType(String name, ClassPool cp)78     CtClassType(String name, ClassPool cp) {
79         super(name);
80         classPool = cp;
81         wasChanged = wasFrozen = wasPruned = gcConstPool = false;
82         classfile = null;
83         rawClassfile = null;
84         memberCache = null;
85         accessors = null;
86         fieldInitializers = null;
87         hiddenMethods = null;
88         uniqueNumberSeed = 0;
89         getCount = 0;
90     }
91 
CtClassType(InputStream ins, ClassPool cp)92     CtClassType(InputStream ins, ClassPool cp) throws IOException {
93         this((String)null, cp);
94         classfile = new ClassFile(new DataInputStream(ins));
95         qualifiedName = classfile.getName();
96     }
97 
extendToString(StringBuffer buffer)98     protected void extendToString(StringBuffer buffer) {
99         if (wasChanged)
100             buffer.append("changed ");
101 
102         if (wasFrozen)
103             buffer.append("frozen ");
104 
105         if (wasPruned)
106             buffer.append("pruned ");
107 
108         buffer.append(Modifier.toString(getModifiers()));
109         buffer.append(" class ");
110         buffer.append(getName());
111 
112         try {
113             CtClass ext = getSuperclass();
114             if (ext != null) {
115                 String name = ext.getName();
116                 if (!name.equals("java.lang.Object"))
117                     buffer.append(" extends " + ext.getName());
118             }
119         }
120         catch (NotFoundException e) {
121             buffer.append(" extends ??");
122         }
123 
124         try {
125             CtClass[] intf = getInterfaces();
126             if (intf.length > 0)
127                 buffer.append(" implements ");
128 
129             for (int i = 0; i < intf.length; ++i) {
130                 buffer.append(intf[i].getName());
131                 buffer.append(", ");
132             }
133         }
134         catch (NotFoundException e) {
135             buffer.append(" extends ??");
136         }
137 
138         CtMember.Cache memCache = getMembers();
139         exToString(buffer, " fields=",
140                 memCache.fieldHead(), memCache.lastField());
141         exToString(buffer, " constructors=",
142                 memCache.consHead(), memCache.lastCons());
143         exToString(buffer, " methods=",
144                    memCache.methodHead(), memCache.lastMethod());
145     }
146 
exToString(StringBuffer buffer, String msg, CtMember head, CtMember tail)147     private void exToString(StringBuffer buffer, String msg,
148                             CtMember head, CtMember tail) {
149         buffer.append(msg);
150         while (head != tail) {
151             head = head.next();
152             buffer.append(head);
153             buffer.append(", ");
154         }
155     }
156 
getAccessorMaker()157     public AccessorMaker getAccessorMaker() {
158         if (accessors == null)
159             accessors = new AccessorMaker(this);
160 
161         return accessors;
162     }
163 
getClassFile2()164     public ClassFile getClassFile2() {
165         ClassFile cfile = classfile;
166         if (cfile != null)
167             return cfile;
168 
169         classPool.compress();
170         if (rawClassfile != null) {
171             try {
172                 classfile = new ClassFile(new DataInputStream(
173                                             new ByteArrayInputStream(rawClassfile)));
174                 rawClassfile = null;
175                 getCount = GET_THRESHOLD;
176                 return classfile;
177             }
178             catch (IOException e) {
179                 throw new RuntimeException(e.toString(), e);
180             }
181         }
182 
183         InputStream fin = null;
184         try {
185             fin = classPool.openClassfile(getName());
186             if (fin == null)
187                 throw new NotFoundException(getName());
188 
189             fin = new BufferedInputStream(fin);
190             ClassFile cf = new ClassFile(new DataInputStream(fin));
191             if (!cf.getName().equals(qualifiedName))
192                 throw new RuntimeException("cannot find " + qualifiedName + ": "
193                         + cf.getName() + " found in "
194                         + qualifiedName.replace('.', '/') + ".class");
195 
196             classfile = cf;
197             return cf;
198         }
199         catch (NotFoundException e) {
200             throw new RuntimeException(e.toString(), e);
201         }
202         catch (IOException e) {
203             throw new RuntimeException(e.toString(), e);
204         }
205         finally {
206             if (fin != null)
207                 try {
208                     fin.close();
209                 }
210                 catch (IOException e) {}
211         }
212     }
213 
214    /* Inherited from CtClass.  Called by get() in ClassPool.
215     *
216     * @see javassist.CtClass#incGetCounter()
217     * @see #toBytecode(DataOutputStream)
218     */
incGetCounter()219    final void incGetCounter() { ++getCount; }
220 
221    /**
222     * Invoked from ClassPool#compress().
223     * It releases the class files that have not been recently used
224     * if they are unmodified.
225     */
compress()226    void compress() {
227        if (getCount < GET_THRESHOLD)
228            if (!isModified() && ClassPool.releaseUnmodifiedClassFile)
229                removeClassFile();
230            else if (isFrozen() && !wasPruned)
231                saveClassFile();
232 
233        getCount = 0;
234    }
235 
236    /**
237      * Converts a ClassFile object into a byte array
238      * for saving memory space.
239      */
saveClassFile()240     private synchronized void saveClassFile() {
241         /* getMembers() and releaseClassFile() are also synchronized.
242          */
243         if (classfile == null || hasMemberCache() != null)
244             return;
245 
246         ByteArrayOutputStream barray = new ByteArrayOutputStream();
247         DataOutputStream out = new DataOutputStream(barray);
248         try {
249             classfile.write(out);
250             barray.close();
251             rawClassfile = barray.toByteArray();
252             classfile = null;
253         }
254         catch (IOException e) {}
255     }
256 
removeClassFile()257     private synchronized void removeClassFile() {
258         if (classfile != null && !isModified() && hasMemberCache() == null)
259             classfile = null;
260     }
261 
getClassPool()262     public ClassPool getClassPool() { return classPool; }
263 
setClassPool(ClassPool cp)264     void setClassPool(ClassPool cp) { classPool = cp; }
265 
getURL()266     public URL getURL() throws NotFoundException {
267         URL url = classPool.find(getName());
268         if (url == null)
269             throw new NotFoundException(getName());
270         else
271             return url;
272     }
273 
isModified()274     public boolean isModified() { return wasChanged; }
275 
isFrozen()276     public boolean isFrozen() { return wasFrozen; }
277 
freeze()278     public void freeze() { wasFrozen = true; }
279 
checkModify()280     void checkModify() throws RuntimeException {
281         if (isFrozen()) {
282             String msg = getName() + " class is frozen";
283             if (wasPruned)
284                 msg += " and pruned";
285 
286             throw new RuntimeException(msg);
287         }
288 
289         wasChanged = true;
290     }
291 
defrost()292     public void defrost() {
293         checkPruned("defrost");
294         wasFrozen = false;
295     }
296 
subtypeOf(CtClass clazz)297     public boolean subtypeOf(CtClass clazz) throws NotFoundException {
298         int i;
299         String cname = clazz.getName();
300         if (this == clazz || getName().equals(cname))
301             return true;
302 
303         ClassFile file = getClassFile2();
304         String supername = file.getSuperclass();
305         if (supername != null && supername.equals(cname))
306             return true;
307 
308         String[] ifs = file.getInterfaces();
309         int num = ifs.length;
310         for (i = 0; i < num; ++i)
311             if (ifs[i].equals(cname))
312                 return true;
313 
314         if (supername != null && classPool.get(supername).subtypeOf(clazz))
315             return true;
316 
317         for (i = 0; i < num; ++i)
318             if (classPool.get(ifs[i]).subtypeOf(clazz))
319                 return true;
320 
321         return false;
322     }
323 
setName(String name)324     public void setName(String name) throws RuntimeException {
325         String oldname = getName();
326         if (name.equals(oldname))
327             return;
328 
329         // check this in advance although classNameChanged() below does.
330         classPool.checkNotFrozen(name);
331         ClassFile cf = getClassFile2();
332         super.setName(name);
333         cf.setName(name);
334         nameReplaced();
335         classPool.classNameChanged(oldname, this);
336     }
337 
replaceClassName(ClassMap classnames)338     public void replaceClassName(ClassMap classnames)
339         throws RuntimeException
340     {
341         String oldClassName = getName();
342         String newClassName
343             = (String)classnames.get(Descriptor.toJvmName(oldClassName));
344         if (newClassName != null) {
345             newClassName = Descriptor.toJavaName(newClassName);
346             // check this in advance although classNameChanged() below does.
347             classPool.checkNotFrozen(newClassName);
348         }
349 
350         super.replaceClassName(classnames);
351         ClassFile cf = getClassFile2();
352         cf.renameClass(classnames);
353         nameReplaced();
354 
355         if (newClassName != null) {
356             super.setName(newClassName);
357             classPool.classNameChanged(oldClassName, this);
358         }
359     }
360 
replaceClassName(String oldname, String newname)361     public void replaceClassName(String oldname, String newname)
362         throws RuntimeException
363     {
364         String thisname = getName();
365         if (thisname.equals(oldname))
366             setName(newname);
367         else {
368             super.replaceClassName(oldname, newname);
369             getClassFile2().renameClass(oldname, newname);
370             nameReplaced();
371         }
372     }
373 
isInterface()374     public boolean isInterface() {
375         return Modifier.isInterface(getModifiers());
376     }
377 
isAnnotation()378     public boolean isAnnotation() {
379         return Modifier.isAnnotation(getModifiers());
380     }
381 
isEnum()382     public boolean isEnum() {
383        return Modifier.isEnum(getModifiers());
384     }
385 
getModifiers()386     public int getModifiers() {
387         ClassFile cf = getClassFile2();
388         int acc = cf.getAccessFlags();
389         acc = AccessFlag.clear(acc, AccessFlag.SUPER);
390         int inner = cf.getInnerAccessFlags();
391         if (inner != -1 && (inner & AccessFlag.STATIC) != 0)
392             acc |= AccessFlag.STATIC;
393 
394         return AccessFlag.toModifier(acc);
395     }
396 
getNestedClasses()397     public CtClass[] getNestedClasses() throws NotFoundException {
398         ClassFile cf = getClassFile2();
399         InnerClassesAttribute ica
400             = (InnerClassesAttribute)cf.getAttribute(InnerClassesAttribute.tag);
401         if (ica == null)
402             return new CtClass[0];
403 
404         String thisName = cf.getName() + "$";
405         int n = ica.tableLength();
406         ArrayList list = new ArrayList(n);
407         for (int i = 0; i < n; i++) {
408             String name = ica.innerClass(i);
409             if (name != null)
410                 if (name.startsWith(thisName)) {
411                     // if it is an immediate nested class
412                     if (name.lastIndexOf('$') < thisName.length())
413                         list.add(classPool.get(name));
414                 }
415         }
416 
417         return (CtClass[])list.toArray(new CtClass[list.size()]);
418     }
419 
setModifiers(int mod)420     public void setModifiers(int mod) {
421         ClassFile cf = getClassFile2();
422         if (Modifier.isStatic(mod)) {
423             int flags = cf.getInnerAccessFlags();
424             if (flags != -1 && (flags & AccessFlag.STATIC) != 0)
425                 mod = mod & ~Modifier.STATIC;
426             else
427                 throw new RuntimeException("cannot change " + getName() + " into a static class");
428         }
429 
430         checkModify();
431         cf.setAccessFlags(AccessFlag.of(mod));
432     }
433 
hasAnnotation(Class clz)434     public boolean hasAnnotation(Class clz) {
435         ClassFile cf = getClassFile2();
436         AnnotationsAttribute ainfo = (AnnotationsAttribute)
437                 cf.getAttribute(AnnotationsAttribute.invisibleTag);
438         AnnotationsAttribute ainfo2 = (AnnotationsAttribute)
439                 cf.getAttribute(AnnotationsAttribute.visibleTag);
440         return hasAnnotationType(clz, getClassPool(), ainfo, ainfo2);
441     }
442 
hasAnnotationType(Class clz, ClassPool cp, AnnotationsAttribute a1, AnnotationsAttribute a2)443     static boolean hasAnnotationType(Class clz, ClassPool cp,
444                                      AnnotationsAttribute a1, AnnotationsAttribute a2)
445     {
446         Annotation[] anno1, anno2;
447 
448         if (a1 == null)
449             anno1 = null;
450         else
451             anno1 = a1.getAnnotations();
452 
453         if (a2 == null)
454             anno2 = null;
455         else
456             anno2 = a2.getAnnotations();
457 
458         String typeName = clz.getName();
459         if (anno1 != null)
460            for (int i = 0; i < anno1.length; i++)
461               if (anno1[i].getTypeName().equals(typeName))
462                   return true;
463 
464         if (anno2 != null)
465            for (int i = 0; i < anno2.length; i++)
466               if (anno2[i].getTypeName().equals(typeName))
467                   return true;
468 
469         return false;
470     }
471 
getAnnotation(Class clz)472     public Object getAnnotation(Class clz) throws ClassNotFoundException {
473         ClassFile cf = getClassFile2();
474         AnnotationsAttribute ainfo = (AnnotationsAttribute)
475                 cf.getAttribute(AnnotationsAttribute.invisibleTag);
476         AnnotationsAttribute ainfo2 = (AnnotationsAttribute)
477                 cf.getAttribute(AnnotationsAttribute.visibleTag);
478         return getAnnotationType(clz, getClassPool(), ainfo, ainfo2);
479     }
480 
getAnnotationType(Class clz, ClassPool cp, AnnotationsAttribute a1, AnnotationsAttribute a2)481     static Object getAnnotationType(Class clz, ClassPool cp,
482                                     AnnotationsAttribute a1, AnnotationsAttribute a2)
483         throws ClassNotFoundException
484     {
485         Annotation[] anno1, anno2;
486 
487         if (a1 == null)
488             anno1 = null;
489         else
490             anno1 = a1.getAnnotations();
491 
492         if (a2 == null)
493             anno2 = null;
494         else
495             anno2 = a2.getAnnotations();
496 
497         String typeName = clz.getName();
498         if (anno1 != null)
499            for (int i = 0; i < anno1.length; i++)
500               if (anno1[i].getTypeName().equals(typeName))
501                   return toAnnoType(anno1[i], cp);
502 
503         if (anno2 != null)
504            for (int i = 0; i < anno2.length; i++)
505               if (anno2[i].getTypeName().equals(typeName))
506                   return toAnnoType(anno2[i], cp);
507 
508         return null;
509     }
510 
getAnnotations()511     public Object[] getAnnotations() throws ClassNotFoundException {
512        return getAnnotations(false);
513     }
514 
getAvailableAnnotations()515     public Object[] getAvailableAnnotations(){
516        try {
517            return getAnnotations(true);
518        }
519        catch (ClassNotFoundException e) {
520            throw new RuntimeException("Unexpected exception ", e);
521        }
522     }
523 
getAnnotations(boolean ignoreNotFound)524     private Object[] getAnnotations(boolean ignoreNotFound)
525         throws ClassNotFoundException
526     {
527         ClassFile cf = getClassFile2();
528         AnnotationsAttribute ainfo = (AnnotationsAttribute)
529                 cf.getAttribute(AnnotationsAttribute.invisibleTag);
530         AnnotationsAttribute ainfo2 = (AnnotationsAttribute)
531                 cf.getAttribute(AnnotationsAttribute.visibleTag);
532         return toAnnotationType(ignoreNotFound, getClassPool(), ainfo, ainfo2);
533     }
534 
toAnnotationType(boolean ignoreNotFound, ClassPool cp, AnnotationsAttribute a1, AnnotationsAttribute a2)535     static Object[] toAnnotationType(boolean ignoreNotFound, ClassPool cp,
536                              AnnotationsAttribute a1, AnnotationsAttribute a2)
537         throws ClassNotFoundException
538     {
539         Annotation[] anno1, anno2;
540         int size1, size2;
541 
542         if (a1 == null) {
543             anno1 = null;
544             size1 = 0;
545         }
546         else {
547             anno1 = a1.getAnnotations();
548             size1 = anno1.length;
549         }
550 
551         if (a2 == null) {
552             anno2 = null;
553             size2 = 0;
554         }
555         else {
556             anno2 = a2.getAnnotations();
557             size2 = anno2.length;
558         }
559 
560         if (!ignoreNotFound){
561            Object[] result = new Object[size1 + size2];
562            for (int i = 0; i < size1; i++)
563                result[i] = toAnnoType(anno1[i], cp);
564 
565            for (int j = 0; j < size2; j++)
566                result[j + size1] = toAnnoType(anno2[j], cp);
567 
568            return result;
569         }
570         else{
571            ArrayList annotations = new ArrayList();
572            for (int i = 0 ; i < size1 ; i++){
573               try{
574                  annotations.add(toAnnoType(anno1[i], cp));
575               }
576               catch(ClassNotFoundException e){}
577            }
578            for (int j = 0; j < size2; j++) {
579               try{
580                  annotations.add(toAnnoType(anno2[j], cp));
581               }
582               catch(ClassNotFoundException e){}
583            }
584 
585            return annotations.toArray();
586         }
587     }
588 
toAnnotationType(boolean ignoreNotFound, ClassPool cp, ParameterAnnotationsAttribute a1, ParameterAnnotationsAttribute a2, MethodInfo minfo)589     static Object[][] toAnnotationType(boolean ignoreNotFound, ClassPool cp,
590                                        ParameterAnnotationsAttribute a1,
591                                        ParameterAnnotationsAttribute a2,
592                                        MethodInfo minfo)
593         throws ClassNotFoundException
594     {
595         int numParameters = 0;
596         if (a1 != null)
597             numParameters = a1.numParameters();
598         else if (a2 != null)
599             numParameters = a2.numParameters();
600         else
601             numParameters = Descriptor.numOfParameters(minfo.getDescriptor());
602 
603         Object[][] result = new Object[numParameters][];
604         for (int i = 0; i < numParameters; i++) {
605             Annotation[] anno1, anno2;
606             int size1, size2;
607 
608             if (a1 == null) {
609                 anno1 = null;
610                 size1 = 0;
611             }
612             else {
613                 anno1 = a1.getAnnotations()[i];
614                 size1 = anno1.length;
615             }
616 
617             if (a2 == null) {
618                 anno2 = null;
619                 size2 = 0;
620             }
621             else {
622                 anno2 = a2.getAnnotations()[i];
623                 size2 = anno2.length;
624             }
625 
626             if (!ignoreNotFound){
627                 result[i] = new Object[size1 + size2];
628                 for (int j = 0; j < size1; ++j)
629                     result[i][j] = toAnnoType(anno1[j], cp);
630 
631                 for (int j = 0; j < size2; ++j)
632                     result[i][j + size1] = toAnnoType(anno2[j], cp);
633             }
634             else{
635                 ArrayList annotations = new ArrayList();
636                 for (int j = 0 ; j < size1 ; j++){
637                     try{
638                         annotations.add(toAnnoType(anno1[j], cp));
639                     }
640                     catch(ClassNotFoundException e){}
641                 }
642                 for (int j = 0; j < size2; j++){
643                     try{
644                         annotations.add(toAnnoType(anno2[j], cp));
645                     }
646                     catch(ClassNotFoundException e){}
647                 }
648 
649                 result[i] = annotations.toArray();
650             }
651         }
652 
653         return result;
654     }
655 
toAnnoType(Annotation anno, ClassPool cp)656     private static Object toAnnoType(Annotation anno, ClassPool cp)
657         throws ClassNotFoundException
658     {
659         try {
660             ClassLoader cl = cp.getClassLoader();
661             return anno.toAnnotationType(cl, cp);
662         }
663         catch (ClassNotFoundException e) {
664             ClassLoader cl2 = cp.getClass().getClassLoader();
665             return anno.toAnnotationType(cl2, cp);
666         }
667     }
668 
subclassOf(CtClass superclass)669     public boolean subclassOf(CtClass superclass) {
670         if (superclass == null)
671             return false;
672 
673         String superName = superclass.getName();
674         CtClass curr = this;
675         try {
676             while (curr != null) {
677                 if (curr.getName().equals(superName))
678                     return true;
679 
680                 curr = curr.getSuperclass();
681             }
682         }
683         catch (Exception ignored) {}
684         return false;
685     }
686 
getSuperclass()687     public CtClass getSuperclass() throws NotFoundException {
688         String supername = getClassFile2().getSuperclass();
689         if (supername == null)
690             return null;
691         else
692             return classPool.get(supername);
693     }
694 
setSuperclass(CtClass clazz)695     public void setSuperclass(CtClass clazz) throws CannotCompileException {
696         checkModify();
697         if (isInterface())
698             addInterface(clazz);
699         else
700             getClassFile2().setSuperclass(clazz.getName());
701     }
702 
getInterfaces()703     public CtClass[] getInterfaces() throws NotFoundException {
704         String[] ifs = getClassFile2().getInterfaces();
705         int num = ifs.length;
706         CtClass[] ifc = new CtClass[num];
707         for (int i = 0; i < num; ++i)
708             ifc[i] = classPool.get(ifs[i]);
709 
710         return ifc;
711     }
712 
setInterfaces(CtClass[] list)713     public void setInterfaces(CtClass[] list) {
714         checkModify();
715         String[] ifs;
716         if (list == null)
717             ifs = new String[0];
718         else {
719             int num = list.length;
720             ifs = new String[num];
721             for (int i = 0; i < num; ++i)
722                 ifs[i] = list[i].getName();
723         }
724 
725         getClassFile2().setInterfaces(ifs);
726     }
727 
addInterface(CtClass anInterface)728     public void addInterface(CtClass anInterface) {
729         checkModify();
730         if (anInterface != null)
731             getClassFile2().addInterface(anInterface.getName());
732     }
733 
getDeclaringClass()734     public CtClass getDeclaringClass() throws NotFoundException {
735         ClassFile cf = getClassFile2();
736         InnerClassesAttribute ica = (InnerClassesAttribute)cf.getAttribute(
737                                                 InnerClassesAttribute.tag);
738         if (ica == null)
739             return null;
740 
741         String name = getName();
742         int n = ica.tableLength();
743         for (int i = 0; i < n; ++i)
744             if (name.equals(ica.innerClass(i))) {
745                 String outName = ica.outerClass(i);
746                 if (outName != null)
747                     return classPool.get(outName);
748                 else {
749                     // maybe anonymous or local class.
750                     EnclosingMethodAttribute ema
751                         = (EnclosingMethodAttribute)cf.getAttribute(
752                                                     EnclosingMethodAttribute.tag);
753                     if (ema != null)
754                         return classPool.get(ema.className());
755                 }
756             }
757 
758         return null;
759     }
760 
getEnclosingMethod()761     public CtMethod getEnclosingMethod() throws NotFoundException {
762         ClassFile cf = getClassFile2();
763         EnclosingMethodAttribute ema
764                 = (EnclosingMethodAttribute)cf.getAttribute(
765                                                 EnclosingMethodAttribute.tag);
766         if (ema != null) {
767             CtClass enc = classPool.get(ema.className());
768             return enc.getMethod(ema.methodName(), ema.methodDescriptor());
769         }
770 
771         return null;
772     }
773 
makeNestedClass(String name, boolean isStatic)774     public CtClass makeNestedClass(String name, boolean isStatic) {
775         if (!isStatic)
776             throw new RuntimeException(
777                         "sorry, only nested static class is supported");
778 
779         checkModify();
780         CtClass c = classPool.makeNestedClass(getName() + "$" + name);
781         ClassFile cf = getClassFile2();
782         ClassFile cf2 = c.getClassFile2();
783         InnerClassesAttribute ica = (InnerClassesAttribute)cf.getAttribute(
784                                                 InnerClassesAttribute.tag);
785         if (ica == null) {
786             ica = new InnerClassesAttribute(cf.getConstPool());
787             cf.addAttribute(ica);
788         }
789 
790         ica.append(c.getName(), this.getName(), name,
791                    (cf2.getAccessFlags() & ~AccessFlag.SUPER) | AccessFlag.STATIC);
792         cf2.addAttribute(ica.copy(cf2.getConstPool(), null));
793         return c;
794     }
795 
796     /* flush cached names.
797      */
nameReplaced()798     private void nameReplaced() {
799         CtMember.Cache cache = hasMemberCache();
800         if (cache != null) {
801             CtMember mth = cache.methodHead();
802             CtMember tail = cache.lastMethod();
803             while (mth != tail) {
804                 mth = mth.next();
805                 mth.nameReplaced();
806             }
807         }
808     }
809 
810     /**
811      * Returns null if members are not cached.
812      */
hasMemberCache()813     protected CtMember.Cache hasMemberCache() {
814         if (memberCache != null)
815             return (CtMember.Cache)memberCache.get();
816         else
817             return null;
818     }
819 
getMembers()820     protected synchronized CtMember.Cache getMembers() {
821         CtMember.Cache cache = null;
822         if (memberCache == null
823             || (cache = (CtMember.Cache)memberCache.get()) == null) {
824             cache = new CtMember.Cache(this);
825             makeFieldCache(cache);
826             makeBehaviorCache(cache);
827             memberCache = new WeakReference(cache);
828         }
829 
830         return cache;
831     }
832 
makeFieldCache(CtMember.Cache cache)833     private void makeFieldCache(CtMember.Cache cache) {
834         List list = getClassFile2().getFields();
835         int n = list.size();
836         for (int i = 0; i < n; ++i) {
837             FieldInfo finfo = (FieldInfo)list.get(i);
838             CtField newField = new CtField(finfo, this);
839             cache.addField(newField);
840         }
841     }
842 
makeBehaviorCache(CtMember.Cache cache)843     private void makeBehaviorCache(CtMember.Cache cache) {
844         List list = getClassFile2().getMethods();
845         int n = list.size();
846         for (int i = 0; i < n; ++i) {
847             MethodInfo minfo = (MethodInfo)list.get(i);
848             if (minfo.isMethod()) {
849                 CtMethod newMethod = new CtMethod(minfo, this);
850                 cache.addMethod(newMethod);
851             }
852             else {
853                 CtConstructor newCons = new CtConstructor(minfo, this);
854                 cache.addConstructor(newCons);
855             }
856         }
857     }
858 
getFields()859     public CtField[] getFields() {
860         ArrayList alist = new ArrayList();
861         getFields(alist, this);
862         return (CtField[])alist.toArray(new CtField[alist.size()]);
863     }
864 
getFields(ArrayList alist, CtClass cc)865     private static void getFields(ArrayList alist, CtClass cc) {
866         int i, num;
867         if (cc == null)
868             return;
869 
870         try {
871             getFields(alist, cc.getSuperclass());
872         }
873         catch (NotFoundException e) {}
874 
875         try {
876             CtClass[] ifs = cc.getInterfaces();
877             num = ifs.length;
878             for (i = 0; i < num; ++i)
879                 getFields(alist, ifs[i]);
880         }
881         catch (NotFoundException e) {}
882 
883         CtMember.Cache memCache = ((CtClassType)cc).getMembers();
884         CtMember field = memCache.fieldHead();
885         CtMember tail = memCache.lastField();
886         while (field != tail) {
887             field = field.next();
888             if (!Modifier.isPrivate(field.getModifiers()))
889                 alist.add(field);
890         }
891     }
892 
getField(String name, String desc)893     public CtField getField(String name, String desc) throws NotFoundException {
894         CtField f = getField2(name, desc);
895         return checkGetField(f, name, desc);
896     }
897 
checkGetField(CtField f, String name, String desc)898     private CtField checkGetField(CtField f, String name, String desc)
899         throws NotFoundException
900     {
901         if (f == null) {
902             String msg = "field: " + name;
903             if (desc != null)
904                 msg += " type " + desc;
905 
906             throw new NotFoundException(msg + " in " + getName());
907         }
908         else
909             return f;
910     }
911 
getField2(String name, String desc)912     CtField getField2(String name, String desc) {
913         CtField df = getDeclaredField2(name, desc);
914         if (df != null)
915             return df;
916 
917         try {
918             CtClass[] ifs = getInterfaces();
919             int num = ifs.length;
920             for (int i = 0; i < num; ++i) {
921                 CtField f = ifs[i].getField2(name, desc);
922                 if (f != null)
923                     return f;
924             }
925 
926             CtClass s = getSuperclass();
927             if (s != null)
928                 return s.getField2(name, desc);
929         }
930         catch (NotFoundException e) {}
931         return null;
932     }
933 
getDeclaredFields()934     public CtField[] getDeclaredFields() {
935         CtMember.Cache memCache = getMembers();
936         CtMember field = memCache.fieldHead();
937         CtMember tail = memCache.lastField();
938         int num = CtMember.Cache.count(field, tail);
939         CtField[] cfs = new CtField[num];
940         int i = 0;
941         while (field != tail) {
942             field = field.next();
943             cfs[i++] = (CtField)field;
944         }
945 
946         return cfs;
947     }
948 
getDeclaredField(String name)949     public CtField getDeclaredField(String name) throws NotFoundException {
950         return getDeclaredField(name, null);
951     }
952 
getDeclaredField(String name, String desc)953     public CtField getDeclaredField(String name, String desc) throws NotFoundException {
954         CtField f = getDeclaredField2(name, desc);
955         return checkGetField(f, name, desc);
956     }
957 
getDeclaredField2(String name, String desc)958     private CtField getDeclaredField2(String name, String desc) {
959         CtMember.Cache memCache = getMembers();
960         CtMember field = memCache.fieldHead();
961         CtMember tail = memCache.lastField();
962         while (field != tail) {
963             field = field.next();
964             if (field.getName().equals(name)
965                 && (desc == null || desc.equals(field.getSignature())))
966                 return (CtField)field;
967         }
968 
969         return null;
970     }
971 
getDeclaredBehaviors()972     public CtBehavior[] getDeclaredBehaviors() {
973         CtMember.Cache memCache = getMembers();
974         CtMember cons = memCache.consHead();
975         CtMember consTail = memCache.lastCons();
976         int cnum = CtMember.Cache.count(cons, consTail);
977         CtMember mth = memCache.methodHead();
978         CtMember mthTail = memCache.lastMethod();
979         int mnum = CtMember.Cache.count(mth, mthTail);
980 
981         CtBehavior[] cb = new CtBehavior[cnum + mnum];
982         int i = 0;
983         while (cons != consTail) {
984             cons = cons.next();
985             cb[i++] = (CtBehavior)cons;
986         }
987 
988         while (mth != mthTail) {
989             mth = mth.next();
990             cb[i++] = (CtBehavior)mth;
991         }
992 
993         return cb;
994     }
995 
getConstructors()996     public CtConstructor[] getConstructors() {
997         CtMember.Cache memCache = getMembers();
998         CtMember cons = memCache.consHead();
999         CtMember consTail = memCache.lastCons();
1000 
1001         int n = 0;
1002         CtMember mem = cons;
1003         while (mem != consTail) {
1004             mem = mem.next();
1005             if (isPubCons((CtConstructor)mem))
1006                 n++;
1007         }
1008 
1009         CtConstructor[] result = new CtConstructor[n];
1010         int i = 0;
1011         mem = cons;
1012         while (mem != consTail) {
1013             mem = mem.next();
1014             CtConstructor cc = (CtConstructor)mem;
1015             if (isPubCons(cc))
1016                 result[i++] = cc;
1017         }
1018 
1019         return result;
1020     }
1021 
isPubCons(CtConstructor cons)1022     private static boolean isPubCons(CtConstructor cons) {
1023         return !Modifier.isPrivate(cons.getModifiers())
1024                 && cons.isConstructor();
1025     }
1026 
getConstructor(String desc)1027     public CtConstructor getConstructor(String desc)
1028         throws NotFoundException
1029     {
1030         CtMember.Cache memCache = getMembers();
1031         CtMember cons = memCache.consHead();
1032         CtMember consTail = memCache.lastCons();
1033 
1034         while (cons != consTail) {
1035             cons = cons.next();
1036             CtConstructor cc = (CtConstructor)cons;
1037             if (cc.getMethodInfo2().getDescriptor().equals(desc)
1038                 && cc.isConstructor())
1039                 return cc;
1040         }
1041 
1042         return super.getConstructor(desc);
1043     }
1044 
getDeclaredConstructors()1045     public CtConstructor[] getDeclaredConstructors() {
1046         CtMember.Cache memCache = getMembers();
1047         CtMember cons = memCache.consHead();
1048         CtMember consTail = memCache.lastCons();
1049 
1050         int n = 0;
1051         CtMember mem = cons;
1052         while (mem != consTail) {
1053             mem = mem.next();
1054             CtConstructor cc = (CtConstructor)mem;
1055             if (cc.isConstructor())
1056                 n++;
1057         }
1058 
1059         CtConstructor[] result = new CtConstructor[n];
1060         int i = 0;
1061         mem = cons;
1062         while (mem != consTail) {
1063             mem = mem.next();
1064             CtConstructor cc = (CtConstructor)mem;
1065             if (cc.isConstructor())
1066                 result[i++] = cc;
1067         }
1068 
1069         return result;
1070     }
1071 
getClassInitializer()1072     public CtConstructor getClassInitializer() {
1073         CtMember.Cache memCache = getMembers();
1074         CtMember cons = memCache.consHead();
1075         CtMember consTail = memCache.lastCons();
1076 
1077         while (cons != consTail) {
1078             cons = cons.next();
1079             CtConstructor cc = (CtConstructor)cons;
1080             if (cc.isClassInitializer())
1081                 return cc;
1082         }
1083 
1084         return null;
1085     }
1086 
getMethods()1087     public CtMethod[] getMethods() {
1088         HashMap h = new HashMap();
1089         getMethods0(h, this);
1090         return (CtMethod[])h.values().toArray(new CtMethod[h.size()]);
1091     }
1092 
getMethods0(HashMap h, CtClass cc)1093     private static void getMethods0(HashMap h, CtClass cc) {
1094         try {
1095             CtClass[] ifs = cc.getInterfaces();
1096             int size = ifs.length;
1097             for (int i = 0; i < size; ++i)
1098                 getMethods0(h, ifs[i]);
1099         }
1100         catch (NotFoundException e) {}
1101 
1102         try {
1103             CtClass s = cc.getSuperclass();
1104             if (s != null)
1105                 getMethods0(h, s);
1106         }
1107         catch (NotFoundException e) {}
1108 
1109         if (cc instanceof CtClassType) {
1110             CtMember.Cache memCache = ((CtClassType)cc).getMembers();
1111             CtMember mth = memCache.methodHead();
1112             CtMember mthTail = memCache.lastMethod();
1113 
1114             while (mth != mthTail) {
1115                 mth = mth.next();
1116                 if (!Modifier.isPrivate(mth.getModifiers()))
1117                     h.put(((CtMethod)mth).getStringRep(), mth);
1118             }
1119         }
1120     }
1121 
getMethod(String name, String desc)1122     public CtMethod getMethod(String name, String desc)
1123         throws NotFoundException
1124     {
1125         CtMethod m = getMethod0(this, name, desc);
1126         if (m != null)
1127             return m;
1128         else
1129             throw new NotFoundException(name + "(..) is not found in "
1130                                         + getName());
1131     }
1132 
getMethod0(CtClass cc, String name, String desc)1133     private static CtMethod getMethod0(CtClass cc,
1134                                        String name, String desc) {
1135         if (cc instanceof CtClassType) {
1136             CtMember.Cache memCache = ((CtClassType)cc).getMembers();
1137             CtMember mth = memCache.methodHead();
1138             CtMember mthTail = memCache.lastMethod();
1139 
1140             while (mth != mthTail) {
1141                 mth = mth.next();
1142                 if (mth.getName().equals(name)
1143                         && ((CtMethod)mth).getMethodInfo2().getDescriptor().equals(desc))
1144                     return (CtMethod)mth;
1145             }
1146         }
1147 
1148         try {
1149             CtClass s = cc.getSuperclass();
1150             if (s != null) {
1151                 CtMethod m = getMethod0(s, name, desc);
1152                 if (m != null)
1153                     return m;
1154             }
1155         }
1156         catch (NotFoundException e) {}
1157 
1158         try {
1159             CtClass[] ifs = cc.getInterfaces();
1160             int size = ifs.length;
1161             for (int i = 0; i < size; ++i) {
1162                 CtMethod m = getMethod0(ifs[i], name, desc);
1163                 if (m != null)
1164                     return m;
1165             }
1166         }
1167         catch (NotFoundException e) {}
1168         return null;
1169     }
1170 
getDeclaredMethods()1171     public CtMethod[] getDeclaredMethods() {
1172         CtMember.Cache memCache = getMembers();
1173         CtMember mth = memCache.methodHead();
1174         CtMember mthTail = memCache.lastMethod();
1175         int num = CtMember.Cache.count(mth, mthTail);
1176         CtMethod[] cms = new CtMethod[num];
1177         int i = 0;
1178         while (mth != mthTail) {
1179             mth = mth.next();
1180             cms[i++] = (CtMethod)mth;
1181         }
1182 
1183         return cms;
1184     }
1185 
getDeclaredMethod(String name)1186     public CtMethod getDeclaredMethod(String name) throws NotFoundException {
1187         CtMember.Cache memCache = getMembers();
1188         CtMember mth = memCache.methodHead();
1189         CtMember mthTail = memCache.lastMethod();
1190         while (mth != mthTail) {
1191             mth = mth.next();
1192             if (mth.getName().equals(name))
1193                 return (CtMethod)mth;
1194         }
1195 
1196         throw new NotFoundException(name + "(..) is not found in "
1197                                     + getName());
1198     }
1199 
getDeclaredMethod(String name, CtClass[] params)1200     public CtMethod getDeclaredMethod(String name, CtClass[] params)
1201         throws NotFoundException
1202     {
1203         String desc = Descriptor.ofParameters(params);
1204         CtMember.Cache memCache = getMembers();
1205         CtMember mth = memCache.methodHead();
1206         CtMember mthTail = memCache.lastMethod();
1207 
1208         while (mth != mthTail) {
1209             mth = mth.next();
1210             if (mth.getName().equals(name)
1211                     && ((CtMethod)mth).getMethodInfo2().getDescriptor().startsWith(desc))
1212                 return (CtMethod)mth;
1213         }
1214 
1215         throw new NotFoundException(name + "(..) is not found in "
1216                                     + getName());
1217     }
1218 
addField(CtField f, String init)1219     public void addField(CtField f, String init)
1220         throws CannotCompileException
1221     {
1222         addField(f, CtField.Initializer.byExpr(init));
1223     }
1224 
addField(CtField f, CtField.Initializer init)1225     public void addField(CtField f, CtField.Initializer init)
1226         throws CannotCompileException
1227     {
1228         checkModify();
1229         if (f.getDeclaringClass() != this)
1230             throw new CannotCompileException("cannot add");
1231 
1232         if (init == null)
1233             init = f.getInit();
1234 
1235         if (init != null) {
1236             init.check(f.getSignature());
1237             int mod = f.getModifiers();
1238             if (Modifier.isStatic(mod) && Modifier.isFinal(mod))
1239                 try {
1240                     ConstPool cp = getClassFile2().getConstPool();
1241                     int index = init.getConstantValue(cp, f.getType());
1242                     if (index != 0) {
1243                         f.getFieldInfo2().addAttribute(new ConstantAttribute(cp, index));
1244                         init = null;
1245                     }
1246                 }
1247                 catch (NotFoundException e) {}
1248         }
1249 
1250         getMembers().addField(f);
1251         getClassFile2().addField(f.getFieldInfo2());
1252 
1253         if (init != null) {
1254             FieldInitLink fil = new FieldInitLink(f, init);
1255             FieldInitLink link = fieldInitializers;
1256             if (link == null)
1257                 fieldInitializers = fil;
1258             else {
1259                 while (link.next != null)
1260                     link = link.next;
1261 
1262                 link.next = fil;
1263             }
1264         }
1265     }
1266 
removeField(CtField f)1267     public void removeField(CtField f) throws NotFoundException {
1268         checkModify();
1269         FieldInfo fi = f.getFieldInfo2();
1270         ClassFile cf = getClassFile2();
1271         if (cf.getFields().remove(fi)) {
1272             getMembers().remove(f);
1273             gcConstPool = true;
1274         }
1275         else
1276             throw new NotFoundException(f.toString());
1277     }
1278 
makeClassInitializer()1279     public CtConstructor makeClassInitializer()
1280         throws CannotCompileException
1281     {
1282         CtConstructor clinit = getClassInitializer();
1283         if (clinit != null)
1284             return clinit;
1285 
1286         checkModify();
1287         ClassFile cf = getClassFile2();
1288         Bytecode code = new Bytecode(cf.getConstPool(), 0, 0);
1289         modifyClassConstructor(cf, code, 0, 0);
1290         return getClassInitializer();
1291     }
1292 
addConstructor(CtConstructor c)1293     public void addConstructor(CtConstructor c)
1294         throws CannotCompileException
1295     {
1296         checkModify();
1297         if (c.getDeclaringClass() != this)
1298             throw new CannotCompileException("cannot add");
1299 
1300         getMembers().addConstructor(c);
1301         getClassFile2().addMethod(c.getMethodInfo2());
1302     }
1303 
removeConstructor(CtConstructor m)1304     public void removeConstructor(CtConstructor m) throws NotFoundException {
1305         checkModify();
1306         MethodInfo mi = m.getMethodInfo2();
1307         ClassFile cf = getClassFile2();
1308         if (cf.getMethods().remove(mi)) {
1309             getMembers().remove(m);
1310             gcConstPool = true;
1311         }
1312         else
1313             throw new NotFoundException(m.toString());
1314     }
1315 
addMethod(CtMethod m)1316     public void addMethod(CtMethod m) throws CannotCompileException {
1317         checkModify();
1318         if (m.getDeclaringClass() != this)
1319             throw new CannotCompileException("bad declaring class");
1320 
1321         int mod = m.getModifiers();
1322         if ((getModifiers() & Modifier.INTERFACE) != 0) {
1323             m.setModifiers(mod | Modifier.PUBLIC);
1324             if ((mod & Modifier.ABSTRACT) == 0)
1325                 throw new CannotCompileException(
1326                         "an interface method must be abstract: " + m.toString());
1327         }
1328 
1329         getMembers().addMethod(m);
1330         getClassFile2().addMethod(m.getMethodInfo2());
1331         if ((mod & Modifier.ABSTRACT) != 0)
1332             setModifiers(getModifiers() | Modifier.ABSTRACT);
1333     }
1334 
removeMethod(CtMethod m)1335     public void removeMethod(CtMethod m) throws NotFoundException {
1336         checkModify();
1337         MethodInfo mi = m.getMethodInfo2();
1338         ClassFile cf = getClassFile2();
1339         if (cf.getMethods().remove(mi)) {
1340             getMembers().remove(m);
1341             gcConstPool = true;
1342         }
1343         else
1344             throw new NotFoundException(m.toString());
1345     }
1346 
getAttribute(String name)1347     public byte[] getAttribute(String name) {
1348         AttributeInfo ai = getClassFile2().getAttribute(name);
1349         if (ai == null)
1350             return null;
1351         else
1352             return ai.get();
1353     }
1354 
setAttribute(String name, byte[] data)1355     public void setAttribute(String name, byte[] data) {
1356         checkModify();
1357         ClassFile cf = getClassFile2();
1358         cf.addAttribute(new AttributeInfo(cf.getConstPool(), name, data));
1359     }
1360 
instrument(CodeConverter converter)1361     public void instrument(CodeConverter converter)
1362         throws CannotCompileException
1363     {
1364         checkModify();
1365         ClassFile cf = getClassFile2();
1366         ConstPool cp = cf.getConstPool();
1367         List list = cf.getMethods();
1368         int n = list.size();
1369         for (int i = 0; i < n; ++i) {
1370             MethodInfo minfo = (MethodInfo)list.get(i);
1371             converter.doit(this, minfo, cp);
1372         }
1373     }
1374 
instrument(ExprEditor editor)1375     public void instrument(ExprEditor editor)
1376         throws CannotCompileException
1377     {
1378         checkModify();
1379         ClassFile cf = getClassFile2();
1380         List list = cf.getMethods();
1381         int n = list.size();
1382         for (int i = 0; i < n; ++i) {
1383             MethodInfo minfo = (MethodInfo)list.get(i);
1384             editor.doit(this, minfo);
1385         }
1386     }
1387 
1388     /**
1389      * @see javassist.CtClass#prune()
1390      * @see javassist.CtClass#stopPruning(boolean)
1391      */
prune()1392     public void prune() {
1393         if (wasPruned)
1394             return;
1395 
1396         wasPruned = wasFrozen = true;
1397         getClassFile2().prune();
1398     }
1399 
rebuildClassFile()1400     public void rebuildClassFile() { gcConstPool = true; }
1401 
toBytecode(DataOutputStream out)1402     public void toBytecode(DataOutputStream out)
1403         throws CannotCompileException, IOException
1404     {
1405         try {
1406             if (isModified()) {
1407                 checkPruned("toBytecode");
1408                 ClassFile cf = getClassFile2();
1409                 if (gcConstPool) {
1410                     cf.compact();
1411                     gcConstPool = false;
1412                 }
1413 
1414                 modifyClassConstructor(cf);
1415                 modifyConstructors(cf);
1416                 cf.write(out);
1417                 out.flush();
1418                 fieldInitializers = null;
1419                 if (doPruning) {
1420                     // to save memory
1421                     cf.prune();
1422                     wasPruned = true;
1423                 }
1424             }
1425             else {
1426                 classPool.writeClassfile(getName(), out);
1427                 // to save memory
1428                 // classfile = null;
1429             }
1430 
1431             getCount = 0;
1432             wasFrozen = true;
1433         }
1434         catch (NotFoundException e) {
1435             throw new CannotCompileException(e);
1436         }
1437         catch (IOException e) {
1438             throw new CannotCompileException(e);
1439         }
1440     }
1441 
1442     /* See also checkModified()
1443      */
checkPruned(String method)1444     private void checkPruned(String method) {
1445         if (wasPruned)
1446             throw new RuntimeException(method + "(): " + getName()
1447                                        + " was pruned.");
1448     }
1449 
stopPruning(boolean stop)1450     public boolean stopPruning(boolean stop) {
1451         boolean prev = !doPruning;
1452         doPruning = !stop;
1453         return prev;
1454     }
1455 
modifyClassConstructor(ClassFile cf)1456     private void modifyClassConstructor(ClassFile cf)
1457         throws CannotCompileException, NotFoundException
1458     {
1459         if (fieldInitializers == null)
1460             return;
1461 
1462         Bytecode code = new Bytecode(cf.getConstPool(), 0, 0);
1463         Javac jv = new Javac(code, this);
1464         int stacksize = 0;
1465         boolean doInit = false;
1466         for (FieldInitLink fi = fieldInitializers; fi != null; fi = fi.next) {
1467             CtField f = fi.field;
1468             if (Modifier.isStatic(f.getModifiers())) {
1469                 doInit = true;
1470                 int s = fi.init.compileIfStatic(f.getType(), f.getName(),
1471                                                 code, jv);
1472                 if (stacksize < s)
1473                     stacksize = s;
1474             }
1475         }
1476 
1477         if (doInit)    // need an initializer for static fileds.
1478             modifyClassConstructor(cf, code, stacksize, 0);
1479     }
1480 
modifyClassConstructor(ClassFile cf, Bytecode code, int stacksize, int localsize)1481     private void modifyClassConstructor(ClassFile cf, Bytecode code,
1482                                         int stacksize, int localsize)
1483         throws CannotCompileException
1484     {
1485         MethodInfo m = cf.getStaticInitializer();
1486         if (m == null) {
1487             code.add(Bytecode.RETURN);
1488             code.setMaxStack(stacksize);
1489             code.setMaxLocals(localsize);
1490             m = new MethodInfo(cf.getConstPool(), "<clinit>", "()V");
1491             m.setAccessFlags(AccessFlag.STATIC);
1492             m.setCodeAttribute(code.toCodeAttribute());
1493             cf.addMethod(m);
1494             CtMember.Cache cache = hasMemberCache();
1495             if (cache != null)
1496                 cache.addConstructor(new CtConstructor(m, this));
1497         }
1498         else {
1499             CodeAttribute codeAttr = m.getCodeAttribute();
1500             if (codeAttr == null)
1501                 throw new CannotCompileException("empty <clinit>");
1502 
1503             try {
1504                 CodeIterator it = codeAttr.iterator();
1505                 int pos = it.insertEx(code.get());
1506                 it.insert(code.getExceptionTable(), pos);
1507                 int maxstack = codeAttr.getMaxStack();
1508                 if (maxstack < stacksize)
1509                     codeAttr.setMaxStack(stacksize);
1510 
1511                 int maxlocals = codeAttr.getMaxLocals();
1512                 if (maxlocals < localsize)
1513                     codeAttr.setMaxLocals(localsize);
1514             }
1515             catch (BadBytecode e) {
1516                 throw new CannotCompileException(e);
1517             }
1518         }
1519 
1520         try {
1521             m.rebuildStackMapIf6(classPool, cf);
1522         }
1523         catch (BadBytecode e) {
1524             throw new CannotCompileException(e);
1525         }
1526     }
1527 
modifyConstructors(ClassFile cf)1528     private void modifyConstructors(ClassFile cf)
1529         throws CannotCompileException, NotFoundException
1530     {
1531         if (fieldInitializers == null)
1532             return;
1533 
1534         ConstPool cp = cf.getConstPool();
1535         List list = cf.getMethods();
1536         int n = list.size();
1537         for (int i = 0; i < n; ++i) {
1538             MethodInfo minfo = (MethodInfo)list.get(i);
1539             if (minfo.isConstructor()) {
1540                 CodeAttribute codeAttr = minfo.getCodeAttribute();
1541                 if (codeAttr != null)
1542                     try {
1543                         Bytecode init = new Bytecode(cp, 0,
1544                                                 codeAttr.getMaxLocals());
1545                         CtClass[] params
1546                             = Descriptor.getParameterTypes(
1547                                                 minfo.getDescriptor(),
1548                                                 classPool);
1549                         int stacksize = makeFieldInitializer(init, params);
1550                         insertAuxInitializer(codeAttr, init, stacksize);
1551                         minfo.rebuildStackMapIf6(classPool, cf);
1552                     }
1553                     catch (BadBytecode e) {
1554                         throw new CannotCompileException(e);
1555                     }
1556             }
1557         }
1558     }
1559 
insertAuxInitializer(CodeAttribute codeAttr, Bytecode initializer, int stacksize)1560     private static void insertAuxInitializer(CodeAttribute codeAttr,
1561                                              Bytecode initializer,
1562                                              int stacksize)
1563         throws BadBytecode
1564     {
1565         CodeIterator it = codeAttr.iterator();
1566         int index = it.skipSuperConstructor();
1567         if (index < 0) {
1568             index = it.skipThisConstructor();
1569             if (index >= 0)
1570                 return;         // this() is called.
1571 
1572             // Neither this() or super() is called.
1573         }
1574 
1575         int pos = it.insertEx(initializer.get());
1576         it.insert(initializer.getExceptionTable(), pos);
1577         int maxstack = codeAttr.getMaxStack();
1578         if (maxstack < stacksize)
1579             codeAttr.setMaxStack(stacksize);
1580     }
1581 
makeFieldInitializer(Bytecode code, CtClass[] parameters)1582     private int makeFieldInitializer(Bytecode code, CtClass[] parameters)
1583         throws CannotCompileException, NotFoundException
1584     {
1585         int stacksize = 0;
1586         Javac jv = new Javac(code, this);
1587         try {
1588             jv.recordParams(parameters, false);
1589         }
1590         catch (CompileError e) {
1591             throw new CannotCompileException(e);
1592         }
1593 
1594         for (FieldInitLink fi = fieldInitializers; fi != null; fi = fi.next) {
1595             CtField f = fi.field;
1596             if (!Modifier.isStatic(f.getModifiers())) {
1597                 int s = fi.init.compile(f.getType(), f.getName(), code,
1598                                         parameters, jv);
1599                 if (stacksize < s)
1600                     stacksize = s;
1601             }
1602         }
1603 
1604         return stacksize;
1605     }
1606 
1607     // Methods used by CtNewWrappedMethod
1608 
getHiddenMethods()1609     Hashtable getHiddenMethods() {
1610         if (hiddenMethods == null)
1611             hiddenMethods = new Hashtable();
1612 
1613         return hiddenMethods;
1614     }
1615 
getUniqueNumber()1616     int getUniqueNumber() { return uniqueNumberSeed++; }
1617 
makeUniqueName(String prefix)1618     public String makeUniqueName(String prefix) {
1619         HashMap table = new HashMap();
1620         makeMemberList(table);
1621         Set keys = table.keySet();
1622         String[] methods = new String[keys.size()];
1623         keys.toArray(methods);
1624 
1625         if (notFindInArray(prefix, methods))
1626             return prefix;
1627 
1628         int i = 100;
1629         String name;
1630         do {
1631             if (i > 999)
1632                 throw new RuntimeException("too many unique name");
1633 
1634             name = prefix + i++;
1635         } while (!notFindInArray(name, methods));
1636         return name;
1637     }
1638 
notFindInArray(String prefix, String[] values)1639     private static boolean notFindInArray(String prefix, String[] values) {
1640         int len = values.length;
1641         for (int i = 0; i < len; i++)
1642             if (values[i].startsWith(prefix))
1643                 return false;
1644 
1645         return true;
1646     }
1647 
makeMemberList(HashMap table)1648     private void makeMemberList(HashMap table) {
1649         int mod = getModifiers();
1650         if (Modifier.isAbstract(mod) || Modifier.isInterface(mod))
1651             try {
1652                 CtClass[] ifs = getInterfaces();
1653                 int size = ifs.length;
1654                 for (int i = 0; i < size; i++) {
1655                     CtClass ic =ifs[i];
1656                     if (ic != null && ic instanceof CtClassType)
1657                         ((CtClassType)ic).makeMemberList(table);
1658                 }
1659             }
1660             catch (NotFoundException e) {}
1661 
1662         try {
1663             CtClass s = getSuperclass();
1664             if (s != null && s instanceof CtClassType)
1665                 ((CtClassType)s).makeMemberList(table);
1666         }
1667         catch (NotFoundException e) {}
1668 
1669         List list = getClassFile2().getMethods();
1670         int n = list.size();
1671         for (int i = 0; i < n; i++) {
1672             MethodInfo minfo = (MethodInfo)list.get(i);
1673             table.put(minfo.getName(), this);
1674         }
1675 
1676         list = getClassFile2().getFields();
1677         n = list.size();
1678         for (int i = 0; i < n; i++) {
1679             FieldInfo finfo = (FieldInfo)list.get(i);
1680             table.put(finfo.getName(), this);
1681         }
1682     }
1683 }
1684 
1685 class FieldInitLink {
1686     FieldInitLink next;
1687     CtField field;
1688     CtField.Initializer init;
1689 
FieldInitLink(CtField f, CtField.Initializer i)1690     FieldInitLink(CtField f, CtField.Initializer i) {
1691         next = null;
1692         field = f;
1693         init = i;
1694     }
1695 }
1696