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