KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javassist > compiler > MemberCodeGen


1 /*
2  * Javassist, a Java-bytecode translator toolkit.
3  * Copyright (C) 1999-2005 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.compiler;
17
18 import javassist.*;
19 import javassist.bytecode.*;
20 import javassist.compiler.ast.*;
21 import java.util.ArrayList JavaDoc;
22
23 /* Code generator methods depending on javassist.* classes.
24  */

25 public class MemberCodeGen extends CodeGen {
26     protected MemberResolver resolver;
27     protected CtClass thisClass;
28     protected MethodInfo thisMethod;
29
30     protected boolean resultStatic;
31
32     public MemberCodeGen(Bytecode b, CtClass cc, ClassPool cp)
33     {
34         super(b);
35         resolver = new MemberResolver(cp);
36         thisClass = cc;
37         thisMethod = null;
38     }
39
40     /**
41      * Records the currently compiled method.
42      */

43     public void setThisMethod(CtMethod m) {
44         thisMethod = m.getMethodInfo2();
45         if (typeChecker != null)
46             typeChecker.setThisMethod(thisMethod);
47     }
48
49     public CtClass getThisClass() { return thisClass; }
50
51     /**
52      * Returns the JVM-internal representation of this class name.
53      */

54     protected String JavaDoc getThisName() {
55         return MemberResolver.javaToJvmName(thisClass.getName());
56     }
57
58     /**
59      * Returns the JVM-internal representation of this super class name.
60      */

61     protected String JavaDoc getSuperName() throws CompileError {
62         return MemberResolver.javaToJvmName(
63                         MemberResolver.getSuperclass(thisClass).getName());
64     }
65
66     protected void insertDefaultSuperCall() throws CompileError {
67         bytecode.addAload(0);
68         bytecode.addInvokespecial(MemberResolver.getSuperclass(thisClass),
69                                   "<init>", "()V");
70     }
71
72     static class JsrHook extends ReturnHook {
73         ArrayList JavaDoc jsrList;
74         int var;
75
76         JsrHook(CodeGen gen) {
77             super(gen);
78             jsrList = new ArrayList JavaDoc();
79             var = gen.getMaxLocals();
80             gen.incMaxLocals(1);
81         }
82
83         private void jsrJmp(Bytecode b) {
84             b.addOpcode(JSR);
85             jsrList.add(new Integer JavaDoc(b.currentPc()));
86             b.addIndex(0);
87         }
88
89         protected void doit(Bytecode b, int opcode) {
90             switch (opcode) {
91             case Opcode.RETURN :
92                 jsrJmp(b);
93                 break;
94             case ARETURN :
95                 b.addAstore(var);
96                 jsrJmp(b);
97                 b.addAload(var);
98                 break;
99             case IRETURN :
100                 b.addIstore(var);
101                 jsrJmp(b);
102                 b.addIload(var);
103                 break;
104             case LRETURN :
105                 b.addLstore(var);
106                 jsrJmp(b);
107                 b.addLload(var);
108                 break;
109             case DRETURN :
110                 b.addDstore(var);
111                 jsrJmp(b);
112                 b.addDload(var);
113                 break;
114             case FRETURN :
115                 b.addFstore(var);
116                 jsrJmp(b);
117                 b.addFload(var);
118                 break;
119             default :
120                 throw new RuntimeException JavaDoc("fatal");
121             }
122         }
123     }
124
125     protected void atTryStmnt(Stmnt st) throws CompileError {
126         Bytecode bc = bytecode;
127         Stmnt body = (Stmnt)st.getLeft();
128         if (body == null)
129             return;
130
131         ASTList catchList = (ASTList)st.getRight().getLeft();
132         Stmnt finallyBlock = (Stmnt)st.getRight().getRight().getLeft();
133         ArrayList JavaDoc gotoList = new ArrayList JavaDoc();
134
135         JsrHook jsrHook = null;
136         if (finallyBlock != null)
137             jsrHook = new JsrHook(this);
138
139         int start = bc.currentPc();
140         body.accept(this);
141         int end = bc.currentPc();
142         if (start == end)
143             throw new CompileError("empty try block");
144
145         boolean tryNotReturn = !hasReturned;
146         if (tryNotReturn) {
147             bc.addOpcode(Opcode.GOTO);
148             gotoList.add(new Integer JavaDoc(bc.currentPc()));
149             bc.addIndex(0); // correct later
150
}
151
152         int var = getMaxLocals();
153         incMaxLocals(1);
154         while (catchList != null) {
155             // catch clause
156
Pair p = (Pair)catchList.head();
157             catchList = catchList.tail();
158             Declarator decl = (Declarator)p.getLeft();
159             Stmnt block = (Stmnt)p.getRight();
160
161             decl.setLocalVar(var);
162
163             CtClass type = resolver.lookupClassByJvmName(decl.getClassName());
164             decl.setClassName(MemberResolver.javaToJvmName(type.getName()));
165             bc.addExceptionHandler(start, end, bc.currentPc(), type);
166             bc.growStack(1);
167             bc.addAstore(var);
168             hasReturned = false;
169             if (block != null)
170                 block.accept(this);
171
172             if (!hasReturned) {
173                 bc.addOpcode(Opcode.GOTO);
174                 gotoList.add(new Integer JavaDoc(bc.currentPc()));
175                 bc.addIndex(0); // correct later
176
tryNotReturn = true;
177             }
178         }
179
180         int pcFinally = -1;
181         if (finallyBlock != null) {
182             jsrHook.remove(this);
183             // catch (any) clause
184
int pcAnyCatch = bc.currentPc();
185             bc.addExceptionHandler(start, pcAnyCatch, pcAnyCatch, 0);
186             bc.growStack(1);
187             bc.addAstore(var);
188             bc.addOpcode(JSR);
189             int pcJsrIndex = bc.currentPc();
190             bc.addIndex(0); // correct later
191
bc.addAload(var);
192             bc.addOpcode(ATHROW);
193
194             // finally clause
195
pcFinally = bc.currentPc();
196             bc.write16bit(pcJsrIndex, pcFinally - pcJsrIndex + 1);
197             int retAddr = getMaxLocals();
198             incMaxLocals(1);
199             bc.growStack(1); // return address
200
bc.addAstore(retAddr);
201             hasReturned = false;
202             finallyBlock.accept(this);
203             if (!hasReturned) {
204                 bc.addOpcode(RET);
205                 bc.add(retAddr);
206             }
207         }
208
209         int pcEnd = bc.currentPc();
210         patchGoto(gotoList, pcEnd);
211         if (finallyBlock != null) {
212             patchGoto(jsrHook.jsrList, pcFinally);
213             if (tryNotReturn) {
214                 bc.addOpcode(JSR);
215                 bc.addIndex(pcFinally - pcEnd);
216             }
217         }
218
219         hasReturned = !tryNotReturn;
220     }
221
222     public void atNewExpr(NewExpr expr) throws CompileError {
223         if (expr.isArray())
224             atNewArrayExpr(expr);
225         else {
226             CtClass clazz = resolver.lookupClassByName(expr.getClassName());
227             String JavaDoc cname = clazz.getName();
228             ASTList args = expr.getArguments();
229             bytecode.addNew(cname);
230             bytecode.addOpcode(DUP);
231
232             atMethodCallCore(clazz, MethodInfo.nameInit, args,
233                              false, true, -1, null);
234
235             exprType = CLASS;
236             arrayDim = 0;
237             className = MemberResolver.javaToJvmName(cname);
238         }
239     }
240
241     public void atNewArrayExpr(NewExpr expr) throws CompileError {
242         if (expr.getInitializer() != null)
243             throw new CompileError("array initializer is not supported");
244
245         int type = expr.getArrayType();
246         ASTList size = expr.getArraySize();
247         ASTList classname = expr.getClassName();
248         if (size.length() > 1) {
249             atMultiNewArray(type, classname, size);
250             return;
251         }
252
253         size.head().accept(this);
254         exprType = type;
255         arrayDim = 1;
256         if (type == CLASS) {
257             className = resolveClassName(classname);
258             bytecode.addAnewarray(MemberResolver.jvmToJavaName(className));
259         }
260         else {
261             className = null;
262             int atype = 0;
263             switch (type) {
264             case BOOLEAN :
265                 atype = T_BOOLEAN;
266                 break;
267             case CHAR :
268                 atype = T_CHAR;
269                 break;
270             case FLOAT :
271                 atype = T_FLOAT;
272                 break;
273             case DOUBLE :
274                 atype = T_DOUBLE;
275                 break;
276             case BYTE :
277                 atype = T_BYTE;
278                 break;
279             case SHORT :
280                 atype = T_SHORT;
281                 break;
282             case INT :
283                 atype = T_INT;
284                 break;
285             case LONG :
286                 atype = T_LONG;
287                 break;
288             default :
289                 badNewExpr();
290                 break;
291             }
292
293             bytecode.addOpcode(NEWARRAY);
294             bytecode.add(atype);
295         }
296     }
297
298     private static void badNewExpr() throws CompileError {
299         throw new CompileError("bad new expression");
300     }
301
302     protected void atMultiNewArray(int type, ASTList classname, ASTList size)
303         throws CompileError
304     {
305         int count, dim;
306         dim = size.length();
307         for (count = 0; size != null; size = size.tail()) {
308             ASTree s = size.head();
309             if (s == null)
310                 break; // int[][][] a = new int[3][4][];
311

312             ++count;
313             s.accept(this);
314             if (exprType != INT)
315                 throw new CompileError("bad type for array size");
316         }
317
318         String JavaDoc desc;
319         exprType = type;
320         arrayDim = dim;
321         if (type == CLASS) {
322             className = resolveClassName(classname);
323             desc = toJvmArrayName(className, dim);
324         }
325         else
326             desc = toJvmTypeName(type, dim);
327
328         bytecode.addMultiNewarray(desc, count);
329     }
330
331     public void atCallExpr(CallExpr expr) throws CompileError {
332         String JavaDoc mname = null;
333         CtClass targetClass = null;
334         ASTree method = expr.oprand1();
335         ASTList args = (ASTList)expr.oprand2();
336         boolean isStatic = false;
337         boolean isSpecial = false;
338         int aload0pos = -1;
339
340         MemberResolver.Method cached = expr.getMethod();
341         if (method instanceof Member) {
342             mname = ((Member)method).get();
343             targetClass = thisClass;
344             if (inStaticMethod || (cached != null && cached.isStatic()))
345                 isStatic = true; // should be static
346
else {
347                 aload0pos = bytecode.currentPc();
348                 bytecode.addAload(0); // this
349
}
350         }
351         else if (method instanceof Keyword) { // constructor
352
isSpecial = true;
353             mname = MethodInfo.nameInit; // <init>
354
targetClass = thisClass;
355             if (inStaticMethod)
356                 throw new CompileError("a constructor cannot be static");
357             else
358                 bytecode.addAload(0); // this
359

360             if (((Keyword)method).get() == SUPER)
361                 targetClass = MemberResolver.getSuperclass(targetClass);
362         }
363         else if (method instanceof Expr) {
364             Expr e = (Expr)method;
365             mname = ((Symbol)e.oprand2()).get();
366             int op = e.getOperator();
367             if (op == MEMBER) { // static method
368
targetClass
369                     = resolver.lookupClass(((Symbol)e.oprand1()).get(), false);
370                 isStatic = true;
371             }
372             else if (op == '.') {
373                 ASTree target = e.oprand1();
374                 if (target instanceof Keyword)
375                     if (((Keyword)target).get() == SUPER)
376                         isSpecial = true;
377
378                 try {
379                     target.accept(this);
380                 }
381                 catch (NoFieldException nfe) {
382                     if (nfe.getExpr() != target)
383                         throw nfe;
384
385                     // it should be a static method.
386
exprType = CLASS;
387                     arrayDim = 0;
388                     className = nfe.getField(); // JVM-internal
389
resolver.recordPackage(className);
390                     isStatic = true;
391                 }
392
393                 if (arrayDim > 0)
394                     targetClass = resolver.lookupClass(javaLangObject, true);
395                 else if (exprType == CLASS /* && arrayDim == 0 */)
396                     targetClass = resolver.lookupClassByJvmName(className);
397                 else
398                     badMethod();
399             }
400             else
401                 badMethod();
402         }
403         else
404             fatal();
405
406         atMethodCallCore(targetClass, mname, args, isStatic, isSpecial,
407                          aload0pos, cached);
408     }
409
410     private static void badMethod() throws CompileError {
411         throw new CompileError("bad method");
412     }
413
414     /*
415      * atMethodCallCore() is also called by doit() in NewExpr.ProceedForNew
416      *
417      * @param targetClass the class at which method lookup starts.
418      * @param found not null if the method look has been already done.
419      */

420     public void atMethodCallCore(CtClass targetClass, String JavaDoc mname,
421                         ASTList args, boolean isStatic, boolean isSpecial,
422                         int aload0pos, MemberResolver.Method found)
423         throws CompileError
424     {
425         int nargs = getMethodArgsLength(args);
426         int[] types = new int[nargs];
427         int[] dims = new int[nargs];
428         String JavaDoc[] cnames = new String JavaDoc[nargs];
429
430         if (!isStatic && found != null && found.isStatic()) {
431             bytecode.addOpcode(POP);
432             isStatic = true;
433         }
434
435         int stack = bytecode.getStackDepth();
436
437         // generate code for evaluating arguments.
438
atMethodArgs(args, types, dims, cnames);
439
440         // used by invokeinterface
441
int count = bytecode.getStackDepth() - stack + 1;
442
443         if (found == null)
444             found = resolver.lookupMethod(targetClass, thisMethod, mname,
445                                           types, dims, cnames, false);
446
447         if (found == null) {
448             String JavaDoc msg;
449             if (mname.equals(MethodInfo.nameInit))
450                 msg = "constructor not found";
451             else
452                 msg = "Method " + mname + " not found in "
453                     + targetClass.getName();
454
455             throw new CompileError(msg);
456         }
457
458         atMethodCallCore2(targetClass, mname, isStatic, isSpecial,
459                           aload0pos, count, found);
460     }
461
462     private void atMethodCallCore2(CtClass targetClass, String JavaDoc mname,
463                                    boolean isStatic, boolean isSpecial,
464                                    int aload0pos, int count,
465                                    MemberResolver.Method found)
466         throws CompileError
467     {
468         CtClass declClass = found.declaring;
469         MethodInfo minfo = found.info;
470         String JavaDoc desc = minfo.getDescriptor();
471         int acc = minfo.getAccessFlags();
472
473         if (mname.equals(MethodInfo.nameInit)) {
474             isSpecial = true;
475             if (declClass != targetClass)
476                 throw new CompileError("no such a constructor");
477
478             if (declClass != thisClass && AccessFlag.isPrivate(acc)) {
479                 desc = getAccessibleConstructor(desc, declClass, minfo);
480                 bytecode.addOpcode(Opcode.ACONST_NULL); // the last parameter
481
}
482         }
483         else if (AccessFlag.isPrivate(acc))
484             if (declClass == thisClass)
485                 isSpecial = true;
486             else {
487                 isSpecial = false;
488                 isStatic = true;
489                 String JavaDoc origDesc = desc;
490                 if ((acc & AccessFlag.STATIC) == 0)
491                     desc = Descriptor.insertParameter(declClass.getName(),
492                                                       origDesc);
493
494                 acc = AccessFlag.setPackage(acc) | AccessFlag.STATIC;
495                 mname = getAccessiblePrivate(mname, origDesc, desc,
496                                              minfo, declClass);
497             }
498
499         boolean popTarget = false;
500         if ((acc & AccessFlag.STATIC) != 0) {
501             if (!isStatic) {
502                 /* this method is static but the target object is
503                    on stack. It must be popped out. If aload0pos >= 0,
504                    then the target object was pushed by aload_0. It is
505                    overwritten by NOP.
506                 */

507                 isStatic = true;
508                 if (aload0pos >= 0)
509                     bytecode.write(aload0pos, NOP);
510                 else
511                     popTarget = true;
512             }
513
514             bytecode.addInvokestatic(declClass, mname, desc);
515         }
516         else if (isSpecial) // if (isSpecial && notStatic(acc))
517
bytecode.addInvokespecial(declClass, mname, desc);
518         else if (declClass.isInterface())
519             bytecode.addInvokeinterface(declClass, mname, desc, count);
520         else
521             if (isStatic)
522                 throw new CompileError(mname + " is not static");
523             else
524                 bytecode.addInvokevirtual(declClass, mname, desc);
525
526         setReturnType(desc, isStatic, popTarget);
527     }
528
529     /*
530      * Finds (or adds if necessary) a hidden accessor if the method
531      * is in an enclosing class.
532      *
533      * @param desc the descriptor of the method.
534      * @param declClass the class declaring the method.
535      */

536     protected String JavaDoc getAccessiblePrivate(String JavaDoc methodName, String JavaDoc desc,
537                                           String JavaDoc newDesc, MethodInfo minfo,
538                                           CtClass declClass)
539         throws CompileError
540     {
541         if (isEnclosing(declClass, thisClass)) {
542             AccessorMaker maker = declClass.getAccessorMaker();
543             if (maker != null)
544                 return maker.getMethodAccessor(methodName, desc, newDesc,
545                                                minfo);
546         }
547
548         throw new CompileError("Method " + methodName
549                                + " is private");
550     }
551
552     /*
553      * Finds (or adds if necessary) a hidden constructor if the given
554      * constructor is in an enclosing class.
555      *
556      * @param desc the descriptor of the constructor.
557      * @param declClass the class declaring the constructor.
558      * @param minfo the method info of the constructor.
559      * @return the descriptor of the hidden constructor.
560      */

561     protected String JavaDoc getAccessibleConstructor(String JavaDoc desc, CtClass declClass,
562                                               MethodInfo minfo)
563         throws CompileError
564     {
565         if (isEnclosing(declClass, thisClass)) {
566             AccessorMaker maker = declClass.getAccessorMaker();
567             if (maker != null)
568                 return maker.getConstructor(declClass, desc, minfo);
569         }
570
571         throw new CompileError("the called constructor is private in "
572                                + declClass.getName());
573     }
574
575     private boolean isEnclosing(CtClass outer, CtClass inner) {
576         try {
577             while (inner != null) {
578                 inner = inner.getDeclaringClass();
579                 if (inner == outer)
580                     return true;
581             }
582         }
583         catch (NotFoundException e) {}
584         return false;
585     }
586
587     public int getMethodArgsLength(ASTList args) {
588         return ASTList.length(args);
589     }
590
591     public void atMethodArgs(ASTList args, int[] types, int[] dims,
592                              String JavaDoc[] cnames) throws CompileError {
593         int i = 0;
594         while (args != null) {
595             ASTree a = args.head();
596             a.accept(this);
597             types[i] = exprType;
598             dims[i] = arrayDim;
599             cnames[i] = className;
600             ++i;
601             args = args.tail();
602         }
603     }
604
605     void setReturnType(String JavaDoc desc, boolean isStatic, boolean popTarget)
606         throws CompileError
607     {
608         int i = desc.indexOf(')');
609         if (i < 0)
610             badMethod();
611
612         char c = desc.charAt(++i);
613         int dim = 0;
614         while (c == '[') {
615             ++dim;
616             c = desc.charAt(++i);
617         }
618
619         arrayDim = dim;
620         if (c == 'L') {
621             int j = desc.indexOf(';', i + 1);
622             if (j < 0)
623                 badMethod();
624
625             exprType = CLASS;
626             className = desc.substring(i + 1, j);
627         }
628         else {
629             exprType = MemberResolver.descToType(c);
630             className = null;
631         }
632
633         int etype = exprType;
634         if (isStatic) {
635             if (popTarget) {
636                 if (is2word(etype, dim)) {
637                     bytecode.addOpcode(DUP2_X1);
638                     bytecode.addOpcode(POP2);
639                     bytecode.addOpcode(POP);
640                 }
641                 else if (etype == VOID)
642                     bytecode.addOpcode(POP);
643                 else {
644                     bytecode.addOpcode(SWAP);
645                     bytecode.addOpcode(POP);
646                 }
647             }
648         }
649     }
650
651     protected void atFieldAssign(Expr expr, int op, ASTree left,
652                         ASTree right, boolean doDup) throws CompileError
653     {
654         CtField f = fieldAccess(left);
655         boolean is_static = resultStatic;
656         if (op != '=' && !is_static)
657             bytecode.addOpcode(DUP);
658
659         int fi;
660         if (op == '=') {
661             FieldInfo finfo = f.getFieldInfo2();
662             setFieldType(finfo);
663             AccessorMaker maker = isAccessibleField(f, finfo);
664             if (maker == null)
665                 fi = addFieldrefInfo(f, finfo);
666             else
667                 fi = 0;
668         }
669         else
670             fi = atFieldRead(f, is_static);
671
672         int fType = exprType;
673         int fDim = arrayDim;
674         String JavaDoc cname = className;
675
676         atAssignCore(expr, op, right, fType, fDim, cname);
677
678         boolean is2w = is2word(fType, fDim);
679         if (doDup) {
680             int dup_code;
681             if (is_static)
682                 dup_code = (is2w ? DUP2 : DUP);
683             else
684                 dup_code = (is2w ? DUP2_X1 : DUP_X1);
685
686             bytecode.addOpcode(dup_code);
687         }
688
689         atFieldAssignCore(f, is_static, fi, is2w);
690
691         exprType = fType;
692         arrayDim = fDim;
693         className = cname;
694     }
695
696     /* If fi == 0, the field must be a private field in an enclosing class.
697      */

698     private void atFieldAssignCore(CtField f, boolean is_static, int fi,
699                                    boolean is2byte) throws CompileError {
700         if (fi != 0) {
701             if (is_static) {
702                bytecode.add(PUTSTATIC);
703                bytecode.growStack(is2byte ? -2 : -1);
704             }
705             else {
706                 bytecode.add(PUTFIELD);
707                 bytecode.growStack(is2byte ? -3 : -2);
708             }
709         
710             bytecode.addIndex(fi);
711         }
712         else {
713             CtClass declClass = f.getDeclaringClass();
714             AccessorMaker maker = declClass.getAccessorMaker();
715             // make should be non null.
716
FieldInfo finfo = f.getFieldInfo2();
717             MethodInfo minfo = maker.getFieldSetter(finfo, is_static);
718             bytecode.addInvokestatic(declClass, minfo.getName(),
719                                      minfo.getDescriptor());
720         }
721     }
722
723     /* overwritten in JvstCodeGen.
724      */

725     public void atMember(Member mem) throws CompileError {
726         atFieldRead(mem);
727     }
728
729     protected void atFieldRead(ASTree expr) throws CompileError
730     {
731         CtField f = fieldAccess(expr);
732         boolean is_static = resultStatic;
733         ASTree cexpr = TypeChecker.getConstantFieldValue(f);
734         if (cexpr == null)
735             atFieldRead(f, is_static);
736         else {
737             cexpr.accept(this);
738             setFieldType(f.getFieldInfo2());
739         }
740     }
741
742     /**
743      * Generates bytecode for reading a field value.
744      * It returns a fieldref_info index or zero if the field is a private
745      * one declared in an enclosing class.
746      */

747     private int atFieldRead(CtField f, boolean isStatic) throws CompileError {
748         FieldInfo finfo = f.getFieldInfo2();
749         boolean is2byte = setFieldType(finfo);
750         AccessorMaker maker = isAccessibleField(f, finfo);
751         if (maker != null) {
752             MethodInfo minfo = maker.getFieldGetter(finfo, isStatic);
753             bytecode.addInvokestatic(f.getDeclaringClass(), minfo.getName(),
754                                      minfo.getDescriptor());
755             return 0;
756         }
757         else {
758             int fi = addFieldrefInfo(f, finfo);
759             if (isStatic) {
760                 bytecode.add(GETSTATIC);
761                 bytecode.growStack(is2byte ? 2 : 1);
762             }
763             else {
764                 bytecode.add(GETFIELD);
765                 bytecode.growStack(is2byte ? 1 : 0);
766             }
767
768             bytecode.addIndex(fi);
769             return fi;
770         }
771     }
772
773     /**
774      * Returns null if the field is accessible. Otherwise, it throws
775      * an exception or it returns AccessorMaker if the field is a private
776      * one declared in an enclosing class.
777      */

778     private AccessorMaker isAccessibleField(CtField f, FieldInfo finfo)
779         throws CompileError
780     {
781         if (AccessFlag.isPrivate(finfo.getAccessFlags())
782             && f.getDeclaringClass() != thisClass) {
783             CtClass declClass = f.getDeclaringClass();
784             if (isEnclosing(declClass, thisClass)) {
785                 AccessorMaker maker = declClass.getAccessorMaker();
786                 if (maker != null)
787                     return maker;
788                 else
789                     throw new CompileError("fatal error. bug?");
790             }
791             else
792                 throw new CompileError("Field " + f.getName() + " in "
793                                        + declClass.getName() + " is private.");
794         }
795
796         return null; // accessible field
797
}
798
799     /**
800      * Sets exprType, arrayDim, and className.
801      *
802      * @return true if the field type is long or double.
803      */

804     private boolean setFieldType(FieldInfo finfo) throws CompileError {
805         String JavaDoc type = finfo.getDescriptor();
806
807         int i = 0;
808         int dim = 0;
809         char c = type.charAt(i);
810         while (c == '[') {
811             ++dim;
812             c = type.charAt(++i);
813         }
814
815         arrayDim = dim;
816         exprType = MemberResolver.descToType(c);
817
818         if (c == 'L')
819             className = type.substring(i + 1, type.indexOf(';', i + 1));
820         else
821             className = null;
822
823         boolean is2byte = (c == 'J' || c == 'D');
824         return is2byte;
825     }
826
827     private int addFieldrefInfo(CtField f, FieldInfo finfo) {
828         ConstPool cp = bytecode.getConstPool();
829         String JavaDoc cname = f.getDeclaringClass().getName();
830         int ci = cp.addClassInfo(cname);
831         String JavaDoc name = finfo.getName();
832         String JavaDoc type = finfo.getDescriptor();
833         return cp.addFieldrefInfo(ci, name, type);
834     }
835
836     protected void atFieldPlusPlus(int token, boolean isPost,
837                                    ASTree oprand, Expr expr, boolean doDup)
838         throws CompileError
839     {
840         CtField f = fieldAccess(oprand);
841         boolean is_static = resultStatic;
842         if (!is_static)
843             bytecode.addOpcode(DUP);
844
845         int fi = atFieldRead(f, is_static);
846         int t = exprType;
847         boolean is2w = is2word(t, arrayDim);
848
849         int dup_code;
850         if (is_static)
851             dup_code = (is2w ? DUP2 : DUP);
852         else
853             dup_code = (is2w ? DUP2_X1 : DUP_X1);
854
855         atPlusPlusCore(dup_code, doDup, token, isPost, expr);
856         atFieldAssignCore(f, is_static, fi, is2w);
857     }
858
859     /* This method also returns a value in resultStatic.
860      */

861     protected CtField fieldAccess(ASTree expr) throws CompileError {
862         if (expr instanceof Member) {
863             String JavaDoc name = ((Member)expr).get();
864             CtField f = null;
865             try {
866                 f = thisClass.getField(name);
867             }
868             catch (NotFoundException e) {
869                 // EXPR might be part of a static member access?
870
throw new NoFieldException(name, expr);
871             }
872
873             boolean is_static = Modifier.isStatic(f.getModifiers());
874             if (!is_static)
875                 if (inStaticMethod)
876                     throw new CompileError(
877                                 "not available in a static method: " + name);
878                 else
879                     bytecode.addAload(0); // this
880

881             resultStatic = is_static;
882             return f;
883         }
884         else if (expr instanceof Expr) {
885             Expr e = (Expr)expr;
886             int op = e.getOperator();
887             if (op == MEMBER) {
888                 /* static member by # (extension by Javassist)
889                  * For example, if int.class is parsed, the resulting tree
890                  * is (# "java.lang.Integer" "TYPE").
891                  */

892                 CtField f = resolver.lookupField(((Symbol)e.oprand1()).get(),
893                                          (Symbol)e.oprand2());
894                 resultStatic = true;
895                 return f;
896             }
897             else if (op == '.') {
898                 CtField f = null;
899                 try {
900                     e.oprand1().accept(this);
901                     /* Don't call lookupFieldByJvmName2().
902                      * The left operand of . is not a class name but
903                      * a normal expression.
904                      */

905                     if (exprType == CLASS && arrayDim == 0)
906                         f = resolver.lookupFieldByJvmName(className,
907                                                     (Symbol)e.oprand2());
908                     else
909                         badLvalue();
910
911                     boolean is_static = Modifier.isStatic(f.getModifiers());
912                     if (is_static)
913                         bytecode.addOpcode(POP);
914
915                     resultStatic = is_static;
916                     return f;
917                 }
918                 catch (NoFieldException nfe) {
919                     if (nfe.getExpr() != e.oprand1())
920                         throw nfe;
921
922                     /* EXPR should be a static field.
923                      * If EXPR might be part of a qualified class name,
924                      * lookupFieldByJvmName2() throws NoFieldException.
925                      */

926                     Symbol fname = (Symbol)e.oprand2();
927                     String JavaDoc cname = nfe.getField();
928                     f = resolver.lookupFieldByJvmName2(cname, fname, expr);
929                     resolver.recordPackage(cname);
930                     resultStatic = true;
931                     return f;
932                 }
933             }
934             else
935                 badLvalue();
936         }
937         else
938             badLvalue();
939
940         resultStatic = false;
941         return null; // never reach
942
}
943
944     private static void badLvalue() throws CompileError {
945         throw new CompileError("bad l-value");
946     }
947
948     public CtClass[] makeParamList(MethodDecl md) throws CompileError {
949         CtClass[] params;
950         ASTList plist = md.getParams();
951         if (plist == null)
952             params = new CtClass[0];
953         else {
954             int i = 0;
955             params = new CtClass[plist.length()];
956             while (plist != null) {
957                 params[i++] = resolver.lookupClass((Declarator)plist.head());
958                 plist = plist.tail();
959             }
960         }
961
962         return params;
963     }
964
965     public CtClass[] makeThrowsList(MethodDecl md) throws CompileError {
966         CtClass[] clist;
967         ASTList list = md.getThrows();
968         if (list == null)
969             return null;
970         else {
971             int i = 0;
972             clist = new CtClass[list.length()];
973             while (list != null) {
974                 clist[i++] = resolver.lookupClassByName((ASTList)list.head());
975                 list = list.tail();
976             }
977
978             return clist;
979         }
980     }
981
982     /* Converts a class name into a JVM-internal representation.
983      *
984      * It may also expand a simple class name to java.lang.*.
985      * For example, this converts Object into java/lang/Object.
986      */

987     protected String JavaDoc resolveClassName(ASTList name) throws CompileError {
988         return resolver.resolveClassName(name);
989     }
990
991     /* Expands a simple class name to java.lang.*.
992      * For example, this converts Object into java/lang/Object.
993      */

994     protected String JavaDoc resolveClassName(String JavaDoc jvmName) throws CompileError {
995         return resolver.resolveJvmClassName(jvmName);
996     }
997 }
998
Popular Tags