123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285 |
- /*
- * Javassist, a Java-bytecode translator toolkit.
- * Copyright (C) 1999- 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,
- * or the Apache License Version 2.0.
- *
- * 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.CannotCompileException;
- import javassist.ClassPool;
- import javassist.CtBehavior;
- import javassist.CtClass;
- import javassist.CtConstructor;
- import javassist.NotFoundException;
- import javassist.bytecode.BadBytecode;
- import javassist.bytecode.Bytecode;
- import javassist.bytecode.CodeAttribute;
- import javassist.bytecode.CodeIterator;
- import javassist.bytecode.ConstPool;
- import javassist.bytecode.Descriptor;
- import javassist.bytecode.MethodInfo;
- import javassist.bytecode.Opcode;
- import javassist.compiler.CompileError;
- import javassist.compiler.Javac;
- import javassist.compiler.JvstCodeGen;
- import javassist.compiler.JvstTypeChecker;
- import javassist.compiler.ProceedHandler;
- import javassist.compiler.ast.ASTList;
-
- /**
- * Object creation (<code>new</code> expression).
- */
- public class NewExpr extends Expr {
- String newTypeName;
- int newPos;
-
- /**
- * Undocumented constructor. Do not use; internal-use only.
- */
- protected NewExpr(int pos, CodeIterator i, CtClass declaring,
- MethodInfo m, String type, int np) {
- super(pos, i, declaring, m);
- newTypeName = type;
- newPos = np;
- }
-
- /*
- * Not used
- *
- private int getNameAndType(ConstPool cp) {
- 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 <code>new</code>
- * expression represented by this object.
- */
- @Override
- public CtBehavior where() { return super.where(); }
-
- /**
- * Returns the line number of the source line containing the
- * <code>new</code> expression.
- *
- * @return -1 if this information is not available.
- */
- @Override
- public int getLineNumber() {
- return super.getLineNumber();
- }
-
- /**
- * Returns the source file containing the <code>new</code> expression.
- *
- * @return null if this information is not available.
- */
- @Override
- 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;
- }
-
- /**
- * Get the signature of the constructor
- *
- * The signature is represented by a character string
- * called method descriptor, which is defined in the JVM specification.
- *
- * @see javassist.CtBehavior#getSignature()
- * @see javassist.bytecode.Descriptor
- * @return the signature
- */
- public String getSignature() {
- ConstPool constPool = getConstPool();
- int methodIndex = iterator.u16bitAt(currentPos + 1); // constructor
- return constPool.getMethodrefType(methodIndex);
- }
-
- /**
- * 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.
- */
- @Override
- 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) // Typical single DUP or Javaflow DUP DUP2_X2 POP2
- return ((iterator.byteAt(newPos + 4) == Opcode.DUP2_X2
- && iterator.byteAt(newPos + 5) == Opcode.POP2)) ? 6 : 4;
- else if (op == Opcode.DUP_X1
- && iterator.byteAt(newPos + 4) == Opcode.SWAP)
- return 5;
- else
- return 3; // for Eclipse. The generated code may include no DUP.
- // throw new CannotCompileException(
- // "sorry, cannot edit NEW followed by no DUP");
- }
-
- /**
- * Replaces the <code>new</code> expression with the bytecode derived from
- * the given source text.
- *
- * <p>$0 is available but the value is null.
- *
- * @param statement a Java statement except try-catch.
- */
- @Override
- public void replace(String statement) throws CannotCompileException {
- thisClass.getClassFile(); // to call checkModify().
-
- 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 codeSize = canReplace();
- int end = pos + codeSize;
- //check isStoreBeforeInit ,such as : new xx/xx ; dup;[astoreN];invokespecial xx/xx;
- int beforeStoreOp = 0;
- int preOp = iterator.byteAt(currentPos - 1);
- if (iterator.byteAt(newPos + 3) == Opcode.DUP
- && (preOp >= Opcode.ASTORE_0
- && preOp <= Opcode.ASTORE_3) && currentPos - newPos == 5) {
- beforeStoreOp = preOp;
- }
- 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.recordLocalVariables(ca, pos);
-
- bytecode.addConstZero(newType);
- bytecode.addStore(retVar, newType); // initialize $_
-
- jc.compileStmnt(statement);
- if (codeSize > 3) // if the original code includes DUP.
- bytecode.addAload(retVar);
-
- if (beforeStoreOp >= Opcode.ASTORE_0) {
- bytecode.addOpcode(beforeStoreOp);
- replace0(pos - 1, bytecode, bytecodeSize + 1);
- } else {
- 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;
- }
-
- @Override
- public void doit(JvstCodeGen gen, Bytecode bytecode, ASTList args)
- throws CompileError
- {
- bytecode.addOpcode(NEW);
- bytecode.addIndex(newIndex);
- bytecode.addOpcode(DUP);
- gen.atMethodCallCore(newType, MethodInfo.nameInit, args,
- false, true, -1, null);
- gen.setType(newType);
- }
-
- @Override
- public void setReturnType(JvstTypeChecker c, ASTList args)
- throws CompileError
- {
- c.atMethodCallCore(newType, MethodInfo.nameInit, args);
- c.setType(newType);
- }
- }
- }
|