diff options
author | patriot1burke <patriot1burke@30ef5769-5b8d-40dd-aea6-55b5d6557bb3> | 2003-04-22 13:47:06 +0000 |
---|---|---|
committer | patriot1burke <patriot1burke@30ef5769-5b8d-40dd-aea6-55b5d6557bb3> | 2003-04-22 13:47:06 +0000 |
commit | 069bceaf72fd0d6ffad14ce4e3e00ca91a280bde (patch) | |
tree | b8230a15d3061c64d5a64bf9efa654d0d6311ff2 /src/main/javassist/expr | |
parent | f610083ba0adbcb3fe92a504015fb26fb5a42530 (diff) | |
download | javassist-069bceaf72fd0d6ffad14ce4e3e00ca91a280bde.tar.gz javassist-069bceaf72fd0d6ffad14ce4e3e00ca91a280bde.zip |
This commit was generated by cvs2svn to compensate for changes in r2, which
included commits to RCS files with non-trunk default branches.
git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@6 30ef5769-5b8d-40dd-aea6-55b5d6557bb3
Diffstat (limited to 'src/main/javassist/expr')
-rw-r--r-- | src/main/javassist/expr/Cast.java | 162 | ||||
-rw-r--r-- | src/main/javassist/expr/Expr.java | 223 | ||||
-rw-r--r-- | src/main/javassist/expr/ExprEditor.java | 211 | ||||
-rw-r--r-- | src/main/javassist/expr/FieldAccess.java | 300 | ||||
-rw-r--r-- | src/main/javassist/expr/Instanceof.java | 165 | ||||
-rw-r--r-- | src/main/javassist/expr/MethodCall.java | 220 | ||||
-rw-r--r-- | src/main/javassist/expr/NewExpr.java | 224 |
7 files changed, 1505 insertions, 0 deletions
diff --git a/src/main/javassist/expr/Cast.java b/src/main/javassist/expr/Cast.java new file mode 100644 index 00000000..44648e78 --- /dev/null +++ b/src/main/javassist/expr/Cast.java @@ -0,0 +1,162 @@ +/* + * 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; + +/** + * Explicit type cast. + */ +public class Cast extends Expr { + /** + * Undocumented constructor. Do not use; internal-use only. + */ + Cast(int pos, CodeIterator i, CtClass declaring, MethodInfo m) { + super(pos, i, declaring, m); + } + + /** + * Returns the method or constructor containing the type cast + * expression represented by this object. + */ + public CtBehavior where() { return super.where(); } + + /** + * Returns the line number of the source line containing the + * type-cast expression. + * + * @return -1 if this information is not available. + */ + public int getLineNumber() { + return super.getLineNumber(); + } + + /** + * Returns the source file containing the type-cast expression. + * + * @return null if this information is not available. + */ + public String getFileName() { + return super.getFileName(); + } + + /** + * Returns the <code>CtClass</code> object representing + * the type specified by the cast. + */ + public CtClass getType() throws NotFoundException { + ConstPool cp = getConstPool(); + int pos = currentPos; + int index = iterator.u16bitAt(pos + 1); + String name = cp.getClassInfo(index); + return Descriptor.toCtClass(name, thisClass.getClassPool()); + } + + /** + * 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(); + } + + /** + * Replaces the explicit cast operator with the bytecode derived from + * the given source text. + * + * <p>$0 is available but the value is <code>null</code>. + * + * @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); + ClassPool cp = thisClass.getClassPool(); + CodeAttribute ca = iterator.get(); + + try { + CtClass[] params + = new CtClass[] { cp.get(javaLangObject) }; + CtClass retType = getType(); + + int paramVar = ca.getMaxLocals(); + jc.recordParams(javaLangObject, params, true, paramVar, + withinStatic()); + int retVar = jc.recordReturnType(retType, true); + jc.recordProceed(new ProceedForCast(index, retType)); + + /* Is $_ included in the source code? + */ + checkResultValue(retType, statement); + + Bytecode bytecode = jc.getBytecode(); + storeStack(params, true, paramVar, bytecode); + jc.compileStmnt(statement); + 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"); + } + } + + /* <type> $proceed(Object obj) + */ + static class ProceedForCast implements ProceedHandler { + int index; + CtClass retType; + + ProceedForCast(int i, CtClass t) { + index = i; + retType = t; + } + + 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 cast"); + + gen.atMethodArgs(args, new int[1], new int[1], new String[1]); + bytecode.addOpcode(Opcode.CHECKCAST); + bytecode.addIndex(index); + gen.setType(retType); + } + } +} diff --git a/src/main/javassist/expr/Expr.java b/src/main/javassist/expr/Expr.java new file mode 100644 index 00000000..d88d7939 --- /dev/null +++ b/src/main/javassist/expr/Expr.java @@ -0,0 +1,223 @@ +/* + * 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 java.util.LinkedList; +import java.util.Iterator; + +/** + * Caller-side expression. + */ +abstract class Expr implements Opcode { + int currentPos; + CodeIterator iterator; + CtClass thisClass; + MethodInfo thisMethod; + + boolean edited; + int maxLocals, maxStack; + + static final String javaLangObject = "java.lang.Object"; + + Expr(int pos, CodeIterator i, CtClass declaring, MethodInfo m) { + currentPos = pos; + iterator = i; + thisClass = declaring; + thisMethod = m; + } + + final ConstPool getConstPool() { + return thisMethod.getConstPool(); + } + + final boolean edited() { return edited; } + + final int locals() { return maxLocals; } + + final int stack() { return maxStack; } + + /** + * Returns true if this method is static. + */ + final boolean withinStatic() { + return (thisMethod.getAccessFlags() & AccessFlag.STATIC) != 0; + } + + /** + * Returns the constructor or method containing the expression. + */ + public CtBehavior where() { + MethodInfo mi = thisMethod; + CtBehavior[] cb = thisClass.getDeclaredBehaviors(); + for (int i = cb.length - 1; i >= 0; --i) + if (cb[i].getMethodInfo() == mi) + return cb[i]; + + throw new RuntimeException("fatal: not found"); + } + + /** + * 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() { + ClassPool pool = thisClass.getClassPool(); + ConstPool cp = thisMethod.getConstPool(); + LinkedList list = new LinkedList(); + try { + CodeAttribute ca = thisMethod.getCodeAttribute(); + ExceptionTable et = ca.getExceptionTable(); + int pos = currentPos; + int n = et.size(); + for (int i = 0; i < n; ++i) + if (et.startPc(i) <= pos && pos < et.endPc(i)) { + int t = et.catchType(i); + if (t > 0) + try { + addClass(list, pool.get(cp.getClassInfo(t))); + } + catch (NotFoundException e) {} + } + } + catch (NullPointerException e) {} + + ExceptionsAttribute ea = thisMethod.getExceptionsAttribute(); + if (ea != null) { + String[] exceptions = ea.getExceptions(); + if (exceptions != null) { + int n = exceptions.length; + for (int i = 0; i < n; ++i) + try { + addClass(list, pool.get(exceptions[i])); + } + catch (NotFoundException e) {} + } + } + + return (CtClass[])list.toArray(new CtClass[list.size()]); + } + + private static void addClass(LinkedList list, CtClass c) { + Iterator it = list.iterator(); + while (it.hasNext()) + if (it.next() == c) + return; + + list.add(c); + } + + /** + * Returns the line number of the source line containing the + * expression. + * + * @return -1 if this information is not available. + */ + public int getLineNumber() { + return thisMethod.getLineNumber(currentPos); + } + + /** + * Returns the source file containing the expression. + * + * @return null if this information is not available. + */ + public String getFileName() { + ClassFile cf = thisClass.getClassFile2(); + if (cf == null) + return null; + else + return cf.getSourceFile(); + } + + static final boolean checkResultValue(CtClass retType, String prog) + throws CannotCompileException + { + /* Is $_ included in the source code? + */ + boolean hasIt = (prog.indexOf(Javac.resultVarName) >= 0); + if (!hasIt && retType != CtClass.voidType) + throw new CannotCompileException( + "the resulting value is not stored in " + + Javac.resultVarName); + + return hasIt; + } + + /* If isStaticCall is true, null is assigned to $0. So $0 must + * be declared by calling Javac.recordParams(). + * + * After executing this method, the current stack depth might + * be less than 0. + */ + static final void storeStack(CtClass[] params, boolean isStaticCall, + int regno, Bytecode bytecode) { + storeStack0(0, params.length, params, regno + 1, bytecode); + if (isStaticCall) + bytecode.addOpcode(ACONST_NULL); + + bytecode.addAstore(regno); + } + + private static void storeStack0(int i, int n, CtClass[] params, + int regno, Bytecode bytecode) { + if (i >= n) + return; + else { + CtClass c = params[i]; + int size; + if (c instanceof CtPrimitiveType) + size = ((CtPrimitiveType)c).getDataSize(); + else + size = 1; + + storeStack0(i + 1, n, params, regno + size, bytecode); + bytecode.addStore(regno, c); + } + } + + protected void replace0(int pos, Bytecode bytecode, int size) + throws BadBytecode + { + byte[] code = bytecode.get(); + edited = true; + int gap = code.length - size; + if (gap > 0) + iterator.insertGap(pos, gap); + else + for (int i = 0; i < size; ++i) + iterator.writeByte(NOP, pos + i); + + iterator.write(code, pos); + iterator.insert(bytecode.getExceptionTable(), pos); + maxLocals = bytecode.getMaxLocals(); + maxStack = bytecode.getMaxStack(); + } +} diff --git a/src/main/javassist/expr/ExprEditor.java b/src/main/javassist/expr/ExprEditor.java new file mode 100644 index 00000000..c6814ef5 --- /dev/null +++ b/src/main/javassist/expr/ExprEditor.java @@ -0,0 +1,211 @@ +/* + * 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.bytecode.*; +import javassist.CtClass; +import javassist.CannotCompileException; + +/** + * A translator of method bodies. + * + * <p>The users can define a subclass of this class to customize how to + * modify a method body. The overall architecture is similar to the + * strategy pattern. + * + * <p>If <code>instrument()</code> is called in + * <code>CtMethod</code>, the method body is scanned from the beginning + * to the end. + * Whenever an expression, such as a method call and a <tt>new</tt> + * expression (object creation), + * is found, <code>edit()</code> is called in <code>ExprEdit</code>. + * <code>edit()</code> can inspect and modify the given expression. + * The modification is reflected on the original method body. If + * <code>edit()</code> does nothing, the original method body is not + * changed. + * + * <p>The following code is an example: + * + * <ul><pre> + * CtMethod cm = ...; + * cm.instrument(new ExprEditor() { + * public void edit(MethodCall m) throws CannotCompileException { + * if (m.getClassName().equals("Point")) { + * System.out.println(m.getMethodName() + " line: " + * + m.getLineNumber()); + * } + * }); + * </pre></ul> + * + * <p>This code inspects all method calls appearing in the method represented + * by <code>cm</code> and it prints the names and the line numbers of the + * methods declared in class <code>Point</code>. This code does not modify + * the body of the method represented by <code>cm</code>. If the method + * body must be modified, call <code>replace()</code> + * in <code>MethodCall</code>. + * + * @see javassist.CtClass#instrument(ExprEditor) + * @see javassist.CtMethod#instrument(ExprEditor) + * @see javassist.CtConstructor#instrument(ExprEditor) + * @see MethodCall + * @see NewExpr + * @see FieldAccess + * + * @see javassist.CodeConverter + */ +public class ExprEditor { + /** + * Default constructor. It does nothing. + */ + public ExprEditor() {} + + static class NewOp { + NewOp next; + int pos; + String type; + + NewOp(NewOp n, int p, String t) { + next = n; + pos = p; + type = t; + } + } + + /** + * Undocumented method. Do not use; internal-use only. + */ + public boolean doit(CtClass clazz, MethodInfo minfo) + throws CannotCompileException + { + CodeAttribute codeAttr = minfo.getCodeAttribute(); + if (codeAttr == null) + return false; + + CodeIterator iterator = codeAttr.iterator(); + boolean edited = false; + int maxLocals = codeAttr.getMaxLocals(); + int maxStack = 0; + + NewOp newList = null; + ConstPool cp = minfo.getConstPool(); + + while (iterator.hasNext()) + try { + Expr expr = null; + int pos = iterator.next(); + int c = iterator.byteAt(pos); + + if (c == Opcode.INVOKESTATIC || c == Opcode.INVOKEINTERFACE + || c == Opcode.INVOKEVIRTUAL) { + expr = new MethodCall(pos, iterator, clazz, minfo); + edit((MethodCall)expr); + } + else if (c == Opcode.GETFIELD || c == Opcode.GETSTATIC + || c == Opcode.PUTFIELD || c == Opcode.PUTSTATIC) { + expr = new FieldAccess(pos, iterator, clazz, minfo, c); + edit((FieldAccess)expr); + } + else if (c == Opcode.NEW) { + int index = iterator.u16bitAt(pos + 1); + newList = new NewOp(newList, pos, + cp.getClassInfo(index)); + } + else if (c == Opcode.INVOKESPECIAL) { + if (newList != null && cp.isConstructor(newList.type, + iterator.u16bitAt(pos + 1)) > 0) { + expr = new NewExpr(pos, iterator, clazz, minfo, + newList.type, newList.pos); + edit((NewExpr)expr); + newList = newList.next; + } + else { + expr = new MethodCall(pos, iterator, clazz, minfo); + MethodCall mcall = (MethodCall)expr; + if (!mcall.getMethodName().equals( + MethodInfo.nameInit)) + edit(mcall); + } + } + else if (c == Opcode.INSTANCEOF) { + expr = new Instanceof(pos, iterator, clazz, minfo); + edit((Instanceof)expr); + } + else if (c == Opcode.CHECKCAST) { + expr = new Cast(pos, iterator, clazz, minfo); + edit((Cast)expr); + } + + if (expr != null && expr.edited()) { + edited = true; + if (maxLocals < expr.locals()) + maxLocals = expr.locals(); + + if (maxStack < expr.stack()) + maxStack = expr.stack(); + } + } + catch (BadBytecode e) { + throw new CannotCompileException(e); + } + + codeAttr.setMaxLocals(maxLocals); + codeAttr.setMaxStack(codeAttr.getMaxStack() + maxStack); + return edited; + } + + /** + * Edits a <tt>new</tt> expression (overridable). + * The default implementation performs nothing. + * + * @param e the <tt>new</tt> expression creating an object. + */ + public void edit(NewExpr e) throws CannotCompileException {} + + /** + * Edits a method call (overridable). + * The default implementation performs nothing. + */ + public void edit(MethodCall m) throws CannotCompileException {} + + /** + * Edits a field-access expression (overridable). + * Field access means both read and write. + * The default implementation performs nothing. + */ + public void edit(FieldAccess f) throws CannotCompileException {} + + /** + * Edits an instanceof expression (overridable). + * The default implementation performs nothing. + */ + public void edit(Instanceof i) throws CannotCompileException {} + + /** + * Edits an expression for explicit type casting (overridable). + * The default implementation performs nothing. + */ + public void edit(Cast c) throws CannotCompileException {} +} 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(); + } + } +} diff --git a/src/main/javassist/expr/Instanceof.java b/src/main/javassist/expr/Instanceof.java new file mode 100644 index 00000000..5b980f8e --- /dev/null +++ b/src/main/javassist/expr/Instanceof.java @@ -0,0 +1,165 @@ +/* + * 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; + +/** + * Instanceof operator. + */ +public class Instanceof extends Expr { + /** + * Undocumented constructor. Do not use; internal-use only. + */ + Instanceof(int pos, CodeIterator i, CtClass declaring, MethodInfo m) { + super(pos, i, declaring, m); + } + + /** + * Returns the method or constructor containing the instanceof + * expression represented by this object. + */ + public CtBehavior where() { return super.where(); } + + /** + * Returns the line number of the source line containing the + * instanceof expression. + * + * @return -1 if this information is not available. + */ + public int getLineNumber() { + return super.getLineNumber(); + } + + /** + * Returns the source file containing the + * instanceof expression. + * + * @return null if this information is not available. + */ + public String getFileName() { + return super.getFileName(); + } + + /** + * Returns the <code>CtClass</code> object representing + * the type name on the right hand side + * of the instanceof operator. + */ + public CtClass getType() throws NotFoundException { + ConstPool cp = getConstPool(); + int pos = currentPos; + int index = iterator.u16bitAt(pos + 1); + String name = cp.getClassInfo(index); + return Descriptor.toCtClass(name, thisClass.getClassPool()); + } + + /** + * 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(); + } + + /** + * Replaces the instanceof operator with the bytecode derived from + * the given source text. + * + * <p>$0 is available but the value is <code>null</code>. + * + * @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); + ClassPool cp = thisClass.getClassPool(); + CodeAttribute ca = iterator.get(); + + try { + CtClass[] params + = new CtClass[] { cp.get(javaLangObject) }; + CtClass retType = CtClass.booleanType; + + int paramVar = ca.getMaxLocals(); + jc.recordParams(javaLangObject, params, true, paramVar, + withinStatic()); + int retVar = jc.recordReturnType(retType, true); + jc.recordProceed(new ProceedForInstanceof(index)); + + // because $type is not the return type... + jc.recordType(getType()); + + /* Is $_ included in the source code? + */ + checkResultValue(retType, statement); + + Bytecode bytecode = jc.getBytecode(); + storeStack(params, true, paramVar, bytecode); + jc.compileStmnt(statement); + 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"); + } + } + + /* boolean $proceed(Object obj) + */ + static class ProceedForInstanceof implements ProceedHandler { + int index; + + ProceedForInstanceof(int i) { + 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 instanceof"); + + gen.atMethodArgs(args, new int[1], new int[1], new String[1]); + bytecode.addOpcode(Opcode.INSTANCEOF); + bytecode.addIndex(index); + gen.setType(CtClass.booleanType); + } + } +} diff --git a/src/main/javassist/expr/MethodCall.java b/src/main/javassist/expr/MethodCall.java new file mode 100644 index 00000000..747380b4 --- /dev/null +++ b/src/main/javassist/expr/MethodCall.java @@ -0,0 +1,220 @@ +/* + * 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.*; + +/** + * Method invocation (caller-side expression). + */ +public class MethodCall extends Expr { + /** + * Undocumented constructor. Do not use; internal-use only. + */ + MethodCall(int pos, CodeIterator i, CtClass declaring, MethodInfo m) { + super(pos, i, declaring, m); + } + + private int getNameAndType(ConstPool cp) { + String cname; + int pos = currentPos; + int c = iterator.byteAt(pos); + int index = iterator.u16bitAt(pos + 1); + + if (c == INVOKEINTERFACE) + return cp.getInterfaceMethodrefNameAndType(index); + else + return cp.getMethodrefNameAndType(index); + } + + /** + * Returns the method or constructor containing the method-call + * expression represented by this object. + */ + public CtBehavior where() { return super.where(); } + + /** + * Returns the line number of the source line containing the + * method call. + * + * @return -1 if this information is not available. + */ + public int getLineNumber() { + return super.getLineNumber(); + } + + /** + * Returns the source file containing the method call. + * + * @return null if this information is not available. + */ + public String getFileName() { + return super.getFileName(); + } + + /** + * Returns the class of the target object, + * which the method is called on. + */ + private CtClass getCtClass() throws NotFoundException { + return thisClass.getClassPool().get(getClassName()); + } + + /** + * Returns the class name of the target object, + * which the method is called on. + */ + public String getClassName() { + String cname; + + ConstPool cp = getConstPool(); + int pos = currentPos; + int c = iterator.byteAt(pos); + int index = iterator.u16bitAt(pos + 1); + + if (c == INVOKEINTERFACE) + cname = cp.getInterfaceMethodrefClassName(index); + else + cname = cp.getMethodrefClassName(index); + + return cname; + } + + /** + * Returns the name of the called method. + */ + public String getMethodName() { + ConstPool cp = getConstPool(); + int nt = getNameAndType(cp); + return cp.getUtf8Info(cp.getNameAndTypeName(nt)); + } + + /** + * Returns the called method. + */ + public CtMethod getMethod() throws NotFoundException { + return getCtClass().getMethod(getMethodName(), getMethodDesc()); + } + + private String getMethodDesc() { + ConstPool cp = getConstPool(); + int nt = getNameAndType(cp); + return cp.getUtf8Info(cp.getNameAndTypeDescriptor(nt)); + } + + /** + * 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 parameter types of the called method. + + public CtClass[] getParameterTypes() throws NotFoundException { + return Descriptor.getParameterTypes(getMethodDesc(), + thisClass.getClassPool()); + } + */ + + /* + * Returns the return type of the called method. + + public CtClass getReturnType() throws NotFoundException { + return Descriptor.getReturnType(getMethodDesc(), + 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. + * + * @param statement a Java statement. + */ + public void replace(String statement) throws CannotCompileException { + ConstPool constPool = getConstPool(); + int pos = currentPos; + int index = iterator.u16bitAt(pos + 1); + + String classname, methodname, signature; + int opcodeSize; + int c = iterator.byteAt(pos); + if (c == INVOKEINTERFACE) { + opcodeSize = 5; + classname = constPool.getInterfaceMethodrefClassName(index); + methodname = constPool.getInterfaceMethodrefName(index); + signature = constPool.getInterfaceMethodrefType(index); + } + else if (c == INVOKESTATIC + || c == INVOKESPECIAL || c == INVOKEVIRTUAL) { + opcodeSize = 3; + classname = constPool.getMethodrefClassName(index); + methodname = constPool.getMethodrefName(index); + signature = constPool.getMethodrefType(index); + } + else + throw new CannotCompileException("not method invocation"); + + Javac jc = new Javac(thisClass); + ClassPool cp = thisClass.getClassPool(); + CodeAttribute ca = iterator.get(); + try { + CtClass[] params = Descriptor.getParameterTypes(signature, cp); + CtClass retType = Descriptor.getReturnType(signature, cp); + int paramVar = ca.getMaxLocals(); + jc.recordParams(classname, params, + true, paramVar, withinStatic()); + int retVar = jc.recordReturnType(retType, true); + jc.recordProceed(Javac.param0Name, methodname); + + /* Is $_ included in the source code? + */ + checkResultValue(retType, statement); + + Bytecode bytecode = jc.getBytecode(); + storeStack(params, c == INVOKESTATIC, paramVar, bytecode); + jc.compileStmnt(statement); + if (retType != CtClass.voidType) + bytecode.addLoad(retVar, retType); + + replace0(pos, bytecode, opcodeSize); + } + catch (CompileError e) { throw new CannotCompileException(e); } + catch (NotFoundException e) { throw new CannotCompileException(e); } + catch (BadBytecode e) { + throw new CannotCompileException("broken method"); + } + } +} diff --git a/src/main/javassist/expr/NewExpr.java b/src/main/javassist/expr/NewExpr.java new file mode 100644 index 00000000..73546238 --- /dev/null +++ b/src/main/javassist/expr/NewExpr.java @@ -0,0 +1,224 @@ +/* + * 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.ASTree; +import javassist.compiler.ast.ASTList; + +/** + * Object creation (<tt>new</tt> expression). + */ +public class NewExpr extends Expr { + String newTypeName; + int newPos; + + /** + * Undocumented constructor. Do not use; internal-use only. + */ + NewExpr(int pos, CodeIterator i, CtClass declaring, MethodInfo m, + String type, int np) + { + super(pos, i, declaring, m); + newTypeName = type; + newPos = np; + } + + private int getNameAndType(ConstPool cp) { + String cname; + int pos = currentPos; + int c = iterator.byteAt(pos); + int index = iterator.u16bitAt(pos + 1); + + if (c == INVOKEINTERFACE) + return cp.getInterfaceMethodrefNameAndType(index); + else + return cp.getMethodrefNameAndType(index); + } + + /** + * Returns the method or constructor containing the <tt>new</tt> + * expression represented by this object. + */ + public CtBehavior where() { return super.where(); } + + /** + * Returns the line number of the source line containing the + * <tt>new</tt> expression. + * + * @return -1 if this information is not available. + */ + public int getLineNumber() { + return super.getLineNumber(); + } + + /** + * Returns the source file containing the <tt>new</tt> expression. + * + * @return null if this information is not available. + */ + public String getFileName() { + return super.getFileName(); + } + + /** + * Returns the class of the created object. + */ + private CtClass getCtClass() throws NotFoundException { + return thisClass.getClassPool().get(newTypeName); + } + + /** + * Returns the class name of the created object. + */ + public String getClassName() { + return newTypeName; + } + + /** + * Returns the constructor called for creating the object. + */ + public CtConstructor getConstructor() throws NotFoundException { + ConstPool cp = getConstPool(); + int index = iterator.u16bitAt(currentPos + 1); + String desc = cp.getMethodrefType(index); + return getCtClass().getConstructor(desc); + } + + /** + * 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 parameter types of the constructor. + + public CtClass[] getParameterTypes() throws NotFoundException { + ConstPool cp = getConstPool(); + int index = iterator.u16bitAt(currentPos + 1); + String desc = cp.getMethodrefType(index); + return Descriptor.getParameterTypes(desc, thisClass.getClassPool()); + } + */ + + private int canReplace() throws CannotCompileException { + int op = iterator.byteAt(newPos + 3); + if (op == Opcode.DUP) + return 4; + else if (op == Opcode.DUP_X1 + && iterator.byteAt(newPos + 4) == Opcode.SWAP) + return 5; + else + throw new CannotCompileException( + "sorry, cannot edit NEW followed by no DUP"); + } + + /** + * Replaces the <tt>new</tt> expression with the bytecode derived from + * the given source text. + * + * <p>$0 is available but the value is null. + * + * @param statement a Java statement. + */ + public void replace(String statement) throws CannotCompileException { + final int bytecodeSize = 3; + int pos = newPos; + + int newIndex = iterator.u16bitAt(pos + 1); + + /* delete the preceding NEW and DUP (or DUP_X1, SWAP) instructions. + */ + int end = pos + canReplace(); + for (int i = pos; i < end; ++i) + iterator.writeByte(NOP, i); + + ConstPool constPool = getConstPool(); + pos = currentPos; + int methodIndex = iterator.u16bitAt(pos + 1); // constructor + + String signature = constPool.getMethodrefType(methodIndex); + + Javac jc = new Javac(thisClass); + ClassPool cp = thisClass.getClassPool(); + CodeAttribute ca = iterator.get(); + try { + CtClass[] params = Descriptor.getParameterTypes(signature, cp); + CtClass newType = cp.get(newTypeName); + int paramVar = ca.getMaxLocals(); + jc.recordParams(newTypeName, params, + true, paramVar, withinStatic()); + int retVar = jc.recordReturnType(newType, true); + jc.recordProceed(new ProceedForNew(newType, newIndex, + methodIndex)); + + /* Is $_ included in the source code? + */ + checkResultValue(newType, statement); + + Bytecode bytecode = jc.getBytecode(); + storeStack(params, true, paramVar, bytecode); + jc.compileStmnt(statement); + bytecode.addAload(retVar); + + replace0(pos, bytecode, bytecodeSize); + } + catch (CompileError e) { throw new CannotCompileException(e); } + catch (NotFoundException e) { throw new CannotCompileException(e); } + catch (BadBytecode e) { + throw new CannotCompileException("broken method"); + } + } + + static class ProceedForNew implements ProceedHandler { + CtClass newType; + int newIndex, methodIndex; + + ProceedForNew(CtClass nt, int ni, int mi) { + newType = nt; + newIndex = ni; + methodIndex = mi; + } + + public void doit(JvstCodeGen gen, Bytecode bytecode, ASTList args) + throws CompileError + { + bytecode.addOpcode(NEW); + bytecode.addIndex(newIndex); + bytecode.addOpcode(DUP); + gen.atMethodCall2(newType, MethodInfo.nameInit, + args, false, true); + gen.setType(newType); + } + } +} |