1 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 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 39 public CtBehavior where() { return super.where(); } 40 41 47 public int getLineNumber() { 48 return super.getLineNumber(); 49 } 50 51 56 public String getFileName() { 57 return super.getFileName(); 58 } 59 60 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 74 public boolean isReader() { 75 return opcode == Opcode.GETFIELD || opcode == Opcode.GETSTATIC; 76 } 77 78 81 public boolean isWriter() { 82 return opcode == Opcode.PUTFIELD || opcode == Opcode.PUTSTATIC; 83 } 84 85 88 private CtClass getCtClass() throws NotFoundException { 89 return thisClass.getClassPool().get(getClassName()); 90 } 91 92 95 public String getClassName() { 96 int index = iterator.u16bitAt(currentPos + 1); 97 return getConstPool().getFieldrefClassName(index); 98 } 99 100 103 public String getFieldName() { 104 int index = iterator.u16bitAt(currentPos + 1); 105 return getConstPool().getFieldrefName(index); 106 } 107 108 111 public CtField getField() throws NotFoundException { 112 CtClass cc = getCtClass(); 113 return cc.getField(getFieldName()); 114 } 115 116 122 public CtClass[] mayThrow() { 123 return super.mayThrow(); 124 } 125 126 135 136 146 public void replace(String 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 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 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); } 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 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 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 [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 [1]); 314 c.setType(CtClass.voidType); 315 c.addNullIfVoid(); 316 } 317 } 318 } 319 | Popular Tags |