001: /*
002: * Javassist, a Java-bytecode translator toolkit.
003: * Copyright (C) 1999-2006 Shigeru Chiba. All Rights Reserved.
004: *
005: * The contents of this file are subject to the Mozilla Public License Version
006: * 1.1 (the "License"); you may not use this file except in compliance with
007: * the License. Alternatively, the contents of this file may be used under
008: * the terms of the GNU Lesser General Public License Version 2.1 or later.
009: *
010: * Software distributed under the License is distributed on an "AS IS" basis,
011: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
012: * for the specific language governing rights and limitations under the
013: * License.
014: */
015:
016: package javassist.compiler;
017:
018: import javassist.*;
019: import javassist.bytecode.*;
020: import java.util.HashMap;
021:
022: /**
023: * AccessorMaker maintains accessors to private members of an enclosing
024: * class. It is necessary for compiling a method in an inner class.
025: */
026: public class AccessorMaker {
027: private CtClass clazz;
028: private int uniqueNumber;
029: private HashMap accessors;
030:
031: static final String lastParamType = "javassist.runtime.Inner";
032:
033: public AccessorMaker(CtClass c) {
034: clazz = c;
035: uniqueNumber = 1;
036: accessors = new HashMap();
037: }
038:
039: public String getConstructor(CtClass c, String desc, MethodInfo orig)
040: throws CompileError {
041: String key = "<init>:" + desc;
042: String consDesc = (String) accessors.get(key);
043: if (consDesc != null)
044: return consDesc; // already exists.
045:
046: consDesc = Descriptor.appendParameter(lastParamType, desc);
047: ClassFile cf = clazz.getClassFile(); // turn on the modified flag.
048: try {
049: ConstPool cp = cf.getConstPool();
050: ClassPool pool = clazz.getClassPool();
051: MethodInfo minfo = new MethodInfo(cp, MethodInfo.nameInit,
052: consDesc);
053: minfo.setAccessFlags(0);
054: minfo.addAttribute(new SyntheticAttribute(cp));
055: ExceptionsAttribute ea = orig.getExceptionsAttribute();
056: if (ea != null)
057: minfo.addAttribute(ea.copy(cp, null));
058:
059: CtClass[] params = Descriptor.getParameterTypes(desc, pool);
060: Bytecode code = new Bytecode(cp);
061: code.addAload(0);
062: int regno = 1;
063: for (int i = 0; i < params.length; ++i)
064: regno += code.addLoad(regno, params[i]);
065: code.setMaxLocals(regno + 1); // the last parameter is added.
066: code.addInvokespecial(clazz, MethodInfo.nameInit, desc);
067:
068: code.addReturn(null);
069: minfo.setCodeAttribute(code.toCodeAttribute());
070: cf.addMethod(minfo);
071: } catch (CannotCompileException e) {
072: throw new CompileError(e);
073: } catch (NotFoundException e) {
074: throw new CompileError(e);
075: }
076:
077: accessors.put(key, consDesc);
078: return consDesc;
079: }
080:
081: /**
082: * Returns the name of the method for accessing a private method.
083: *
084: * @param name the name of the private method.
085: * @param desc the descriptor of the private method.
086: * @param accDesc the descriptor of the accessor method. The first
087: * parameter type is <code>clazz</code>.
088: * If the private method is static,
089: * <code>accDesc<code> must be equal to <code>desc</code>.
090: *
091: * @param orig the method info of the private method.
092: * @return
093: */
094: public String getMethodAccessor(String name, String desc,
095: String accDesc, MethodInfo orig) throws CompileError {
096: String key = name + ":" + desc;
097: String accName = (String) accessors.get(key);
098: if (accName != null)
099: return accName; // already exists.
100:
101: ClassFile cf = clazz.getClassFile(); // turn on the modified flag.
102: accName = findAccessorName(cf);
103: try {
104: ConstPool cp = cf.getConstPool();
105: ClassPool pool = clazz.getClassPool();
106: MethodInfo minfo = new MethodInfo(cp, accName, accDesc);
107: minfo.setAccessFlags(AccessFlag.STATIC);
108: minfo.addAttribute(new SyntheticAttribute(cp));
109: ExceptionsAttribute ea = orig.getExceptionsAttribute();
110: if (ea != null)
111: minfo.addAttribute(ea.copy(cp, null));
112:
113: CtClass[] params = Descriptor.getParameterTypes(accDesc,
114: pool);
115: int regno = 0;
116: Bytecode code = new Bytecode(cp);
117: for (int i = 0; i < params.length; ++i)
118: regno += code.addLoad(regno, params[i]);
119:
120: code.setMaxLocals(regno);
121: if (desc == accDesc)
122: code.addInvokestatic(clazz, name, desc);
123: else
124: code.addInvokevirtual(clazz, name, desc);
125:
126: code.addReturn(Descriptor.getReturnType(desc, pool));
127: minfo.setCodeAttribute(code.toCodeAttribute());
128: cf.addMethod(minfo);
129: } catch (CannotCompileException e) {
130: throw new CompileError(e);
131: } catch (NotFoundException e) {
132: throw new CompileError(e);
133: }
134:
135: accessors.put(key, accName);
136: return accName;
137: }
138:
139: /**
140: * Returns the method_info representing the added getter.
141: */
142: public MethodInfo getFieldGetter(FieldInfo finfo, boolean is_static)
143: throws CompileError {
144: String fieldName = finfo.getName();
145: String key = fieldName + ":getter";
146: Object res = accessors.get(key);
147: if (res != null)
148: return (MethodInfo) res; // already exists.
149:
150: ClassFile cf = clazz.getClassFile(); // turn on the modified flag.
151: String accName = findAccessorName(cf);
152: try {
153: ConstPool cp = cf.getConstPool();
154: ClassPool pool = clazz.getClassPool();
155: String fieldType = finfo.getDescriptor();
156: String accDesc;
157: if (is_static)
158: accDesc = "()" + fieldType;
159: else
160: accDesc = "(" + Descriptor.of(clazz) + ")" + fieldType;
161:
162: MethodInfo minfo = new MethodInfo(cp, accName, accDesc);
163: minfo.setAccessFlags(AccessFlag.STATIC);
164: minfo.addAttribute(new SyntheticAttribute(cp));
165: Bytecode code = new Bytecode(cp);
166: if (is_static) {
167: code.addGetstatic(Bytecode.THIS, fieldName, fieldType);
168: } else {
169: code.addAload(0);
170: code.addGetfield(Bytecode.THIS, fieldName, fieldType);
171: code.setMaxLocals(1);
172: }
173:
174: code.addReturn(Descriptor.toCtClass(fieldType, pool));
175: minfo.setCodeAttribute(code.toCodeAttribute());
176: cf.addMethod(minfo);
177: accessors.put(key, minfo);
178: return minfo;
179: } catch (CannotCompileException e) {
180: throw new CompileError(e);
181: } catch (NotFoundException e) {
182: throw new CompileError(e);
183: }
184: }
185:
186: /**
187: * Returns the method_info representing the added setter.
188: */
189: public MethodInfo getFieldSetter(FieldInfo finfo, boolean is_static)
190: throws CompileError {
191: String fieldName = finfo.getName();
192: String key = fieldName + ":setter";
193: Object res = accessors.get(key);
194: if (res != null)
195: return (MethodInfo) res; // already exists.
196:
197: ClassFile cf = clazz.getClassFile(); // turn on the modified flag.
198: String accName = findAccessorName(cf);
199: try {
200: ConstPool cp = cf.getConstPool();
201: ClassPool pool = clazz.getClassPool();
202: String fieldType = finfo.getDescriptor();
203: String accDesc;
204: if (is_static)
205: accDesc = "(" + fieldType + ")V";
206: else
207: accDesc = "(" + Descriptor.of(clazz) + fieldType + ")V";
208:
209: MethodInfo minfo = new MethodInfo(cp, accName, accDesc);
210: minfo.setAccessFlags(AccessFlag.STATIC);
211: minfo.addAttribute(new SyntheticAttribute(cp));
212: Bytecode code = new Bytecode(cp);
213: int reg;
214: if (is_static) {
215: reg = code.addLoad(0, Descriptor.toCtClass(fieldType,
216: pool));
217: code.addPutstatic(Bytecode.THIS, fieldName, fieldType);
218: } else {
219: code.addAload(0);
220: reg = code.addLoad(1, Descriptor.toCtClass(fieldType,
221: pool)) + 1;
222: code.addPutfield(Bytecode.THIS, fieldName, fieldType);
223: }
224:
225: code.addReturn(null);
226: code.setMaxLocals(reg);
227: minfo.setCodeAttribute(code.toCodeAttribute());
228: cf.addMethod(minfo);
229: accessors.put(key, minfo);
230: return minfo;
231: } catch (CannotCompileException e) {
232: throw new CompileError(e);
233: } catch (NotFoundException e) {
234: throw new CompileError(e);
235: }
236: }
237:
238: private String findAccessorName(ClassFile cf) {
239: String accName;
240: do {
241: accName = "access$" + uniqueNumber++;
242: } while (cf.getMethod(accName) != null);
243: return accName;
244: }
245: }
|