123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321 |
- /*
- * Javassist, a Java-bytecode translator toolkit.
- * Copyright (C) 1999-2006 Shigeru Chiba. All Rights Reserved.
- *
- * 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. Alternatively, the contents of this file may be used under
- * the terms of the GNU Lesser General Public License Version 2.1 or later.
- *
- * 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.
- */
-
- 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;
-
- protected 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 signature of the field type.
- * The signature is represented by a character string
- * called field descriptor, which is defined in the JVM specification.
- *
- * @see javassist.bytecode.Descriptor#toCtClass(String, ClassPool)
- * @since 3.1
- */
- public String getSignature() {
- int index = iterator.u16bitAt(currentPos + 1);
- return getConstPool().getFieldrefType(index);
- }
-
- /**
- * 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);
- if (read)
- included = true;
-
- 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.recordLocalVariables(ca, pos);
-
- if (included)
- if (retType == CtClass.voidType) {
- bytecode.addOpcode(ACONST_NULL);
- bytecode.addAstore(retVar);
- }
- else {
- bytecode.addConstZero(retType);
- bytecode.addStore(retVar, retType); // initialize $_
- }
-
- 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);
- }
-
- public void setReturnType(JvstTypeChecker c, ASTList args)
- throws CompileError
- {
- c.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.getMethodArgsLength(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();
- }
-
- public void setReturnType(JvstTypeChecker c, ASTList args)
- throws CompileError
- {
- c.atMethodArgs(args, new int[1], new int[1], new String[1]);
- c.setType(CtClass.voidType);
- c.addNullIfVoid();
- }
- }
- }
|