diff options
Diffstat (limited to 'src/main/javassist/expr/FieldAccess.java')
-rw-r--r-- | src/main/javassist/expr/FieldAccess.java | 300 |
1 files changed, 300 insertions, 0 deletions
diff --git a/src/main/javassist/expr/FieldAccess.java b/src/main/javassist/expr/FieldAccess.java new file mode 100644 index 00000000..a524b07d --- /dev/null +++ b/src/main/javassist/expr/FieldAccess.java @@ -0,0 +1,300 @@ +/* + * 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.expr; + +import javassist.*; +import javassist.bytecode.*; +import javassist.compiler.*; +import javassist.compiler.ast.ASTList; + +/** + * Expression for accessing a field. + */ +public class FieldAccess extends Expr { + int opcode; + + FieldAccess(int pos, CodeIterator i, CtClass declaring, MethodInfo m, + int op) { + super(pos, i, declaring, m); + opcode = op; + } + + /** + * Returns the method or constructor containing the field-access + * expression represented by this object. + */ + public CtBehavior where() { return super.where(); } + + /** + * Returns the line number of the source line containing the + * field access. + * + * @return -1 if this information is not available. + */ + public int getLineNumber() { + return super.getLineNumber(); + } + + /** + * Returns the source file containing the field access. + * + * @return null if this information is not available. + */ + public String getFileName() { + return super.getFileName(); + } + + /** + * Returns true if the field is static. + */ + public boolean isStatic() { + return isStatic(opcode); + } + + static boolean isStatic(int c) { + return c == Opcode.GETSTATIC || c == Opcode.PUTSTATIC; + } + + /** + * Returns true if the field is read. + */ + public boolean isReader() { + return opcode == Opcode.GETFIELD || opcode == Opcode.GETSTATIC; + } + + /** + * Returns true if the field is written in. + */ + public boolean isWriter() { + return opcode == Opcode.PUTFIELD || opcode == Opcode.PUTSTATIC; + } + + /** + * Returns the class in which the field is declared. + */ + private CtClass getCtClass() throws NotFoundException { + return thisClass.getClassPool().get(getClassName()); + } + + /** + * Returns the name of the class in which the field is declared. + */ + public String getClassName() { + int index = iterator.u16bitAt(currentPos + 1); + return getConstPool().getFieldrefClassName(index); + } + + /** + * Returns the name of the field. + */ + public String getFieldName() { + int index = iterator.u16bitAt(currentPos + 1); + return getConstPool().getFieldrefName(index); + } + + /** + * Returns the field accessed by this expression. + */ + public CtField getField() throws NotFoundException { + CtClass cc = getCtClass(); + return cc.getField(getFieldName()); + } + + /** + * Returns the list of exceptions that the expression may throw. + * This list includes both the exceptions that the try-catch statements + * including the expression can catch and the exceptions that + * the throws declaration allows the method to throw. + */ + public CtClass[] mayThrow() { + return super.mayThrow(); + } + + /* + * Returns the type of the field. + + public CtClass getFieldType() throws NotFoundException { + int index = iterator.u16bitAt(currentPos + 1); + String type = getConstPool().getFieldrefType(index); + return Descriptor.toCtClass(type, thisClass.getClassPool()); + } + */ + + /** + * Replaces the method call with the bytecode derived from + * the given source text. + * + * <p>$0 is available even if the called method is static. + * If the field access is writing, $_ is available but the value + * of $_ is ignored. + * + * @param statement a Java statement. + */ + public void replace(String statement) throws CannotCompileException { + ConstPool constPool = getConstPool(); + int pos = currentPos; + int index = iterator.u16bitAt(pos + 1); + + Javac jc = new Javac(thisClass); + CodeAttribute ca = iterator.get(); + try { + CtClass[] params; + CtClass retType; + CtClass fieldType + = Descriptor.toCtClass(constPool.getFieldrefType(index), + thisClass.getClassPool()); + boolean read = isReader(); + if (read) { + params = new CtClass[0]; + retType = fieldType; + } + else { + params = new CtClass[1]; + params[0] = fieldType; + retType = CtClass.voidType; + } + + int paramVar = ca.getMaxLocals(); + jc.recordParams(constPool.getFieldrefClassName(index), params, + true, paramVar, withinStatic()); + + /* Is $_ included in the source code? + */ + boolean included = checkResultValue(retType, statement); + + int retVar = jc.recordReturnType(retType, included); + if (read) + jc.recordProceed(new ProceedForRead(retType, opcode, + index, paramVar)); + else { + // because $type is not the return type... + jc.recordType(fieldType); + jc.recordProceed(new ProceedForWrite(params[0], opcode, + index, paramVar)); + } + + Bytecode bytecode = jc.getBytecode(); + storeStack(params, isStatic(), paramVar, bytecode); + jc.compileStmnt(statement); + if (read) + bytecode.addLoad(retVar, retType); + + replace0(pos, bytecode, 3); + } + catch (CompileError e) { throw new CannotCompileException(e); } + catch (NotFoundException e) { throw new CannotCompileException(e); } + catch (BadBytecode e) { + throw new CannotCompileException("broken method"); + } + } + + /* <field type> $proceed() + */ + static class ProceedForRead implements ProceedHandler { + CtClass fieldType; + int opcode; + int targetVar, index; + + ProceedForRead(CtClass type, int op, int i, int var) { + fieldType = type; + targetVar = var; + opcode = op; + index = i; + } + + public void doit(JvstCodeGen gen, Bytecode bytecode, ASTList args) + throws CompileError + { + if (args != null && !gen.isParamListName(args)) + throw new CompileError(Javac.proceedName + + "() cannot take a parameter for field reading"); + + int stack; + if (isStatic(opcode)) + stack = 0; + else { + stack = -1; + bytecode.addAload(targetVar); + } + + if (fieldType instanceof CtPrimitiveType) + stack += ((CtPrimitiveType)fieldType).getDataSize(); + else + ++stack; + + bytecode.add(opcode); + bytecode.addIndex(index); + bytecode.growStack(stack); + gen.setType(fieldType); + } + } + + /* void $proceed(<field type>) + * the return type is not the field type but void. + */ + static class ProceedForWrite implements ProceedHandler { + CtClass fieldType; + int opcode; + int targetVar, index; + + ProceedForWrite(CtClass type, int op, int i, int var) { + fieldType = type; + targetVar = var; + opcode = op; + index = i; + } + + public void doit(JvstCodeGen gen, Bytecode bytecode, ASTList args) + throws CompileError + { + if (gen.atMethodArgsLength(args) != 1) + throw new CompileError(Javac.proceedName + + "() cannot take more than one parameter " + + "for field writing"); + + int stack; + if (isStatic(opcode)) + stack = 0; + else { + stack = -1; + bytecode.addAload(targetVar); + } + + gen.atMethodArgs(args, new int[1], new int[1], new String[1]); + gen.doNumCast(fieldType); + if (fieldType instanceof CtPrimitiveType) + stack -= ((CtPrimitiveType)fieldType).getDataSize(); + else + --stack; + + bytecode.add(opcode); + bytecode.addIndex(index); + bytecode.growStack(stack); + gen.setType(CtClass.voidType); + gen.addNullIfVoid(); + } + } +} |