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