/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