xref: /aosp_15_r20/external/javassist/src/main/javassist/compiler/CodeGen.java (revision f1fbf3c2ab775ce834e0af96b7a85bdc7a0eac65)
1*f1fbf3c2SXin Li /*
2*f1fbf3c2SXin Li  * Javassist, a Java-bytecode translator toolkit.
3*f1fbf3c2SXin Li  * Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.
4*f1fbf3c2SXin Li  *
5*f1fbf3c2SXin Li  * The contents of this file are subject to the Mozilla Public License Version
6*f1fbf3c2SXin Li  * 1.1 (the "License"); you may not use this file except in compliance with
7*f1fbf3c2SXin Li  * the License.  Alternatively, the contents of this file may be used under
8*f1fbf3c2SXin Li  * the terms of the GNU Lesser General Public License Version 2.1 or later,
9*f1fbf3c2SXin Li  * or the Apache License Version 2.0.
10*f1fbf3c2SXin Li  *
11*f1fbf3c2SXin Li  * Software distributed under the License is distributed on an "AS IS" basis,
12*f1fbf3c2SXin Li  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13*f1fbf3c2SXin Li  * for the specific language governing rights and limitations under the
14*f1fbf3c2SXin Li  * License.
15*f1fbf3c2SXin Li  */
16*f1fbf3c2SXin Li 
17*f1fbf3c2SXin Li package javassist.compiler;
18*f1fbf3c2SXin Li 
19*f1fbf3c2SXin Li import java.util.ArrayList;
20*f1fbf3c2SXin Li import java.util.Arrays;
21*f1fbf3c2SXin Li import java.util.List;
22*f1fbf3c2SXin Li 
23*f1fbf3c2SXin Li import javassist.bytecode.Bytecode;
24*f1fbf3c2SXin Li import javassist.bytecode.Opcode;
25*f1fbf3c2SXin Li import javassist.compiler.ast.ASTList;
26*f1fbf3c2SXin Li import javassist.compiler.ast.ASTree;
27*f1fbf3c2SXin Li import javassist.compiler.ast.ArrayInit;
28*f1fbf3c2SXin Li import javassist.compiler.ast.AssignExpr;
29*f1fbf3c2SXin Li import javassist.compiler.ast.BinExpr;
30*f1fbf3c2SXin Li import javassist.compiler.ast.CallExpr;
31*f1fbf3c2SXin Li import javassist.compiler.ast.CastExpr;
32*f1fbf3c2SXin Li import javassist.compiler.ast.CondExpr;
33*f1fbf3c2SXin Li import javassist.compiler.ast.Declarator;
34*f1fbf3c2SXin Li import javassist.compiler.ast.DoubleConst;
35*f1fbf3c2SXin Li import javassist.compiler.ast.Expr;
36*f1fbf3c2SXin Li import javassist.compiler.ast.FieldDecl;
37*f1fbf3c2SXin Li import javassist.compiler.ast.InstanceOfExpr;
38*f1fbf3c2SXin Li import javassist.compiler.ast.IntConst;
39*f1fbf3c2SXin Li import javassist.compiler.ast.Keyword;
40*f1fbf3c2SXin Li import javassist.compiler.ast.Member;
41*f1fbf3c2SXin Li import javassist.compiler.ast.MethodDecl;
42*f1fbf3c2SXin Li import javassist.compiler.ast.NewExpr;
43*f1fbf3c2SXin Li import javassist.compiler.ast.Pair;
44*f1fbf3c2SXin Li import javassist.compiler.ast.Stmnt;
45*f1fbf3c2SXin Li import javassist.compiler.ast.StringL;
46*f1fbf3c2SXin Li import javassist.compiler.ast.Symbol;
47*f1fbf3c2SXin Li import javassist.compiler.ast.Variable;
48*f1fbf3c2SXin Li import javassist.compiler.ast.Visitor;
49*f1fbf3c2SXin Li 
50*f1fbf3c2SXin Li /* The code generator is implemented by three files:
51*f1fbf3c2SXin Li  * CodeGen.java, MemberCodeGen.java, and JvstCodeGen.
52*f1fbf3c2SXin Li  * I just wanted to split a big file into three smaller ones.
53*f1fbf3c2SXin Li  */
54*f1fbf3c2SXin Li 
55*f1fbf3c2SXin Li public abstract class CodeGen extends Visitor implements Opcode, TokenId {
56*f1fbf3c2SXin Li     static final String javaLangObject = "java.lang.Object";
57*f1fbf3c2SXin Li     static final String jvmJavaLangObject = "java/lang/Object";
58*f1fbf3c2SXin Li 
59*f1fbf3c2SXin Li     static final String javaLangString = "java.lang.String";
60*f1fbf3c2SXin Li     static final String jvmJavaLangString = "java/lang/String";
61*f1fbf3c2SXin Li 
62*f1fbf3c2SXin Li     protected Bytecode bytecode;
63*f1fbf3c2SXin Li     private int tempVar;
64*f1fbf3c2SXin Li     TypeChecker typeChecker;
65*f1fbf3c2SXin Li 
66*f1fbf3c2SXin Li     /**
67*f1fbf3c2SXin Li      * true if the last visited node is a return statement.
68*f1fbf3c2SXin Li      */
69*f1fbf3c2SXin Li     protected boolean hasReturned;
70*f1fbf3c2SXin Li 
71*f1fbf3c2SXin Li     /**
72*f1fbf3c2SXin Li      * Must be true if compilation is for a static method.
73*f1fbf3c2SXin Li      */
74*f1fbf3c2SXin Li     public boolean inStaticMethod;
75*f1fbf3c2SXin Li 
76*f1fbf3c2SXin Li     protected List<Integer>  breakList, continueList;
77*f1fbf3c2SXin Li 
78*f1fbf3c2SXin Li     /**
79*f1fbf3c2SXin Li      * doit() in ReturnHook is called from atReturn().
80*f1fbf3c2SXin Li      */
81*f1fbf3c2SXin Li     protected static abstract class ReturnHook {
82*f1fbf3c2SXin Li         ReturnHook next;
83*f1fbf3c2SXin Li 
84*f1fbf3c2SXin Li         /**
85*f1fbf3c2SXin Li          * Returns true if the generated code ends with return,
86*f1fbf3c2SXin Li          * throw, or goto.
87*f1fbf3c2SXin Li          */
doit(Bytecode b, int opcode)88*f1fbf3c2SXin Li         protected abstract boolean doit(Bytecode b, int opcode);
89*f1fbf3c2SXin Li 
ReturnHook(CodeGen gen)90*f1fbf3c2SXin Li         protected ReturnHook(CodeGen gen) {
91*f1fbf3c2SXin Li             next = gen.returnHooks;
92*f1fbf3c2SXin Li             gen.returnHooks = this;
93*f1fbf3c2SXin Li         }
94*f1fbf3c2SXin Li 
remove(CodeGen gen)95*f1fbf3c2SXin Li         protected void remove(CodeGen gen) {
96*f1fbf3c2SXin Li             gen.returnHooks = next;
97*f1fbf3c2SXin Li         }
98*f1fbf3c2SXin Li     }
99*f1fbf3c2SXin Li 
100*f1fbf3c2SXin Li     protected ReturnHook returnHooks;
101*f1fbf3c2SXin Li 
102*f1fbf3c2SXin Li     /* The following fields are used by atXXX() methods
103*f1fbf3c2SXin Li      * for returning the type of the compiled expression.
104*f1fbf3c2SXin Li      */
105*f1fbf3c2SXin Li     protected int exprType;     // VOID, NULL, CLASS, BOOLEAN, INT, ...
106*f1fbf3c2SXin Li     protected int arrayDim;
107*f1fbf3c2SXin Li     protected String className; // JVM-internal representation
108*f1fbf3c2SXin Li 
CodeGen(Bytecode b)109*f1fbf3c2SXin Li     public CodeGen(Bytecode b) {
110*f1fbf3c2SXin Li         bytecode = b;
111*f1fbf3c2SXin Li         tempVar = -1;
112*f1fbf3c2SXin Li         typeChecker = null;
113*f1fbf3c2SXin Li         hasReturned = false;
114*f1fbf3c2SXin Li         inStaticMethod = false;
115*f1fbf3c2SXin Li         breakList = null;
116*f1fbf3c2SXin Li         continueList = null;
117*f1fbf3c2SXin Li         returnHooks = null;
118*f1fbf3c2SXin Li     }
119*f1fbf3c2SXin Li 
setTypeChecker(TypeChecker checker)120*f1fbf3c2SXin Li     public void setTypeChecker(TypeChecker checker) {
121*f1fbf3c2SXin Li         typeChecker = checker;
122*f1fbf3c2SXin Li     }
123*f1fbf3c2SXin Li 
fatal()124*f1fbf3c2SXin Li     protected static void fatal() throws CompileError {
125*f1fbf3c2SXin Li         throw new CompileError("fatal");
126*f1fbf3c2SXin Li     }
127*f1fbf3c2SXin Li 
is2word(int type, int dim)128*f1fbf3c2SXin Li     public static boolean is2word(int type, int dim) {
129*f1fbf3c2SXin Li         return dim == 0 && (type == DOUBLE || type == LONG);
130*f1fbf3c2SXin Li     }
131*f1fbf3c2SXin Li 
getMaxLocals()132*f1fbf3c2SXin Li     public int getMaxLocals() { return bytecode.getMaxLocals(); }
133*f1fbf3c2SXin Li 
setMaxLocals(int n)134*f1fbf3c2SXin Li     public void setMaxLocals(int n) {
135*f1fbf3c2SXin Li         bytecode.setMaxLocals(n);
136*f1fbf3c2SXin Li     }
137*f1fbf3c2SXin Li 
incMaxLocals(int size)138*f1fbf3c2SXin Li     protected void incMaxLocals(int size) {
139*f1fbf3c2SXin Li         bytecode.incMaxLocals(size);
140*f1fbf3c2SXin Li     }
141*f1fbf3c2SXin Li 
142*f1fbf3c2SXin Li     /**
143*f1fbf3c2SXin Li      * Returns a local variable that single or double words can be
144*f1fbf3c2SXin Li      * stored in.
145*f1fbf3c2SXin Li      */
getTempVar()146*f1fbf3c2SXin Li     protected int getTempVar() {
147*f1fbf3c2SXin Li         if (tempVar < 0) {
148*f1fbf3c2SXin Li             tempVar = getMaxLocals();
149*f1fbf3c2SXin Li             incMaxLocals(2);
150*f1fbf3c2SXin Li         }
151*f1fbf3c2SXin Li 
152*f1fbf3c2SXin Li         return tempVar;
153*f1fbf3c2SXin Li     }
154*f1fbf3c2SXin Li 
getLocalVar(Declarator d)155*f1fbf3c2SXin Li     protected int getLocalVar(Declarator d) {
156*f1fbf3c2SXin Li         int v = d.getLocalVar();
157*f1fbf3c2SXin Li         if (v < 0) {
158*f1fbf3c2SXin Li             v = getMaxLocals(); // delayed variable allocation.
159*f1fbf3c2SXin Li             d.setLocalVar(v);
160*f1fbf3c2SXin Li             incMaxLocals(1);
161*f1fbf3c2SXin Li         }
162*f1fbf3c2SXin Li 
163*f1fbf3c2SXin Li         return v;
164*f1fbf3c2SXin Li     }
165*f1fbf3c2SXin Li 
166*f1fbf3c2SXin Li     /**
167*f1fbf3c2SXin Li      * Returns the JVM-internal representation of this class name.
168*f1fbf3c2SXin Li      */
getThisName()169*f1fbf3c2SXin Li     protected abstract String getThisName();
170*f1fbf3c2SXin Li 
171*f1fbf3c2SXin Li     /**
172*f1fbf3c2SXin Li      * Returns the JVM-internal representation of this super class name.
173*f1fbf3c2SXin Li      */
getSuperName()174*f1fbf3c2SXin Li     protected abstract String getSuperName() throws CompileError;
175*f1fbf3c2SXin Li 
176*f1fbf3c2SXin Li     /* Converts a class name into a JVM-internal representation.
177*f1fbf3c2SXin Li      *
178*f1fbf3c2SXin Li      * It may also expand a simple class name to java.lang.*.
179*f1fbf3c2SXin Li      * For example, this converts Object into java/lang/Object.
180*f1fbf3c2SXin Li      */
resolveClassName(ASTList name)181*f1fbf3c2SXin Li     protected abstract String resolveClassName(ASTList name)
182*f1fbf3c2SXin Li         throws CompileError;
183*f1fbf3c2SXin Li 
184*f1fbf3c2SXin Li     /* Expands a simple class name to java.lang.*.
185*f1fbf3c2SXin Li      * For example, this converts Object into java/lang/Object.
186*f1fbf3c2SXin Li      */
resolveClassName(String jvmClassName)187*f1fbf3c2SXin Li     protected abstract String resolveClassName(String jvmClassName)
188*f1fbf3c2SXin Li         throws CompileError;
189*f1fbf3c2SXin Li 
190*f1fbf3c2SXin Li     /**
191*f1fbf3c2SXin Li      * @param name      the JVM-internal representation.
192*f1fbf3c2SXin Li      *                  name is not exapnded to java.lang.*.
193*f1fbf3c2SXin Li      */
toJvmArrayName(String name, int dim)194*f1fbf3c2SXin Li     protected static String toJvmArrayName(String name, int dim) {
195*f1fbf3c2SXin Li         if (name == null)
196*f1fbf3c2SXin Li             return null;
197*f1fbf3c2SXin Li 
198*f1fbf3c2SXin Li         if (dim == 0)
199*f1fbf3c2SXin Li             return name;
200*f1fbf3c2SXin Li         StringBuffer sbuf = new StringBuffer();
201*f1fbf3c2SXin Li         int d = dim;
202*f1fbf3c2SXin Li         while (d-- > 0)
203*f1fbf3c2SXin Li             sbuf.append('[');
204*f1fbf3c2SXin Li 
205*f1fbf3c2SXin Li         sbuf.append('L');
206*f1fbf3c2SXin Li         sbuf.append(name);
207*f1fbf3c2SXin Li         sbuf.append(';');
208*f1fbf3c2SXin Li 
209*f1fbf3c2SXin Li         return sbuf.toString();
210*f1fbf3c2SXin Li     }
211*f1fbf3c2SXin Li 
toJvmTypeName(int type, int dim)212*f1fbf3c2SXin Li     protected static String toJvmTypeName(int type, int dim) {
213*f1fbf3c2SXin Li         char c = 'I';
214*f1fbf3c2SXin Li         switch(type) {
215*f1fbf3c2SXin Li         case BOOLEAN :
216*f1fbf3c2SXin Li             c = 'Z';
217*f1fbf3c2SXin Li             break;
218*f1fbf3c2SXin Li         case BYTE :
219*f1fbf3c2SXin Li             c = 'B';
220*f1fbf3c2SXin Li             break;
221*f1fbf3c2SXin Li         case CHAR :
222*f1fbf3c2SXin Li             c = 'C';
223*f1fbf3c2SXin Li             break;
224*f1fbf3c2SXin Li         case SHORT :
225*f1fbf3c2SXin Li             c = 'S';
226*f1fbf3c2SXin Li             break;
227*f1fbf3c2SXin Li         case INT :
228*f1fbf3c2SXin Li             c = 'I';
229*f1fbf3c2SXin Li             break;
230*f1fbf3c2SXin Li         case LONG :
231*f1fbf3c2SXin Li             c = 'J';
232*f1fbf3c2SXin Li             break;
233*f1fbf3c2SXin Li         case FLOAT :
234*f1fbf3c2SXin Li             c = 'F';
235*f1fbf3c2SXin Li             break;
236*f1fbf3c2SXin Li         case DOUBLE :
237*f1fbf3c2SXin Li             c = 'D';
238*f1fbf3c2SXin Li             break;
239*f1fbf3c2SXin Li         case VOID :
240*f1fbf3c2SXin Li             c = 'V';
241*f1fbf3c2SXin Li             break;
242*f1fbf3c2SXin Li         }
243*f1fbf3c2SXin Li 
244*f1fbf3c2SXin Li         StringBuffer sbuf = new StringBuffer();
245*f1fbf3c2SXin Li         while (dim-- > 0)
246*f1fbf3c2SXin Li                 sbuf.append('[');
247*f1fbf3c2SXin Li 
248*f1fbf3c2SXin Li         sbuf.append(c);
249*f1fbf3c2SXin Li         return sbuf.toString();
250*f1fbf3c2SXin Li     }
251*f1fbf3c2SXin Li 
compileExpr(ASTree expr)252*f1fbf3c2SXin Li     public void compileExpr(ASTree expr) throws CompileError {
253*f1fbf3c2SXin Li         doTypeCheck(expr);
254*f1fbf3c2SXin Li         expr.accept(this);
255*f1fbf3c2SXin Li     }
256*f1fbf3c2SXin Li 
compileBooleanExpr(boolean branchIf, ASTree expr)257*f1fbf3c2SXin Li     public boolean compileBooleanExpr(boolean branchIf, ASTree expr)
258*f1fbf3c2SXin Li         throws CompileError
259*f1fbf3c2SXin Li     {
260*f1fbf3c2SXin Li         doTypeCheck(expr);
261*f1fbf3c2SXin Li         return booleanExpr(branchIf, expr);
262*f1fbf3c2SXin Li     }
263*f1fbf3c2SXin Li 
doTypeCheck(ASTree expr)264*f1fbf3c2SXin Li     public void doTypeCheck(ASTree expr) throws CompileError {
265*f1fbf3c2SXin Li         if (typeChecker != null)
266*f1fbf3c2SXin Li             expr.accept(typeChecker);
267*f1fbf3c2SXin Li     }
268*f1fbf3c2SXin Li 
269*f1fbf3c2SXin Li     @Override
atASTList(ASTList n)270*f1fbf3c2SXin Li     public void atASTList(ASTList n) throws CompileError { fatal(); }
271*f1fbf3c2SXin Li 
272*f1fbf3c2SXin Li     @Override
atPair(Pair n)273*f1fbf3c2SXin Li     public void atPair(Pair n) throws CompileError { fatal(); }
274*f1fbf3c2SXin Li 
275*f1fbf3c2SXin Li     @Override
atSymbol(Symbol n)276*f1fbf3c2SXin Li     public void atSymbol(Symbol n) throws CompileError { fatal(); }
277*f1fbf3c2SXin Li 
278*f1fbf3c2SXin Li     @Override
atFieldDecl(FieldDecl field)279*f1fbf3c2SXin Li     public void atFieldDecl(FieldDecl field) throws CompileError {
280*f1fbf3c2SXin Li         field.getInit().accept(this);
281*f1fbf3c2SXin Li     }
282*f1fbf3c2SXin Li 
283*f1fbf3c2SXin Li     @Override
atMethodDecl(MethodDecl method)284*f1fbf3c2SXin Li     public void atMethodDecl(MethodDecl method) throws CompileError {
285*f1fbf3c2SXin Li         ASTList mods = method.getModifiers();
286*f1fbf3c2SXin Li         setMaxLocals(1);
287*f1fbf3c2SXin Li         while (mods != null) {
288*f1fbf3c2SXin Li             Keyword k = (Keyword)mods.head();
289*f1fbf3c2SXin Li             mods = mods.tail();
290*f1fbf3c2SXin Li             if (k.get() == STATIC) {
291*f1fbf3c2SXin Li                 setMaxLocals(0);
292*f1fbf3c2SXin Li                 inStaticMethod = true;
293*f1fbf3c2SXin Li             }
294*f1fbf3c2SXin Li         }
295*f1fbf3c2SXin Li 
296*f1fbf3c2SXin Li         ASTList params = method.getParams();
297*f1fbf3c2SXin Li         while (params != null) {
298*f1fbf3c2SXin Li             atDeclarator((Declarator)params.head());
299*f1fbf3c2SXin Li             params = params.tail();
300*f1fbf3c2SXin Li         }
301*f1fbf3c2SXin Li 
302*f1fbf3c2SXin Li         Stmnt s = method.getBody();
303*f1fbf3c2SXin Li         atMethodBody(s, method.isConstructor(),
304*f1fbf3c2SXin Li                      method.getReturn().getType() == VOID);
305*f1fbf3c2SXin Li     }
306*f1fbf3c2SXin Li 
307*f1fbf3c2SXin Li     /**
308*f1fbf3c2SXin Li      * @param isCons	true if super() must be called.
309*f1fbf3c2SXin Li      *			false if the method is a class initializer.
310*f1fbf3c2SXin Li      */
atMethodBody(Stmnt s, boolean isCons, boolean isVoid)311*f1fbf3c2SXin Li     public void atMethodBody(Stmnt s, boolean isCons, boolean isVoid)
312*f1fbf3c2SXin Li         throws CompileError
313*f1fbf3c2SXin Li     {
314*f1fbf3c2SXin Li         if (s == null)
315*f1fbf3c2SXin Li             return;
316*f1fbf3c2SXin Li 
317*f1fbf3c2SXin Li         if (isCons && needsSuperCall(s))
318*f1fbf3c2SXin Li             insertDefaultSuperCall();
319*f1fbf3c2SXin Li 
320*f1fbf3c2SXin Li         hasReturned = false;
321*f1fbf3c2SXin Li         s.accept(this);
322*f1fbf3c2SXin Li         if (!hasReturned)
323*f1fbf3c2SXin Li             if (isVoid) {
324*f1fbf3c2SXin Li                 bytecode.addOpcode(Opcode.RETURN);
325*f1fbf3c2SXin Li                 hasReturned = true;
326*f1fbf3c2SXin Li             }
327*f1fbf3c2SXin Li             else
328*f1fbf3c2SXin Li                 throw new CompileError("no return statement");
329*f1fbf3c2SXin Li     }
330*f1fbf3c2SXin Li 
needsSuperCall(Stmnt body)331*f1fbf3c2SXin Li     private boolean needsSuperCall(Stmnt body) throws CompileError {
332*f1fbf3c2SXin Li         if (body.getOperator() == BLOCK)
333*f1fbf3c2SXin Li             body = (Stmnt)body.head();
334*f1fbf3c2SXin Li 
335*f1fbf3c2SXin Li         if (body != null && body.getOperator() == EXPR) {
336*f1fbf3c2SXin Li             ASTree expr = body.head();
337*f1fbf3c2SXin Li             if (expr != null && expr instanceof Expr
338*f1fbf3c2SXin Li                 && ((Expr)expr).getOperator() == CALL) {
339*f1fbf3c2SXin Li                 ASTree target = ((Expr)expr).head();
340*f1fbf3c2SXin Li                 if (target instanceof Keyword) {
341*f1fbf3c2SXin Li                     int token = ((Keyword)target).get();
342*f1fbf3c2SXin Li                     return token != THIS && token != SUPER;
343*f1fbf3c2SXin Li                 }
344*f1fbf3c2SXin Li             }
345*f1fbf3c2SXin Li         }
346*f1fbf3c2SXin Li 
347*f1fbf3c2SXin Li         return true;
348*f1fbf3c2SXin Li     }
349*f1fbf3c2SXin Li 
insertDefaultSuperCall()350*f1fbf3c2SXin Li     protected abstract void insertDefaultSuperCall() throws CompileError;
351*f1fbf3c2SXin Li 
352*f1fbf3c2SXin Li     @Override
atStmnt(Stmnt st)353*f1fbf3c2SXin Li     public void atStmnt(Stmnt st) throws CompileError {
354*f1fbf3c2SXin Li         if (st == null)
355*f1fbf3c2SXin Li             return;     // empty
356*f1fbf3c2SXin Li 
357*f1fbf3c2SXin Li         int op = st.getOperator();
358*f1fbf3c2SXin Li         if (op == EXPR) {
359*f1fbf3c2SXin Li             ASTree expr = st.getLeft();
360*f1fbf3c2SXin Li             doTypeCheck(expr);
361*f1fbf3c2SXin Li             if (expr instanceof AssignExpr)
362*f1fbf3c2SXin Li                 atAssignExpr((AssignExpr)expr, false);
363*f1fbf3c2SXin Li             else if (isPlusPlusExpr(expr)) {
364*f1fbf3c2SXin Li                 Expr e = (Expr)expr;
365*f1fbf3c2SXin Li                 atPlusPlus(e.getOperator(), e.oprand1(), e, false);
366*f1fbf3c2SXin Li             }
367*f1fbf3c2SXin Li             else {
368*f1fbf3c2SXin Li                 expr.accept(this);
369*f1fbf3c2SXin Li                 if (is2word(exprType, arrayDim))
370*f1fbf3c2SXin Li                     bytecode.addOpcode(POP2);
371*f1fbf3c2SXin Li                 else if (exprType != VOID)
372*f1fbf3c2SXin Li                     bytecode.addOpcode(POP);
373*f1fbf3c2SXin Li             }
374*f1fbf3c2SXin Li         }
375*f1fbf3c2SXin Li         else if (op == DECL || op == BLOCK) {
376*f1fbf3c2SXin Li             ASTList list = st;
377*f1fbf3c2SXin Li             while (list != null) {
378*f1fbf3c2SXin Li                 ASTree h = list.head();
379*f1fbf3c2SXin Li                 list = list.tail();
380*f1fbf3c2SXin Li                 if (h != null)
381*f1fbf3c2SXin Li                     h.accept(this);
382*f1fbf3c2SXin Li             }
383*f1fbf3c2SXin Li         }
384*f1fbf3c2SXin Li         else if (op == IF)
385*f1fbf3c2SXin Li             atIfStmnt(st);
386*f1fbf3c2SXin Li         else if (op == WHILE || op == DO)
387*f1fbf3c2SXin Li             atWhileStmnt(st, op == WHILE);
388*f1fbf3c2SXin Li         else if (op == FOR)
389*f1fbf3c2SXin Li             atForStmnt(st);
390*f1fbf3c2SXin Li         else if (op == BREAK || op == CONTINUE)
391*f1fbf3c2SXin Li             atBreakStmnt(st, op == BREAK);
392*f1fbf3c2SXin Li         else if (op == TokenId.RETURN)
393*f1fbf3c2SXin Li             atReturnStmnt(st);
394*f1fbf3c2SXin Li         else if (op == THROW)
395*f1fbf3c2SXin Li             atThrowStmnt(st);
396*f1fbf3c2SXin Li         else if (op == TRY)
397*f1fbf3c2SXin Li             atTryStmnt(st);
398*f1fbf3c2SXin Li         else if (op == SWITCH)
399*f1fbf3c2SXin Li             atSwitchStmnt(st);
400*f1fbf3c2SXin Li         else if (op == SYNCHRONIZED)
401*f1fbf3c2SXin Li             atSyncStmnt(st);
402*f1fbf3c2SXin Li         else {
403*f1fbf3c2SXin Li             // LABEL, SWITCH label stament might be null?.
404*f1fbf3c2SXin Li             hasReturned = false;
405*f1fbf3c2SXin Li             throw new CompileError(
406*f1fbf3c2SXin Li                 "sorry, not supported statement: TokenId " + op);
407*f1fbf3c2SXin Li         }
408*f1fbf3c2SXin Li     }
409*f1fbf3c2SXin Li 
atIfStmnt(Stmnt st)410*f1fbf3c2SXin Li     private void atIfStmnt(Stmnt st) throws CompileError {
411*f1fbf3c2SXin Li         ASTree expr = st.head();
412*f1fbf3c2SXin Li         Stmnt thenp = (Stmnt)st.tail().head();
413*f1fbf3c2SXin Li         Stmnt elsep = (Stmnt)st.tail().tail().head();
414*f1fbf3c2SXin Li         if (compileBooleanExpr(false, expr)) {
415*f1fbf3c2SXin Li             hasReturned = false;
416*f1fbf3c2SXin Li             if (elsep != null)
417*f1fbf3c2SXin Li                 elsep.accept(this);
418*f1fbf3c2SXin Li 
419*f1fbf3c2SXin Li             return;
420*f1fbf3c2SXin Li         }
421*f1fbf3c2SXin Li 
422*f1fbf3c2SXin Li         int pc = bytecode.currentPc();
423*f1fbf3c2SXin Li         int pc2 = 0;
424*f1fbf3c2SXin Li         bytecode.addIndex(0);   // correct later
425*f1fbf3c2SXin Li 
426*f1fbf3c2SXin Li         hasReturned = false;
427*f1fbf3c2SXin Li         if (thenp != null)
428*f1fbf3c2SXin Li             thenp.accept(this);
429*f1fbf3c2SXin Li 
430*f1fbf3c2SXin Li         boolean thenHasReturned = hasReturned;
431*f1fbf3c2SXin Li         hasReturned = false;
432*f1fbf3c2SXin Li 
433*f1fbf3c2SXin Li         if (elsep != null && !thenHasReturned) {
434*f1fbf3c2SXin Li             bytecode.addOpcode(Opcode.GOTO);
435*f1fbf3c2SXin Li             pc2 = bytecode.currentPc();
436*f1fbf3c2SXin Li             bytecode.addIndex(0);
437*f1fbf3c2SXin Li         }
438*f1fbf3c2SXin Li 
439*f1fbf3c2SXin Li         bytecode.write16bit(pc, bytecode.currentPc() - pc + 1);
440*f1fbf3c2SXin Li         if (elsep != null) {
441*f1fbf3c2SXin Li             elsep.accept(this);
442*f1fbf3c2SXin Li             if (!thenHasReturned)
443*f1fbf3c2SXin Li                 bytecode.write16bit(pc2, bytecode.currentPc() - pc2 + 1);
444*f1fbf3c2SXin Li 
445*f1fbf3c2SXin Li             hasReturned = thenHasReturned && hasReturned;
446*f1fbf3c2SXin Li         }
447*f1fbf3c2SXin Li     }
448*f1fbf3c2SXin Li 
atWhileStmnt(Stmnt st, boolean notDo)449*f1fbf3c2SXin Li     private void atWhileStmnt(Stmnt st, boolean notDo) throws CompileError {
450*f1fbf3c2SXin Li         List<Integer>  prevBreakList = breakList;
451*f1fbf3c2SXin Li         List<Integer>  prevContList = continueList;
452*f1fbf3c2SXin Li         breakList = new ArrayList<Integer>();
453*f1fbf3c2SXin Li         continueList = new ArrayList<Integer>();
454*f1fbf3c2SXin Li 
455*f1fbf3c2SXin Li         ASTree expr = st.head();
456*f1fbf3c2SXin Li         Stmnt body = (Stmnt)st.tail();
457*f1fbf3c2SXin Li 
458*f1fbf3c2SXin Li         int pc = 0;
459*f1fbf3c2SXin Li         if (notDo) {
460*f1fbf3c2SXin Li             bytecode.addOpcode(Opcode.GOTO);
461*f1fbf3c2SXin Li             pc = bytecode.currentPc();
462*f1fbf3c2SXin Li             bytecode.addIndex(0);
463*f1fbf3c2SXin Li         }
464*f1fbf3c2SXin Li 
465*f1fbf3c2SXin Li         int pc2 = bytecode.currentPc();
466*f1fbf3c2SXin Li         if (body != null)
467*f1fbf3c2SXin Li             body.accept(this);
468*f1fbf3c2SXin Li 
469*f1fbf3c2SXin Li         int pc3 = bytecode.currentPc();
470*f1fbf3c2SXin Li         if (notDo)
471*f1fbf3c2SXin Li             bytecode.write16bit(pc, pc3 - pc + 1);
472*f1fbf3c2SXin Li 
473*f1fbf3c2SXin Li         boolean alwaysBranch = compileBooleanExpr(true, expr);
474*f1fbf3c2SXin Li         if (alwaysBranch) {
475*f1fbf3c2SXin Li             bytecode.addOpcode(Opcode.GOTO);
476*f1fbf3c2SXin Li             alwaysBranch = breakList.size() == 0;
477*f1fbf3c2SXin Li         }
478*f1fbf3c2SXin Li 
479*f1fbf3c2SXin Li         bytecode.addIndex(pc2 - bytecode.currentPc() + 1);
480*f1fbf3c2SXin Li         patchGoto(breakList, bytecode.currentPc());
481*f1fbf3c2SXin Li         patchGoto(continueList, pc3);
482*f1fbf3c2SXin Li         continueList = prevContList;
483*f1fbf3c2SXin Li         breakList = prevBreakList;
484*f1fbf3c2SXin Li         hasReturned = alwaysBranch;
485*f1fbf3c2SXin Li     }
486*f1fbf3c2SXin Li 
patchGoto(List<Integer> list, int targetPc)487*f1fbf3c2SXin Li     protected void patchGoto(List<Integer> list, int targetPc) {
488*f1fbf3c2SXin Li         for (int pc:list)
489*f1fbf3c2SXin Li             bytecode.write16bit(pc, targetPc - pc + 1);
490*f1fbf3c2SXin Li     }
491*f1fbf3c2SXin Li 
atForStmnt(Stmnt st)492*f1fbf3c2SXin Li     private void atForStmnt(Stmnt st) throws CompileError {
493*f1fbf3c2SXin Li         List<Integer>  prevBreakList = breakList;
494*f1fbf3c2SXin Li         List<Integer>  prevContList = continueList;
495*f1fbf3c2SXin Li         breakList = new ArrayList<Integer>();
496*f1fbf3c2SXin Li         continueList = new ArrayList<Integer>();
497*f1fbf3c2SXin Li 
498*f1fbf3c2SXin Li         Stmnt init = (Stmnt)st.head();
499*f1fbf3c2SXin Li         ASTList p = st.tail();
500*f1fbf3c2SXin Li         ASTree expr = p.head();
501*f1fbf3c2SXin Li         p = p.tail();
502*f1fbf3c2SXin Li         Stmnt update = (Stmnt)p.head();
503*f1fbf3c2SXin Li         Stmnt body = (Stmnt)p.tail();
504*f1fbf3c2SXin Li 
505*f1fbf3c2SXin Li         if (init != null)
506*f1fbf3c2SXin Li             init.accept(this);
507*f1fbf3c2SXin Li 
508*f1fbf3c2SXin Li         int pc = bytecode.currentPc();
509*f1fbf3c2SXin Li         int pc2 = 0;
510*f1fbf3c2SXin Li         if (expr != null) {
511*f1fbf3c2SXin Li             if (compileBooleanExpr(false, expr)) {
512*f1fbf3c2SXin Li                 // in case of "for (...; false; ...)"
513*f1fbf3c2SXin Li                 continueList = prevContList;
514*f1fbf3c2SXin Li                 breakList = prevBreakList;
515*f1fbf3c2SXin Li                 hasReturned = false;
516*f1fbf3c2SXin Li                 return;
517*f1fbf3c2SXin Li             }
518*f1fbf3c2SXin Li 
519*f1fbf3c2SXin Li             pc2 = bytecode.currentPc();
520*f1fbf3c2SXin Li             bytecode.addIndex(0);
521*f1fbf3c2SXin Li         }
522*f1fbf3c2SXin Li 
523*f1fbf3c2SXin Li         if (body != null)
524*f1fbf3c2SXin Li             body.accept(this);
525*f1fbf3c2SXin Li 
526*f1fbf3c2SXin Li         int pc3 = bytecode.currentPc();
527*f1fbf3c2SXin Li         if (update != null)
528*f1fbf3c2SXin Li             update.accept(this);
529*f1fbf3c2SXin Li 
530*f1fbf3c2SXin Li         bytecode.addOpcode(Opcode.GOTO);
531*f1fbf3c2SXin Li         bytecode.addIndex(pc - bytecode.currentPc() + 1);
532*f1fbf3c2SXin Li 
533*f1fbf3c2SXin Li         int pc4 = bytecode.currentPc();
534*f1fbf3c2SXin Li         if (expr != null)
535*f1fbf3c2SXin Li             bytecode.write16bit(pc2, pc4 - pc2 + 1);
536*f1fbf3c2SXin Li 
537*f1fbf3c2SXin Li         patchGoto(breakList, pc4);
538*f1fbf3c2SXin Li         patchGoto(continueList, pc3);
539*f1fbf3c2SXin Li         continueList = prevContList;
540*f1fbf3c2SXin Li         breakList = prevBreakList;
541*f1fbf3c2SXin Li         hasReturned = false;
542*f1fbf3c2SXin Li     }
543*f1fbf3c2SXin Li 
atSwitchStmnt(Stmnt st)544*f1fbf3c2SXin Li     private void atSwitchStmnt(Stmnt st) throws CompileError {
545*f1fbf3c2SXin Li         compileExpr(st.head());
546*f1fbf3c2SXin Li 
547*f1fbf3c2SXin Li         List<Integer>  prevBreakList = breakList;
548*f1fbf3c2SXin Li         breakList = new ArrayList<Integer>();
549*f1fbf3c2SXin Li         int opcodePc = bytecode.currentPc();
550*f1fbf3c2SXin Li         bytecode.addOpcode(LOOKUPSWITCH);
551*f1fbf3c2SXin Li         int npads = 3 - (opcodePc & 3);
552*f1fbf3c2SXin Li         while (npads-- > 0)
553*f1fbf3c2SXin Li             bytecode.add(0);
554*f1fbf3c2SXin Li 
555*f1fbf3c2SXin Li         Stmnt body = (Stmnt)st.tail();
556*f1fbf3c2SXin Li         int npairs = 0;
557*f1fbf3c2SXin Li         for (ASTList list = body; list != null; list = list.tail())
558*f1fbf3c2SXin Li             if (((Stmnt)list.head()).getOperator() == CASE)
559*f1fbf3c2SXin Li                 ++npairs;
560*f1fbf3c2SXin Li 
561*f1fbf3c2SXin Li         // opcodePc2 is the position at which the default jump offset is.
562*f1fbf3c2SXin Li         int opcodePc2 = bytecode.currentPc();
563*f1fbf3c2SXin Li         bytecode.addGap(4);
564*f1fbf3c2SXin Li         bytecode.add32bit(npairs);
565*f1fbf3c2SXin Li         bytecode.addGap(npairs * 8);
566*f1fbf3c2SXin Li 
567*f1fbf3c2SXin Li         long[] pairs = new long[npairs];
568*f1fbf3c2SXin Li         int ipairs = 0;
569*f1fbf3c2SXin Li         int defaultPc = -1;
570*f1fbf3c2SXin Li         for (ASTList list = body; list != null; list = list.tail()) {
571*f1fbf3c2SXin Li             Stmnt label = (Stmnt)list.head();
572*f1fbf3c2SXin Li             int op = label.getOperator();
573*f1fbf3c2SXin Li             if (op == DEFAULT)
574*f1fbf3c2SXin Li                 defaultPc = bytecode.currentPc();
575*f1fbf3c2SXin Li             else if (op != CASE)
576*f1fbf3c2SXin Li                 fatal();
577*f1fbf3c2SXin Li             else {
578*f1fbf3c2SXin Li                 pairs[ipairs++]
579*f1fbf3c2SXin Li                     = ((long)computeLabel(label.head()) << 32) +
580*f1fbf3c2SXin Li                       ((long)(bytecode.currentPc() - opcodePc) & 0xffffffff);
581*f1fbf3c2SXin Li             }
582*f1fbf3c2SXin Li 
583*f1fbf3c2SXin Li             hasReturned = false;
584*f1fbf3c2SXin Li             ((Stmnt)label.tail()).accept(this);
585*f1fbf3c2SXin Li         }
586*f1fbf3c2SXin Li 
587*f1fbf3c2SXin Li         Arrays.sort(pairs);
588*f1fbf3c2SXin Li         int pc = opcodePc2 + 8;
589*f1fbf3c2SXin Li         for (int i = 0; i < npairs; ++i) {
590*f1fbf3c2SXin Li             bytecode.write32bit(pc, (int)(pairs[i] >>> 32));
591*f1fbf3c2SXin Li             bytecode.write32bit(pc + 4, (int)pairs[i]);
592*f1fbf3c2SXin Li             pc += 8;
593*f1fbf3c2SXin Li         }
594*f1fbf3c2SXin Li 
595*f1fbf3c2SXin Li         if (defaultPc < 0 || breakList.size() > 0)
596*f1fbf3c2SXin Li             hasReturned = false;
597*f1fbf3c2SXin Li 
598*f1fbf3c2SXin Li         int endPc = bytecode.currentPc();
599*f1fbf3c2SXin Li         if (defaultPc < 0)
600*f1fbf3c2SXin Li             defaultPc = endPc;
601*f1fbf3c2SXin Li 
602*f1fbf3c2SXin Li         bytecode.write32bit(opcodePc2, defaultPc - opcodePc);
603*f1fbf3c2SXin Li 
604*f1fbf3c2SXin Li         patchGoto(breakList, endPc);
605*f1fbf3c2SXin Li         breakList = prevBreakList;
606*f1fbf3c2SXin Li     }
607*f1fbf3c2SXin Li 
computeLabel(ASTree expr)608*f1fbf3c2SXin Li     private int computeLabel(ASTree expr) throws CompileError {
609*f1fbf3c2SXin Li         doTypeCheck(expr);
610*f1fbf3c2SXin Li         expr = TypeChecker.stripPlusExpr(expr);
611*f1fbf3c2SXin Li         if (expr instanceof IntConst)
612*f1fbf3c2SXin Li             return (int)((IntConst)expr).get();
613*f1fbf3c2SXin Li         throw new CompileError("bad case label");
614*f1fbf3c2SXin Li     }
615*f1fbf3c2SXin Li 
atBreakStmnt(Stmnt st, boolean notCont)616*f1fbf3c2SXin Li     private void atBreakStmnt(Stmnt st, boolean notCont)
617*f1fbf3c2SXin Li         throws CompileError
618*f1fbf3c2SXin Li     {
619*f1fbf3c2SXin Li         if (st.head() != null)
620*f1fbf3c2SXin Li             throw new CompileError(
621*f1fbf3c2SXin Li                         "sorry, not support labeled break or continue");
622*f1fbf3c2SXin Li 
623*f1fbf3c2SXin Li         bytecode.addOpcode(Opcode.GOTO);
624*f1fbf3c2SXin Li         Integer pc = Integer.valueOf(bytecode.currentPc());
625*f1fbf3c2SXin Li         bytecode.addIndex(0);
626*f1fbf3c2SXin Li         if (notCont)
627*f1fbf3c2SXin Li             breakList.add(pc);
628*f1fbf3c2SXin Li         else
629*f1fbf3c2SXin Li             continueList.add(pc);
630*f1fbf3c2SXin Li     }
631*f1fbf3c2SXin Li 
atReturnStmnt(Stmnt st)632*f1fbf3c2SXin Li     protected void atReturnStmnt(Stmnt st) throws CompileError {
633*f1fbf3c2SXin Li         atReturnStmnt2(st.getLeft());
634*f1fbf3c2SXin Li     }
635*f1fbf3c2SXin Li 
atReturnStmnt2(ASTree result)636*f1fbf3c2SXin Li     protected final void atReturnStmnt2(ASTree result) throws CompileError {
637*f1fbf3c2SXin Li         int op;
638*f1fbf3c2SXin Li         if (result == null)
639*f1fbf3c2SXin Li             op = Opcode.RETURN;
640*f1fbf3c2SXin Li         else {
641*f1fbf3c2SXin Li             compileExpr(result);
642*f1fbf3c2SXin Li             if (arrayDim > 0)
643*f1fbf3c2SXin Li                 op = ARETURN;
644*f1fbf3c2SXin Li             else {
645*f1fbf3c2SXin Li                 int type = exprType;
646*f1fbf3c2SXin Li                 if (type == DOUBLE)
647*f1fbf3c2SXin Li                     op = DRETURN;
648*f1fbf3c2SXin Li                 else if (type == FLOAT)
649*f1fbf3c2SXin Li                     op = FRETURN;
650*f1fbf3c2SXin Li                 else if (type == LONG)
651*f1fbf3c2SXin Li                     op = LRETURN;
652*f1fbf3c2SXin Li                 else if (isRefType(type))
653*f1fbf3c2SXin Li                     op = ARETURN;
654*f1fbf3c2SXin Li                 else
655*f1fbf3c2SXin Li                     op = IRETURN;
656*f1fbf3c2SXin Li             }
657*f1fbf3c2SXin Li         }
658*f1fbf3c2SXin Li 
659*f1fbf3c2SXin Li         for (ReturnHook har = returnHooks; har != null; har = har.next)
660*f1fbf3c2SXin Li             if (har.doit(bytecode, op)) {
661*f1fbf3c2SXin Li                 hasReturned = true;
662*f1fbf3c2SXin Li                 return;
663*f1fbf3c2SXin Li             }
664*f1fbf3c2SXin Li 
665*f1fbf3c2SXin Li         bytecode.addOpcode(op);
666*f1fbf3c2SXin Li         hasReturned = true;
667*f1fbf3c2SXin Li     }
668*f1fbf3c2SXin Li 
atThrowStmnt(Stmnt st)669*f1fbf3c2SXin Li     private void atThrowStmnt(Stmnt st) throws CompileError {
670*f1fbf3c2SXin Li         ASTree e = st.getLeft();
671*f1fbf3c2SXin Li         compileExpr(e);
672*f1fbf3c2SXin Li         if (exprType != CLASS || arrayDim > 0)
673*f1fbf3c2SXin Li             throw new CompileError("bad throw statement");
674*f1fbf3c2SXin Li 
675*f1fbf3c2SXin Li         bytecode.addOpcode(ATHROW);
676*f1fbf3c2SXin Li         hasReturned = true;
677*f1fbf3c2SXin Li     }
678*f1fbf3c2SXin Li 
679*f1fbf3c2SXin Li     /* overridden in MemberCodeGen
680*f1fbf3c2SXin Li      */
atTryStmnt(Stmnt st)681*f1fbf3c2SXin Li     protected void atTryStmnt(Stmnt st) throws CompileError {
682*f1fbf3c2SXin Li         hasReturned = false;
683*f1fbf3c2SXin Li     }
684*f1fbf3c2SXin Li 
atSyncStmnt(Stmnt st)685*f1fbf3c2SXin Li     private void atSyncStmnt(Stmnt st) throws CompileError {
686*f1fbf3c2SXin Li         int nbreaks = getListSize(breakList);
687*f1fbf3c2SXin Li         int ncontinues = getListSize(continueList);
688*f1fbf3c2SXin Li 
689*f1fbf3c2SXin Li         compileExpr(st.head());
690*f1fbf3c2SXin Li         if (exprType != CLASS && arrayDim == 0)
691*f1fbf3c2SXin Li             throw new CompileError("bad type expr for synchronized block");
692*f1fbf3c2SXin Li 
693*f1fbf3c2SXin Li         Bytecode bc = bytecode;
694*f1fbf3c2SXin Li         final int var = bc.getMaxLocals();
695*f1fbf3c2SXin Li         bc.incMaxLocals(1);
696*f1fbf3c2SXin Li         bc.addOpcode(DUP);
697*f1fbf3c2SXin Li         bc.addAstore(var);
698*f1fbf3c2SXin Li         bc.addOpcode(MONITORENTER);
699*f1fbf3c2SXin Li 
700*f1fbf3c2SXin Li         ReturnHook rh = new ReturnHook(this) {
701*f1fbf3c2SXin Li             @Override
702*f1fbf3c2SXin Li             protected boolean doit(Bytecode b, int opcode) {
703*f1fbf3c2SXin Li                 b.addAload(var);
704*f1fbf3c2SXin Li                 b.addOpcode(MONITOREXIT);
705*f1fbf3c2SXin Li                 return false;
706*f1fbf3c2SXin Li             }
707*f1fbf3c2SXin Li         };
708*f1fbf3c2SXin Li 
709*f1fbf3c2SXin Li         int pc = bc.currentPc();
710*f1fbf3c2SXin Li         Stmnt body = (Stmnt)st.tail();
711*f1fbf3c2SXin Li         if (body != null)
712*f1fbf3c2SXin Li             body.accept(this);
713*f1fbf3c2SXin Li 
714*f1fbf3c2SXin Li         int pc2 = bc.currentPc();
715*f1fbf3c2SXin Li         int pc3 = 0;
716*f1fbf3c2SXin Li         if (!hasReturned) {
717*f1fbf3c2SXin Li             rh.doit(bc, 0);     // the 2nd arg is ignored.
718*f1fbf3c2SXin Li             bc.addOpcode(Opcode.GOTO);
719*f1fbf3c2SXin Li             pc3 = bc.currentPc();
720*f1fbf3c2SXin Li             bc.addIndex(0);
721*f1fbf3c2SXin Li         }
722*f1fbf3c2SXin Li 
723*f1fbf3c2SXin Li         if (pc < pc2) {         // if the body is not empty
724*f1fbf3c2SXin Li             int pc4 = bc.currentPc();
725*f1fbf3c2SXin Li             rh.doit(bc, 0);         // the 2nd arg is ignored.
726*f1fbf3c2SXin Li             bc.addOpcode(ATHROW);
727*f1fbf3c2SXin Li             bc.addExceptionHandler(pc, pc2, pc4, 0);
728*f1fbf3c2SXin Li         }
729*f1fbf3c2SXin Li 
730*f1fbf3c2SXin Li         if (!hasReturned)
731*f1fbf3c2SXin Li             bc.write16bit(pc3, bc.currentPc() - pc3 + 1);
732*f1fbf3c2SXin Li 
733*f1fbf3c2SXin Li         rh.remove(this);
734*f1fbf3c2SXin Li 
735*f1fbf3c2SXin Li         if (getListSize(breakList) != nbreaks
736*f1fbf3c2SXin Li             || getListSize(continueList) != ncontinues)
737*f1fbf3c2SXin Li             throw new CompileError(
738*f1fbf3c2SXin Li                 "sorry, cannot break/continue in synchronized block");
739*f1fbf3c2SXin Li     }
740*f1fbf3c2SXin Li 
getListSize(List<Integer> list)741*f1fbf3c2SXin Li     private static int getListSize(List<Integer>  list) {
742*f1fbf3c2SXin Li         return list == null ? 0 : list.size();
743*f1fbf3c2SXin Li     }
744*f1fbf3c2SXin Li 
isPlusPlusExpr(ASTree expr)745*f1fbf3c2SXin Li     private static boolean isPlusPlusExpr(ASTree expr) {
746*f1fbf3c2SXin Li         if (expr instanceof Expr) {
747*f1fbf3c2SXin Li             int op = ((Expr)expr).getOperator();
748*f1fbf3c2SXin Li             return op == PLUSPLUS || op == MINUSMINUS;
749*f1fbf3c2SXin Li         }
750*f1fbf3c2SXin Li 
751*f1fbf3c2SXin Li         return false;
752*f1fbf3c2SXin Li     }
753*f1fbf3c2SXin Li 
754*f1fbf3c2SXin Li     @Override
atDeclarator(Declarator d)755*f1fbf3c2SXin Li     public void atDeclarator(Declarator d) throws CompileError {
756*f1fbf3c2SXin Li         d.setLocalVar(getMaxLocals());
757*f1fbf3c2SXin Li         d.setClassName(resolveClassName(d.getClassName()));
758*f1fbf3c2SXin Li 
759*f1fbf3c2SXin Li         int size;
760*f1fbf3c2SXin Li         if (is2word(d.getType(), d.getArrayDim()))
761*f1fbf3c2SXin Li             size = 2;
762*f1fbf3c2SXin Li         else
763*f1fbf3c2SXin Li             size = 1;
764*f1fbf3c2SXin Li 
765*f1fbf3c2SXin Li         incMaxLocals(size);
766*f1fbf3c2SXin Li 
767*f1fbf3c2SXin Li         /*  NOTE: Array initializers has not been supported.
768*f1fbf3c2SXin Li          */
769*f1fbf3c2SXin Li         ASTree init = d.getInitializer();
770*f1fbf3c2SXin Li         if (init != null) {
771*f1fbf3c2SXin Li             doTypeCheck(init);
772*f1fbf3c2SXin Li             atVariableAssign(null, '=', null, d, init, false);
773*f1fbf3c2SXin Li         }
774*f1fbf3c2SXin Li     }
775*f1fbf3c2SXin Li 
776*f1fbf3c2SXin Li     @Override
atNewExpr(NewExpr n)777*f1fbf3c2SXin Li     public abstract void atNewExpr(NewExpr n) throws CompileError;
778*f1fbf3c2SXin Li 
779*f1fbf3c2SXin Li     @Override
atArrayInit(ArrayInit init)780*f1fbf3c2SXin Li     public abstract void atArrayInit(ArrayInit init) throws CompileError;
781*f1fbf3c2SXin Li 
782*f1fbf3c2SXin Li     @Override
atAssignExpr(AssignExpr expr)783*f1fbf3c2SXin Li     public void atAssignExpr(AssignExpr expr) throws CompileError {
784*f1fbf3c2SXin Li         atAssignExpr(expr, true);
785*f1fbf3c2SXin Li     }
786*f1fbf3c2SXin Li 
atAssignExpr(AssignExpr expr, boolean doDup)787*f1fbf3c2SXin Li     protected void atAssignExpr(AssignExpr expr, boolean doDup)
788*f1fbf3c2SXin Li         throws CompileError
789*f1fbf3c2SXin Li     {
790*f1fbf3c2SXin Li         // =, %=, &=, *=, /=, +=, -=, ^=, |=, <<=, >>=, >>>=
791*f1fbf3c2SXin Li         int op = expr.getOperator();
792*f1fbf3c2SXin Li         ASTree left = expr.oprand1();
793*f1fbf3c2SXin Li         ASTree right = expr.oprand2();
794*f1fbf3c2SXin Li         if (left instanceof Variable)
795*f1fbf3c2SXin Li             atVariableAssign(expr, op, (Variable)left,
796*f1fbf3c2SXin Li                              ((Variable)left).getDeclarator(),
797*f1fbf3c2SXin Li                              right, doDup);
798*f1fbf3c2SXin Li         else {
799*f1fbf3c2SXin Li             if (left instanceof Expr) {
800*f1fbf3c2SXin Li                 Expr e = (Expr)left;
801*f1fbf3c2SXin Li                 if (e.getOperator() == ARRAY) {
802*f1fbf3c2SXin Li                     atArrayAssign(expr, op, (Expr)left, right, doDup);
803*f1fbf3c2SXin Li                     return;
804*f1fbf3c2SXin Li                 }
805*f1fbf3c2SXin Li             }
806*f1fbf3c2SXin Li 
807*f1fbf3c2SXin Li             atFieldAssign(expr, op, left, right, doDup);
808*f1fbf3c2SXin Li         }
809*f1fbf3c2SXin Li     }
810*f1fbf3c2SXin Li 
badAssign(Expr expr)811*f1fbf3c2SXin Li     protected static void badAssign(Expr expr) throws CompileError {
812*f1fbf3c2SXin Li         String msg;
813*f1fbf3c2SXin Li         if (expr == null)
814*f1fbf3c2SXin Li             msg = "incompatible type for assignment";
815*f1fbf3c2SXin Li         else
816*f1fbf3c2SXin Li             msg = "incompatible type for " + expr.getName();
817*f1fbf3c2SXin Li 
818*f1fbf3c2SXin Li         throw new CompileError(msg);
819*f1fbf3c2SXin Li     }
820*f1fbf3c2SXin Li 
821*f1fbf3c2SXin Li     /* op is either =, %=, &=, *=, /=, +=, -=, ^=, |=, <<=, >>=, or >>>=.
822*f1fbf3c2SXin Li      *
823*f1fbf3c2SXin Li      * expr and var can be null.
824*f1fbf3c2SXin Li      */
atVariableAssign(Expr expr, int op, Variable var, Declarator d, ASTree right, boolean doDup)825*f1fbf3c2SXin Li     private void atVariableAssign(Expr expr, int op, Variable var,
826*f1fbf3c2SXin Li                                   Declarator d, ASTree right,
827*f1fbf3c2SXin Li                                   boolean doDup) throws CompileError
828*f1fbf3c2SXin Li     {
829*f1fbf3c2SXin Li         int varType = d.getType();
830*f1fbf3c2SXin Li         int varArray = d.getArrayDim();
831*f1fbf3c2SXin Li         String varClass = d.getClassName();
832*f1fbf3c2SXin Li         int varNo = getLocalVar(d);
833*f1fbf3c2SXin Li 
834*f1fbf3c2SXin Li         if (op != '=')
835*f1fbf3c2SXin Li             atVariable(var);
836*f1fbf3c2SXin Li 
837*f1fbf3c2SXin Li         // expr is null if the caller is atDeclarator().
838*f1fbf3c2SXin Li         if (expr == null && right instanceof ArrayInit)
839*f1fbf3c2SXin Li             atArrayVariableAssign((ArrayInit)right, varType, varArray, varClass);
840*f1fbf3c2SXin Li         else
841*f1fbf3c2SXin Li             atAssignCore(expr, op, right, varType, varArray, varClass);
842*f1fbf3c2SXin Li 
843*f1fbf3c2SXin Li         if (doDup)
844*f1fbf3c2SXin Li             if (is2word(varType, varArray))
845*f1fbf3c2SXin Li                 bytecode.addOpcode(DUP2);
846*f1fbf3c2SXin Li             else
847*f1fbf3c2SXin Li                 bytecode.addOpcode(DUP);
848*f1fbf3c2SXin Li 
849*f1fbf3c2SXin Li         if (varArray > 0)
850*f1fbf3c2SXin Li             bytecode.addAstore(varNo);
851*f1fbf3c2SXin Li         else if (varType == DOUBLE)
852*f1fbf3c2SXin Li             bytecode.addDstore(varNo);
853*f1fbf3c2SXin Li         else if (varType == FLOAT)
854*f1fbf3c2SXin Li             bytecode.addFstore(varNo);
855*f1fbf3c2SXin Li         else if (varType == LONG)
856*f1fbf3c2SXin Li             bytecode.addLstore(varNo);
857*f1fbf3c2SXin Li         else if (isRefType(varType))
858*f1fbf3c2SXin Li             bytecode.addAstore(varNo);
859*f1fbf3c2SXin Li         else
860*f1fbf3c2SXin Li             bytecode.addIstore(varNo);
861*f1fbf3c2SXin Li 
862*f1fbf3c2SXin Li         exprType = varType;
863*f1fbf3c2SXin Li         arrayDim = varArray;
864*f1fbf3c2SXin Li         className = varClass;
865*f1fbf3c2SXin Li     }
866*f1fbf3c2SXin Li 
atArrayVariableAssign(ArrayInit init, int varType, int varArray, String varClass)867*f1fbf3c2SXin Li     protected abstract void atArrayVariableAssign(ArrayInit init,
868*f1fbf3c2SXin Li             int varType, int varArray, String varClass) throws CompileError;
869*f1fbf3c2SXin Li 
atArrayAssign(Expr expr, int op, Expr array, ASTree right, boolean doDup)870*f1fbf3c2SXin Li     private void atArrayAssign(Expr expr, int op, Expr array,
871*f1fbf3c2SXin Li                         ASTree right, boolean doDup) throws CompileError
872*f1fbf3c2SXin Li     {
873*f1fbf3c2SXin Li         arrayAccess(array.oprand1(), array.oprand2());
874*f1fbf3c2SXin Li 
875*f1fbf3c2SXin Li         if (op != '=') {
876*f1fbf3c2SXin Li             bytecode.addOpcode(DUP2);
877*f1fbf3c2SXin Li             bytecode.addOpcode(getArrayReadOp(exprType, arrayDim));
878*f1fbf3c2SXin Li         }
879*f1fbf3c2SXin Li 
880*f1fbf3c2SXin Li         int aType = exprType;
881*f1fbf3c2SXin Li         int aDim = arrayDim;
882*f1fbf3c2SXin Li         String cname = className;
883*f1fbf3c2SXin Li 
884*f1fbf3c2SXin Li         atAssignCore(expr, op, right, aType, aDim, cname);
885*f1fbf3c2SXin Li 
886*f1fbf3c2SXin Li         if (doDup)
887*f1fbf3c2SXin Li             if (is2word(aType, aDim))
888*f1fbf3c2SXin Li                 bytecode.addOpcode(DUP2_X2);
889*f1fbf3c2SXin Li             else
890*f1fbf3c2SXin Li                 bytecode.addOpcode(DUP_X2);
891*f1fbf3c2SXin Li 
892*f1fbf3c2SXin Li         bytecode.addOpcode(getArrayWriteOp(aType, aDim));
893*f1fbf3c2SXin Li         exprType = aType;
894*f1fbf3c2SXin Li         arrayDim = aDim;
895*f1fbf3c2SXin Li         className = cname;
896*f1fbf3c2SXin Li     }
897*f1fbf3c2SXin Li 
atFieldAssign(Expr expr, int op, ASTree left, ASTree right, boolean doDup)898*f1fbf3c2SXin Li     protected abstract void atFieldAssign(Expr expr, int op, ASTree left,
899*f1fbf3c2SXin Li                         ASTree right, boolean doDup) throws CompileError;
900*f1fbf3c2SXin Li 
atAssignCore(Expr expr, int op, ASTree right, int type, int dim, String cname)901*f1fbf3c2SXin Li     protected void atAssignCore(Expr expr, int op, ASTree right,
902*f1fbf3c2SXin Li                                 int type, int dim, String cname)
903*f1fbf3c2SXin Li         throws CompileError
904*f1fbf3c2SXin Li     {
905*f1fbf3c2SXin Li         if (op == PLUS_E && dim == 0 && type == CLASS)
906*f1fbf3c2SXin Li             atStringPlusEq(expr, type, dim, cname, right);
907*f1fbf3c2SXin Li         else {
908*f1fbf3c2SXin Li             right.accept(this);
909*f1fbf3c2SXin Li             if (invalidDim(exprType, arrayDim, className, type, dim, cname,
910*f1fbf3c2SXin Li                            false) || (op != '=' && dim > 0))
911*f1fbf3c2SXin Li                 badAssign(expr);
912*f1fbf3c2SXin Li 
913*f1fbf3c2SXin Li             if (op != '=') {
914*f1fbf3c2SXin Li                 int token = assignOps[op - MOD_E];
915*f1fbf3c2SXin Li                 int k = lookupBinOp(token);
916*f1fbf3c2SXin Li                 if (k < 0)
917*f1fbf3c2SXin Li                     fatal();
918*f1fbf3c2SXin Li 
919*f1fbf3c2SXin Li                 atArithBinExpr(expr, token, k, type);
920*f1fbf3c2SXin Li             }
921*f1fbf3c2SXin Li         }
922*f1fbf3c2SXin Li 
923*f1fbf3c2SXin Li         if (op != '=' || (dim == 0 && !isRefType(type)))
924*f1fbf3c2SXin Li             atNumCastExpr(exprType, type);
925*f1fbf3c2SXin Li 
926*f1fbf3c2SXin Li         // type check should be done here.
927*f1fbf3c2SXin Li     }
928*f1fbf3c2SXin Li 
atStringPlusEq(Expr expr, int type, int dim, String cname, ASTree right)929*f1fbf3c2SXin Li     private void atStringPlusEq(Expr expr, int type, int dim, String cname,
930*f1fbf3c2SXin Li                                 ASTree right)
931*f1fbf3c2SXin Li         throws CompileError
932*f1fbf3c2SXin Li     {
933*f1fbf3c2SXin Li         if (!jvmJavaLangString.equals(cname))
934*f1fbf3c2SXin Li             badAssign(expr);
935*f1fbf3c2SXin Li 
936*f1fbf3c2SXin Li         convToString(type, dim);    // the value might be null.
937*f1fbf3c2SXin Li         right.accept(this);
938*f1fbf3c2SXin Li         convToString(exprType, arrayDim);
939*f1fbf3c2SXin Li         bytecode.addInvokevirtual(javaLangString, "concat",
940*f1fbf3c2SXin Li                                 "(Ljava/lang/String;)Ljava/lang/String;");
941*f1fbf3c2SXin Li         exprType = CLASS;
942*f1fbf3c2SXin Li         arrayDim = 0;
943*f1fbf3c2SXin Li         className = jvmJavaLangString;
944*f1fbf3c2SXin Li     }
945*f1fbf3c2SXin Li 
invalidDim(int srcType, int srcDim, String srcClass, int destType, int destDim, String destClass, boolean isCast)946*f1fbf3c2SXin Li     private boolean invalidDim(int srcType, int srcDim, String srcClass,
947*f1fbf3c2SXin Li                                int destType, int destDim, String destClass,
948*f1fbf3c2SXin Li                                boolean isCast)
949*f1fbf3c2SXin Li     {
950*f1fbf3c2SXin Li         if (srcDim != destDim)
951*f1fbf3c2SXin Li             if (srcType == NULL)
952*f1fbf3c2SXin Li                 return false;
953*f1fbf3c2SXin Li             else if (destDim == 0 && destType == CLASS
954*f1fbf3c2SXin Li                      && jvmJavaLangObject.equals(destClass))
955*f1fbf3c2SXin Li                 return false;
956*f1fbf3c2SXin Li             else if (isCast && srcDim == 0 && srcType == CLASS
957*f1fbf3c2SXin Li                      && jvmJavaLangObject.equals(srcClass))
958*f1fbf3c2SXin Li                 return false;
959*f1fbf3c2SXin Li             else
960*f1fbf3c2SXin Li                 return true;
961*f1fbf3c2SXin Li 
962*f1fbf3c2SXin Li         return false;
963*f1fbf3c2SXin Li     }
964*f1fbf3c2SXin Li 
965*f1fbf3c2SXin Li     @Override
atCondExpr(CondExpr expr)966*f1fbf3c2SXin Li     public void atCondExpr(CondExpr expr) throws CompileError {
967*f1fbf3c2SXin Li         if (booleanExpr(false, expr.condExpr()))
968*f1fbf3c2SXin Li             expr.elseExpr().accept(this);
969*f1fbf3c2SXin Li         else {
970*f1fbf3c2SXin Li             int pc = bytecode.currentPc();
971*f1fbf3c2SXin Li             bytecode.addIndex(0);   // correct later
972*f1fbf3c2SXin Li             expr.thenExpr().accept(this);
973*f1fbf3c2SXin Li             int dim1 = arrayDim;
974*f1fbf3c2SXin Li             bytecode.addOpcode(Opcode.GOTO);
975*f1fbf3c2SXin Li             int pc2 = bytecode.currentPc();
976*f1fbf3c2SXin Li             bytecode.addIndex(0);
977*f1fbf3c2SXin Li             bytecode.write16bit(pc, bytecode.currentPc() - pc + 1);
978*f1fbf3c2SXin Li             expr.elseExpr().accept(this);
979*f1fbf3c2SXin Li             if (dim1 != arrayDim)
980*f1fbf3c2SXin Li                 throw new CompileError("type mismatch in ?:");
981*f1fbf3c2SXin Li 
982*f1fbf3c2SXin Li             bytecode.write16bit(pc2, bytecode.currentPc() - pc2 + 1);
983*f1fbf3c2SXin Li         }
984*f1fbf3c2SXin Li     }
985*f1fbf3c2SXin Li 
986*f1fbf3c2SXin Li     static final int[] binOp = {
987*f1fbf3c2SXin Li         '+', DADD, FADD, LADD, IADD,
988*f1fbf3c2SXin Li         '-', DSUB, FSUB, LSUB, ISUB,
989*f1fbf3c2SXin Li         '*', DMUL, FMUL, LMUL, IMUL,
990*f1fbf3c2SXin Li         '/', DDIV, FDIV, LDIV, IDIV,
991*f1fbf3c2SXin Li         '%', DREM, FREM, LREM, IREM,
992*f1fbf3c2SXin Li         '|', NOP,  NOP,  LOR,  IOR,
993*f1fbf3c2SXin Li         '^', NOP,  NOP,  LXOR, IXOR,
994*f1fbf3c2SXin Li         '&', NOP,  NOP,  LAND, IAND,
995*f1fbf3c2SXin Li         LSHIFT, NOP, NOP, LSHL, ISHL,
996*f1fbf3c2SXin Li         RSHIFT, NOP, NOP, LSHR, ISHR,
997*f1fbf3c2SXin Li         ARSHIFT, NOP, NOP, LUSHR, IUSHR };
998*f1fbf3c2SXin Li 
lookupBinOp(int token)999*f1fbf3c2SXin Li     static int lookupBinOp(int token) {
1000*f1fbf3c2SXin Li         int[] code = binOp;
1001*f1fbf3c2SXin Li         int s = code.length;
1002*f1fbf3c2SXin Li         for (int k = 0; k < s; k = k + 5)
1003*f1fbf3c2SXin Li             if (code[k] == token)
1004*f1fbf3c2SXin Li                 return k;
1005*f1fbf3c2SXin Li 
1006*f1fbf3c2SXin Li         return -1;
1007*f1fbf3c2SXin Li     }
1008*f1fbf3c2SXin Li 
1009*f1fbf3c2SXin Li     @Override
atBinExpr(BinExpr expr)1010*f1fbf3c2SXin Li     public void atBinExpr(BinExpr expr) throws CompileError {
1011*f1fbf3c2SXin Li         int token = expr.getOperator();
1012*f1fbf3c2SXin Li 
1013*f1fbf3c2SXin Li         /* arithmetic operators: +, -, *, /, %, |, ^, &, <<, >>, >>>
1014*f1fbf3c2SXin Li          */
1015*f1fbf3c2SXin Li         int k = lookupBinOp(token);
1016*f1fbf3c2SXin Li         if (k >= 0) {
1017*f1fbf3c2SXin Li             expr.oprand1().accept(this);
1018*f1fbf3c2SXin Li             ASTree right = expr.oprand2();
1019*f1fbf3c2SXin Li             if (right == null)
1020*f1fbf3c2SXin Li                 return;     // see TypeChecker.atBinExpr().
1021*f1fbf3c2SXin Li 
1022*f1fbf3c2SXin Li             int type1 = exprType;
1023*f1fbf3c2SXin Li             int dim1 = arrayDim;
1024*f1fbf3c2SXin Li             String cname1 = className;
1025*f1fbf3c2SXin Li             right.accept(this);
1026*f1fbf3c2SXin Li             if (dim1 != arrayDim)
1027*f1fbf3c2SXin Li                 throw new CompileError("incompatible array types");
1028*f1fbf3c2SXin Li 
1029*f1fbf3c2SXin Li             if (token == '+' && dim1 == 0
1030*f1fbf3c2SXin Li                 && (type1 == CLASS || exprType == CLASS))
1031*f1fbf3c2SXin Li                 atStringConcatExpr(expr, type1, dim1, cname1);
1032*f1fbf3c2SXin Li             else
1033*f1fbf3c2SXin Li                 atArithBinExpr(expr, token, k, type1);
1034*f1fbf3c2SXin Li         }
1035*f1fbf3c2SXin Li         else {
1036*f1fbf3c2SXin Li             /* equation: &&, ||, ==, !=, <=, >=, <, >
1037*f1fbf3c2SXin Li             */
1038*f1fbf3c2SXin Li             if (!booleanExpr(true, expr)) {
1039*f1fbf3c2SXin Li                 bytecode.addIndex(7);
1040*f1fbf3c2SXin Li                 bytecode.addIconst(0);  // false
1041*f1fbf3c2SXin Li                 bytecode.addOpcode(Opcode.GOTO);
1042*f1fbf3c2SXin Li                 bytecode.addIndex(4);
1043*f1fbf3c2SXin Li             }
1044*f1fbf3c2SXin Li 
1045*f1fbf3c2SXin Li             bytecode.addIconst(1);  // true
1046*f1fbf3c2SXin Li         }
1047*f1fbf3c2SXin Li     }
1048*f1fbf3c2SXin Li 
1049*f1fbf3c2SXin Li     /* arrayDim values of the two oprands must be equal.
1050*f1fbf3c2SXin Li      * If an oprand type is not a numeric type, this method
1051*f1fbf3c2SXin Li      * throws an exception.
1052*f1fbf3c2SXin Li      */
atArithBinExpr(Expr expr, int token, int index, int type1)1053*f1fbf3c2SXin Li     private void atArithBinExpr(Expr expr, int token,
1054*f1fbf3c2SXin Li                                 int index, int type1) throws CompileError
1055*f1fbf3c2SXin Li     {
1056*f1fbf3c2SXin Li         if (arrayDim != 0)
1057*f1fbf3c2SXin Li             badTypes(expr);
1058*f1fbf3c2SXin Li 
1059*f1fbf3c2SXin Li         int type2 = exprType;
1060*f1fbf3c2SXin Li         if (token == LSHIFT || token == RSHIFT || token == ARSHIFT)
1061*f1fbf3c2SXin Li             if (type2 == INT || type2 == SHORT
1062*f1fbf3c2SXin Li                 || type2 == CHAR || type2 == BYTE)
1063*f1fbf3c2SXin Li                 exprType = type1;
1064*f1fbf3c2SXin Li             else
1065*f1fbf3c2SXin Li                 badTypes(expr);
1066*f1fbf3c2SXin Li         else
1067*f1fbf3c2SXin Li             convertOprandTypes(type1, type2, expr);
1068*f1fbf3c2SXin Li 
1069*f1fbf3c2SXin Li         int p = typePrecedence(exprType);
1070*f1fbf3c2SXin Li         if (p >= 0) {
1071*f1fbf3c2SXin Li             int op = binOp[index + p + 1];
1072*f1fbf3c2SXin Li             if (op != NOP) {
1073*f1fbf3c2SXin Li                 if (p == P_INT && exprType != BOOLEAN)
1074*f1fbf3c2SXin Li                     exprType = INT;     // type1 may be BYTE, ...
1075*f1fbf3c2SXin Li 
1076*f1fbf3c2SXin Li                 bytecode.addOpcode(op);
1077*f1fbf3c2SXin Li                 return;
1078*f1fbf3c2SXin Li             }
1079*f1fbf3c2SXin Li         }
1080*f1fbf3c2SXin Li 
1081*f1fbf3c2SXin Li         badTypes(expr);
1082*f1fbf3c2SXin Li     }
1083*f1fbf3c2SXin Li 
atStringConcatExpr(Expr expr, int type1, int dim1, String cname1)1084*f1fbf3c2SXin Li     private void atStringConcatExpr(Expr expr, int type1, int dim1,
1085*f1fbf3c2SXin Li                                     String cname1) throws CompileError
1086*f1fbf3c2SXin Li     {
1087*f1fbf3c2SXin Li         int type2 = exprType;
1088*f1fbf3c2SXin Li         int dim2 = arrayDim;
1089*f1fbf3c2SXin Li         boolean type2Is2 = is2word(type2, dim2);
1090*f1fbf3c2SXin Li         boolean type2IsString
1091*f1fbf3c2SXin Li             = (type2 == CLASS && jvmJavaLangString.equals(className));
1092*f1fbf3c2SXin Li 
1093*f1fbf3c2SXin Li         if (type2Is2)
1094*f1fbf3c2SXin Li             convToString(type2, dim2);
1095*f1fbf3c2SXin Li 
1096*f1fbf3c2SXin Li         if (is2word(type1, dim1)) {
1097*f1fbf3c2SXin Li             bytecode.addOpcode(DUP_X2);
1098*f1fbf3c2SXin Li             bytecode.addOpcode(POP);
1099*f1fbf3c2SXin Li         }
1100*f1fbf3c2SXin Li         else
1101*f1fbf3c2SXin Li             bytecode.addOpcode(SWAP);
1102*f1fbf3c2SXin Li 
1103*f1fbf3c2SXin Li         // even if type1 is String, the left operand might be null.
1104*f1fbf3c2SXin Li         convToString(type1, dim1);
1105*f1fbf3c2SXin Li         bytecode.addOpcode(SWAP);
1106*f1fbf3c2SXin Li 
1107*f1fbf3c2SXin Li         if (!type2Is2 && !type2IsString)
1108*f1fbf3c2SXin Li             convToString(type2, dim2);
1109*f1fbf3c2SXin Li 
1110*f1fbf3c2SXin Li         bytecode.addInvokevirtual(javaLangString, "concat",
1111*f1fbf3c2SXin Li                                 "(Ljava/lang/String;)Ljava/lang/String;");
1112*f1fbf3c2SXin Li         exprType = CLASS;
1113*f1fbf3c2SXin Li         arrayDim = 0;
1114*f1fbf3c2SXin Li         className = jvmJavaLangString;
1115*f1fbf3c2SXin Li     }
1116*f1fbf3c2SXin Li 
convToString(int type, int dim)1117*f1fbf3c2SXin Li     private void convToString(int type, int dim) throws CompileError {
1118*f1fbf3c2SXin Li         final String method = "valueOf";
1119*f1fbf3c2SXin Li 
1120*f1fbf3c2SXin Li         if (isRefType(type) || dim > 0)
1121*f1fbf3c2SXin Li             bytecode.addInvokestatic(javaLangString, method,
1122*f1fbf3c2SXin Li                                 "(Ljava/lang/Object;)Ljava/lang/String;");
1123*f1fbf3c2SXin Li         else if (type == DOUBLE)
1124*f1fbf3c2SXin Li             bytecode.addInvokestatic(javaLangString, method,
1125*f1fbf3c2SXin Li                                      "(D)Ljava/lang/String;");
1126*f1fbf3c2SXin Li         else if (type == FLOAT)
1127*f1fbf3c2SXin Li             bytecode.addInvokestatic(javaLangString, method,
1128*f1fbf3c2SXin Li                                      "(F)Ljava/lang/String;");
1129*f1fbf3c2SXin Li         else if (type == LONG)
1130*f1fbf3c2SXin Li             bytecode.addInvokestatic(javaLangString, method,
1131*f1fbf3c2SXin Li                                      "(J)Ljava/lang/String;");
1132*f1fbf3c2SXin Li         else if (type == BOOLEAN)
1133*f1fbf3c2SXin Li             bytecode.addInvokestatic(javaLangString, method,
1134*f1fbf3c2SXin Li                                      "(Z)Ljava/lang/String;");
1135*f1fbf3c2SXin Li         else if (type == CHAR)
1136*f1fbf3c2SXin Li             bytecode.addInvokestatic(javaLangString, method,
1137*f1fbf3c2SXin Li                                      "(C)Ljava/lang/String;");
1138*f1fbf3c2SXin Li         else if (type == VOID)
1139*f1fbf3c2SXin Li             throw new CompileError("void type expression");
1140*f1fbf3c2SXin Li         else /* INT, BYTE, SHORT */
1141*f1fbf3c2SXin Li             bytecode.addInvokestatic(javaLangString, method,
1142*f1fbf3c2SXin Li                                      "(I)Ljava/lang/String;");
1143*f1fbf3c2SXin Li     }
1144*f1fbf3c2SXin Li 
1145*f1fbf3c2SXin Li     /* Produces the opcode to branch if the condition is true.
1146*f1fbf3c2SXin Li      * The oprand (branch offset) is not produced.
1147*f1fbf3c2SXin Li      *
1148*f1fbf3c2SXin Li      * @return	true if the compiled code is GOTO (always branch).
1149*f1fbf3c2SXin Li      * 			GOTO is not produced.
1150*f1fbf3c2SXin Li      */
booleanExpr(boolean branchIf, ASTree expr)1151*f1fbf3c2SXin Li     private boolean booleanExpr(boolean branchIf, ASTree expr)
1152*f1fbf3c2SXin Li         throws CompileError
1153*f1fbf3c2SXin Li     {
1154*f1fbf3c2SXin Li         boolean isAndAnd;
1155*f1fbf3c2SXin Li         int op = getCompOperator(expr);
1156*f1fbf3c2SXin Li         if (op == EQ) {         // ==, !=, ...
1157*f1fbf3c2SXin Li             BinExpr bexpr = (BinExpr)expr;
1158*f1fbf3c2SXin Li             int type1 = compileOprands(bexpr);
1159*f1fbf3c2SXin Li             // here, arrayDim might represent the array dim. of the left oprand
1160*f1fbf3c2SXin Li             // if the right oprand is NULL.
1161*f1fbf3c2SXin Li             compareExpr(branchIf, bexpr.getOperator(), type1, bexpr);
1162*f1fbf3c2SXin Li         }
1163*f1fbf3c2SXin Li         else if (op == '!')
1164*f1fbf3c2SXin Li             return booleanExpr(!branchIf, ((Expr)expr).oprand1());
1165*f1fbf3c2SXin Li         else if ((isAndAnd = (op == ANDAND)) || op == OROR) {
1166*f1fbf3c2SXin Li             BinExpr bexpr = (BinExpr)expr;
1167*f1fbf3c2SXin Li             if (booleanExpr(!isAndAnd, bexpr.oprand1())) {
1168*f1fbf3c2SXin Li                 exprType = BOOLEAN;
1169*f1fbf3c2SXin Li                 arrayDim = 0;
1170*f1fbf3c2SXin Li                 return true;
1171*f1fbf3c2SXin Li             }
1172*f1fbf3c2SXin Li             	int pc = bytecode.currentPc();
1173*f1fbf3c2SXin Li             	bytecode.addIndex(0);       // correct later
1174*f1fbf3c2SXin Li             	if (booleanExpr(isAndAnd, bexpr.oprand2()))
1175*f1fbf3c2SXin Li             		bytecode.addOpcode(Opcode.GOTO);
1176*f1fbf3c2SXin Li 
1177*f1fbf3c2SXin Li             	bytecode.write16bit(pc, bytecode.currentPc() - pc + 3);
1178*f1fbf3c2SXin Li             	if (branchIf != isAndAnd) {
1179*f1fbf3c2SXin Li             		bytecode.addIndex(6);   // skip GOTO instruction
1180*f1fbf3c2SXin Li             		bytecode.addOpcode(Opcode.GOTO);
1181*f1fbf3c2SXin Li             	}
1182*f1fbf3c2SXin Li         }
1183*f1fbf3c2SXin Li         else if (isAlwaysBranch(expr, branchIf)) {
1184*f1fbf3c2SXin Li         	// Opcode.GOTO is not added here.  The caller must add it.
1185*f1fbf3c2SXin Li             exprType = BOOLEAN;
1186*f1fbf3c2SXin Li             arrayDim = 0;
1187*f1fbf3c2SXin Li             return true;	// always branch
1188*f1fbf3c2SXin Li         }
1189*f1fbf3c2SXin Li         else {                          // others
1190*f1fbf3c2SXin Li             expr.accept(this);
1191*f1fbf3c2SXin Li             if (exprType != BOOLEAN || arrayDim != 0)
1192*f1fbf3c2SXin Li                 throw new CompileError("boolean expr is required");
1193*f1fbf3c2SXin Li 
1194*f1fbf3c2SXin Li             bytecode.addOpcode(branchIf ? IFNE : IFEQ);
1195*f1fbf3c2SXin Li         }
1196*f1fbf3c2SXin Li 
1197*f1fbf3c2SXin Li         exprType = BOOLEAN;
1198*f1fbf3c2SXin Li         arrayDim = 0;
1199*f1fbf3c2SXin Li         return false;
1200*f1fbf3c2SXin Li     }
1201*f1fbf3c2SXin Li 
isAlwaysBranch(ASTree expr, boolean branchIf)1202*f1fbf3c2SXin Li     private static boolean isAlwaysBranch(ASTree expr, boolean branchIf) {
1203*f1fbf3c2SXin Li         if (expr instanceof Keyword) {
1204*f1fbf3c2SXin Li             int t = ((Keyword)expr).get();
1205*f1fbf3c2SXin Li             return branchIf ? t == TRUE : t == FALSE;
1206*f1fbf3c2SXin Li         }
1207*f1fbf3c2SXin Li 
1208*f1fbf3c2SXin Li         return false;
1209*f1fbf3c2SXin Li     }
1210*f1fbf3c2SXin Li 
getCompOperator(ASTree expr)1211*f1fbf3c2SXin Li     static int getCompOperator(ASTree expr) throws CompileError {
1212*f1fbf3c2SXin Li         if (expr instanceof Expr) {
1213*f1fbf3c2SXin Li             Expr bexpr = (Expr)expr;
1214*f1fbf3c2SXin Li             int token = bexpr.getOperator();
1215*f1fbf3c2SXin Li             if (token == '!')
1216*f1fbf3c2SXin Li                 return '!';
1217*f1fbf3c2SXin Li             else if ((bexpr instanceof BinExpr)
1218*f1fbf3c2SXin Li                      && token != OROR && token != ANDAND
1219*f1fbf3c2SXin Li                      && token != '&' && token != '|')
1220*f1fbf3c2SXin Li                 return EQ;      // ==, !=, ...
1221*f1fbf3c2SXin Li             else
1222*f1fbf3c2SXin Li                 return token;
1223*f1fbf3c2SXin Li         }
1224*f1fbf3c2SXin Li 
1225*f1fbf3c2SXin Li         return ' ';     // others
1226*f1fbf3c2SXin Li     }
1227*f1fbf3c2SXin Li 
compileOprands(BinExpr expr)1228*f1fbf3c2SXin Li     private int compileOprands(BinExpr expr) throws CompileError {
1229*f1fbf3c2SXin Li         expr.oprand1().accept(this);
1230*f1fbf3c2SXin Li         int type1 = exprType;
1231*f1fbf3c2SXin Li         int dim1 = arrayDim;
1232*f1fbf3c2SXin Li         expr.oprand2().accept(this);
1233*f1fbf3c2SXin Li         if (dim1 != arrayDim)
1234*f1fbf3c2SXin Li             if (type1 != NULL && exprType != NULL)
1235*f1fbf3c2SXin Li                 throw new CompileError("incompatible array types");
1236*f1fbf3c2SXin Li             else if (exprType == NULL)
1237*f1fbf3c2SXin Li                 arrayDim = dim1;
1238*f1fbf3c2SXin Li 
1239*f1fbf3c2SXin Li         if (type1 == NULL)
1240*f1fbf3c2SXin Li             return exprType;
1241*f1fbf3c2SXin Li         return type1;
1242*f1fbf3c2SXin Li     }
1243*f1fbf3c2SXin Li 
1244*f1fbf3c2SXin Li     private static final int ifOp[] = { EQ, IF_ICMPEQ, IF_ICMPNE,
1245*f1fbf3c2SXin Li                                         NEQ, IF_ICMPNE, IF_ICMPEQ,
1246*f1fbf3c2SXin Li                                         LE, IF_ICMPLE, IF_ICMPGT,
1247*f1fbf3c2SXin Li                                         GE, IF_ICMPGE, IF_ICMPLT,
1248*f1fbf3c2SXin Li                                         '<', IF_ICMPLT, IF_ICMPGE,
1249*f1fbf3c2SXin Li                                         '>', IF_ICMPGT, IF_ICMPLE };
1250*f1fbf3c2SXin Li 
1251*f1fbf3c2SXin Li     private static final int ifOp2[] = { EQ, IFEQ, IFNE,
1252*f1fbf3c2SXin Li                                          NEQ, IFNE, IFEQ,
1253*f1fbf3c2SXin Li                                          LE, IFLE, IFGT,
1254*f1fbf3c2SXin Li                                          GE, IFGE, IFLT,
1255*f1fbf3c2SXin Li                                          '<', IFLT, IFGE,
1256*f1fbf3c2SXin Li                                          '>', IFGT, IFLE };
1257*f1fbf3c2SXin Li 
1258*f1fbf3c2SXin Li     /* Produces the opcode to branch if the condition is true.
1259*f1fbf3c2SXin Li      * The oprands are not produced.
1260*f1fbf3c2SXin Li      *
1261*f1fbf3c2SXin Li      * Parameter expr - compare expression ==, !=, <=, >=, <, >
1262*f1fbf3c2SXin Li      */
compareExpr(boolean branchIf, int token, int type1, BinExpr expr)1263*f1fbf3c2SXin Li     private void compareExpr(boolean branchIf,
1264*f1fbf3c2SXin Li                              int token, int type1, BinExpr expr)
1265*f1fbf3c2SXin Li         throws CompileError
1266*f1fbf3c2SXin Li     {
1267*f1fbf3c2SXin Li         if (arrayDim == 0)
1268*f1fbf3c2SXin Li             convertOprandTypes(type1, exprType, expr);
1269*f1fbf3c2SXin Li 
1270*f1fbf3c2SXin Li         int p = typePrecedence(exprType);
1271*f1fbf3c2SXin Li         if (p == P_OTHER || arrayDim > 0)
1272*f1fbf3c2SXin Li             if (token == EQ)
1273*f1fbf3c2SXin Li                 bytecode.addOpcode(branchIf ? IF_ACMPEQ : IF_ACMPNE);
1274*f1fbf3c2SXin Li             else if (token == NEQ)
1275*f1fbf3c2SXin Li                 bytecode.addOpcode(branchIf ? IF_ACMPNE : IF_ACMPEQ);
1276*f1fbf3c2SXin Li             else
1277*f1fbf3c2SXin Li                 badTypes(expr);
1278*f1fbf3c2SXin Li         else
1279*f1fbf3c2SXin Li             if (p == P_INT) {
1280*f1fbf3c2SXin Li                 int op[] = ifOp;
1281*f1fbf3c2SXin Li                 for (int i = 0; i < op.length; i += 3)
1282*f1fbf3c2SXin Li                     if (op[i] == token) {
1283*f1fbf3c2SXin Li                         bytecode.addOpcode(op[i + (branchIf ? 1 : 2)]);
1284*f1fbf3c2SXin Li                         return;
1285*f1fbf3c2SXin Li                     }
1286*f1fbf3c2SXin Li 
1287*f1fbf3c2SXin Li                 badTypes(expr);
1288*f1fbf3c2SXin Li             }
1289*f1fbf3c2SXin Li             else {
1290*f1fbf3c2SXin Li                 if (p == P_DOUBLE)
1291*f1fbf3c2SXin Li                     if (token == '<' || token == LE)
1292*f1fbf3c2SXin Li                         bytecode.addOpcode(DCMPG);
1293*f1fbf3c2SXin Li                     else
1294*f1fbf3c2SXin Li                         bytecode.addOpcode(DCMPL);
1295*f1fbf3c2SXin Li                 else if (p == P_FLOAT)
1296*f1fbf3c2SXin Li                     if (token == '<' || token == LE)
1297*f1fbf3c2SXin Li                         bytecode.addOpcode(FCMPG);
1298*f1fbf3c2SXin Li                     else
1299*f1fbf3c2SXin Li                         bytecode.addOpcode(FCMPL);
1300*f1fbf3c2SXin Li                 else if (p == P_LONG)
1301*f1fbf3c2SXin Li                     bytecode.addOpcode(LCMP); // 1: >, 0: =, -1: <
1302*f1fbf3c2SXin Li                 else
1303*f1fbf3c2SXin Li                     fatal();
1304*f1fbf3c2SXin Li 
1305*f1fbf3c2SXin Li                 int[] op = ifOp2;
1306*f1fbf3c2SXin Li                 for (int i = 0; i < op.length; i += 3)
1307*f1fbf3c2SXin Li                     if (op[i] == token) {
1308*f1fbf3c2SXin Li                         bytecode.addOpcode(op[i + (branchIf ? 1 : 2)]);
1309*f1fbf3c2SXin Li                         return;
1310*f1fbf3c2SXin Li                     }
1311*f1fbf3c2SXin Li 
1312*f1fbf3c2SXin Li                 badTypes(expr);
1313*f1fbf3c2SXin Li             }
1314*f1fbf3c2SXin Li     }
1315*f1fbf3c2SXin Li 
badTypes(Expr expr)1316*f1fbf3c2SXin Li     protected static void badTypes(Expr expr) throws CompileError {
1317*f1fbf3c2SXin Li         throw new CompileError("invalid types for " + expr.getName());
1318*f1fbf3c2SXin Li     }
1319*f1fbf3c2SXin Li 
1320*f1fbf3c2SXin Li     private static final int P_DOUBLE = 0;
1321*f1fbf3c2SXin Li     private static final int P_FLOAT = 1;
1322*f1fbf3c2SXin Li     private static final int P_LONG = 2;
1323*f1fbf3c2SXin Li     private static final int P_INT = 3;
1324*f1fbf3c2SXin Li     private static final int P_OTHER = -1;
1325*f1fbf3c2SXin Li 
isRefType(int type)1326*f1fbf3c2SXin Li     protected static boolean isRefType(int type) {
1327*f1fbf3c2SXin Li         return type == CLASS || type == NULL;
1328*f1fbf3c2SXin Li     }
1329*f1fbf3c2SXin Li 
typePrecedence(int type)1330*f1fbf3c2SXin Li     private static int typePrecedence(int type) {
1331*f1fbf3c2SXin Li         if (type == DOUBLE)
1332*f1fbf3c2SXin Li             return P_DOUBLE;
1333*f1fbf3c2SXin Li         else if (type == FLOAT)
1334*f1fbf3c2SXin Li             return P_FLOAT;
1335*f1fbf3c2SXin Li         else if (type == LONG)
1336*f1fbf3c2SXin Li             return P_LONG;
1337*f1fbf3c2SXin Li         else if (isRefType(type))
1338*f1fbf3c2SXin Li             return P_OTHER;
1339*f1fbf3c2SXin Li         else if (type == VOID)
1340*f1fbf3c2SXin Li             return P_OTHER;     // this is wrong, but ...
1341*f1fbf3c2SXin Li         else
1342*f1fbf3c2SXin Li             return P_INT;       // BOOLEAN, BYTE, CHAR, SHORT, INT
1343*f1fbf3c2SXin Li     }
1344*f1fbf3c2SXin Li 
1345*f1fbf3c2SXin Li     // used in TypeChecker.
isP_INT(int type)1346*f1fbf3c2SXin Li     static boolean isP_INT(int type) {
1347*f1fbf3c2SXin Li         return typePrecedence(type) == P_INT;
1348*f1fbf3c2SXin Li     }
1349*f1fbf3c2SXin Li 
1350*f1fbf3c2SXin Li     // used in TypeChecker.
rightIsStrong(int type1, int type2)1351*f1fbf3c2SXin Li     static boolean rightIsStrong(int type1, int type2) {
1352*f1fbf3c2SXin Li         int type1_p = typePrecedence(type1);
1353*f1fbf3c2SXin Li         int type2_p = typePrecedence(type2);
1354*f1fbf3c2SXin Li         return type1_p >= 0 && type2_p >= 0 && type1_p > type2_p;
1355*f1fbf3c2SXin Li     }
1356*f1fbf3c2SXin Li 
1357*f1fbf3c2SXin Li     private static final int[] castOp = {
1358*f1fbf3c2SXin Li             /*            D    F    L    I */
1359*f1fbf3c2SXin Li             /* double */ NOP, D2F, D2L, D2I,
1360*f1fbf3c2SXin Li             /* float  */ F2D, NOP, F2L, F2I,
1361*f1fbf3c2SXin Li             /* long   */ L2D, L2F, NOP, L2I,
1362*f1fbf3c2SXin Li             /* other  */ I2D, I2F, I2L, NOP };
1363*f1fbf3c2SXin Li 
1364*f1fbf3c2SXin Li     /* do implicit type conversion.
1365*f1fbf3c2SXin Li      * arrayDim values of the two oprands must be zero.
1366*f1fbf3c2SXin Li      */
convertOprandTypes(int type1, int type2, Expr expr)1367*f1fbf3c2SXin Li     private void convertOprandTypes(int type1, int type2, Expr expr)
1368*f1fbf3c2SXin Li         throws CompileError
1369*f1fbf3c2SXin Li     {
1370*f1fbf3c2SXin Li         boolean rightStrong;
1371*f1fbf3c2SXin Li         int type1_p = typePrecedence(type1);
1372*f1fbf3c2SXin Li         int type2_p = typePrecedence(type2);
1373*f1fbf3c2SXin Li 
1374*f1fbf3c2SXin Li         if (type2_p < 0 && type1_p < 0) // not primitive types
1375*f1fbf3c2SXin Li             return;
1376*f1fbf3c2SXin Li 
1377*f1fbf3c2SXin Li         if (type2_p < 0 || type1_p < 0) // either is not a primitive type
1378*f1fbf3c2SXin Li             badTypes(expr);
1379*f1fbf3c2SXin Li 
1380*f1fbf3c2SXin Li         int op, result_type;
1381*f1fbf3c2SXin Li         if (type1_p <= type2_p) {
1382*f1fbf3c2SXin Li             rightStrong = false;
1383*f1fbf3c2SXin Li             exprType = type1;
1384*f1fbf3c2SXin Li             op = castOp[type2_p * 4 + type1_p];
1385*f1fbf3c2SXin Li             result_type = type1_p;
1386*f1fbf3c2SXin Li         }
1387*f1fbf3c2SXin Li         else {
1388*f1fbf3c2SXin Li             rightStrong = true;
1389*f1fbf3c2SXin Li             op = castOp[type1_p * 4 + type2_p];
1390*f1fbf3c2SXin Li             result_type = type2_p;
1391*f1fbf3c2SXin Li         }
1392*f1fbf3c2SXin Li 
1393*f1fbf3c2SXin Li         if (rightStrong) {
1394*f1fbf3c2SXin Li             if (result_type == P_DOUBLE || result_type == P_LONG) {
1395*f1fbf3c2SXin Li                 if (type1_p == P_DOUBLE || type1_p == P_LONG)
1396*f1fbf3c2SXin Li                     bytecode.addOpcode(DUP2_X2);
1397*f1fbf3c2SXin Li                 else
1398*f1fbf3c2SXin Li                     bytecode.addOpcode(DUP2_X1);
1399*f1fbf3c2SXin Li 
1400*f1fbf3c2SXin Li                 bytecode.addOpcode(POP2);
1401*f1fbf3c2SXin Li                 bytecode.addOpcode(op);
1402*f1fbf3c2SXin Li                 bytecode.addOpcode(DUP2_X2);
1403*f1fbf3c2SXin Li                 bytecode.addOpcode(POP2);
1404*f1fbf3c2SXin Li             }
1405*f1fbf3c2SXin Li             else if (result_type == P_FLOAT) {
1406*f1fbf3c2SXin Li                 if (type1_p == P_LONG) {
1407*f1fbf3c2SXin Li                     bytecode.addOpcode(DUP_X2);
1408*f1fbf3c2SXin Li                     bytecode.addOpcode(POP);
1409*f1fbf3c2SXin Li                 }
1410*f1fbf3c2SXin Li                 else
1411*f1fbf3c2SXin Li                     bytecode.addOpcode(SWAP);
1412*f1fbf3c2SXin Li 
1413*f1fbf3c2SXin Li                 bytecode.addOpcode(op);
1414*f1fbf3c2SXin Li                 bytecode.addOpcode(SWAP);
1415*f1fbf3c2SXin Li             }
1416*f1fbf3c2SXin Li             else
1417*f1fbf3c2SXin Li                 fatal();
1418*f1fbf3c2SXin Li         }
1419*f1fbf3c2SXin Li         else if (op != NOP)
1420*f1fbf3c2SXin Li             bytecode.addOpcode(op);
1421*f1fbf3c2SXin Li     }
1422*f1fbf3c2SXin Li 
1423*f1fbf3c2SXin Li     @Override
atCastExpr(CastExpr expr)1424*f1fbf3c2SXin Li     public void atCastExpr(CastExpr expr) throws CompileError {
1425*f1fbf3c2SXin Li         String cname = resolveClassName(expr.getClassName());
1426*f1fbf3c2SXin Li         String toClass = checkCastExpr(expr, cname);
1427*f1fbf3c2SXin Li         int srcType = exprType;
1428*f1fbf3c2SXin Li         exprType = expr.getType();
1429*f1fbf3c2SXin Li         arrayDim = expr.getArrayDim();
1430*f1fbf3c2SXin Li         className = cname;
1431*f1fbf3c2SXin Li         if (toClass == null)
1432*f1fbf3c2SXin Li             atNumCastExpr(srcType, exprType);   // built-in type
1433*f1fbf3c2SXin Li         else
1434*f1fbf3c2SXin Li             bytecode.addCheckcast(toClass);
1435*f1fbf3c2SXin Li     }
1436*f1fbf3c2SXin Li 
1437*f1fbf3c2SXin Li     @Override
atInstanceOfExpr(InstanceOfExpr expr)1438*f1fbf3c2SXin Li     public void atInstanceOfExpr(InstanceOfExpr expr) throws CompileError {
1439*f1fbf3c2SXin Li         String cname = resolveClassName(expr.getClassName());
1440*f1fbf3c2SXin Li         String toClass = checkCastExpr(expr, cname);
1441*f1fbf3c2SXin Li         bytecode.addInstanceof(toClass);
1442*f1fbf3c2SXin Li         exprType = BOOLEAN;
1443*f1fbf3c2SXin Li         arrayDim = 0;
1444*f1fbf3c2SXin Li     }
1445*f1fbf3c2SXin Li 
checkCastExpr(CastExpr expr, String name)1446*f1fbf3c2SXin Li     private String checkCastExpr(CastExpr expr, String name)
1447*f1fbf3c2SXin Li         throws CompileError
1448*f1fbf3c2SXin Li     {
1449*f1fbf3c2SXin Li         final String msg = "invalid cast";
1450*f1fbf3c2SXin Li         ASTree oprand = expr.getOprand();
1451*f1fbf3c2SXin Li         int dim = expr.getArrayDim();
1452*f1fbf3c2SXin Li         int type = expr.getType();
1453*f1fbf3c2SXin Li         oprand.accept(this);
1454*f1fbf3c2SXin Li         int srcType = exprType;
1455*f1fbf3c2SXin Li         int srcDim = arrayDim;
1456*f1fbf3c2SXin Li         if (invalidDim(srcType, arrayDim, className, type, dim, name, true)
1457*f1fbf3c2SXin Li             || srcType == VOID || type == VOID)
1458*f1fbf3c2SXin Li             throw new CompileError(msg);
1459*f1fbf3c2SXin Li 
1460*f1fbf3c2SXin Li         if (type == CLASS) {
1461*f1fbf3c2SXin Li             if (!isRefType(srcType) && srcDim == 0)
1462*f1fbf3c2SXin Li                 throw new CompileError(msg);
1463*f1fbf3c2SXin Li 
1464*f1fbf3c2SXin Li             return toJvmArrayName(name, dim);
1465*f1fbf3c2SXin Li         }
1466*f1fbf3c2SXin Li         else
1467*f1fbf3c2SXin Li             if (dim > 0)
1468*f1fbf3c2SXin Li                 return toJvmTypeName(type, dim);
1469*f1fbf3c2SXin Li             else
1470*f1fbf3c2SXin Li                 return null;    // built-in type
1471*f1fbf3c2SXin Li     }
1472*f1fbf3c2SXin Li 
atNumCastExpr(int srcType, int destType)1473*f1fbf3c2SXin Li     void atNumCastExpr(int srcType, int destType)
1474*f1fbf3c2SXin Li         throws CompileError
1475*f1fbf3c2SXin Li     {
1476*f1fbf3c2SXin Li         if (srcType == destType)
1477*f1fbf3c2SXin Li             return;
1478*f1fbf3c2SXin Li 
1479*f1fbf3c2SXin Li         int op, op2;
1480*f1fbf3c2SXin Li         int stype = typePrecedence(srcType);
1481*f1fbf3c2SXin Li         int dtype = typePrecedence(destType);
1482*f1fbf3c2SXin Li         if (0 <= stype && stype < 3)
1483*f1fbf3c2SXin Li             op = castOp[stype * 4 + dtype];
1484*f1fbf3c2SXin Li         else
1485*f1fbf3c2SXin Li             op = NOP;
1486*f1fbf3c2SXin Li 
1487*f1fbf3c2SXin Li         if (destType == DOUBLE)
1488*f1fbf3c2SXin Li             op2 = I2D;
1489*f1fbf3c2SXin Li         else if (destType == FLOAT)
1490*f1fbf3c2SXin Li             op2 = I2F;
1491*f1fbf3c2SXin Li         else if (destType == LONG)
1492*f1fbf3c2SXin Li             op2 = I2L;
1493*f1fbf3c2SXin Li         else if (destType == SHORT)
1494*f1fbf3c2SXin Li             op2 = I2S;
1495*f1fbf3c2SXin Li         else if (destType == CHAR)
1496*f1fbf3c2SXin Li             op2 = I2C;
1497*f1fbf3c2SXin Li         else if (destType == BYTE)
1498*f1fbf3c2SXin Li             op2 = I2B;
1499*f1fbf3c2SXin Li         else
1500*f1fbf3c2SXin Li             op2 = NOP;
1501*f1fbf3c2SXin Li 
1502*f1fbf3c2SXin Li         if (op != NOP)
1503*f1fbf3c2SXin Li             bytecode.addOpcode(op);
1504*f1fbf3c2SXin Li 
1505*f1fbf3c2SXin Li         if (op == NOP || op == L2I || op == F2I || op == D2I)
1506*f1fbf3c2SXin Li             if (op2 != NOP)
1507*f1fbf3c2SXin Li                 bytecode.addOpcode(op2);
1508*f1fbf3c2SXin Li     }
1509*f1fbf3c2SXin Li 
1510*f1fbf3c2SXin Li     @Override
atExpr(Expr expr)1511*f1fbf3c2SXin Li     public void atExpr(Expr expr) throws CompileError {
1512*f1fbf3c2SXin Li         // array access, member access,
1513*f1fbf3c2SXin Li         // (unary) +, (unary) -, ++, --, !, ~
1514*f1fbf3c2SXin Li 
1515*f1fbf3c2SXin Li         int token = expr.getOperator();
1516*f1fbf3c2SXin Li         ASTree oprand = expr.oprand1();
1517*f1fbf3c2SXin Li         if (token == '.') {
1518*f1fbf3c2SXin Li             String member = ((Symbol)expr.oprand2()).get();
1519*f1fbf3c2SXin Li             if (member.equals("class"))
1520*f1fbf3c2SXin Li                 atClassObject(expr);  // .class
1521*f1fbf3c2SXin Li             else
1522*f1fbf3c2SXin Li                 atFieldRead(expr);
1523*f1fbf3c2SXin Li         }
1524*f1fbf3c2SXin Li         else if (token == MEMBER) {     // field read
1525*f1fbf3c2SXin Li             /* MEMBER ('#') is an extension by Javassist.
1526*f1fbf3c2SXin Li              * The compiler internally uses # for compiling .class
1527*f1fbf3c2SXin Li              * expressions such as "int.class".
1528*f1fbf3c2SXin Li              */
1529*f1fbf3c2SXin Li             atFieldRead(expr);
1530*f1fbf3c2SXin Li         }
1531*f1fbf3c2SXin Li         else if (token == ARRAY)
1532*f1fbf3c2SXin Li             atArrayRead(oprand, expr.oprand2());
1533*f1fbf3c2SXin Li         else if (token == PLUSPLUS || token == MINUSMINUS)
1534*f1fbf3c2SXin Li             atPlusPlus(token, oprand, expr, true);
1535*f1fbf3c2SXin Li         else if (token == '!') {
1536*f1fbf3c2SXin Li             if (!booleanExpr(false, expr)) {
1537*f1fbf3c2SXin Li                 bytecode.addIndex(7);
1538*f1fbf3c2SXin Li                 bytecode.addIconst(1);
1539*f1fbf3c2SXin Li                 bytecode.addOpcode(Opcode.GOTO);
1540*f1fbf3c2SXin Li                 bytecode.addIndex(4);
1541*f1fbf3c2SXin Li             }
1542*f1fbf3c2SXin Li 
1543*f1fbf3c2SXin Li             bytecode.addIconst(0);
1544*f1fbf3c2SXin Li         }
1545*f1fbf3c2SXin Li         else if (token == CALL)         // method call
1546*f1fbf3c2SXin Li             fatal();
1547*f1fbf3c2SXin Li         else {
1548*f1fbf3c2SXin Li             expr.oprand1().accept(this);
1549*f1fbf3c2SXin Li             int type = typePrecedence(exprType);
1550*f1fbf3c2SXin Li             if (arrayDim > 0)
1551*f1fbf3c2SXin Li                 badType(expr);
1552*f1fbf3c2SXin Li 
1553*f1fbf3c2SXin Li             if (token == '-') {
1554*f1fbf3c2SXin Li                 if (type == P_DOUBLE)
1555*f1fbf3c2SXin Li                     bytecode.addOpcode(DNEG);
1556*f1fbf3c2SXin Li                 else if (type == P_FLOAT)
1557*f1fbf3c2SXin Li                     bytecode.addOpcode(FNEG);
1558*f1fbf3c2SXin Li                 else if (type == P_LONG)
1559*f1fbf3c2SXin Li                     bytecode.addOpcode(LNEG);
1560*f1fbf3c2SXin Li                 else if (type == P_INT) {
1561*f1fbf3c2SXin Li                     bytecode.addOpcode(INEG);
1562*f1fbf3c2SXin Li                     exprType = INT;     // type may be BYTE, ...
1563*f1fbf3c2SXin Li                 }
1564*f1fbf3c2SXin Li                 else
1565*f1fbf3c2SXin Li                     badType(expr);
1566*f1fbf3c2SXin Li             }
1567*f1fbf3c2SXin Li             else if (token == '~') {
1568*f1fbf3c2SXin Li                 if (type == P_INT) {
1569*f1fbf3c2SXin Li                     bytecode.addIconst(-1);
1570*f1fbf3c2SXin Li                     bytecode.addOpcode(IXOR);
1571*f1fbf3c2SXin Li                     exprType = INT;     // type may be BYTE. ...
1572*f1fbf3c2SXin Li                 }
1573*f1fbf3c2SXin Li                 else if (type == P_LONG) {
1574*f1fbf3c2SXin Li                     bytecode.addLconst(-1);
1575*f1fbf3c2SXin Li                     bytecode.addOpcode(LXOR);
1576*f1fbf3c2SXin Li                 }
1577*f1fbf3c2SXin Li                 else
1578*f1fbf3c2SXin Li                     badType(expr);
1579*f1fbf3c2SXin Li 
1580*f1fbf3c2SXin Li             }
1581*f1fbf3c2SXin Li             else if (token == '+') {
1582*f1fbf3c2SXin Li                 if (type == P_OTHER)
1583*f1fbf3c2SXin Li                     badType(expr);
1584*f1fbf3c2SXin Li 
1585*f1fbf3c2SXin Li                 // do nothing. ignore.
1586*f1fbf3c2SXin Li             }
1587*f1fbf3c2SXin Li             else
1588*f1fbf3c2SXin Li                 fatal();
1589*f1fbf3c2SXin Li         }
1590*f1fbf3c2SXin Li     }
1591*f1fbf3c2SXin Li 
badType(Expr expr)1592*f1fbf3c2SXin Li     protected static void badType(Expr expr) throws CompileError {
1593*f1fbf3c2SXin Li         throw new CompileError("invalid type for " + expr.getName());
1594*f1fbf3c2SXin Li     }
1595*f1fbf3c2SXin Li 
1596*f1fbf3c2SXin Li     @Override
atCallExpr(CallExpr expr)1597*f1fbf3c2SXin Li     public abstract void atCallExpr(CallExpr expr) throws CompileError;
1598*f1fbf3c2SXin Li 
atFieldRead(ASTree expr)1599*f1fbf3c2SXin Li     protected abstract void atFieldRead(ASTree expr) throws CompileError;
1600*f1fbf3c2SXin Li 
atClassObject(Expr expr)1601*f1fbf3c2SXin Li     public void atClassObject(Expr expr) throws CompileError {
1602*f1fbf3c2SXin Li         ASTree op1 = expr.oprand1();
1603*f1fbf3c2SXin Li         if (!(op1 instanceof Symbol))
1604*f1fbf3c2SXin Li             throw new CompileError("fatal error: badly parsed .class expr");
1605*f1fbf3c2SXin Li 
1606*f1fbf3c2SXin Li         String cname = ((Symbol)op1).get();
1607*f1fbf3c2SXin Li         if (cname.startsWith("[")) {
1608*f1fbf3c2SXin Li             int i = cname.indexOf("[L");
1609*f1fbf3c2SXin Li             if (i >= 0) {
1610*f1fbf3c2SXin Li                 String name = cname.substring(i + 2, cname.length() - 1);
1611*f1fbf3c2SXin Li                 String name2 = resolveClassName(name);
1612*f1fbf3c2SXin Li                 if (!name.equals(name2)) {
1613*f1fbf3c2SXin Li                     /* For example, to obtain String[].class,
1614*f1fbf3c2SXin Li                      * "[Ljava.lang.String;" (not "[Ljava/lang/String"!)
1615*f1fbf3c2SXin Li                      * must be passed to Class.forName().
1616*f1fbf3c2SXin Li                      */
1617*f1fbf3c2SXin Li                     name2 = MemberResolver.jvmToJavaName(name2);
1618*f1fbf3c2SXin Li                     StringBuffer sbuf = new StringBuffer();
1619*f1fbf3c2SXin Li                     while (i-- >= 0)
1620*f1fbf3c2SXin Li                         sbuf.append('[');
1621*f1fbf3c2SXin Li 
1622*f1fbf3c2SXin Li                     sbuf.append('L').append(name2).append(';');
1623*f1fbf3c2SXin Li                     cname = sbuf.toString();
1624*f1fbf3c2SXin Li                 }
1625*f1fbf3c2SXin Li             }
1626*f1fbf3c2SXin Li         }
1627*f1fbf3c2SXin Li         else {
1628*f1fbf3c2SXin Li             cname = resolveClassName(MemberResolver.javaToJvmName(cname));
1629*f1fbf3c2SXin Li             cname = MemberResolver.jvmToJavaName(cname);
1630*f1fbf3c2SXin Li         }
1631*f1fbf3c2SXin Li 
1632*f1fbf3c2SXin Li         atClassObject2(cname);
1633*f1fbf3c2SXin Li         exprType = CLASS;
1634*f1fbf3c2SXin Li         arrayDim = 0;
1635*f1fbf3c2SXin Li         className = "java/lang/Class";
1636*f1fbf3c2SXin Li     }
1637*f1fbf3c2SXin Li 
1638*f1fbf3c2SXin Li     /* MemberCodeGen overrides this method.
1639*f1fbf3c2SXin Li      */
atClassObject2(String cname)1640*f1fbf3c2SXin Li     protected void atClassObject2(String cname) throws CompileError {
1641*f1fbf3c2SXin Li         int start = bytecode.currentPc();
1642*f1fbf3c2SXin Li         bytecode.addLdc(cname);
1643*f1fbf3c2SXin Li         bytecode.addInvokestatic("java.lang.Class", "forName",
1644*f1fbf3c2SXin Li                                  "(Ljava/lang/String;)Ljava/lang/Class;");
1645*f1fbf3c2SXin Li         int end = bytecode.currentPc();
1646*f1fbf3c2SXin Li         bytecode.addOpcode(Opcode.GOTO);
1647*f1fbf3c2SXin Li         int pc = bytecode.currentPc();
1648*f1fbf3c2SXin Li         bytecode.addIndex(0);   // correct later
1649*f1fbf3c2SXin Li 
1650*f1fbf3c2SXin Li         bytecode.addExceptionHandler(start, end, bytecode.currentPc(),
1651*f1fbf3c2SXin Li                                      "java.lang.ClassNotFoundException");
1652*f1fbf3c2SXin Li 
1653*f1fbf3c2SXin Li         /* -- the following code is for inlining a call to DotClass.fail().
1654*f1fbf3c2SXin Li 
1655*f1fbf3c2SXin Li         int var = getMaxLocals();
1656*f1fbf3c2SXin Li         incMaxLocals(1);
1657*f1fbf3c2SXin Li         bytecode.growStack(1);
1658*f1fbf3c2SXin Li         bytecode.addAstore(var);
1659*f1fbf3c2SXin Li 
1660*f1fbf3c2SXin Li         bytecode.addNew("java.lang.NoClassDefFoundError");
1661*f1fbf3c2SXin Li         bytecode.addOpcode(DUP);
1662*f1fbf3c2SXin Li         bytecode.addAload(var);
1663*f1fbf3c2SXin Li         bytecode.addInvokevirtual("java.lang.ClassNotFoundException",
1664*f1fbf3c2SXin Li                                   "getMessage", "()Ljava/lang/String;");
1665*f1fbf3c2SXin Li         bytecode.addInvokespecial("java.lang.NoClassDefFoundError", "<init>",
1666*f1fbf3c2SXin Li                                   "(Ljava/lang/String;)V");
1667*f1fbf3c2SXin Li         */
1668*f1fbf3c2SXin Li 
1669*f1fbf3c2SXin Li         bytecode.growStack(1);
1670*f1fbf3c2SXin Li         bytecode.addInvokestatic("javassist.runtime.DotClass", "fail",
1671*f1fbf3c2SXin Li                                  "(Ljava/lang/ClassNotFoundException;)"
1672*f1fbf3c2SXin Li                                  + "Ljava/lang/NoClassDefFoundError;");
1673*f1fbf3c2SXin Li         bytecode.addOpcode(ATHROW);
1674*f1fbf3c2SXin Li         bytecode.write16bit(pc, bytecode.currentPc() - pc + 1);
1675*f1fbf3c2SXin Li     }
1676*f1fbf3c2SXin Li 
atArrayRead(ASTree array, ASTree index)1677*f1fbf3c2SXin Li     public void atArrayRead(ASTree array, ASTree index)
1678*f1fbf3c2SXin Li         throws CompileError
1679*f1fbf3c2SXin Li     {
1680*f1fbf3c2SXin Li         arrayAccess(array, index);
1681*f1fbf3c2SXin Li         bytecode.addOpcode(getArrayReadOp(exprType, arrayDim));
1682*f1fbf3c2SXin Li     }
1683*f1fbf3c2SXin Li 
arrayAccess(ASTree array, ASTree index)1684*f1fbf3c2SXin Li     protected void arrayAccess(ASTree array, ASTree index)
1685*f1fbf3c2SXin Li         throws CompileError
1686*f1fbf3c2SXin Li     {
1687*f1fbf3c2SXin Li         array.accept(this);
1688*f1fbf3c2SXin Li         int type = exprType;
1689*f1fbf3c2SXin Li         int dim = arrayDim;
1690*f1fbf3c2SXin Li         if (dim == 0)
1691*f1fbf3c2SXin Li             throw new CompileError("bad array access");
1692*f1fbf3c2SXin Li 
1693*f1fbf3c2SXin Li         String cname = className;
1694*f1fbf3c2SXin Li 
1695*f1fbf3c2SXin Li         index.accept(this);
1696*f1fbf3c2SXin Li         if (typePrecedence(exprType) != P_INT || arrayDim > 0)
1697*f1fbf3c2SXin Li             throw new CompileError("bad array index");
1698*f1fbf3c2SXin Li 
1699*f1fbf3c2SXin Li         exprType = type;
1700*f1fbf3c2SXin Li         arrayDim = dim - 1;
1701*f1fbf3c2SXin Li         className = cname;
1702*f1fbf3c2SXin Li     }
1703*f1fbf3c2SXin Li 
getArrayReadOp(int type, int dim)1704*f1fbf3c2SXin Li     protected static int getArrayReadOp(int type, int dim) {
1705*f1fbf3c2SXin Li         if (dim > 0)
1706*f1fbf3c2SXin Li             return AALOAD;
1707*f1fbf3c2SXin Li 
1708*f1fbf3c2SXin Li         switch (type) {
1709*f1fbf3c2SXin Li         case DOUBLE :
1710*f1fbf3c2SXin Li             return DALOAD;
1711*f1fbf3c2SXin Li         case FLOAT :
1712*f1fbf3c2SXin Li             return FALOAD;
1713*f1fbf3c2SXin Li         case LONG :
1714*f1fbf3c2SXin Li             return LALOAD;
1715*f1fbf3c2SXin Li         case INT :
1716*f1fbf3c2SXin Li             return IALOAD;
1717*f1fbf3c2SXin Li         case SHORT :
1718*f1fbf3c2SXin Li             return SALOAD;
1719*f1fbf3c2SXin Li         case CHAR :
1720*f1fbf3c2SXin Li             return CALOAD;
1721*f1fbf3c2SXin Li         case BYTE :
1722*f1fbf3c2SXin Li         case BOOLEAN :
1723*f1fbf3c2SXin Li             return BALOAD;
1724*f1fbf3c2SXin Li         default :
1725*f1fbf3c2SXin Li             return AALOAD;
1726*f1fbf3c2SXin Li         }
1727*f1fbf3c2SXin Li     }
1728*f1fbf3c2SXin Li 
getArrayWriteOp(int type, int dim)1729*f1fbf3c2SXin Li     protected static int getArrayWriteOp(int type, int dim) {
1730*f1fbf3c2SXin Li         if (dim > 0)
1731*f1fbf3c2SXin Li             return AASTORE;
1732*f1fbf3c2SXin Li 
1733*f1fbf3c2SXin Li         switch (type) {
1734*f1fbf3c2SXin Li         case DOUBLE :
1735*f1fbf3c2SXin Li             return DASTORE;
1736*f1fbf3c2SXin Li         case FLOAT :
1737*f1fbf3c2SXin Li             return FASTORE;
1738*f1fbf3c2SXin Li         case LONG :
1739*f1fbf3c2SXin Li             return LASTORE;
1740*f1fbf3c2SXin Li         case INT :
1741*f1fbf3c2SXin Li             return IASTORE;
1742*f1fbf3c2SXin Li         case SHORT :
1743*f1fbf3c2SXin Li             return SASTORE;
1744*f1fbf3c2SXin Li         case CHAR :
1745*f1fbf3c2SXin Li             return CASTORE;
1746*f1fbf3c2SXin Li         case BYTE :
1747*f1fbf3c2SXin Li         case BOOLEAN :
1748*f1fbf3c2SXin Li             return BASTORE;
1749*f1fbf3c2SXin Li         default :
1750*f1fbf3c2SXin Li             return AASTORE;
1751*f1fbf3c2SXin Li         }
1752*f1fbf3c2SXin Li     }
1753*f1fbf3c2SXin Li 
atPlusPlus(int token, ASTree oprand, Expr expr, boolean doDup)1754*f1fbf3c2SXin Li     private void atPlusPlus(int token, ASTree oprand, Expr expr,
1755*f1fbf3c2SXin Li                             boolean doDup) throws CompileError
1756*f1fbf3c2SXin Li     {
1757*f1fbf3c2SXin Li         boolean isPost = oprand == null;        // ++i or i++?
1758*f1fbf3c2SXin Li         if (isPost)
1759*f1fbf3c2SXin Li             oprand = expr.oprand2();
1760*f1fbf3c2SXin Li 
1761*f1fbf3c2SXin Li         if (oprand instanceof Variable) {
1762*f1fbf3c2SXin Li             Declarator d = ((Variable)oprand).getDeclarator();
1763*f1fbf3c2SXin Li             int t = exprType = d.getType();
1764*f1fbf3c2SXin Li             arrayDim = d.getArrayDim();
1765*f1fbf3c2SXin Li             int var = getLocalVar(d);
1766*f1fbf3c2SXin Li             if (arrayDim > 0)
1767*f1fbf3c2SXin Li                 badType(expr);
1768*f1fbf3c2SXin Li 
1769*f1fbf3c2SXin Li             if (t == DOUBLE) {
1770*f1fbf3c2SXin Li                 bytecode.addDload(var);
1771*f1fbf3c2SXin Li                 if (doDup && isPost)
1772*f1fbf3c2SXin Li                     bytecode.addOpcode(DUP2);
1773*f1fbf3c2SXin Li 
1774*f1fbf3c2SXin Li                 bytecode.addDconst(1.0);
1775*f1fbf3c2SXin Li                 bytecode.addOpcode(token == PLUSPLUS ? DADD : DSUB);
1776*f1fbf3c2SXin Li                 if (doDup && !isPost)
1777*f1fbf3c2SXin Li                     bytecode.addOpcode(DUP2);
1778*f1fbf3c2SXin Li 
1779*f1fbf3c2SXin Li                 bytecode.addDstore(var);
1780*f1fbf3c2SXin Li             }
1781*f1fbf3c2SXin Li             else if (t == LONG) {
1782*f1fbf3c2SXin Li                 bytecode.addLload(var);
1783*f1fbf3c2SXin Li                 if (doDup && isPost)
1784*f1fbf3c2SXin Li                     bytecode.addOpcode(DUP2);
1785*f1fbf3c2SXin Li 
1786*f1fbf3c2SXin Li                 bytecode.addLconst(1);
1787*f1fbf3c2SXin Li                 bytecode.addOpcode(token == PLUSPLUS ? LADD : LSUB);
1788*f1fbf3c2SXin Li                 if (doDup && !isPost)
1789*f1fbf3c2SXin Li                     bytecode.addOpcode(DUP2);
1790*f1fbf3c2SXin Li 
1791*f1fbf3c2SXin Li                 bytecode.addLstore(var);
1792*f1fbf3c2SXin Li             }
1793*f1fbf3c2SXin Li             else if (t == FLOAT) {
1794*f1fbf3c2SXin Li                 bytecode.addFload(var);
1795*f1fbf3c2SXin Li                 if (doDup && isPost)
1796*f1fbf3c2SXin Li                     bytecode.addOpcode(DUP);
1797*f1fbf3c2SXin Li 
1798*f1fbf3c2SXin Li                 bytecode.addFconst(1.0f);
1799*f1fbf3c2SXin Li                 bytecode.addOpcode(token == PLUSPLUS ? FADD : FSUB);
1800*f1fbf3c2SXin Li                 if (doDup && !isPost)
1801*f1fbf3c2SXin Li                     bytecode.addOpcode(DUP);
1802*f1fbf3c2SXin Li 
1803*f1fbf3c2SXin Li                 bytecode.addFstore(var);
1804*f1fbf3c2SXin Li             }
1805*f1fbf3c2SXin Li             else if (t == BYTE || t == CHAR || t == SHORT || t == INT) {
1806*f1fbf3c2SXin Li                 if (doDup && isPost)
1807*f1fbf3c2SXin Li                     bytecode.addIload(var);
1808*f1fbf3c2SXin Li 
1809*f1fbf3c2SXin Li                 int delta = token == PLUSPLUS ? 1 : -1;
1810*f1fbf3c2SXin Li                 if (var > 0xff) {
1811*f1fbf3c2SXin Li                     bytecode.addOpcode(WIDE);
1812*f1fbf3c2SXin Li                     bytecode.addOpcode(IINC);
1813*f1fbf3c2SXin Li                     bytecode.addIndex(var);
1814*f1fbf3c2SXin Li                     bytecode.addIndex(delta);
1815*f1fbf3c2SXin Li                 }
1816*f1fbf3c2SXin Li                 else {
1817*f1fbf3c2SXin Li                     bytecode.addOpcode(IINC);
1818*f1fbf3c2SXin Li                     bytecode.add(var);
1819*f1fbf3c2SXin Li                     bytecode.add(delta);
1820*f1fbf3c2SXin Li                 }
1821*f1fbf3c2SXin Li 
1822*f1fbf3c2SXin Li                 if (doDup && !isPost)
1823*f1fbf3c2SXin Li                     bytecode.addIload(var);
1824*f1fbf3c2SXin Li             }
1825*f1fbf3c2SXin Li             else
1826*f1fbf3c2SXin Li                 badType(expr);
1827*f1fbf3c2SXin Li         }
1828*f1fbf3c2SXin Li         else {
1829*f1fbf3c2SXin Li             if (oprand instanceof Expr) {
1830*f1fbf3c2SXin Li                 Expr e = (Expr)oprand;
1831*f1fbf3c2SXin Li                 if (e.getOperator() == ARRAY) {
1832*f1fbf3c2SXin Li                     atArrayPlusPlus(token, isPost, e, doDup);
1833*f1fbf3c2SXin Li                     return;
1834*f1fbf3c2SXin Li                 }
1835*f1fbf3c2SXin Li             }
1836*f1fbf3c2SXin Li 
1837*f1fbf3c2SXin Li             atFieldPlusPlus(token, isPost, oprand, expr, doDup);
1838*f1fbf3c2SXin Li         }
1839*f1fbf3c2SXin Li     }
1840*f1fbf3c2SXin Li 
atArrayPlusPlus(int token, boolean isPost, Expr expr, boolean doDup)1841*f1fbf3c2SXin Li     public void atArrayPlusPlus(int token, boolean isPost,
1842*f1fbf3c2SXin Li                         Expr expr, boolean doDup) throws CompileError
1843*f1fbf3c2SXin Li     {
1844*f1fbf3c2SXin Li         arrayAccess(expr.oprand1(), expr.oprand2());
1845*f1fbf3c2SXin Li         int t = exprType;
1846*f1fbf3c2SXin Li         int dim = arrayDim;
1847*f1fbf3c2SXin Li         if (dim > 0)
1848*f1fbf3c2SXin Li             badType(expr);
1849*f1fbf3c2SXin Li 
1850*f1fbf3c2SXin Li         bytecode.addOpcode(DUP2);
1851*f1fbf3c2SXin Li         bytecode.addOpcode(getArrayReadOp(t, arrayDim));
1852*f1fbf3c2SXin Li         int dup_code = is2word(t, dim) ? DUP2_X2 : DUP_X2;
1853*f1fbf3c2SXin Li         atPlusPlusCore(dup_code, doDup, token, isPost, expr);
1854*f1fbf3c2SXin Li         bytecode.addOpcode(getArrayWriteOp(t, dim));
1855*f1fbf3c2SXin Li     }
1856*f1fbf3c2SXin Li 
atPlusPlusCore(int dup_code, boolean doDup, int token, boolean isPost, Expr expr)1857*f1fbf3c2SXin Li     protected void atPlusPlusCore(int dup_code, boolean doDup,
1858*f1fbf3c2SXin Li                                   int token, boolean isPost,
1859*f1fbf3c2SXin Li                                   Expr expr) throws CompileError
1860*f1fbf3c2SXin Li     {
1861*f1fbf3c2SXin Li         int t = exprType;
1862*f1fbf3c2SXin Li 
1863*f1fbf3c2SXin Li         if (doDup && isPost)
1864*f1fbf3c2SXin Li             bytecode.addOpcode(dup_code);
1865*f1fbf3c2SXin Li 
1866*f1fbf3c2SXin Li         if (t == INT || t == BYTE || t == CHAR || t == SHORT) {
1867*f1fbf3c2SXin Li             bytecode.addIconst(1);
1868*f1fbf3c2SXin Li             bytecode.addOpcode(token == PLUSPLUS ? IADD : ISUB);
1869*f1fbf3c2SXin Li             exprType = INT;
1870*f1fbf3c2SXin Li         }
1871*f1fbf3c2SXin Li         else if (t == LONG) {
1872*f1fbf3c2SXin Li             bytecode.addLconst(1);
1873*f1fbf3c2SXin Li             bytecode.addOpcode(token == PLUSPLUS ? LADD : LSUB);
1874*f1fbf3c2SXin Li         }
1875*f1fbf3c2SXin Li         else if (t == FLOAT) {
1876*f1fbf3c2SXin Li             bytecode.addFconst(1.0f);
1877*f1fbf3c2SXin Li             bytecode.addOpcode(token == PLUSPLUS ? FADD : FSUB);
1878*f1fbf3c2SXin Li         }
1879*f1fbf3c2SXin Li         else if (t == DOUBLE) {
1880*f1fbf3c2SXin Li             bytecode.addDconst(1.0);
1881*f1fbf3c2SXin Li             bytecode.addOpcode(token == PLUSPLUS ? DADD : DSUB);
1882*f1fbf3c2SXin Li         }
1883*f1fbf3c2SXin Li         else
1884*f1fbf3c2SXin Li             badType(expr);
1885*f1fbf3c2SXin Li 
1886*f1fbf3c2SXin Li         if (doDup && !isPost)
1887*f1fbf3c2SXin Li             bytecode.addOpcode(dup_code);
1888*f1fbf3c2SXin Li     }
1889*f1fbf3c2SXin Li 
atFieldPlusPlus(int token, boolean isPost, ASTree oprand, Expr expr, boolean doDup)1890*f1fbf3c2SXin Li     protected abstract void atFieldPlusPlus(int token, boolean isPost,
1891*f1fbf3c2SXin Li                 ASTree oprand, Expr expr, boolean doDup) throws CompileError;
1892*f1fbf3c2SXin Li 
1893*f1fbf3c2SXin Li     @Override
atMember(Member n)1894*f1fbf3c2SXin Li     public abstract void atMember(Member n) throws CompileError;
1895*f1fbf3c2SXin Li 
1896*f1fbf3c2SXin Li     @Override
atVariable(Variable v)1897*f1fbf3c2SXin Li     public void atVariable(Variable v) throws CompileError {
1898*f1fbf3c2SXin Li         Declarator d = v.getDeclarator();
1899*f1fbf3c2SXin Li         exprType = d.getType();
1900*f1fbf3c2SXin Li         arrayDim = d.getArrayDim();
1901*f1fbf3c2SXin Li         className = d.getClassName();
1902*f1fbf3c2SXin Li         int var = getLocalVar(d);
1903*f1fbf3c2SXin Li 
1904*f1fbf3c2SXin Li         if (arrayDim > 0)
1905*f1fbf3c2SXin Li             bytecode.addAload(var);
1906*f1fbf3c2SXin Li         else
1907*f1fbf3c2SXin Li             switch (exprType) {
1908*f1fbf3c2SXin Li             case CLASS :
1909*f1fbf3c2SXin Li                 bytecode.addAload(var);
1910*f1fbf3c2SXin Li                 break;
1911*f1fbf3c2SXin Li             case LONG :
1912*f1fbf3c2SXin Li                 bytecode.addLload(var);
1913*f1fbf3c2SXin Li                 break;
1914*f1fbf3c2SXin Li             case FLOAT :
1915*f1fbf3c2SXin Li                 bytecode.addFload(var);
1916*f1fbf3c2SXin Li                 break;
1917*f1fbf3c2SXin Li             case DOUBLE :
1918*f1fbf3c2SXin Li                 bytecode.addDload(var);
1919*f1fbf3c2SXin Li                 break;
1920*f1fbf3c2SXin Li             default :   // BOOLEAN, BYTE, CHAR, SHORT, INT
1921*f1fbf3c2SXin Li                 bytecode.addIload(var);
1922*f1fbf3c2SXin Li                 break;
1923*f1fbf3c2SXin Li             }
1924*f1fbf3c2SXin Li     }
1925*f1fbf3c2SXin Li 
1926*f1fbf3c2SXin Li     @Override
atKeyword(Keyword k)1927*f1fbf3c2SXin Li     public void atKeyword(Keyword k) throws CompileError {
1928*f1fbf3c2SXin Li         arrayDim = 0;
1929*f1fbf3c2SXin Li         int token = k.get();
1930*f1fbf3c2SXin Li         switch (token) {
1931*f1fbf3c2SXin Li         case TRUE :
1932*f1fbf3c2SXin Li             bytecode.addIconst(1);
1933*f1fbf3c2SXin Li             exprType = BOOLEAN;
1934*f1fbf3c2SXin Li             break;
1935*f1fbf3c2SXin Li         case FALSE :
1936*f1fbf3c2SXin Li             bytecode.addIconst(0);
1937*f1fbf3c2SXin Li             exprType = BOOLEAN;
1938*f1fbf3c2SXin Li             break;
1939*f1fbf3c2SXin Li         case NULL :
1940*f1fbf3c2SXin Li             bytecode.addOpcode(ACONST_NULL);
1941*f1fbf3c2SXin Li             exprType = NULL;
1942*f1fbf3c2SXin Li             break;
1943*f1fbf3c2SXin Li         case THIS :
1944*f1fbf3c2SXin Li         case SUPER :
1945*f1fbf3c2SXin Li             if (inStaticMethod)
1946*f1fbf3c2SXin Li                 throw new CompileError("not-available: "
1947*f1fbf3c2SXin Li                                        + (token == THIS ? "this" : "super"));
1948*f1fbf3c2SXin Li 
1949*f1fbf3c2SXin Li             bytecode.addAload(0);
1950*f1fbf3c2SXin Li             exprType = CLASS;
1951*f1fbf3c2SXin Li             if (token == THIS)
1952*f1fbf3c2SXin Li                 className = getThisName();
1953*f1fbf3c2SXin Li             else
1954*f1fbf3c2SXin Li                 className = getSuperName();
1955*f1fbf3c2SXin Li             break;
1956*f1fbf3c2SXin Li         default :
1957*f1fbf3c2SXin Li             fatal();
1958*f1fbf3c2SXin Li         }
1959*f1fbf3c2SXin Li     }
1960*f1fbf3c2SXin Li 
1961*f1fbf3c2SXin Li     @Override
atStringL(StringL s)1962*f1fbf3c2SXin Li     public void atStringL(StringL s) throws CompileError {
1963*f1fbf3c2SXin Li         exprType = CLASS;
1964*f1fbf3c2SXin Li         arrayDim = 0;
1965*f1fbf3c2SXin Li         className = jvmJavaLangString;
1966*f1fbf3c2SXin Li         bytecode.addLdc(s.get());
1967*f1fbf3c2SXin Li     }
1968*f1fbf3c2SXin Li 
1969*f1fbf3c2SXin Li     @Override
atIntConst(IntConst i)1970*f1fbf3c2SXin Li     public void atIntConst(IntConst i) throws CompileError {
1971*f1fbf3c2SXin Li         arrayDim = 0;
1972*f1fbf3c2SXin Li         long value = i.get();
1973*f1fbf3c2SXin Li         int type = i.getType();
1974*f1fbf3c2SXin Li         if (type == IntConstant || type == CharConstant) {
1975*f1fbf3c2SXin Li             exprType = (type == IntConstant ? INT : CHAR);
1976*f1fbf3c2SXin Li             bytecode.addIconst((int)value);
1977*f1fbf3c2SXin Li         }
1978*f1fbf3c2SXin Li         else {
1979*f1fbf3c2SXin Li             exprType = LONG;
1980*f1fbf3c2SXin Li             bytecode.addLconst(value);
1981*f1fbf3c2SXin Li         }
1982*f1fbf3c2SXin Li     }
1983*f1fbf3c2SXin Li 
1984*f1fbf3c2SXin Li     @Override
atDoubleConst(DoubleConst d)1985*f1fbf3c2SXin Li     public void atDoubleConst(DoubleConst d) throws CompileError {
1986*f1fbf3c2SXin Li         arrayDim = 0;
1987*f1fbf3c2SXin Li         if (d.getType() == DoubleConstant) {
1988*f1fbf3c2SXin Li             exprType = DOUBLE;
1989*f1fbf3c2SXin Li             bytecode.addDconst(d.get());
1990*f1fbf3c2SXin Li         }
1991*f1fbf3c2SXin Li         else {
1992*f1fbf3c2SXin Li             exprType = FLOAT;
1993*f1fbf3c2SXin Li             bytecode.addFconst((float)d.get());
1994*f1fbf3c2SXin Li         }
1995*f1fbf3c2SXin Li     }
1996*f1fbf3c2SXin Li }
1997