KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javassist > expr > FieldAccess


1 /*
2  * Javassist, a Java-bytecode translator toolkit.
3  * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.
4  *
5  * The contents of this file are subject to the Mozilla Public License Version
6  * 1.1 (the "License"); you may not use this file except in compliance with
7  * the License. Alternatively, the contents of this file may be used under
8  * the terms of the GNU Lesser General Public License Version 2.1 or later.
9  *
10  * Software distributed under the License is distributed on an "AS IS" basis,
11  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12  * for the specific language governing rights and limitations under the
13  * License.
14  */

15
16 package javassist.expr;
17
18 import javassist.*;
19 import javassist.bytecode.*;
20 import javassist.compiler.*;
21 import javassist.compiler.ast.ASTList;
22
23 /**
24  * Expression for accessing a field.
25  */

26 public class FieldAccess extends Expr {
27     int opcode;
28
29     protected FieldAccess(int pos, CodeIterator i, CtClass declaring,
30                           MethodInfo m, int op) {
31         super(pos, i, declaring, m);
32         opcode = op;
33     }
34
35     /**
36      * Returns the method or constructor containing the field-access
37      * expression represented by this object.
38      */

39     public CtBehavior where() { return super.where(); }
40
41     /**
42      * Returns the line number of the source line containing the
43      * field access.
44      *
45      * @return -1 if this information is not available.
46      */

47     public int getLineNumber() {
48         return super.getLineNumber();
49     }
50
51     /**
52      * Returns the source file containing the field access.
53      *
54      * @return null if this information is not available.
55      */

56     public String JavaDoc getFileName() {
57         return super.getFileName();
58     }
59
60     /**
61      * Returns true if the field is static.
62      */

63     public boolean isStatic() {
64         return isStatic(opcode);
65     }
66
67     static boolean isStatic(int c) {
68         return c == Opcode.GETSTATIC || c == Opcode.PUTSTATIC;
69     }
70
71     /**
72      * Returns true if the field is read.
73      */

74     public boolean isReader() {
75         return opcode == Opcode.GETFIELD || opcode == Opcode.GETSTATIC;
76     }
77
78     /**
79      * Returns true if the field is written in.
80      */

81     public boolean isWriter() {
82         return opcode == Opcode.PUTFIELD || opcode == Opcode.PUTSTATIC;
83     }
84
85     /**
86      * Returns the class in which the field is declared.
87      */

88     private CtClass getCtClass() throws NotFoundException {
89         return thisClass.getClassPool().get(getClassName());
90     }
91
92     /**
93      * Returns the name of the class in which the field is declared.
94      */

95     public String JavaDoc getClassName() {
96         int index = iterator.u16bitAt(currentPos + 1);
97         return getConstPool().getFieldrefClassName(index);
98     }
99
100     /**
101      * Returns the name of the field.
102      */

103     public String JavaDoc getFieldName() {
104         int index = iterator.u16bitAt(currentPos + 1);
105         return getConstPool().getFieldrefName(index);
106     }
107
108     /**
109      * Returns the field accessed by this expression.
110      */

111     public CtField getField() throws NotFoundException {
112         CtClass cc = getCtClass();
113         return cc.getField(getFieldName());
114     }
115
116     /**
117      * Returns the list of exceptions that the expression may throw.
118      * This list includes both the exceptions that the try-catch statements
119      * including the expression can catch and the exceptions that
120      * the throws declaration allows the method to throw.
121      */

122     public CtClass[] mayThrow() {
123         return super.mayThrow();
124     }
125
126     /*
127      * Returns the type of the field.
128
129     public CtClass getFieldType() throws NotFoundException {
130         int index = iterator.u16bitAt(currentPos + 1);
131         String type = getConstPool().getFieldrefType(index);
132         return Descriptor.toCtClass(type, thisClass.getClassPool());
133     }
134     */

135
136     /**
137      * Replaces the method call with the bytecode derived from
138      * the given source text.
139      *
140      * <p>$0 is available even if the called method is static.
141      * If the field access is writing, $_ is available but the value
142      * of $_ is ignored.
143      *
144      * @param statement a Java statement.
145      */

146     public void replace(String JavaDoc statement) throws CannotCompileException {
147         ConstPool constPool = getConstPool();
148         int pos = currentPos;
149         int index = iterator.u16bitAt(pos + 1);
150
151         Javac jc = new Javac(thisClass);
152         CodeAttribute ca = iterator.get();
153         try {
154             CtClass[] params;
155             CtClass retType;
156             CtClass fieldType
157                 = Descriptor.toCtClass(constPool.getFieldrefType(index),
158                                        thisClass.getClassPool());
159             boolean read = isReader();
160             if (read) {
161                 params = new CtClass[0];
162                 retType = fieldType;
163             }
164             else {
165                 params = new CtClass[1];
166                 params[0] = fieldType;
167                 retType = CtClass.voidType;
168             }
169
170             int paramVar = ca.getMaxLocals();
171             jc.recordParams(constPool.getFieldrefClassName(index), params,
172                             true, paramVar, withinStatic());
173
174             /* Is $_ included in the source code?
175              */

176             boolean included = checkResultValue(retType, statement);
177             if (read)
178                 included = true;
179
180             int retVar = jc.recordReturnType(retType, included);
181             if (read)
182                 jc.recordProceed(new ProceedForRead(retType, opcode,
183                                                     index, paramVar));
184             else {
185                 // because $type is not the return type...
186
jc.recordType(fieldType);
187                 jc.recordProceed(new ProceedForWrite(params[0], opcode,
188                                                      index, paramVar));
189             }
190
191             Bytecode bytecode = jc.getBytecode();
192             storeStack(params, isStatic(), paramVar, bytecode);
193             jc.recordLocalVariables(ca, pos);
194
195             if (included)
196                 if (retType == CtClass.voidType) {
197                     bytecode.addOpcode(ACONST_NULL);
198                     bytecode.addAstore(retVar);
199                 }
200                 else {
201                     bytecode.addConstZero(retType);
202                     bytecode.addStore(retVar, retType); // initialize $_
203
}
204
205             jc.compileStmnt(statement);
206             if (read)
207                 bytecode.addLoad(retVar, retType);
208
209             replace0(pos, bytecode, 3);
210         }
211         catch (CompileError e) { throw new CannotCompileException(e); }
212         catch (NotFoundException e) { throw new CannotCompileException(e); }
213         catch (BadBytecode e) {
214             throw new CannotCompileException("broken method");
215         }
216     }
217
218     /* <field type> $proceed()
219      */

220     static class ProceedForRead implements ProceedHandler {
221         CtClass fieldType;
222         int opcode;
223         int targetVar, index;
224
225         ProceedForRead(CtClass type, int op, int i, int var) {
226             fieldType = type;
227             targetVar = var;
228             opcode = op;
229             index = i;
230         }
231
232         public void doit(JvstCodeGen gen, Bytecode bytecode, ASTList args)
233             throws CompileError
234         {
235             if (args != null && !gen.isParamListName(args))
236                 throw new CompileError(Javac.proceedName
237                         + "() cannot take a parameter for field reading");
238
239             int stack;
240             if (isStatic(opcode))
241                 stack = 0;
242             else {
243                 stack = -1;
244                 bytecode.addAload(targetVar);
245             }
246
247             if (fieldType instanceof CtPrimitiveType)
248                 stack += ((CtPrimitiveType)fieldType).getDataSize();
249             else
250                 ++stack;
251
252             bytecode.add(opcode);
253             bytecode.addIndex(index);
254             bytecode.growStack(stack);
255             gen.setType(fieldType);
256         }
257
258         public void setReturnType(JvstTypeChecker c, ASTList args)
259             throws CompileError
260         {
261             c.setType(fieldType);
262         }
263     }
264
265     /* void $proceed(<field type>)
266      * the return type is not the field type but void.
267      */

268     static class ProceedForWrite implements ProceedHandler {
269         CtClass fieldType;
270         int opcode;
271         int targetVar, index;
272
273         ProceedForWrite(CtClass type, int op, int i, int var) {
274             fieldType = type;
275             targetVar = var;
276             opcode = op;
277             index = i;
278         }
279
280         public void doit(JvstCodeGen gen, Bytecode bytecode, ASTList args)
281             throws CompileError
282         {
283             if (gen.getMethodArgsLength(args) != 1)
284                 throw new CompileError(Javac.proceedName
285                         + "() cannot take more than one parameter "
286                         + "for field writing");
287
288             int stack;
289             if (isStatic(opcode))
290                 stack = 0;
291             else {
292                 stack = -1;
293                 bytecode.addAload(targetVar);
294             }
295
296             gen.atMethodArgs(args, new int[1], new int[1], new String JavaDoc[1]);
297             gen.doNumCast(fieldType);
298             if (fieldType instanceof CtPrimitiveType)
299                 stack -= ((CtPrimitiveType)fieldType).getDataSize();
300             else
301                 --stack;
302
303             bytecode.add(opcode);
304             bytecode.addIndex(index);
305             bytecode.growStack(stack);
306             gen.setType(CtClass.voidType);
307             gen.addNullIfVoid();
308         }
309
310         public void setReturnType(JvstTypeChecker c, ASTList args)
311             throws CompileError
312         {
313             c.atMethodArgs(args, new int[1], new int[1], new String JavaDoc[1]);
314             c.setType(CtClass.voidType);
315             c.addNullIfVoid();
316         }
317     }
318 }
319
Popular Tags