1 /*
2  * Javassist, a Java-bytecode translator toolkit.
3  * Copyright (C) 1999-2007 Shigeru Chiba. All Rights Reserved.
4  *
5  * The contents of this file are subject to the Mozilla Public License Version
6  * 1.1 (the "License"); you may not use this file except in compliance with
7  * the License.  Alternatively, the contents of this file may be used under
8  * the terms of the GNU Lesser General Public License Version 2.1 or later.
9  *
10  * Software distributed under the License is distributed on an "AS IS" basis,
11  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12  * for the specific language governing rights and limitations under the
13  * License.
14  */
15 
16 package javassist.expr;
17 
18 import javassist.*;
19 import javassist.bytecode.*;
20 import javassist.compiler.*;
21 import javassist.compiler.ast.ASTList;
22 
23 /**
24  * Instanceof operator.
25  */
26 public class Instanceof extends Expr {
27     /**
28      * Undocumented constructor.  Do not use; internal-use only.
29      */
Instanceof(int pos, CodeIterator i, CtClass declaring, MethodInfo m)30     protected Instanceof(int pos, CodeIterator i, CtClass declaring,
31                          MethodInfo m) {
32         super(pos, i, declaring, m);
33     }
34 
35     /**
36      * Returns the method or constructor containing the instanceof
37      * expression represented by this object.
38      */
where()39     public CtBehavior where() { return super.where(); }
40 
41     /**
42      * Returns the line number of the source line containing the
43      * instanceof expression.
44      *
45      * @return -1       if this information is not available.
46      */
getLineNumber()47     public int getLineNumber() {
48         return super.getLineNumber();
49     }
50 
51     /**
52      * Returns the source file containing the
53      * instanceof expression.
54      *
55      * @return null     if this information is not available.
56      */
getFileName()57     public String getFileName() {
58         return super.getFileName();
59     }
60 
61     /**
62      * Returns the <code>CtClass</code> object representing
63      * the type name on the right hand side
64      * of the instanceof operator.
65      */
getType()66     public CtClass getType() throws NotFoundException {
67         ConstPool cp = getConstPool();
68         int pos = currentPos;
69         int index = iterator.u16bitAt(pos + 1);
70         String name = cp.getClassInfo(index);
71         return thisClass.getClassPool().getCtClass(name);
72     }
73 
74     /**
75      * Returns the list of exceptions that the expression may throw.
76      * This list includes both the exceptions that the try-catch statements
77      * including the expression can catch and the exceptions that
78      * the throws declaration allows the method to throw.
79      */
mayThrow()80     public CtClass[] mayThrow() {
81         return super.mayThrow();
82     }
83 
84     /**
85      * Replaces the instanceof operator with the bytecode derived from
86      * the given source text.
87      *
88      * <p>$0 is available but the value is <code>null</code>.
89      *
90      * @param statement         a Java statement except try-catch.
91      */
replace(String statement)92     public void replace(String statement) throws CannotCompileException {
93         thisClass.getClassFile();   // to call checkModify().
94         ConstPool constPool = getConstPool();
95         int pos = currentPos;
96         int index = iterator.u16bitAt(pos + 1);
97 
98         Javac jc = new Javac(thisClass);
99         ClassPool cp = thisClass.getClassPool();
100         CodeAttribute ca = iterator.get();
101 
102         try {
103             CtClass[] params
104                 = new CtClass[] { cp.get(javaLangObject) };
105             CtClass retType = CtClass.booleanType;
106 
107             int paramVar = ca.getMaxLocals();
108             jc.recordParams(javaLangObject, params, true, paramVar,
109                             withinStatic());
110             int retVar = jc.recordReturnType(retType, true);
111             jc.recordProceed(new ProceedForInstanceof(index));
112 
113             // because $type is not the return type...
114             jc.recordType(getType());
115 
116             /* Is $_ included in the source code?
117              */
118             checkResultValue(retType, statement);
119 
120             Bytecode bytecode = jc.getBytecode();
121             storeStack(params, true, paramVar, bytecode);
122             jc.recordLocalVariables(ca, pos);
123 
124             bytecode.addConstZero(retType);
125             bytecode.addStore(retVar, retType);     // initialize $_
126 
127             jc.compileStmnt(statement);
128             bytecode.addLoad(retVar, retType);
129 
130             replace0(pos, bytecode, 3);
131         }
132         catch (CompileError e) { throw new CannotCompileException(e); }
133         catch (NotFoundException e) { throw new CannotCompileException(e); }
134         catch (BadBytecode e) {
135             throw new CannotCompileException("broken method");
136         }
137     }
138 
139     /* boolean $proceed(Object obj)
140      */
141     static class ProceedForInstanceof implements ProceedHandler {
142         int index;
143 
ProceedForInstanceof(int i)144         ProceedForInstanceof(int i) {
145             index = i;
146         }
147 
doit(JvstCodeGen gen, Bytecode bytecode, ASTList args)148         public void doit(JvstCodeGen gen, Bytecode bytecode, ASTList args)
149             throws CompileError
150         {
151             if (gen.getMethodArgsLength(args) != 1)
152                 throw new CompileError(Javac.proceedName
153                         + "() cannot take more than one parameter "
154                         + "for instanceof");
155 
156             gen.atMethodArgs(args, new int[1], new int[1], new String[1]);
157             bytecode.addOpcode(Opcode.INSTANCEOF);
158             bytecode.addIndex(index);
159             gen.setType(CtClass.booleanType);
160         }
161 
setReturnType(JvstTypeChecker c, ASTList args)162         public void setReturnType(JvstTypeChecker c, ASTList args)
163             throws CompileError
164         {
165             c.atMethodArgs(args, new int[1], new int[1], new String[1]);
166             c.setType(CtClass.booleanType);
167         }
168     }
169 }
170