/Users/lyon/j4p/src/javassist/compiler/MemberCodeGen.java

1    /* 
2     * Javassist, a Java-bytecode translator toolkit. 
3     * Copyright (C) 1999-2003 Shigeru Chiba. All Rights Reserved. 
4     * 
5     * The contents of this file are subject to the Mozilla Public License Version 
6     * 1.1 (the "License"); you may not use this file except in compliance with 
7     * the License.  Alternatively, the contents of this file may be used under 
8     * the terms of the GNU Lesser General Public License Version 2.1 or later. 
9     * 
10    * Software distributed under the License is distributed on an "AS IS" basis, 
11    * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 
12    * for the specific language governing rights and limitations under the 
13    * License. 
14    */ 
15    
16   package javassist.compiler; 
17    
18   import java.util.List; 
19    
20   import javassist.*; 
21   import javassist.bytecode.*; 
22   import javassist.compiler.ast.*; 
23    
24   /* Code generator methods depending on javassist.* classes. 
25    */ 
26    
27   public class MemberCodeGen extends CodeGen { 
28       protected ClassPool classPool; 
29       protected CtClass thisClass; 
30       protected MethodInfo thisMethod; 
31    
32       protected boolean resultStatic; 
33    
34       public MemberCodeGen(Bytecode b, CtClass cc, ClassPool cp) { 
35           super(b); 
36           classPool = cp; 
37           thisClass = cc; 
38           thisMethod = null; 
39       } 
40    
41       /** 
42        * Records the currently compiled method. 
43        */ 
44       public void setThisMethod(CtMethod m) { 
45           thisMethod = m.getMethodInfo2(); 
46       } 
47    
48       public CtClass getThisClass() { 
49           return thisClass; 
50       } 
51    
52       /** 
53        * Returns the JVM-internal representation of this class name. 
54        */ 
55       protected String getThisName() { 
56           return javaToJvmName(thisClass.getName()); 
57       } 
58    
59       /** 
60        * Returns the JVM-internal representation of this super class name. 
61        */ 
62       protected String getSuperName() throws CompileError { 
63           return javaToJvmName(getSuperclass(thisClass).getName()); 
64       } 
65    
66       protected void insertDefaultSuperCall() throws CompileError { 
67           bytecode.addAload(0); 
68           bytecode.addInvokespecial(getSuperclass(thisClass), "<init>", "()V"); 
69       } 
70    
71       protected void atTryStmnt(Stmnt st) throws CompileError { 
72           Stmnt body = (Stmnt) st.getLeft(); 
73           if (body == null) 
74               return; 
75    
76           int start = bytecode.currentPc(); 
77           body.accept(this); 
78           int end = bytecode.currentPc(); 
79           if (start == end) 
80               throw new CompileError("empty try block"); 
81    
82           bytecode.addOpcode(Opcode.GOTO); 
83           int pc = bytecode.currentPc(); 
84           bytecode.addIndex(0);   // correct later 
85    
86           int var = getMaxLocals(); 
87           incMaxLocals(1); 
88           ASTList catchList = (ASTList) st.getRight().getLeft(); 
89           while (catchList != null) { 
90               Pair p = (Pair) catchList.head(); 
91               catchList = catchList.tail(); 
92               Declarator decl = (Declarator) p.getLeft(); 
93               Stmnt block = (Stmnt) p.getRight(); 
94    
95               decl.setLocalVar(var); 
96    
97               CtClass type = lookupClass(decl.getClassName()); 
98               decl.setClassName(javaToJvmName(type.getName())); 
99               bytecode.addExceptionHandler(start, end, bytecode.currentPc(), 
100                      type); 
101              bytecode.growStack(1); 
102              bytecode.addAstore(var); 
103              if (block != null) 
104                  block.accept(this); 
105   
106              bytecode.addOpcode(Opcode.GOTO); 
107              bytecode.addIndex(pc - bytecode.currentPc()); 
108          } 
109   
110          Stmnt finallyBlock = (Stmnt) st.getRight().getRight().getLeft(); 
111          if (finallyBlock != null) 
112              throw new CompileError( 
113                      "sorry, finally has not been supported yet"); 
114   
115          bytecode.write16bit(pc, bytecode.currentPc() - pc + 1); 
116          hasReturned = false; 
117      } 
118   
119      public void atNewExpr(NewExpr expr) throws CompileError { 
120          if (expr.isArray()) 
121              atNewArrayExpr(expr); 
122          else { 
123              CtClass clazz = lookupClass(expr.getClassName()); 
124              String cname = clazz.getName(); 
125              ASTList args = expr.getArguments(); 
126              bytecode.addNew(cname); 
127              bytecode.addOpcode(DUP); 
128   
129              atMethodCall2(clazz, MethodInfo.nameInit, args, false, true); 
130   
131              exprType = CLASS; 
132              arrayDim = 0; 
133              className = javaToJvmName(cname); 
134          } 
135      } 
136   
137      public void atNewArrayExpr(NewExpr expr) throws CompileError { 
138          if (expr.getInitializer() != null) 
139              throw new CompileError("array initializer is not supported"); 
140   
141          int type = expr.getArrayType(); 
142          ASTList size = expr.getArraySize(); 
143          ASTList classname = expr.getClassName(); 
144          if (size.length() > 1) { 
145              atMultiNewArray(type, classname, size); 
146              return; 
147          } 
148   
149          size.head().accept(this); 
150          exprType = type; 
151          arrayDim = 1; 
152          if (type == CLASS) { 
153              className = resolveClassName(classname); 
154              bytecode.addAnewarray(jvmToJavaName(className)); 
155          } else { 
156              className = null; 
157              int atype = 0; 
158              switch (type) { 
159                  case BOOLEAN: 
160                      atype = T_BOOLEAN; 
161                      break; 
162                  case CHAR: 
163                      atype = T_CHAR; 
164                      break; 
165                  case FLOAT: 
166                      atype = T_FLOAT; 
167                      break; 
168                  case DOUBLE: 
169                      atype = T_DOUBLE; 
170                      break; 
171                  case BYTE: 
172                      atype = T_BYTE; 
173                      break; 
174                  case SHORT: 
175                      atype = T_SHORT; 
176                      break; 
177                  case INT: 
178                      atype = T_INT; 
179                      break; 
180                  case LONG: 
181                      atype = T_LONG; 
182                      break; 
183                  default : 
184                      badNewExpr(); 
185                      break; 
186              } 
187   
188              bytecode.addOpcode(NEWARRAY); 
189              bytecode.add(atype); 
190          } 
191      } 
192   
193      private static void badNewExpr() throws CompileError { 
194          throw new CompileError("bad new expression"); 
195      } 
196   
197      protected void atMultiNewArray(int type, ASTList classname, ASTList size) 
198              throws CompileError { 
199          int count, dim; 
200          dim = size.length(); 
201          for (count = 0; size != null; size = size.tail()) { 
202              ASTree s = size.head(); 
203              if (s == null) 
204                  break;          // int[][][] a = new int[3][4][]; 
205   
206              ++count; 
207              s.accept(this); 
208              if (exprType != INT) 
209                  throw new CompileError("bad type for array size"); 
210          } 
211   
212          String desc; 
213          exprType = type; 
214          arrayDim = dim; 
215          if (type == CLASS) { 
216              className = resolveClassName(classname); 
217              desc = toJvmArrayName(className, dim); 
218          } else 
219              desc = toJvmTypeName(type, dim); 
220   
221          bytecode.addMultiNewarray(desc, count); 
222      } 
223   
224      protected void atMethodCall(Expr expr) throws CompileError { 
225          String mname = null; 
226          CtClass targetClass = null; 
227          ASTree method = expr.oprand1(); 
228          ASTList args = (ASTList) expr.oprand2(); 
229          boolean isStatic = false; 
230          boolean isSpecial = false; 
231   
232          if (method instanceof Member) { 
233              mname = ((Member) method).get(); 
234              targetClass = thisClass; 
235              if (inStaticMethod) 
236                  isStatic = true;            // should be static 
237              else 
238                  bytecode.addAload(0);       // this 
239          } else if (method instanceof Keyword) {   // constructor 
240              isSpecial = true; 
241              mname = MethodInfo.nameInit;        // <init> 
242              targetClass = thisClass; 
243              if (inStaticMethod) 
244                  throw new CompileError("a constructor cannot be static"); 
245              else 
246                  bytecode.addAload(0);   // this 
247   
248              if (((Keyword) method).get() == SUPER) 
249                  targetClass = getSuperclass(targetClass); 
250          } else if (method instanceof Expr) { 
251              Expr e = (Expr) method; 
252              mname = ((Symbol) e.oprand2()).get(); 
253              int op = e.getOperator(); 
254              if (op == MEMBER) {                 // static method 
255                  targetClass = lookupClass((ASTList) e.oprand1()); 
256                  isStatic = true; 
257              } else if (op == '.') { 
258                  ASTree target = e.oprand1(); 
259                  if (target instanceof Keyword) 
260                      if (((Keyword) target).get() == SUPER) 
261                          isSpecial = true; 
262   
263                  try { 
264                      target.accept(this); 
265                  } catch (NoFieldException nfe) { 
266                      if (nfe.getExpr() != target) 
267                          throw nfe; 
268   
269                      // it should be a static method. 
270                      exprType = CLASS; 
271                      arrayDim = 0; 
272                      className = nfe.getField(); // JVM-internal 
273                      isStatic = true; 
274                  } 
275   
276                  if (arrayDim > 0) 
277                      targetClass = lookupClass2(javaLangObject); 
278                  else if (exprType == CLASS /* && arrayDim == 0 */) 
279                      targetClass = lookupClass(className); 
280                  else 
281                      badMethod(); 
282              } else 
283                  badMethod(); 
284          } else 
285              fatal(); 
286   
287          atMethodCall2(targetClass, mname, args, isStatic, isSpecial); 
288      } 
289   
290      private static void badMethod() throws CompileError { 
291          throw new CompileError("bad method"); 
292      } 
293   
294      private static CtClass getSuperclass(CtClass c) throws CompileError { 
295          try { 
296              return c.getSuperclass(); 
297          } catch (NotFoundException e) { 
298              throw new CompileError("cannot find the super class of " 
299                      + c.getName()); 
300          } 
301      } 
302   
303      public void atMethodCall2(CtClass targetClass, String mname, 
304                                ASTList args, boolean isStatic, boolean isSpecial) 
305              throws CompileError { 
306          int nargs = atMethodArgsLength(args); 
307          int[] types = new int[nargs]; 
308          int[] dims = new int[nargs]; 
309          String[] cnames = new String[nargs]; 
310   
311          int stack = bytecode.getStackDepth(); 
312   
313          atMethodArgs(args, types, dims, cnames); 
314   
315          // used by invokeinterface 
316          int count = bytecode.getStackDepth() - stack + 1; 
317   
318          Object[] found = lookupMethod(targetClass, thisMethod, mname, 
319                  types, dims, cnames, false); 
320          if (found == null) { 
321              String msg; 
322              if (mname.equals(MethodInfo.nameInit)) 
323                  msg = "constructor not found"; 
324              else 
325                  msg = "Method " + mname + " not found in " 
326                          + targetClass.getName(); 
327   
328              throw new CompileError(msg); 
329          } 
330   
331          CtClass declClass = (CtClass) found[0]; 
332          MethodInfo minfo = (MethodInfo) found[1]; 
333          String desc = minfo.getDescriptor(); 
334          int acc = minfo.getAccessFlags(); 
335   
336          if (mname.equals(MethodInfo.nameInit)) { 
337              isSpecial = true; 
338              if (declClass != targetClass) 
339                  throw new CompileError("no such a constructor"); 
340          } else if ((acc & AccessFlag.PRIVATE) != 0) { 
341              isSpecial = true; 
342              if (declClass != targetClass) 
343                  throw new CompileError("Method " + mname + "is private"); 
344          } 
345   
346          boolean popTarget = false; 
347          if ((acc & AccessFlag.STATIC) != 0) { 
348              if (!isStatic) { 
349                  /* this method is static but the target object is 
350                     on stack.  It must be popped out. 
351                  */ 
352                  isStatic = true; 
353                  popTarget = true; 
354              } 
355   
356              bytecode.addInvokestatic(declClass, mname, desc); 
357          } else if (isSpecial) 
358              bytecode.addInvokespecial(declClass, mname, desc); 
359          else if (declClass.isInterface()) 
360              bytecode.addInvokeinterface(declClass, mname, desc, count); 
361          else if (isStatic) 
362              throw new CompileError(mname + " is not static"); 
363          else 
364              bytecode.addInvokevirtual(declClass, mname, desc); 
365   
366          setReturnType(desc, isStatic, popTarget); 
367      } 
368   
369      public int atMethodArgsLength(ASTList args) { 
370          return ASTList.length(args); 
371      } 
372   
373      public void atMethodArgs(ASTList args, int[] types, int[] dims, 
374                               String[] cnames) throws CompileError { 
375          int i = 0; 
376          while (args != null) { 
377              ASTree a = args.head(); 
378              a.accept(this); 
379              types[i] = exprType; 
380              dims[i] = arrayDim; 
381              cnames[i] = className; 
382              ++i; 
383              args = args.tail(); 
384          } 
385      } 
386   
387      private void setReturnType(String desc, boolean isStatic, 
388                                 boolean popTarget) 
389              throws CompileError { 
390          int i = desc.indexOf(')'); 
391          if (i < 0) 
392              badMethod(); 
393   
394          char c = desc.charAt(++i); 
395          int dim = 0; 
396          while (c == '[') { 
397              ++dim; 
398              c = desc.charAt(++i); 
399          } 
400   
401          arrayDim = dim; 
402          if (c == 'L') { 
403              int j = desc.indexOf(';', i + 1); 
404              if (j < 0) 
405                  badMethod(); 
406   
407              exprType = CLASS; 
408              className = desc.substring(i + 1, j); 
409          } else { 
410              exprType = descToType(c); 
411              className = null; 
412          } 
413   
414          int etype = exprType; 
415          if (isStatic) { 
416              if (popTarget) { 
417                  if (is2word(etype, dim)) { 
418                      bytecode.addOpcode(DUP2_X1); 
419                      bytecode.addOpcode(POP2); 
420                      bytecode.addOpcode(POP); 
421                  } else if (etype == VOID) 
422                      bytecode.addOpcode(POP); 
423                  else { 
424                      bytecode.addOpcode(SWAP); 
425                      bytecode.addOpcode(POP); 
426                  } 
427              } 
428          } 
429      } 
430   
431      private Object[] lookupMethod(CtClass clazz, MethodInfo current, 
432                                    String methodName, 
433                                    int[] argTypes, int[] argDims, 
434                                    String[] argClassNames, boolean onlyExact) 
435              throws CompileError { 
436          Object[] maybe = null; 
437   
438          if (current != null) 
439              if (current.getName().equals(methodName)) { 
440                  int res = compareSignature(current.getDescriptor(), 
441                          argTypes, argDims, argClassNames); 
442                  Object[] r = new Object[]{clazz, current}; 
443                  if (res == YES) 
444                      return r; 
445                  else if (res == MAYBE && maybe == null) 
446                      maybe = r; 
447              } 
448   
449          List list = clazz.getClassFile2().getMethods(); 
450          int n = list.size(); 
451          for (int i = 0; i < n; ++i) { 
452              MethodInfo minfo = (MethodInfo) list.get(i); 
453              if (minfo.getName().equals(methodName)) { 
454                  int res = compareSignature(minfo.getDescriptor(), 
455                          argTypes, argDims, argClassNames); 
456                  Object[] r = new Object[]{clazz, minfo}; 
457                  if (res == YES) 
458                      return r; 
459                  else if (res == MAYBE && maybe == null) 
460                      maybe = r; 
461              } 
462          } 
463   
464          try { 
465              CtClass pclazz = clazz.getSuperclass(); 
466              if (pclazz != null) { 
467                  Object[] r = lookupMethod(pclazz, null, methodName, argTypes, 
468                          argDims, argClassNames, 
469                          (onlyExact || maybe != null)); 
470                  if (r != null) 
471                      return r; 
472              } 
473          } catch (NotFoundException e) { 
474          } 
475   
476          /* -- not necessary to search implemented interfaces. 
477          try { 
478              CtClass[] ifs = clazz.getInterfaces(); 
479              int size = ifs.length; 
480              for (int i = 0; i < size; ++i) { 
481                  Object[] r = lookupMethod(ifs[i], methodName, argTypes, 
482                                            argDims, argClassNames); 
483                  if (r != null) 
484                      return r; 
485              } 
486          } 
487          catch (NotFoundException e) {} 
488          */ 
489   
490          if (onlyExact) 
491              return null; 
492          else 
493              return maybe; 
494      } 
495   
496      private static final int YES = 2; 
497      private static final int MAYBE = 1; 
498      private static final int NO = 0; 
499   
500      /* 
501       * Returns YES if actual parameter types matches the given signature. 
502       * 
503       * argTypes, argDims, and argClassNames represent actual parameters. 
504       * 
505       * This method does not correctly implement the Java method dispatch 
506       * algorithm. 
507       */ 
508      private int compareSignature(String desc, int[] argTypes, 
509                                   int[] argDims, String[] argClassNames) 
510              throws CompileError { 
511          int result = YES; 
512          int i = 1; 
513          int nArgs = argTypes.length; 
514          if (nArgs != Descriptor.numOfParameters(desc)) 
515              return NO; 
516   
517          int len = desc.length(); 
518          for (int n = 0; i < len; ++n) { 
519              char c = desc.charAt(i++); 
520              if (c == ')') 
521                  return (n == nArgs ? result : NO); 
522              else if (n >= nArgs) 
523                  return NO; 
524   
525              int dim = 0; 
526              while (c == '[') { 
527                  ++dim; 
528                  c = desc.charAt(i++); 
529              } 
530   
531              if (argTypes[n] == NULL) { 
532                  if (dim == 0 && c != 'L') 
533                      return NO; 
534              } else if (argDims[n] != dim) { 
535                  if (!(dim == 0 && c == 'L' 
536                          && desc.startsWith("java/lang/Object;", i))) 
537                      return NO; 
538   
539                  // if the thread reaches here, c must be 'L'. 
540                  i = desc.indexOf(';', i) + 1; 
541                  result = MAYBE; 
542                  if (i <= 0) 
543                      return NO;  // invalid descriptor? 
544              } else if (c == 'L') {        // not compare 
545                  int j = desc.indexOf(';', i); 
546                  if (j < 0 || argTypes[n] != CLASS) 
547                      return NO; 
548   
549                  String cname = desc.substring(i, j); 
550                  if (!cname.equals(argClassNames[n])) { 
551                      CtClass clazz = lookupClass(argClassNames[n]); 
552                      try { 
553                          if (clazz.subtypeOf(lookupClass(cname))) 
554                              result = MAYBE; 
555                          else 
556                              return NO; 
557                      } catch (NotFoundException e) { 
558                          result = MAYBE; // should be NO? 
559                      } 
560                  } 
561   
562                  i = j + 1; 
563              } else { 
564                  int t = descToType(c); 
565                  int at = argTypes[n]; 
566                  if (t != at) 
567                      if (t == INT 
568                              && (at == SHORT || at == BYTE || at == CHAR)) 
569                          result = MAYBE; 
570                      else 
571                          return NO; 
572              } 
573          } 
574   
575          return NO; 
576      } 
577   
578      protected static int descToType(char c) throws CompileError { 
579          switch (c) { 
580              case 'Z': 
581                  return BOOLEAN; 
582              case 'C': 
583                  return CHAR; 
584              case 'B': 
585                  return BYTE; 
586              case 'S': 
587                  return SHORT; 
588              case 'I': 
589                  return INT; 
590              case 'J': 
591                  return LONG; 
592              case 'F': 
593                  return FLOAT; 
594              case 'D': 
595                  return DOUBLE; 
596              case 'V': 
597                  return VOID; 
598              case 'L': 
599              case '[': 
600                  return CLASS; 
601              default : 
602                  fatal(); 
603                  return VOID; 
604          } 
605      } 
606   
607      protected void atFieldAssign(Expr expr, int op, ASTree left, 
608                                   ASTree right, boolean doDup) throws CompileError { 
609          CtField f = fieldAccess(left); 
610          boolean is_static = resultStatic; 
611          if (op != '=' && !is_static) 
612              bytecode.addOpcode(DUP); 
613   
614          int fi = atFieldRead(f, is_static, op == '='); 
615          int fType = exprType; 
616          int fDim = arrayDim; 
617          String cname = className; 
618   
619          atAssignCore(expr, op, right, fType, fDim, cname); 
620   
621          boolean is2w = is2word(fType, fDim); 
622          if (doDup) { 
623              int dup_code; 
624              if (is_static) 
625                  dup_code = (is2w ? DUP2 : DUP); 
626              else 
627                  dup_code = (is2w ? DUP2_X1 : DUP_X1); 
628   
629              bytecode.addOpcode(dup_code); 
630          } 
631   
632          if (is_static) { 
633              bytecode.add(PUTSTATIC); 
634              bytecode.growStack(is2w ? -2 : -1); 
635          } else { 
636              bytecode.add(PUTFIELD); 
637              bytecode.growStack(is2w ? -3 : -2); 
638          } 
639   
640          bytecode.addIndex(fi); 
641          exprType = fType; 
642          arrayDim = fDim; 
643          className = cname; 
644      } 
645   
646      /* overwritten in JvstCodeGen. 
647       */ 
648      public void atMember(Member mem) throws CompileError { 
649          atFieldRead(mem); 
650      } 
651   
652      protected void atFieldRead(ASTree expr) throws CompileError { 
653          CtField f = fieldAccess(expr); 
654          boolean is_static = resultStatic; 
655          atFieldRead(f, is_static, false); 
656      } 
657   
658      private int atFieldRead(CtField f, boolean isStatic, boolean noRead) 
659              throws CompileError { 
660          FieldInfo finfo = f.getFieldInfo2(); 
661          String type = finfo.getDescriptor(); 
662   
663          int fi = addFieldrefInfo(f, finfo, type); 
664   
665          int i = 0; 
666          int dim = 0; 
667          char c = type.charAt(i); 
668          while (c == '[') { 
669              ++dim; 
670              c = type.charAt(++i); 
671          } 
672   
673          arrayDim = dim; 
674          boolean is2byte = (c == 'J' || c == 'D'); 
675          exprType = descToType(c); 
676   
677          if (c == 'L') 
678              className = type.substring(i + 1, type.indexOf(';', i + 1)); 
679          else 
680              className = null; 
681   
682          if (noRead) 
683              return fi; 
684   
685          if (isStatic) { 
686              bytecode.add(GETSTATIC); 
687              bytecode.growStack(is2byte ? 2 : 1); 
688          } else { 
689              bytecode.add(GETFIELD); 
690              bytecode.growStack(is2byte ? 1 : 0); 
691          } 
692   
693          bytecode.addIndex(fi); 
694          return fi; 
695      } 
696   
697      protected int addFieldrefInfo(CtField f, FieldInfo finfo, String type) { 
698          ConstPool cp = bytecode.getConstPool(); 
699          String cname = f.getDeclaringClass().getName(); 
700          int ci = cp.addClassInfo(cname); 
701          String name = finfo.getName(); 
702          return cp.addFieldrefInfo(ci, name, type); 
703      } 
704   
705      protected void atFieldPlusPlus(int token, boolean isPost, 
706                                     ASTree oprand, Expr expr, boolean doDup) 
707              throws CompileError { 
708          CtField f = fieldAccess(oprand); 
709          boolean is_static = resultStatic; 
710          if (!is_static) 
711              bytecode.addOpcode(DUP); 
712   
713          int fi = atFieldRead(f, is_static, false); 
714          int t = exprType; 
715          boolean is2w = is2word(t, arrayDim); 
716   
717          int dup_code; 
718          if (is_static) 
719              dup_code = (is2w ? DUP2 : DUP); 
720          else 
721              dup_code = (is2w ? DUP2_X1 : DUP_X1); 
722   
723          atPlusPlusCore(dup_code, doDup, token, isPost, expr); 
724   
725          if (is_static) { 
726              bytecode.add(PUTSTATIC); 
727              bytecode.growStack(is2w ? -2 : -1); 
728          } else { 
729              bytecode.add(PUTFIELD); 
730              bytecode.growStack(is2w ? -3 : -2); 
731          } 
732   
733          bytecode.addIndex(fi); 
734      } 
735   
736      /* This method also returns a value in resultStatic. 
737       */ 
738      protected CtField fieldAccess(ASTree expr) throws CompileError { 
739          CtField f = null; 
740          boolean is_static = false; 
741          if (expr instanceof Member) { 
742              String name = ((Member) expr).get(); 
743              try { 
744                  f = thisClass.getField(name); 
745              } catch (NotFoundException e) { 
746                  // EXPR might be part of a static member access? 
747                  throw new NoFieldException(name, expr); 
748              } 
749   
750              is_static = Modifier.isStatic(f.getModifiers()); 
751              if (!is_static) 
752                  if (inStaticMethod) 
753                      throw new CompileError( 
754                              "not available in a static method: " + name); 
755                  else 
756                      bytecode.addAload(0);       // this 
757          } else if (expr instanceof Expr) { 
758              Expr e = (Expr) expr; 
759              int op = e.getOperator(); 
760              if (op == MEMBER) { 
761                  f = lookupField((ASTList) e.oprand1(), (Symbol) e.oprand2()); 
762                  is_static = true; 
763              } else if (op == '.') { 
764                  try { 
765                      e.oprand1().accept(this); 
766                      if (exprType == CLASS && arrayDim == 0) 
767                          f = lookupField(className, (Symbol) e.oprand2()); 
768                      else 
769                          badLvalue(); 
770   
771                      is_static = Modifier.isStatic(f.getModifiers()); 
772                      if (is_static) 
773                          bytecode.addOpcode(POP); 
774                  } catch (NoFieldException nfe) { 
775                      if (nfe.getExpr() != e.oprand1()) 
776                          throw nfe; 
777   
778                      Symbol fname = (Symbol) e.oprand2(); 
779                      // it should be a static field. 
780                      try { 
781                          f = lookupField(nfe.getField(), fname); 
782                          is_static = true; 
783                      } catch (CompileError ce) { 
784                          // EXPR might be part of a qualified class name. 
785                          throw new NoFieldException(nfe.getField() + "/" 
786                                  + fname.get(), expr); 
787                      } 
788                  } 
789              } else 
790                  badLvalue(); 
791          } else 
792              badLvalue(); 
793   
794          resultStatic = is_static; 
795          return f; 
796      } 
797   
798      private static void badLvalue() throws CompileError { 
799          throw new CompileError("bad l-value"); 
800      } 
801   
802      public CtClass[] makeParamList(MethodDecl md) throws CompileError { 
803          CtClass[] params; 
804          ASTList plist = md.getParams(); 
805          if (plist == null) 
806              params = new CtClass[0]; 
807          else { 
808              int i = 0; 
809              params = new CtClass[plist.length()]; 
810              while (plist != null) { 
811                  params[i++] = lookupClass((Declarator) plist.head()); 
812                  plist = plist.tail(); 
813              } 
814          } 
815   
816          return params; 
817      } 
818   
819      public CtClass[] makeThrowsList(MethodDecl md) throws CompileError { 
820          CtClass[] clist; 
821          ASTList list = md.getThrows(); 
822          if (list == null) 
823              return null; 
824          else { 
825              int i = 0; 
826              clist = new CtClass[list.length()]; 
827              while (list != null) { 
828                  clist[i++] = lookupClass((ASTList) list.head()); 
829                  list = list.tail(); 
830              } 
831   
832              return clist; 
833          } 
834      } 
835   
836      public static int getModifiers(ASTList mods) { 
837          int m = 0; 
838          while (mods != null) { 
839              Keyword k = (Keyword) mods.head(); 
840              mods = mods.tail(); 
841              switch (k.get()) { 
842                  case STATIC: 
843                      m |= Modifier.STATIC; 
844                      break; 
845                  case FINAL: 
846                      m |= Modifier.FINAL; 
847                      break; 
848                  case SYNCHRONIZED: 
849                      m |= Modifier.SYNCHRONIZED; 
850                      break; 
851                  case ABSTRACT: 
852                      m |= Modifier.ABSTRACT; 
853                      break; 
854                  case PUBLIC: 
855                      m |= Modifier.PUBLIC; 
856                      break; 
857                  case PROTECTED: 
858                      m |= Modifier.PROTECTED; 
859                      break; 
860                  case PRIVATE: 
861                      m |= Modifier.PRIVATE; 
862                      break; 
863                  case VOLATILE: 
864                      m |= Modifier.VOLATILE; 
865                      break; 
866                  case TRANSIENT: 
867                      m |= Modifier.TRANSIENT; 
868                      break; 
869                  case STRICT: 
870                      m |= Modifier.STRICT; 
871                      break; 
872              } 
873          } 
874   
875          return m; 
876      } 
877   
878      /* Converts a class name into a JVM-internal representation. 
879       * 
880       * It may also expand a simple class name to java.lang.*. 
881       * For example, this converts Object into java/lang/Object. 
882       */ 
883      protected String resolveClassName(ASTList name) throws CompileError { 
884          if (name == null) 
885              return null; 
886          else 
887              return javaToJvmName(lookupClass(name).getName()); 
888      } 
889   
890      /* Expands a simple class name to java.lang.*. 
891       * For example, this converts Object into java/lang/Object. 
892       */ 
893      protected String resolveClassName(String jvmName) throws CompileError { 
894          if (jvmName == null) 
895              return null; 
896          else 
897              return javaToJvmName(lookupClass(jvmName).getName()); 
898      } 
899   
900      protected CtClass lookupClass(Declarator decl) throws CompileError { 
901          return lookupClass(decl.getType(), decl.getArrayDim(), 
902                  decl.getClassName()); 
903      } 
904   
905      protected CtClass lookupClass(int type, int dim, String classname) 
906              throws CompileError { 
907          String cname = ""; 
908          CtClass clazz; 
909          switch (type) { 
910              case CLASS: 
911                  clazz = lookupClass(classname); 
912                  if (dim > 0) 
913                      cname = clazz.getName(); 
914                  else 
915                      return clazz; 
916   
917                  break; 
918              case BOOLEAN: 
919                  cname = "boolean"; 
920                  break; 
921              case CHAR: 
922                  cname = "char"; 
923                  break; 
924              case BYTE: 
925                  cname = "byte"; 
926                  break; 
927              case SHORT: 
928                  cname = "short"; 
929                  break; 
930              case INT: 
931                  cname = "int"; 
932                  break; 
933              case LONG: 
934                  cname = "long"; 
935                  break; 
936              case FLOAT: 
937                  cname = "float"; 
938                  break; 
939              case DOUBLE: 
940                  cname = "double"; 
941                  break; 
942              case VOID: 
943                  cname = "void"; 
944                  break; 
945              default : 
946                  fatal(); 
947          } 
948   
949          while (dim-- > 0) 
950              cname += "[]"; 
951   
952          return lookupClass2(cname); 
953      } 
954   
955      protected CtClass lookupClass(ASTList name) throws CompileError { 
956          return lookupClass2(Declarator.astToClassName(name, '.')); 
957      } 
958   
959      protected CtClass lookupClass(String jvmName) throws CompileError { 
960          return lookupClass2(jvmToJavaName(jvmName)); 
961      } 
962   
963      /** 
964       * @param name      a qualified class name. e.g. java.lang.String 
965       */ 
966      private CtClass lookupClass2(String name) throws CompileError { 
967          try { 
968              return classPool.get(name); 
969          } catch (NotFoundException e) { 
970          } 
971   
972          try { 
973              if (name.indexOf('.') < 0) 
974                  return classPool.get("java.lang." + name); 
975          } catch (NotFoundException e) { 
976          } 
977   
978          throw new CompileError("no such class: " + name); 
979      } 
980   
981      public CtField lookupField(ASTList className, Symbol fieldName) 
982              throws CompileError { 
983          return lookupField2(Declarator.astToClassName(className, '.'), 
984                  fieldName); 
985      } 
986   
987      public CtField lookupField(String className, Symbol fieldName) 
988              throws CompileError { 
989          return lookupField2(jvmToJavaName(className), fieldName); 
990      } 
991   
992      /** 
993       * @param name      a qualified class name. e.g. java.lang.String 
994       */ 
995      private CtField lookupField2(String className, Symbol fieldName) 
996              throws CompileError { 
997          CtClass cc = lookupClass(className); 
998          try { 
999              return cc.getField(fieldName.get()); 
1000         } catch (NotFoundException e) { 
1001         } 
1002         throw new CompileError("no such field: " + fieldName.get()); 
1003     } 
1004  
1005     protected static String javaToJvmName(String classname) { 
1006         return classname.replace('.', '/'); 
1007     } 
1008  
1009     protected static String jvmToJavaName(String classname) { 
1010         return classname.replace('/', '.'); 
1011     } 
1012 } 
1013