aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/javassist/compiler/MemberCodeGen.java
diff options
context:
space:
mode:
authorpatriot1burke <patriot1burke@30ef5769-5b8d-40dd-aea6-55b5d6557bb3>2003-04-22 13:47:06 +0000
committerpatriot1burke <patriot1burke@30ef5769-5b8d-40dd-aea6-55b5d6557bb3>2003-04-22 13:47:06 +0000
commit069bceaf72fd0d6ffad14ce4e3e00ca91a280bde (patch)
treeb8230a15d3061c64d5a64bf9efa654d0d6311ff2 /src/main/javassist/compiler/MemberCodeGen.java
parentf610083ba0adbcb3fe92a504015fb26fb5a42530 (diff)
downloadjavassist-069bceaf72fd0d6ffad14ce4e3e00ca91a280bde.tar.gz
javassist-069bceaf72fd0d6ffad14ce4e3e00ca91a280bde.zip
This commit was generated by cvs2svn to compensate for changes in r2, which
included commits to RCS files with non-trunk default branches. git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@6 30ef5769-5b8d-40dd-aea6-55b5d6557bb3
Diffstat (limited to 'src/main/javassist/compiler/MemberCodeGen.java')
-rw-r--r--src/main/javassist/compiler/MemberCodeGen.java1045
1 files changed, 1045 insertions, 0 deletions
diff --git a/src/main/javassist/compiler/MemberCodeGen.java b/src/main/javassist/compiler/MemberCodeGen.java
new file mode 100644
index 00000000..d457a836
--- /dev/null
+++ b/src/main/javassist/compiler/MemberCodeGen.java
@@ -0,0 +1,1045 @@
+/*
+ * This file is part of the Javassist toolkit.
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * either http://www.mozilla.org/MPL/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * The Original Code is Javassist.
+ *
+ * The Initial Developer of the Original Code is Shigeru Chiba. Portions
+ * created by Shigeru Chiba are Copyright (C) 1999-2003 Shigeru Chiba.
+ * All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * The development of this software is supported in part by the PRESTO
+ * program (Sakigake Kenkyu 21) of Japan Science and Technology Corporation.
+ */
+
+package javassist.compiler;
+
+import java.util.List;
+import javassist.*;
+import javassist.bytecode.*;
+import javassist.compiler.ast.*;
+
+/* Code generator methods depending on javassist.* classes.
+ */
+public class MemberCodeGen extends CodeGen {
+ protected ClassPool classPool;
+ protected CtClass thisClass;
+ protected MethodInfo thisMethod;
+
+ protected boolean resultStatic;
+
+ public MemberCodeGen(Bytecode b, CtClass cc, ClassPool cp) {
+ super(b);
+ classPool = cp;
+ thisClass = cc;
+ thisMethod = null;
+ }
+
+ /**
+ * Records the currently compiled method.
+ */
+ public void setThisMethod(CtMethod m) {
+ thisMethod = m.getMethodInfo2();
+ }
+
+ public CtClass getThisClass() { return thisClass; }
+
+ /**
+ * Returns the JVM-internal representation of this class name.
+ */
+ protected String getThisName() {
+ return javaToJvmName(thisClass.getName());
+ }
+
+ /**
+ * Returns the JVM-internal representation of this super class name.
+ */
+ protected String getSuperName() throws CompileError {
+ return javaToJvmName(getSuperclass(thisClass).getName());
+ }
+
+ protected void insertDefaultSuperCall() throws CompileError {
+ bytecode.addAload(0);
+ bytecode.addInvokespecial(getSuperclass(thisClass), "<init>", "()V");
+ }
+
+ protected void atTryStmnt(Stmnt st) throws CompileError {
+ Stmnt body = (Stmnt)st.getLeft();
+ if (body == null)
+ return;
+
+ int start = bytecode.currentPc();
+ body.accept(this);
+ int end = bytecode.currentPc();
+
+ bytecode.addOpcode(Opcode.GOTO);
+ int pc = bytecode.currentPc();
+ bytecode.addIndex(0); // correct later
+
+ int var = getMaxLocals();
+ incMaxLocals(1);
+ ASTList catchList = (ASTList)st.getRight().getLeft();
+ while (catchList != null) {
+ Pair p = (Pair)catchList.head();
+ catchList = catchList.tail();
+ Declarator decl = (Declarator)p.getLeft();
+ Stmnt block = (Stmnt)p.getRight();
+
+ decl.setLocalVar(var);
+
+ CtClass type = lookupClass(decl.getClassName());
+ decl.setClassName(javaToJvmName(type.getName()));
+ bytecode.addExceptionHandler(start, end, bytecode.currentPc(),
+ type);
+ if (block != null) {
+ bytecode.addAstore(var);
+ block.accept(this);
+ }
+
+ bytecode.addOpcode(Opcode.GOTO);
+ bytecode.addIndex(pc - bytecode.currentPc());
+ }
+
+ Stmnt finallyBlock = (Stmnt)st.getRight().getRight().getLeft();
+ if (finallyBlock != null)
+ throw new CompileError(
+ "sorry, finally has not been supported yet");
+
+ bytecode.write16bit(pc, bytecode.currentPc() - pc + 1);
+ }
+
+ public void atNewExpr(NewExpr expr) throws CompileError {
+ if (expr.isArray())
+ atNewArrayExpr(expr);
+ else {
+ CtClass clazz = lookupClass(expr.getClassName());
+ String cname = clazz.getName();
+ ASTList args = expr.getArguments();
+ bytecode.addNew(cname);
+ bytecode.addOpcode(DUP);
+
+ atMethodCall2(clazz, MethodInfo.nameInit, args, false, true);
+
+ exprType = CLASS;
+ arrayDim = 0;
+ className = javaToJvmName(cname);
+ }
+ }
+
+ public void atNewArrayExpr(NewExpr expr) throws CompileError {
+ if (expr.getInitializer() != null)
+ throw new CompileError("array initializer is not supported");
+
+ int type = expr.getArrayType();
+ ASTList size = expr.getArraySize();
+ ASTList classname = expr.getClassName();
+ if (size.length() > 1) {
+ atMultiNewArray(type, classname, size);
+ return;
+ }
+
+ size.head().accept(this);
+ exprType = type;
+ arrayDim = 1;
+ if (type == CLASS) {
+ className = resolveClassName(classname);
+ bytecode.addAnewarray(jvmToJavaName(className));
+ }
+ else {
+ className = null;
+ int atype = 0;
+ switch (type) {
+ case BOOLEAN :
+ atype = T_BOOLEAN;
+ break;
+ case CHAR :
+ atype = T_CHAR;
+ break;
+ case FLOAT :
+ atype = T_FLOAT;
+ break;
+ case DOUBLE :
+ atype = T_DOUBLE;
+ break;
+ case BYTE :
+ atype = T_BYTE;
+ break;
+ case SHORT :
+ atype = T_SHORT;
+ break;
+ case INT :
+ atype = T_INT;
+ break;
+ case LONG :
+ atype = T_LONG;
+ break;
+ default :
+ badNewExpr();
+ break;
+ }
+
+ bytecode.addOpcode(NEWARRAY);
+ bytecode.add(atype);
+ }
+ }
+
+ private static void badNewExpr() throws CompileError {
+ throw new CompileError("bad new expression");
+ }
+
+ protected void atMultiNewArray(int type, ASTList classname, ASTList size)
+ throws CompileError
+ {
+ int count, dim;
+ dim = size.length();
+ for (count = 0; size != null; size = size.tail()) {
+ ASTree s = size.head();
+ if (s == null)
+ break; // int[][][] a = new int[3][4][];
+
+ ++count;
+ s.accept(this);
+ if (exprType != INT)
+ throw new CompileError("bad type for array size");
+ }
+
+ String desc;
+ exprType = type;
+ arrayDim = dim;
+ if (type == CLASS) {
+ className = resolveClassName(classname);
+ desc = toJvmArrayName(className, dim);
+ }
+ else
+ desc = toJvmTypeName(type, dim);
+
+ bytecode.addMultiNewarray(desc, count);
+ }
+
+ protected void atMethodCall(Expr expr) throws CompileError {
+ String mname = null;
+ CtClass targetClass = null;
+ ASTree method = expr.oprand1();
+ ASTList args = (ASTList)expr.oprand2();
+ boolean isStatic = false;
+ boolean isSpecial = false;
+
+ if (method instanceof Member) {
+ mname = ((Member)method).get();
+ targetClass = thisClass;
+ bytecode.addAload(0); // this
+ }
+ else if (method instanceof Keyword) { // constructor
+ isSpecial = true;
+ mname = MethodInfo.nameInit; // <init>
+ targetClass = thisClass;
+ bytecode.addAload(0); // this
+ if (((Keyword)method).get() == SUPER)
+ targetClass = getSuperclass(targetClass);
+ }
+ else if (method instanceof Expr) {
+ Expr e = (Expr)method;
+ mname = ((Symbol)e.oprand2()).get();
+ int op = e.getOperator();
+ if (op == MEMBER) { // static method
+ targetClass = lookupClass((ASTList)e.oprand1());
+ isStatic = true;
+ }
+ else if (op == '.') {
+ ASTree target = e.oprand1();
+ if (target instanceof Keyword)
+ if (((Keyword)target).get() == SUPER)
+ isSpecial = true;
+
+ try {
+ target.accept(this);
+ }
+ catch (NoFieldException nfe) {
+ if (nfe.getExpr() != target)
+ throw nfe;
+
+ // it should be a static method.
+ exprType = CLASS;
+ arrayDim = 0;
+ className = nfe.getField(); // JVM-internal
+ isStatic = true;
+ }
+
+ if (arrayDim > 0)
+ targetClass = lookupClass2(javaLangObject);
+ else if (exprType == CLASS /* && arrayDim == 0 */)
+ targetClass = lookupClass(className);
+ else
+ badMethod();
+ }
+ else
+ badMethod();
+ }
+ else
+ fatal();
+
+ atMethodCall2(targetClass, mname, args, isStatic, isSpecial);
+ }
+
+ private static void badMethod() throws CompileError {
+ throw new CompileError("bad method");
+ }
+
+ private static CtClass getSuperclass(CtClass c) throws CompileError {
+ try {
+ return c.getSuperclass();
+ }
+ catch (NotFoundException e) {
+ throw new CompileError("cannot find the super class of "
+ + c.getName());
+ }
+ }
+
+ public void atMethodCall2(CtClass targetClass, String mname,
+ ASTList args, boolean isStatic, boolean isSpecial)
+ throws CompileError
+ {
+ int nargs = atMethodArgsLength(args);
+ int[] types = new int[nargs];
+ int[] dims = new int[nargs];
+ String[] cnames = new String[nargs];
+
+ int stack = bytecode.getStackDepth();
+
+ atMethodArgs(args, types, dims, cnames);
+
+ // used by invokeinterface
+ int count = bytecode.getStackDepth() - stack + 1;
+
+ Object[] found = lookupMethod(targetClass, thisMethod, mname,
+ types, dims, cnames, false);
+ if (found == null) {
+ String msg;
+ if (mname.equals(MethodInfo.nameInit))
+ msg = "constructor not found";
+ else
+ msg = "Method " + mname + " not found in "
+ + targetClass.getName();
+
+ throw new CompileError(msg);
+ }
+
+ CtClass declClass = (CtClass)found[0];
+ MethodInfo minfo = (MethodInfo)found[1];
+ String desc = minfo.getDescriptor();
+ int acc = minfo.getAccessFlags();
+
+ if (mname.equals(MethodInfo.nameInit)) {
+ isSpecial = true;
+ if (declClass != targetClass)
+ throw new CompileError("no such a constructor");
+ }
+ else if ((acc & AccessFlag.PRIVATE) != 0) {
+ isSpecial = true;
+ if (declClass != targetClass)
+ throw new CompileError("Method " + mname + "is private");
+ }
+
+ boolean popTarget = false;
+ if ((acc & AccessFlag.STATIC) != 0) {
+ if (!isStatic) {
+ /* this method is static but the target object is
+ on stack. It must be popped out.
+ */
+ isStatic = true;
+ popTarget = true;
+ }
+
+ bytecode.addInvokestatic(declClass, mname, desc);
+ }
+ else if (isSpecial)
+ bytecode.addInvokespecial(declClass, mname, desc);
+ else if (declClass.isInterface())
+ bytecode.addInvokeinterface(declClass, mname, desc, count);
+ else
+ bytecode.addInvokevirtual(declClass, mname, desc);
+
+ setReturnType(desc, isStatic, popTarget);
+ }
+
+ public int atMethodArgsLength(ASTList args) {
+ return ASTList.length(args);
+ }
+
+ public void atMethodArgs(ASTList args, int[] types, int[] dims,
+ String[] cnames) throws CompileError {
+ int i = 0;
+ while (args != null) {
+ ASTree a = args.head();
+ a.accept(this);
+ types[i] = exprType;
+ dims[i] = arrayDim;
+ cnames[i] = className;
+ ++i;
+ args = args.tail();
+ }
+ }
+
+ private void setReturnType(String desc, boolean isStatic,
+ boolean popTarget)
+ throws CompileError
+ {
+ int i = desc.indexOf(')');
+ if (i < 0)
+ badMethod();
+
+ char c = desc.charAt(++i);
+ int dim = 0;
+ while (c == '[') {
+ ++dim;
+ c = desc.charAt(++i);
+ }
+
+ arrayDim = dim;
+ if (c == 'L') {
+ int j = desc.indexOf(';', i + 1);
+ if (j < 0)
+ badMethod();
+
+ exprType = CLASS;
+ className = desc.substring(i + 1, j);
+ }
+ else {
+ exprType = descToType(c);
+ className = null;
+ }
+
+ int etype = exprType;
+ if (isStatic) {
+ if (popTarget) {
+ if (is2word(etype, dim)) {
+ bytecode.addOpcode(DUP2_X1);
+ bytecode.addOpcode(POP2);
+ bytecode.addOpcode(POP);
+ }
+ else if (etype == VOID)
+ bytecode.addOpcode(POP);
+ else {
+ bytecode.addOpcode(SWAP);
+ bytecode.addOpcode(POP);
+ }
+ }
+ }
+ }
+
+ private Object[] lookupMethod(CtClass clazz, MethodInfo current,
+ String methodName,
+ int[] argTypes, int[] argDims,
+ String[] argClassNames, boolean onlyExact)
+ throws CompileError
+ {
+ Object[] maybe = null;
+
+ if (current != null)
+ if (current.getName().equals(methodName)) {
+ int res = compareSignature(current.getDescriptor(),
+ argTypes, argDims, argClassNames);
+ Object[] r = new Object[] { clazz, current };
+ if (res == YES)
+ return r;
+ else if (res == MAYBE && maybe == null)
+ maybe = r;
+ }
+
+ List list = clazz.getClassFile2().getMethods();
+ int n = list.size();
+ for (int i = 0; i < n; ++i) {
+ MethodInfo minfo = (MethodInfo)list.get(i);
+ if (minfo.getName().equals(methodName)) {
+ int res = compareSignature(minfo.getDescriptor(),
+ argTypes, argDims, argClassNames);
+ Object[] r = new Object[] { clazz, minfo };
+ if (res == YES)
+ return r;
+ else if (res == MAYBE && maybe == null)
+ maybe = r;
+ }
+ }
+
+ try {
+ CtClass pclazz = clazz.getSuperclass();
+ if (pclazz != null) {
+ Object[] r = lookupMethod(pclazz, null, methodName, argTypes,
+ argDims, argClassNames,
+ (onlyExact || maybe != null));
+ if (r != null)
+ return r;
+ }
+ }
+ catch (NotFoundException e) {}
+
+ /* -- not necessary to search implemented interfaces.
+ try {
+ CtClass[] ifs = clazz.getInterfaces();
+ int size = ifs.length;
+ for (int i = 0; i < size; ++i) {
+ Object[] r = lookupMethod(ifs[i], methodName, argTypes,
+ argDims, argClassNames);
+ if (r != null)
+ return r;
+ }
+ }
+ catch (NotFoundException e) {}
+ */
+
+ if (onlyExact)
+ return null;
+ else
+ return maybe;
+ }
+
+ private static final int YES = 2;
+ private static final int MAYBE = 1;
+ private static final int NO = 0;
+
+ /*
+ * Returns YES if actual parameter types matches the given signature.
+ *
+ * argTypes, argDims, and argClassNames represent actual parameters.
+ *
+ * This method does not correctly implement the Java method dispatch
+ * algorithm.
+ */
+ private int compareSignature(String desc, int[] argTypes,
+ int[] argDims, String[] argClassNames)
+ throws CompileError
+ {
+ int result = YES;
+ int i = 1;
+ int nArgs = argTypes.length;
+ if (nArgs != Descriptor.numOfParameters(desc))
+ return NO;
+
+ int len = desc.length();
+ for (int n = 0; i < len; ++n) {
+ char c = desc.charAt(i++);
+ if (c == ')')
+ return (n == nArgs ? result : NO);
+ else if (n >= nArgs)
+ return NO;
+
+ int dim = 0;
+ while (c == '[') {
+ ++dim;
+ c = desc.charAt(i++);
+ }
+
+ if (argTypes[n] == NULL) {
+ if (dim == 0 && c != 'L')
+ return NO;
+ }
+ else if (argDims[n] != dim) {
+ if (!(dim == 0 && c == 'L'
+ && desc.startsWith("java/lang/Object;", i)))
+ return NO;
+
+ // if the thread reaches here, c must be 'L'.
+ i = desc.indexOf(';', i) + 1;
+ result = MAYBE;
+ if (i <= 0)
+ return NO; // invalid descriptor?
+ }
+ else if (c == 'L') { // not compare
+ int j = desc.indexOf(';', i);
+ if (j < 0 || argTypes[n] != CLASS)
+ return NO;
+
+ String cname = desc.substring(i, j);
+ if (!cname.equals(argClassNames[n])) {
+ CtClass clazz = lookupClass(argClassNames[n]);
+ try {
+ if (clazz.subtypeOf(lookupClass(cname)))
+ result = MAYBE;
+ else
+ return NO;
+ }
+ catch (NotFoundException e) {
+ result = MAYBE; // should be NO?
+ }
+ }
+
+ i = j + 1;
+ }
+ else {
+ int t = descToType(c);
+ int at = argTypes[n];
+ if (t != at)
+ if (t == INT
+ && (at == SHORT || at == BYTE || at == CHAR))
+ result = MAYBE;
+ else
+ return NO;
+ }
+ }
+
+ return NO;
+ }
+
+ protected static int descToType(char c) throws CompileError {
+ switch (c) {
+ case 'Z' :
+ return BOOLEAN;
+ case 'C' :
+ return CHAR;
+ case 'B' :
+ return BYTE;
+ case 'S' :
+ return SHORT;
+ case 'I' :
+ return INT;
+ case 'J' :
+ return LONG;
+ case 'F' :
+ return FLOAT;
+ case 'D' :
+ return DOUBLE;
+ case 'V' :
+ return VOID;
+ case 'L' :
+ case '[' :
+ return CLASS;
+ default :
+ fatal();
+ return VOID;
+ }
+ }
+
+ protected void atFieldAssign(Expr expr, int op, ASTree left,
+ ASTree right, boolean doDup) throws CompileError
+ {
+ CtField f = fieldAccess(left);
+ boolean is_static = resultStatic;
+ if (op != '=' && !is_static)
+ bytecode.addOpcode(DUP);
+
+ int fi = atFieldRead(f, is_static, op == '=');
+ int fType = exprType;
+ int fDim = arrayDim;
+ String cname = className;
+
+ atAssignCore(expr, op, right, fType, fDim, cname);
+
+ boolean is2w = is2word(fType, fDim);
+ if (doDup) {
+ int dup_code;
+ if (is_static)
+ dup_code = (is2w ? DUP2 : DUP);
+ else
+ dup_code = (is2w ? DUP2_X1 : DUP_X1);
+
+ bytecode.addOpcode(dup_code);
+ }
+
+ if (is_static) {
+ bytecode.add(PUTSTATIC);
+ bytecode.growStack(is2w ? -2 : -1);
+ }
+ else {
+ bytecode.add(PUTFIELD);
+ bytecode.growStack(is2w ? -3 : -2);
+ }
+
+ bytecode.addIndex(fi);
+ exprType = fType;
+ arrayDim = fDim;
+ className = cname;
+ }
+
+ /* overwritten in JvstCodeGen.
+ */
+ public void atMember(Member mem) throws CompileError {
+ atFieldRead(mem);
+ }
+
+ protected void atFieldRead(ASTree expr) throws CompileError
+ {
+ CtField f = fieldAccess(expr);
+ boolean is_static = resultStatic;
+ atFieldRead(f, is_static, false);
+ }
+
+ private int atFieldRead(CtField f, boolean isStatic, boolean noRead)
+ throws CompileError
+ {
+ FieldInfo finfo = f.getFieldInfo2();
+ String type = finfo.getDescriptor();
+
+ int fi = addFieldrefInfo(f, finfo, type);
+
+ int i = 0;
+ char c = type.charAt(i);
+ boolean is2byte = (c == 'J' || c == 'D');
+ exprType = descToType(c);
+ arrayDim = 0;
+ if (c == '[') {
+ i = 1;
+ while ((c = type.charAt(i)) == '[')
+ ++i;
+
+ arrayDim = i;
+ }
+
+ if (c == 'L')
+ className = type.substring(i + 1, type.indexOf(';', i + 1));
+
+ if (noRead)
+ return fi;
+
+ if (isStatic) {
+ bytecode.add(GETSTATIC);
+ bytecode.growStack(is2byte ? 2 : 1);
+ }
+ else {
+ bytecode.add(GETFIELD);
+ bytecode.growStack(is2byte ? 1 : 0);
+ }
+
+ bytecode.addIndex(fi);
+ return fi;
+ }
+
+ protected int addFieldrefInfo(CtField f, FieldInfo finfo, String type) {
+ ConstPool cp = bytecode.getConstPool();
+ String cname = f.getDeclaringClass().getName();
+ int ci = cp.addClassInfo(cname);
+ String name = finfo.getName();
+ return cp.addFieldrefInfo(ci, name, type);
+ }
+
+ protected void atFieldPlusPlus(int token, boolean isPost,
+ ASTree oprand, Expr expr, boolean doDup)
+ throws CompileError
+ {
+ CtField f = fieldAccess(oprand);
+ boolean is_static = resultStatic;
+ if (!is_static)
+ bytecode.addOpcode(DUP);
+
+ int fi = atFieldRead(f, is_static, false);
+ int t = exprType;
+ boolean is2w = is2word(t, arrayDim);
+
+ int dup_code;
+ if (is_static)
+ dup_code = (is2w ? DUP2 : DUP);
+ else
+ dup_code = (is2w ? DUP2_X1 : DUP_X1);
+
+ atPlusPlusCore(dup_code, doDup, token, isPost, expr);
+
+ if (is_static) {
+ bytecode.add(PUTSTATIC);
+ bytecode.growStack(is2w ? -2 : -1);
+ }
+ else {
+ bytecode.add(PUTFIELD);
+ bytecode.growStack(is2w ? -3 : -2);
+ }
+
+ bytecode.addIndex(fi);
+ }
+
+ /* This method also returns a value in resultStatic.
+ */
+ protected CtField fieldAccess(ASTree expr) throws CompileError {
+ CtField f = null;
+ boolean is_static = false;
+ if (expr instanceof Member) {
+ String name = ((Member)expr).get();
+ try {
+ f = thisClass.getField(name);
+ }
+ catch (NotFoundException e) {
+ // EXPR might be part of a static member access?
+ throw new NoFieldException(name, expr);
+ }
+
+ is_static = Modifier.isStatic(f.getModifiers());
+ if (!is_static)
+ if (inStaticMethod)
+ throw new CompileError(
+ "not available in a static method: " + name);
+ else
+ bytecode.addAload(0); // this
+ }
+ else if (expr instanceof Expr) {
+ Expr e = (Expr)expr;
+ int op = e.getOperator();
+ if (op == MEMBER) {
+ f = lookupField((ASTList)e.oprand1(), (Symbol)e.oprand2());
+ is_static = true;
+ }
+ else if (op == '.') {
+ try {
+ e.oprand1().accept(this);
+ if (exprType == CLASS && arrayDim == 0)
+ f = lookupField(className, (Symbol)e.oprand2());
+ else
+ badLvalue();
+
+ is_static = Modifier.isStatic(f.getModifiers());
+ if (is_static)
+ bytecode.addOpcode(POP);
+ }
+ catch (NoFieldException nfe) {
+ if (nfe.getExpr() != e.oprand1())
+ throw nfe;
+
+ Symbol fname = (Symbol)e.oprand2();
+ // it should be a static field.
+ try {
+ f = lookupField(nfe.getField(), fname);
+ is_static = true;
+ }
+ catch (CompileError ce) {
+ // EXPR might be part of a qualified class name.
+ throw new NoFieldException(nfe.getField() + "/"
+ + fname.get(), expr);
+ }
+ }
+ }
+ else
+ badLvalue();
+ }
+ else
+ badLvalue();
+
+ resultStatic = is_static;
+ return f;
+ }
+
+ private static void badLvalue() throws CompileError {
+ throw new CompileError("bad l-value");
+ }
+
+ public CtClass[] makeParamList(MethodDecl md) throws CompileError {
+ CtClass[] params;
+ ASTList plist = md.getParams();
+ if (plist == null)
+ params = new CtClass[0];
+ else {
+ int i = 0;
+ params = new CtClass[plist.length()];
+ while (plist != null) {
+ params[i++] = lookupClass((Declarator)plist.head());
+ plist = plist.tail();
+ }
+ }
+
+ return params;
+ }
+
+ public CtClass[] makeThrowsList(MethodDecl md) throws CompileError {
+ CtClass[] clist;
+ ASTList list = md.getThrows();
+ if (list == null)
+ return null;
+ else {
+ int i = 0;
+ clist = new CtClass[list.length()];
+ while (list != null) {
+ clist[i++] = lookupClass((ASTList)list.head());
+ list = list.tail();
+ }
+
+ return clist;
+ }
+ }
+
+ public static int getModifiers(ASTList mods) {
+ int m = 0;
+ while (mods != null) {
+ Keyword k = (Keyword)mods.head();
+ mods = mods.tail();
+ switch (k.get()) {
+ case STATIC :
+ m |= Modifier.STATIC;
+ break;
+ case FINAL :
+ m |= Modifier.FINAL;
+ break;
+ case SYNCHRONIZED :
+ m |= Modifier.SYNCHRONIZED;
+ break;
+ case ABSTRACT :
+ m |= Modifier.ABSTRACT;
+ break;
+ case PUBLIC :
+ m |= Modifier.PUBLIC;
+ break;
+ case PROTECTED :
+ m |= Modifier.PROTECTED;
+ break;
+ case PRIVATE :
+ m |= Modifier.PRIVATE;
+ break;
+ case VOLATILE :
+ m |= Modifier.VOLATILE;
+ break;
+ case TRANSIENT :
+ m |= Modifier.TRANSIENT;
+ break;
+ case STRICT :
+ m |= Modifier.STRICT;
+ break;
+ }
+ }
+
+ return m;
+ }
+
+ /* Converts a class name into a JVM-internal representation.
+ *
+ * It may also expand a simple class name to java.lang.*.
+ * For example, this converts Object into java/lang/Object.
+ */
+ protected String resolveClassName(ASTList name) throws CompileError {
+ if (name == null)
+ return null;
+ else
+ return javaToJvmName(lookupClass(name).getName());
+ }
+
+ /* Expands a simple class name to java.lang.*.
+ * For example, this converts Object into java/lang/Object.
+ */
+ protected String resolveClassName(String jvmName) throws CompileError {
+ if (jvmName == null)
+ return null;
+ else
+ return javaToJvmName(lookupClass(jvmName).getName());
+ }
+
+ protected CtClass lookupClass(Declarator decl) throws CompileError {
+ return lookupClass(decl.getType(), decl.getArrayDim(),
+ decl.getClassName());
+ }
+
+ protected CtClass lookupClass(int type, int dim, String classname)
+ throws CompileError
+ {
+ String cname = "";
+ CtClass clazz;
+ switch (type) {
+ case CLASS :
+ clazz = lookupClass(classname);
+ if (dim > 0)
+ cname = clazz.getName();
+ else
+ return clazz;
+
+ break;
+ case BOOLEAN :
+ cname = "boolean";
+ break;
+ case CHAR :
+ cname = "char";
+ break;
+ case BYTE :
+ cname = "byte";
+ break;
+ case SHORT :
+ cname = "short";
+ break;
+ case INT :
+ cname = "int";
+ break;
+ case LONG :
+ cname = "long";
+ break;
+ case FLOAT :
+ cname = "float";
+ break;
+ case DOUBLE :
+ cname = "double";
+ break;
+ case VOID :
+ cname = "void";
+ break;
+ default :
+ fatal();
+ }
+
+ while (dim-- > 0)
+ cname += "[]";
+
+ return lookupClass2(cname);
+ }
+
+ protected CtClass lookupClass(ASTList name) throws CompileError {
+ return lookupClass2(Declarator.astToClassName(name, '.'));
+ }
+
+ protected CtClass lookupClass(String jvmName) throws CompileError {
+ return lookupClass2(jvmToJavaName(jvmName));
+ }
+
+ /**
+ * @param name a qualified class name. e.g. java.lang.String
+ */
+ private CtClass lookupClass2(String name) throws CompileError {
+ try {
+ return classPool.get(name);
+ }
+ catch (NotFoundException e) {}
+
+ try {
+ if (name.indexOf('.') < 0)
+ return classPool.get("java.lang." + name);
+ }
+ catch (NotFoundException e) {}
+
+ throw new CompileError("no such class: " + name);
+ }
+
+ public CtField lookupField(ASTList className, Symbol fieldName)
+ throws CompileError
+ {
+ return lookupField2(Declarator.astToClassName(className, '.'),
+ fieldName);
+ }
+
+ public CtField lookupField(String className, Symbol fieldName)
+ throws CompileError
+ {
+ return lookupField2(jvmToJavaName(className), fieldName);
+ }
+
+ /**
+ * @param name a qualified class name. e.g. java.lang.String
+ */
+ private CtField lookupField2(String className, Symbol fieldName)
+ throws CompileError
+ {
+ CtClass cc = lookupClass(className);
+ try {
+ return cc.getField(fieldName.get());
+ }
+ catch (NotFoundException e) {}
+ throw new CompileError("no such field: " + fieldName.get());
+ }
+
+ protected static String javaToJvmName(String classname) {
+ return classname.replace('.', '/');
+ }
+
+ protected static String jvmToJavaName(String classname) {
+ return classname.replace('/', '.');
+ }
+}