aboutsummaryrefslogtreecommitdiff
path: root/src/main/javassist/expr/FieldAccess.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/javassist/expr/FieldAccess.java')
-rw-r--r--src/main/javassist/expr/FieldAccess.java322
1 files changed, 322 insertions, 0 deletions
diff --git a/src/main/javassist/expr/FieldAccess.java b/src/main/javassist/expr/FieldAccess.java
new file mode 100644
index 0000000..56ead16
--- /dev/null
+++ b/src/main/javassist/expr/FieldAccess.java
@@ -0,0 +1,322 @@
+/*
+ * Javassist, a Java-bytecode translator toolkit.
+ * Copyright (C) 1999-2007 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 except try-catch.
+ */
+ public void replace(String statement) throws CannotCompileException {
+ thisClass.getClassFile(); // to call checkModify().
+ 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();
+ }
+ }
+}