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 javassist.ClassPool; 20*f1fbf3c2SXin Li import javassist.CtClass; 21*f1fbf3c2SXin Li import javassist.CtPrimitiveType; 22*f1fbf3c2SXin Li import javassist.NotFoundException; 23*f1fbf3c2SXin Li import javassist.bytecode.Bytecode; 24*f1fbf3c2SXin Li import javassist.bytecode.Descriptor; 25*f1fbf3c2SXin Li import javassist.compiler.ast.ASTList; 26*f1fbf3c2SXin Li import javassist.compiler.ast.ASTree; 27*f1fbf3c2SXin Li import javassist.compiler.ast.CallExpr; 28*f1fbf3c2SXin Li import javassist.compiler.ast.CastExpr; 29*f1fbf3c2SXin Li import javassist.compiler.ast.Declarator; 30*f1fbf3c2SXin Li import javassist.compiler.ast.Expr; 31*f1fbf3c2SXin Li import javassist.compiler.ast.Member; 32*f1fbf3c2SXin Li import javassist.compiler.ast.Stmnt; 33*f1fbf3c2SXin Li import javassist.compiler.ast.Symbol; 34*f1fbf3c2SXin Li 35*f1fbf3c2SXin Li /* Code generator accepting extended Java syntax for Javassist. 36*f1fbf3c2SXin Li */ 37*f1fbf3c2SXin Li 38*f1fbf3c2SXin Li public class JvstCodeGen extends MemberCodeGen { 39*f1fbf3c2SXin Li String paramArrayName = null; 40*f1fbf3c2SXin Li String paramListName = null; 41*f1fbf3c2SXin Li CtClass[] paramTypeList = null; 42*f1fbf3c2SXin Li private int paramVarBase = 0; // variable index for $0 or $1. 43*f1fbf3c2SXin Li private boolean useParam0 = false; // true if $0 is used. 44*f1fbf3c2SXin Li private String param0Type = null; // JVM name 45*f1fbf3c2SXin Li public static final String sigName = "$sig"; 46*f1fbf3c2SXin Li public static final String dollarTypeName = "$type"; 47*f1fbf3c2SXin Li public static final String clazzName = "$class"; 48*f1fbf3c2SXin Li private CtClass dollarType = null; 49*f1fbf3c2SXin Li CtClass returnType = null; 50*f1fbf3c2SXin Li String returnCastName = null; 51*f1fbf3c2SXin Li @SuppressWarnings("unused") 52*f1fbf3c2SXin Li private String returnVarName = null; // null if $_ is not used. 53*f1fbf3c2SXin Li public static final String wrapperCastName = "$w"; 54*f1fbf3c2SXin Li String proceedName = null; 55*f1fbf3c2SXin Li public static final String cflowName = "$cflow"; 56*f1fbf3c2SXin Li ProceedHandler procHandler = null; // null if not used. 57*f1fbf3c2SXin Li JvstCodeGen(Bytecode b, CtClass cc, ClassPool cp)58*f1fbf3c2SXin Li public JvstCodeGen(Bytecode b, CtClass cc, ClassPool cp) { 59*f1fbf3c2SXin Li super(b, cc, cp); 60*f1fbf3c2SXin Li setTypeChecker(new JvstTypeChecker(cc, cp, this)); 61*f1fbf3c2SXin Li } 62*f1fbf3c2SXin Li 63*f1fbf3c2SXin Li /* Index of $1. 64*f1fbf3c2SXin Li */ indexOfParam1()65*f1fbf3c2SXin Li private int indexOfParam1() { 66*f1fbf3c2SXin Li return paramVarBase + (useParam0 ? 1 : 0); 67*f1fbf3c2SXin Li } 68*f1fbf3c2SXin Li 69*f1fbf3c2SXin Li /* Records a ProceedHandler obejct. 70*f1fbf3c2SXin Li * 71*f1fbf3c2SXin Li * @param name the name of the special method call. 72*f1fbf3c2SXin Li * it is usually $proceed. 73*f1fbf3c2SXin Li */ setProceedHandler(ProceedHandler h, String name)74*f1fbf3c2SXin Li public void setProceedHandler(ProceedHandler h, String name) { 75*f1fbf3c2SXin Li proceedName = name; 76*f1fbf3c2SXin Li procHandler = h; 77*f1fbf3c2SXin Li } 78*f1fbf3c2SXin Li 79*f1fbf3c2SXin Li /* If the type of the expression compiled last is void, 80*f1fbf3c2SXin Li * add ACONST_NULL and change exprType, arrayDim, className. 81*f1fbf3c2SXin Li */ addNullIfVoid()82*f1fbf3c2SXin Li public void addNullIfVoid() { 83*f1fbf3c2SXin Li if (exprType == VOID) { 84*f1fbf3c2SXin Li bytecode.addOpcode(ACONST_NULL); 85*f1fbf3c2SXin Li exprType = CLASS; 86*f1fbf3c2SXin Li arrayDim = 0; 87*f1fbf3c2SXin Li className = jvmJavaLangObject; 88*f1fbf3c2SXin Li } 89*f1fbf3c2SXin Li } 90*f1fbf3c2SXin Li 91*f1fbf3c2SXin Li /* To support $args, $sig, and $type. 92*f1fbf3c2SXin Li * $args is an array of parameter list. 93*f1fbf3c2SXin Li */ 94*f1fbf3c2SXin Li @Override atMember(Member mem)95*f1fbf3c2SXin Li public void atMember(Member mem) throws CompileError { 96*f1fbf3c2SXin Li String name = mem.get(); 97*f1fbf3c2SXin Li if (name.equals(paramArrayName)) { 98*f1fbf3c2SXin Li compileParameterList(bytecode, paramTypeList, indexOfParam1()); 99*f1fbf3c2SXin Li exprType = CLASS; 100*f1fbf3c2SXin Li arrayDim = 1; 101*f1fbf3c2SXin Li className = jvmJavaLangObject; 102*f1fbf3c2SXin Li } 103*f1fbf3c2SXin Li else if (name.equals(sigName)) { 104*f1fbf3c2SXin Li bytecode.addLdc(Descriptor.ofMethod(returnType, paramTypeList)); 105*f1fbf3c2SXin Li bytecode.addInvokestatic("javassist/runtime/Desc", "getParams", 106*f1fbf3c2SXin Li "(Ljava/lang/String;)[Ljava/lang/Class;"); 107*f1fbf3c2SXin Li exprType = CLASS; 108*f1fbf3c2SXin Li arrayDim = 1; 109*f1fbf3c2SXin Li className = "java/lang/Class"; 110*f1fbf3c2SXin Li } 111*f1fbf3c2SXin Li else if (name.equals(dollarTypeName)) { 112*f1fbf3c2SXin Li if (dollarType == null) 113*f1fbf3c2SXin Li throw new CompileError(dollarTypeName + " is not available"); 114*f1fbf3c2SXin Li 115*f1fbf3c2SXin Li bytecode.addLdc(Descriptor.of(dollarType)); 116*f1fbf3c2SXin Li callGetType("getType"); 117*f1fbf3c2SXin Li } 118*f1fbf3c2SXin Li else if (name.equals(clazzName)) { 119*f1fbf3c2SXin Li if (param0Type == null) 120*f1fbf3c2SXin Li throw new CompileError(clazzName + " is not available"); 121*f1fbf3c2SXin Li 122*f1fbf3c2SXin Li bytecode.addLdc(param0Type); 123*f1fbf3c2SXin Li callGetType("getClazz"); 124*f1fbf3c2SXin Li } 125*f1fbf3c2SXin Li else 126*f1fbf3c2SXin Li super.atMember(mem); 127*f1fbf3c2SXin Li } 128*f1fbf3c2SXin Li callGetType(String method)129*f1fbf3c2SXin Li private void callGetType(String method) { 130*f1fbf3c2SXin Li bytecode.addInvokestatic("javassist/runtime/Desc", method, 131*f1fbf3c2SXin Li "(Ljava/lang/String;)Ljava/lang/Class;"); 132*f1fbf3c2SXin Li exprType = CLASS; 133*f1fbf3c2SXin Li arrayDim = 0; 134*f1fbf3c2SXin Li className = "java/lang/Class"; 135*f1fbf3c2SXin Li } 136*f1fbf3c2SXin Li 137*f1fbf3c2SXin Li @Override atFieldAssign(Expr expr, int op, ASTree left, ASTree right, boolean doDup)138*f1fbf3c2SXin Li protected void atFieldAssign(Expr expr, int op, ASTree left, 139*f1fbf3c2SXin Li ASTree right, boolean doDup) throws CompileError 140*f1fbf3c2SXin Li { 141*f1fbf3c2SXin Li if (left instanceof Member 142*f1fbf3c2SXin Li && ((Member)left).get().equals(paramArrayName)) { 143*f1fbf3c2SXin Li if (op != '=') 144*f1fbf3c2SXin Li throw new CompileError("bad operator for " + paramArrayName); 145*f1fbf3c2SXin Li 146*f1fbf3c2SXin Li right.accept(this); 147*f1fbf3c2SXin Li if (arrayDim != 1 || exprType != CLASS) 148*f1fbf3c2SXin Li throw new CompileError("invalid type for " + paramArrayName); 149*f1fbf3c2SXin Li 150*f1fbf3c2SXin Li atAssignParamList(paramTypeList, bytecode); 151*f1fbf3c2SXin Li if (!doDup) 152*f1fbf3c2SXin Li bytecode.addOpcode(POP); 153*f1fbf3c2SXin Li } 154*f1fbf3c2SXin Li else 155*f1fbf3c2SXin Li super.atFieldAssign(expr, op, left, right, doDup); 156*f1fbf3c2SXin Li } 157*f1fbf3c2SXin Li atAssignParamList(CtClass[] params, Bytecode code)158*f1fbf3c2SXin Li protected void atAssignParamList(CtClass[] params, Bytecode code) 159*f1fbf3c2SXin Li throws CompileError 160*f1fbf3c2SXin Li { 161*f1fbf3c2SXin Li if (params == null) 162*f1fbf3c2SXin Li return; 163*f1fbf3c2SXin Li 164*f1fbf3c2SXin Li int varNo = indexOfParam1(); 165*f1fbf3c2SXin Li int n = params.length; 166*f1fbf3c2SXin Li for (int i = 0; i < n; ++i) { 167*f1fbf3c2SXin Li code.addOpcode(DUP); 168*f1fbf3c2SXin Li code.addIconst(i); 169*f1fbf3c2SXin Li code.addOpcode(AALOAD); 170*f1fbf3c2SXin Li compileUnwrapValue(params[i], code); 171*f1fbf3c2SXin Li code.addStore(varNo, params[i]); 172*f1fbf3c2SXin Li varNo += is2word(exprType, arrayDim) ? 2 : 1; 173*f1fbf3c2SXin Li } 174*f1fbf3c2SXin Li } 175*f1fbf3c2SXin Li 176*f1fbf3c2SXin Li @Override atCastExpr(CastExpr expr)177*f1fbf3c2SXin Li public void atCastExpr(CastExpr expr) throws CompileError { 178*f1fbf3c2SXin Li ASTList classname = expr.getClassName(); 179*f1fbf3c2SXin Li if (classname != null && expr.getArrayDim() == 0) { 180*f1fbf3c2SXin Li ASTree p = classname.head(); 181*f1fbf3c2SXin Li if (p instanceof Symbol && classname.tail() == null) { 182*f1fbf3c2SXin Li String typename = ((Symbol)p).get(); 183*f1fbf3c2SXin Li if (typename.equals(returnCastName)) { 184*f1fbf3c2SXin Li atCastToRtype(expr); 185*f1fbf3c2SXin Li return; 186*f1fbf3c2SXin Li } 187*f1fbf3c2SXin Li else if (typename.equals(wrapperCastName)) { 188*f1fbf3c2SXin Li atCastToWrapper(expr); 189*f1fbf3c2SXin Li return; 190*f1fbf3c2SXin Li } 191*f1fbf3c2SXin Li } 192*f1fbf3c2SXin Li } 193*f1fbf3c2SXin Li 194*f1fbf3c2SXin Li super.atCastExpr(expr); 195*f1fbf3c2SXin Li } 196*f1fbf3c2SXin Li 197*f1fbf3c2SXin Li /** 198*f1fbf3c2SXin Li * Inserts a cast operator to the return type. 199*f1fbf3c2SXin Li * If the return type is void, this does nothing. 200*f1fbf3c2SXin Li */ atCastToRtype(CastExpr expr)201*f1fbf3c2SXin Li protected void atCastToRtype(CastExpr expr) throws CompileError { 202*f1fbf3c2SXin Li expr.getOprand().accept(this); 203*f1fbf3c2SXin Li if (exprType == VOID || isRefType(exprType) || arrayDim > 0) 204*f1fbf3c2SXin Li compileUnwrapValue(returnType, bytecode); 205*f1fbf3c2SXin Li else if (returnType instanceof CtPrimitiveType) { 206*f1fbf3c2SXin Li CtPrimitiveType pt = (CtPrimitiveType)returnType; 207*f1fbf3c2SXin Li int destType = MemberResolver.descToType(pt.getDescriptor()); 208*f1fbf3c2SXin Li atNumCastExpr(exprType, destType); 209*f1fbf3c2SXin Li exprType = destType; 210*f1fbf3c2SXin Li arrayDim = 0; 211*f1fbf3c2SXin Li className = null; 212*f1fbf3c2SXin Li } 213*f1fbf3c2SXin Li else 214*f1fbf3c2SXin Li throw new CompileError("invalid cast"); 215*f1fbf3c2SXin Li } 216*f1fbf3c2SXin Li atCastToWrapper(CastExpr expr)217*f1fbf3c2SXin Li protected void atCastToWrapper(CastExpr expr) throws CompileError { 218*f1fbf3c2SXin Li expr.getOprand().accept(this); 219*f1fbf3c2SXin Li if (isRefType(exprType) || arrayDim > 0) 220*f1fbf3c2SXin Li return; // Object type. do nothing. 221*f1fbf3c2SXin Li 222*f1fbf3c2SXin Li CtClass clazz = resolver.lookupClass(exprType, arrayDim, className); 223*f1fbf3c2SXin Li if (clazz instanceof CtPrimitiveType) { 224*f1fbf3c2SXin Li CtPrimitiveType pt = (CtPrimitiveType)clazz; 225*f1fbf3c2SXin Li String wrapper = pt.getWrapperName(); 226*f1fbf3c2SXin Li bytecode.addNew(wrapper); // new <wrapper> 227*f1fbf3c2SXin Li bytecode.addOpcode(DUP); // dup 228*f1fbf3c2SXin Li if (pt.getDataSize() > 1) 229*f1fbf3c2SXin Li bytecode.addOpcode(DUP2_X2); // dup2_x2 230*f1fbf3c2SXin Li else 231*f1fbf3c2SXin Li bytecode.addOpcode(DUP2_X1); // dup2_x1 232*f1fbf3c2SXin Li 233*f1fbf3c2SXin Li bytecode.addOpcode(POP2); // pop2 234*f1fbf3c2SXin Li bytecode.addInvokespecial(wrapper, "<init>", 235*f1fbf3c2SXin Li "(" + pt.getDescriptor() + ")V"); 236*f1fbf3c2SXin Li // invokespecial 237*f1fbf3c2SXin Li exprType = CLASS; 238*f1fbf3c2SXin Li arrayDim = 0; 239*f1fbf3c2SXin Li className = jvmJavaLangObject; 240*f1fbf3c2SXin Li } 241*f1fbf3c2SXin Li } 242*f1fbf3c2SXin Li 243*f1fbf3c2SXin Li /* Delegates to a ProcHandler object if the method call is 244*f1fbf3c2SXin Li * $proceed(). It may process $cflow(). 245*f1fbf3c2SXin Li */ 246*f1fbf3c2SXin Li @Override atCallExpr(CallExpr expr)247*f1fbf3c2SXin Li public void atCallExpr(CallExpr expr) throws CompileError { 248*f1fbf3c2SXin Li ASTree method = expr.oprand1(); 249*f1fbf3c2SXin Li if (method instanceof Member) { 250*f1fbf3c2SXin Li String name = ((Member)method).get(); 251*f1fbf3c2SXin Li if (procHandler != null && name.equals(proceedName)) { 252*f1fbf3c2SXin Li procHandler.doit(this, bytecode, (ASTList)expr.oprand2()); 253*f1fbf3c2SXin Li return; 254*f1fbf3c2SXin Li } 255*f1fbf3c2SXin Li else if (name.equals(cflowName)) { 256*f1fbf3c2SXin Li atCflow((ASTList)expr.oprand2()); 257*f1fbf3c2SXin Li return; 258*f1fbf3c2SXin Li } 259*f1fbf3c2SXin Li } 260*f1fbf3c2SXin Li 261*f1fbf3c2SXin Li super.atCallExpr(expr); 262*f1fbf3c2SXin Li } 263*f1fbf3c2SXin Li 264*f1fbf3c2SXin Li /* To support $cflow(). 265*f1fbf3c2SXin Li */ atCflow(ASTList cname)266*f1fbf3c2SXin Li protected void atCflow(ASTList cname) throws CompileError { 267*f1fbf3c2SXin Li StringBuffer sbuf = new StringBuffer(); 268*f1fbf3c2SXin Li if (cname == null || cname.tail() != null) 269*f1fbf3c2SXin Li throw new CompileError("bad " + cflowName); 270*f1fbf3c2SXin Li 271*f1fbf3c2SXin Li makeCflowName(sbuf, cname.head()); 272*f1fbf3c2SXin Li String name = sbuf.toString(); 273*f1fbf3c2SXin Li Object[] names = resolver.getClassPool().lookupCflow(name); 274*f1fbf3c2SXin Li if (names == null) 275*f1fbf3c2SXin Li throw new CompileError("no such " + cflowName + ": " + name); 276*f1fbf3c2SXin Li 277*f1fbf3c2SXin Li bytecode.addGetstatic((String)names[0], (String)names[1], 278*f1fbf3c2SXin Li "Ljavassist/runtime/Cflow;"); 279*f1fbf3c2SXin Li bytecode.addInvokevirtual("javassist.runtime.Cflow", 280*f1fbf3c2SXin Li "value", "()I"); 281*f1fbf3c2SXin Li exprType = INT; 282*f1fbf3c2SXin Li arrayDim = 0; 283*f1fbf3c2SXin Li className = null; 284*f1fbf3c2SXin Li } 285*f1fbf3c2SXin Li 286*f1fbf3c2SXin Li /* Syntax: 287*f1fbf3c2SXin Li * 288*f1fbf3c2SXin Li * <cflow> : $cflow '(' <cflow name> ')' 289*f1fbf3c2SXin Li * <cflow name> : <identifier> ('.' <identifier>)* 290*f1fbf3c2SXin Li */ makeCflowName(StringBuffer sbuf, ASTree name)291*f1fbf3c2SXin Li private static void makeCflowName(StringBuffer sbuf, ASTree name) 292*f1fbf3c2SXin Li throws CompileError 293*f1fbf3c2SXin Li { 294*f1fbf3c2SXin Li if (name instanceof Symbol) { 295*f1fbf3c2SXin Li sbuf.append(((Symbol)name).get()); 296*f1fbf3c2SXin Li return; 297*f1fbf3c2SXin Li } 298*f1fbf3c2SXin Li else if (name instanceof Expr) { 299*f1fbf3c2SXin Li Expr expr = (Expr)name; 300*f1fbf3c2SXin Li if (expr.getOperator() == '.') { 301*f1fbf3c2SXin Li makeCflowName(sbuf, expr.oprand1()); 302*f1fbf3c2SXin Li sbuf.append('.'); 303*f1fbf3c2SXin Li makeCflowName(sbuf, expr.oprand2()); 304*f1fbf3c2SXin Li return; 305*f1fbf3c2SXin Li } 306*f1fbf3c2SXin Li } 307*f1fbf3c2SXin Li 308*f1fbf3c2SXin Li throw new CompileError("bad " + cflowName); 309*f1fbf3c2SXin Li } 310*f1fbf3c2SXin Li 311*f1fbf3c2SXin Li /* To support $$. ($$) is equivalent to ($1, ..., $n). 312*f1fbf3c2SXin Li * It can be used only as a parameter list of method call. 313*f1fbf3c2SXin Li */ isParamListName(ASTList args)314*f1fbf3c2SXin Li public boolean isParamListName(ASTList args) { 315*f1fbf3c2SXin Li if (paramTypeList != null 316*f1fbf3c2SXin Li && args != null && args.tail() == null) { 317*f1fbf3c2SXin Li ASTree left = args.head(); 318*f1fbf3c2SXin Li return (left instanceof Member 319*f1fbf3c2SXin Li && ((Member)left).get().equals(paramListName)); 320*f1fbf3c2SXin Li } 321*f1fbf3c2SXin Li return false; 322*f1fbf3c2SXin Li } 323*f1fbf3c2SXin Li 324*f1fbf3c2SXin Li /* 325*f1fbf3c2SXin Li public int getMethodArgsLength(ASTList args) { 326*f1fbf3c2SXin Li if (!isParamListName(args)) 327*f1fbf3c2SXin Li return super.getMethodArgsLength(args); 328*f1fbf3c2SXin Li 329*f1fbf3c2SXin Li return paramTypeList.length; 330*f1fbf3c2SXin Li } 331*f1fbf3c2SXin Li */ 332*f1fbf3c2SXin Li 333*f1fbf3c2SXin Li @Override getMethodArgsLength(ASTList args)334*f1fbf3c2SXin Li public int getMethodArgsLength(ASTList args) { 335*f1fbf3c2SXin Li String pname = paramListName; 336*f1fbf3c2SXin Li int n = 0; 337*f1fbf3c2SXin Li while (args != null) { 338*f1fbf3c2SXin Li ASTree a = args.head(); 339*f1fbf3c2SXin Li if (a instanceof Member && ((Member)a).get().equals(pname)) { 340*f1fbf3c2SXin Li if (paramTypeList != null) 341*f1fbf3c2SXin Li n += paramTypeList.length; 342*f1fbf3c2SXin Li } 343*f1fbf3c2SXin Li else 344*f1fbf3c2SXin Li ++n; 345*f1fbf3c2SXin Li 346*f1fbf3c2SXin Li args = args.tail(); 347*f1fbf3c2SXin Li } 348*f1fbf3c2SXin Li 349*f1fbf3c2SXin Li return n; 350*f1fbf3c2SXin Li } 351*f1fbf3c2SXin Li 352*f1fbf3c2SXin Li @Override atMethodArgs(ASTList args, int[] types, int[] dims, String[] cnames)353*f1fbf3c2SXin Li public void atMethodArgs(ASTList args, int[] types, int[] dims, 354*f1fbf3c2SXin Li String[] cnames) throws CompileError { 355*f1fbf3c2SXin Li CtClass[] params = paramTypeList; 356*f1fbf3c2SXin Li String pname = paramListName; 357*f1fbf3c2SXin Li int i = 0; 358*f1fbf3c2SXin Li while (args != null) { 359*f1fbf3c2SXin Li ASTree a = args.head(); 360*f1fbf3c2SXin Li if (a instanceof Member && ((Member)a).get().equals(pname)) { 361*f1fbf3c2SXin Li if (params != null) { 362*f1fbf3c2SXin Li int n = params.length; 363*f1fbf3c2SXin Li int regno = indexOfParam1(); 364*f1fbf3c2SXin Li for (int k = 0; k < n; ++k) { 365*f1fbf3c2SXin Li CtClass p = params[k]; 366*f1fbf3c2SXin Li regno += bytecode.addLoad(regno, p); 367*f1fbf3c2SXin Li setType(p); 368*f1fbf3c2SXin Li types[i] = exprType; 369*f1fbf3c2SXin Li dims[i] = arrayDim; 370*f1fbf3c2SXin Li cnames[i] = className; 371*f1fbf3c2SXin Li ++i; 372*f1fbf3c2SXin Li } 373*f1fbf3c2SXin Li } 374*f1fbf3c2SXin Li } 375*f1fbf3c2SXin Li else { 376*f1fbf3c2SXin Li a.accept(this); 377*f1fbf3c2SXin Li types[i] = exprType; 378*f1fbf3c2SXin Li dims[i] = arrayDim; 379*f1fbf3c2SXin Li cnames[i] = className; 380*f1fbf3c2SXin Li ++i; 381*f1fbf3c2SXin Li } 382*f1fbf3c2SXin Li 383*f1fbf3c2SXin Li args = args.tail(); 384*f1fbf3c2SXin Li } 385*f1fbf3c2SXin Li } 386*f1fbf3c2SXin Li 387*f1fbf3c2SXin Li /* 388*f1fbf3c2SXin Li public void atMethodArgs(ASTList args, int[] types, int[] dims, 389*f1fbf3c2SXin Li String[] cnames) throws CompileError { 390*f1fbf3c2SXin Li if (!isParamListName(args)) { 391*f1fbf3c2SXin Li super.atMethodArgs(args, types, dims, cnames); 392*f1fbf3c2SXin Li return; 393*f1fbf3c2SXin Li } 394*f1fbf3c2SXin Li 395*f1fbf3c2SXin Li CtClass[] params = paramTypeList; 396*f1fbf3c2SXin Li if (params == null) 397*f1fbf3c2SXin Li return; 398*f1fbf3c2SXin Li 399*f1fbf3c2SXin Li int n = params.length; 400*f1fbf3c2SXin Li int regno = indexOfParam1(); 401*f1fbf3c2SXin Li for (int i = 0; i < n; ++i) { 402*f1fbf3c2SXin Li CtClass p = params[i]; 403*f1fbf3c2SXin Li regno += bytecode.addLoad(regno, p); 404*f1fbf3c2SXin Li setType(p); 405*f1fbf3c2SXin Li types[i] = exprType; 406*f1fbf3c2SXin Li dims[i] = arrayDim; 407*f1fbf3c2SXin Li cnames[i] = className; 408*f1fbf3c2SXin Li } 409*f1fbf3c2SXin Li } 410*f1fbf3c2SXin Li */ 411*f1fbf3c2SXin Li 412*f1fbf3c2SXin Li /* called by Javac#recordSpecialProceed(). 413*f1fbf3c2SXin Li */ compileInvokeSpecial(ASTree target, int methodIndex, String descriptor, ASTList args)414*f1fbf3c2SXin Li void compileInvokeSpecial(ASTree target, int methodIndex, 415*f1fbf3c2SXin Li String descriptor, ASTList args) 416*f1fbf3c2SXin Li throws CompileError 417*f1fbf3c2SXin Li { 418*f1fbf3c2SXin Li target.accept(this); 419*f1fbf3c2SXin Li int nargs = getMethodArgsLength(args); 420*f1fbf3c2SXin Li atMethodArgs(args, new int[nargs], new int[nargs], 421*f1fbf3c2SXin Li new String[nargs]); 422*f1fbf3c2SXin Li bytecode.addInvokespecial(methodIndex, descriptor); 423*f1fbf3c2SXin Li setReturnType(descriptor, false, false); 424*f1fbf3c2SXin Li addNullIfVoid(); 425*f1fbf3c2SXin Li } 426*f1fbf3c2SXin Li 427*f1fbf3c2SXin Li /* 428*f1fbf3c2SXin Li * Makes it valid to write "return <expr>;" for a void method. 429*f1fbf3c2SXin Li */ 430*f1fbf3c2SXin Li @Override atReturnStmnt(Stmnt st)431*f1fbf3c2SXin Li protected void atReturnStmnt(Stmnt st) throws CompileError { 432*f1fbf3c2SXin Li ASTree result = st.getLeft(); 433*f1fbf3c2SXin Li if (result != null && returnType == CtClass.voidType) { 434*f1fbf3c2SXin Li compileExpr(result); 435*f1fbf3c2SXin Li if (is2word(exprType, arrayDim)) 436*f1fbf3c2SXin Li bytecode.addOpcode(POP2); 437*f1fbf3c2SXin Li else if (exprType != VOID) 438*f1fbf3c2SXin Li bytecode.addOpcode(POP); 439*f1fbf3c2SXin Li 440*f1fbf3c2SXin Li result = null; 441*f1fbf3c2SXin Li } 442*f1fbf3c2SXin Li 443*f1fbf3c2SXin Li atReturnStmnt2(result); 444*f1fbf3c2SXin Li } 445*f1fbf3c2SXin Li 446*f1fbf3c2SXin Li /** 447*f1fbf3c2SXin Li * Makes a cast to the return type ($r) available. 448*f1fbf3c2SXin Li * It also enables $_. 449*f1fbf3c2SXin Li * 450*f1fbf3c2SXin Li * <p>If the return type is void, ($r) does nothing. 451*f1fbf3c2SXin Li * The type of $_ is java.lang.Object. 452*f1fbf3c2SXin Li * 453*f1fbf3c2SXin Li * @param resultName null if $_ is not used. 454*f1fbf3c2SXin Li * @return -1 or the variable index assigned to $_. 455*f1fbf3c2SXin Li */ recordReturnType(CtClass type, String castName, String resultName, SymbolTable tbl)456*f1fbf3c2SXin Li public int recordReturnType(CtClass type, String castName, 457*f1fbf3c2SXin Li String resultName, SymbolTable tbl) throws CompileError 458*f1fbf3c2SXin Li { 459*f1fbf3c2SXin Li returnType = type; 460*f1fbf3c2SXin Li returnCastName = castName; 461*f1fbf3c2SXin Li returnVarName = resultName; 462*f1fbf3c2SXin Li if (resultName == null) 463*f1fbf3c2SXin Li return -1; 464*f1fbf3c2SXin Li int varNo = getMaxLocals(); 465*f1fbf3c2SXin Li int locals = varNo + recordVar(type, resultName, varNo, tbl); 466*f1fbf3c2SXin Li setMaxLocals(locals); 467*f1fbf3c2SXin Li return varNo; 468*f1fbf3c2SXin Li } 469*f1fbf3c2SXin Li 470*f1fbf3c2SXin Li /** 471*f1fbf3c2SXin Li * Makes $type available. 472*f1fbf3c2SXin Li */ recordType(CtClass t)473*f1fbf3c2SXin Li public void recordType(CtClass t) { 474*f1fbf3c2SXin Li dollarType = t; 475*f1fbf3c2SXin Li } 476*f1fbf3c2SXin Li 477*f1fbf3c2SXin Li /** 478*f1fbf3c2SXin Li * Makes method parameters $0, $1, ..., $args, $$, and $class available. 479*f1fbf3c2SXin Li * $0 is equivalent to THIS if the method is not static. Otherwise, 480*f1fbf3c2SXin Li * if the method is static, then $0 is not available. 481*f1fbf3c2SXin Li */ recordParams(CtClass[] params, boolean isStatic, String prefix, String paramVarName, String paramsName, SymbolTable tbl)482*f1fbf3c2SXin Li public int recordParams(CtClass[] params, boolean isStatic, 483*f1fbf3c2SXin Li String prefix, String paramVarName, 484*f1fbf3c2SXin Li String paramsName, SymbolTable tbl) 485*f1fbf3c2SXin Li throws CompileError 486*f1fbf3c2SXin Li { 487*f1fbf3c2SXin Li return recordParams(params, isStatic, prefix, paramVarName, 488*f1fbf3c2SXin Li paramsName, !isStatic, 0, getThisName(), tbl); 489*f1fbf3c2SXin Li } 490*f1fbf3c2SXin Li 491*f1fbf3c2SXin Li /** 492*f1fbf3c2SXin Li * Makes method parameters $0, $1, ..., $args, $$, and $class available. 493*f1fbf3c2SXin Li * $0 is available only if use0 is true. It might not be equivalent 494*f1fbf3c2SXin Li * to THIS. 495*f1fbf3c2SXin Li * 496*f1fbf3c2SXin Li * @param params the parameter types (the types of $1, $2, ..) 497*f1fbf3c2SXin Li * @param prefix it must be "$" (the first letter of $0, $1, ...) 498*f1fbf3c2SXin Li * @param paramVarName it must be "$args" 499*f1fbf3c2SXin Li * @param paramsName it must be "$$" 500*f1fbf3c2SXin Li * @param use0 true if $0 is used. 501*f1fbf3c2SXin Li * @param paramBase the register number of $0 (use0 is true) 502*f1fbf3c2SXin Li * or $1 (otherwise). 503*f1fbf3c2SXin Li * @param target the class of $0. If use0 is false, target 504*f1fbf3c2SXin Li * can be null. The value of "target" is also used 505*f1fbf3c2SXin Li * as the name of the type represented by $class. 506*f1fbf3c2SXin Li * @param isStatic true if the method in which the compiled bytecode 507*f1fbf3c2SXin Li * is embedded is static. 508*f1fbf3c2SXin Li */ recordParams(CtClass[] params, boolean isStatic, String prefix, String paramVarName, String paramsName, boolean use0, int paramBase, String target, SymbolTable tbl)509*f1fbf3c2SXin Li public int recordParams(CtClass[] params, boolean isStatic, 510*f1fbf3c2SXin Li String prefix, String paramVarName, 511*f1fbf3c2SXin Li String paramsName, boolean use0, 512*f1fbf3c2SXin Li int paramBase, String target, 513*f1fbf3c2SXin Li SymbolTable tbl) 514*f1fbf3c2SXin Li throws CompileError 515*f1fbf3c2SXin Li { 516*f1fbf3c2SXin Li int varNo; 517*f1fbf3c2SXin Li 518*f1fbf3c2SXin Li paramTypeList = params; 519*f1fbf3c2SXin Li paramArrayName = paramVarName; 520*f1fbf3c2SXin Li paramListName = paramsName; 521*f1fbf3c2SXin Li paramVarBase = paramBase; 522*f1fbf3c2SXin Li useParam0 = use0; 523*f1fbf3c2SXin Li 524*f1fbf3c2SXin Li if (target != null) 525*f1fbf3c2SXin Li param0Type = MemberResolver.jvmToJavaName(target); 526*f1fbf3c2SXin Li 527*f1fbf3c2SXin Li inStaticMethod = isStatic; 528*f1fbf3c2SXin Li varNo = paramBase; 529*f1fbf3c2SXin Li if (use0) { 530*f1fbf3c2SXin Li String varName = prefix + "0"; 531*f1fbf3c2SXin Li Declarator decl 532*f1fbf3c2SXin Li = new Declarator(CLASS, MemberResolver.javaToJvmName(target), 533*f1fbf3c2SXin Li 0, varNo++, new Symbol(varName)); 534*f1fbf3c2SXin Li tbl.append(varName, decl); 535*f1fbf3c2SXin Li } 536*f1fbf3c2SXin Li 537*f1fbf3c2SXin Li for (int i = 0; i < params.length; ++i) 538*f1fbf3c2SXin Li varNo += recordVar(params[i], prefix + (i + 1), varNo, tbl); 539*f1fbf3c2SXin Li 540*f1fbf3c2SXin Li if (getMaxLocals() < varNo) 541*f1fbf3c2SXin Li setMaxLocals(varNo); 542*f1fbf3c2SXin Li 543*f1fbf3c2SXin Li return varNo; 544*f1fbf3c2SXin Li } 545*f1fbf3c2SXin Li 546*f1fbf3c2SXin Li /** 547*f1fbf3c2SXin Li * Makes the given variable name available. 548*f1fbf3c2SXin Li * 549*f1fbf3c2SXin Li * @param type variable type 550*f1fbf3c2SXin Li * @param varName variable name 551*f1fbf3c2SXin Li */ recordVariable(CtClass type, String varName, SymbolTable tbl)552*f1fbf3c2SXin Li public int recordVariable(CtClass type, String varName, SymbolTable tbl) 553*f1fbf3c2SXin Li throws CompileError 554*f1fbf3c2SXin Li { 555*f1fbf3c2SXin Li if (varName == null) 556*f1fbf3c2SXin Li return -1; 557*f1fbf3c2SXin Li int varNo = getMaxLocals(); 558*f1fbf3c2SXin Li int locals = varNo + recordVar(type, varName, varNo, tbl); 559*f1fbf3c2SXin Li setMaxLocals(locals); 560*f1fbf3c2SXin Li return varNo; 561*f1fbf3c2SXin Li } 562*f1fbf3c2SXin Li recordVar(CtClass cc, String varName, int varNo, SymbolTable tbl)563*f1fbf3c2SXin Li private int recordVar(CtClass cc, String varName, int varNo, 564*f1fbf3c2SXin Li SymbolTable tbl) throws CompileError 565*f1fbf3c2SXin Li { 566*f1fbf3c2SXin Li if (cc == CtClass.voidType) { 567*f1fbf3c2SXin Li exprType = CLASS; 568*f1fbf3c2SXin Li arrayDim = 0; 569*f1fbf3c2SXin Li className = jvmJavaLangObject; 570*f1fbf3c2SXin Li } 571*f1fbf3c2SXin Li else 572*f1fbf3c2SXin Li setType(cc); 573*f1fbf3c2SXin Li 574*f1fbf3c2SXin Li Declarator decl 575*f1fbf3c2SXin Li = new Declarator(exprType, className, arrayDim, 576*f1fbf3c2SXin Li varNo, new Symbol(varName)); 577*f1fbf3c2SXin Li tbl.append(varName, decl); 578*f1fbf3c2SXin Li return is2word(exprType, arrayDim) ? 2 : 1; 579*f1fbf3c2SXin Li } 580*f1fbf3c2SXin Li 581*f1fbf3c2SXin Li /** 582*f1fbf3c2SXin Li * Makes the given variable name available. 583*f1fbf3c2SXin Li * 584*f1fbf3c2SXin Li * @param typeDesc the type descriptor of the variable 585*f1fbf3c2SXin Li * @param varName variable name 586*f1fbf3c2SXin Li * @param varNo an index into the local variable array 587*f1fbf3c2SXin Li */ recordVariable(String typeDesc, String varName, int varNo, SymbolTable tbl)588*f1fbf3c2SXin Li public void recordVariable(String typeDesc, String varName, int varNo, 589*f1fbf3c2SXin Li SymbolTable tbl) throws CompileError 590*f1fbf3c2SXin Li { 591*f1fbf3c2SXin Li char c; 592*f1fbf3c2SXin Li int dim = 0; 593*f1fbf3c2SXin Li while ((c = typeDesc.charAt(dim)) == '[') 594*f1fbf3c2SXin Li ++dim; 595*f1fbf3c2SXin Li 596*f1fbf3c2SXin Li int type = MemberResolver.descToType(c); 597*f1fbf3c2SXin Li String cname = null; 598*f1fbf3c2SXin Li if (type == CLASS) { 599*f1fbf3c2SXin Li if (dim == 0) 600*f1fbf3c2SXin Li cname = typeDesc.substring(1, typeDesc.length() - 1); 601*f1fbf3c2SXin Li else 602*f1fbf3c2SXin Li cname = typeDesc.substring(dim + 1, typeDesc.length() - 1); 603*f1fbf3c2SXin Li } 604*f1fbf3c2SXin Li 605*f1fbf3c2SXin Li Declarator decl 606*f1fbf3c2SXin Li = new Declarator(type, cname, dim, varNo, new Symbol(varName)); 607*f1fbf3c2SXin Li tbl.append(varName, decl); 608*f1fbf3c2SXin Li } 609*f1fbf3c2SXin Li 610*f1fbf3c2SXin Li /* compileParameterList() returns the stack size used 611*f1fbf3c2SXin Li * by the produced code. 612*f1fbf3c2SXin Li * 613*f1fbf3c2SXin Li * This method correctly computes the max_stack value. 614*f1fbf3c2SXin Li * 615*f1fbf3c2SXin Li * @param regno the index of the local variable in which 616*f1fbf3c2SXin Li * the first argument is received. 617*f1fbf3c2SXin Li * (0: static method, 1: regular method.) 618*f1fbf3c2SXin Li */ compileParameterList(Bytecode code, CtClass[] params, int regno)619*f1fbf3c2SXin Li public static int compileParameterList(Bytecode code, 620*f1fbf3c2SXin Li CtClass[] params, int regno) { 621*f1fbf3c2SXin Li if (params == null) { 622*f1fbf3c2SXin Li code.addIconst(0); // iconst_0 623*f1fbf3c2SXin Li code.addAnewarray(javaLangObject); // anewarray Object 624*f1fbf3c2SXin Li return 1; 625*f1fbf3c2SXin Li } 626*f1fbf3c2SXin Li CtClass[] args = new CtClass[1]; 627*f1fbf3c2SXin Li int n = params.length; 628*f1fbf3c2SXin Li code.addIconst(n); // iconst_<n> 629*f1fbf3c2SXin Li code.addAnewarray(javaLangObject); // anewarray Object 630*f1fbf3c2SXin Li for (int i = 0; i < n; ++i) { 631*f1fbf3c2SXin Li code.addOpcode(Bytecode.DUP); // dup 632*f1fbf3c2SXin Li code.addIconst(i); // iconst_<i> 633*f1fbf3c2SXin Li if (params[i].isPrimitive()) { 634*f1fbf3c2SXin Li CtPrimitiveType pt = (CtPrimitiveType)params[i]; 635*f1fbf3c2SXin Li String wrapper = pt.getWrapperName(); 636*f1fbf3c2SXin Li code.addNew(wrapper); // new <wrapper> 637*f1fbf3c2SXin Li code.addOpcode(Bytecode.DUP); // dup 638*f1fbf3c2SXin Li int s = code.addLoad(regno, pt); // ?load <regno> 639*f1fbf3c2SXin Li regno += s; 640*f1fbf3c2SXin Li args[0] = pt; 641*f1fbf3c2SXin Li code.addInvokespecial(wrapper, "<init>", 642*f1fbf3c2SXin Li Descriptor.ofMethod(CtClass.voidType, args)); 643*f1fbf3c2SXin Li // invokespecial 644*f1fbf3c2SXin Li } 645*f1fbf3c2SXin Li else { 646*f1fbf3c2SXin Li code.addAload(regno); // aload <regno> 647*f1fbf3c2SXin Li ++regno; 648*f1fbf3c2SXin Li } 649*f1fbf3c2SXin Li 650*f1fbf3c2SXin Li code.addOpcode(Bytecode.AASTORE); // aastore 651*f1fbf3c2SXin Li } 652*f1fbf3c2SXin Li 653*f1fbf3c2SXin Li return 8; 654*f1fbf3c2SXin Li } 655*f1fbf3c2SXin Li compileUnwrapValue(CtClass type, Bytecode code)656*f1fbf3c2SXin Li protected void compileUnwrapValue(CtClass type, Bytecode code) 657*f1fbf3c2SXin Li throws CompileError 658*f1fbf3c2SXin Li { 659*f1fbf3c2SXin Li if (type == CtClass.voidType) { 660*f1fbf3c2SXin Li addNullIfVoid(); 661*f1fbf3c2SXin Li return; 662*f1fbf3c2SXin Li } 663*f1fbf3c2SXin Li 664*f1fbf3c2SXin Li if (exprType == VOID) 665*f1fbf3c2SXin Li throw new CompileError("invalid type for " + returnCastName); 666*f1fbf3c2SXin Li 667*f1fbf3c2SXin Li if (type instanceof CtPrimitiveType) { 668*f1fbf3c2SXin Li CtPrimitiveType pt = (CtPrimitiveType)type; 669*f1fbf3c2SXin Li // pt is not voidType. 670*f1fbf3c2SXin Li String wrapper = pt.getWrapperName(); 671*f1fbf3c2SXin Li code.addCheckcast(wrapper); 672*f1fbf3c2SXin Li code.addInvokevirtual(wrapper, pt.getGetMethodName(), 673*f1fbf3c2SXin Li pt.getGetMethodDescriptor()); 674*f1fbf3c2SXin Li setType(type); 675*f1fbf3c2SXin Li } 676*f1fbf3c2SXin Li else { 677*f1fbf3c2SXin Li code.addCheckcast(type); 678*f1fbf3c2SXin Li setType(type); 679*f1fbf3c2SXin Li } 680*f1fbf3c2SXin Li } 681*f1fbf3c2SXin Li 682*f1fbf3c2SXin Li /* Sets exprType, arrayDim, and className; 683*f1fbf3c2SXin Li * If type is void, then this method does nothing. 684*f1fbf3c2SXin Li */ setType(CtClass type)685*f1fbf3c2SXin Li public void setType(CtClass type) throws CompileError { 686*f1fbf3c2SXin Li setType(type, 0); 687*f1fbf3c2SXin Li } 688*f1fbf3c2SXin Li setType(CtClass type, int dim)689*f1fbf3c2SXin Li private void setType(CtClass type, int dim) throws CompileError { 690*f1fbf3c2SXin Li if (type.isPrimitive()) { 691*f1fbf3c2SXin Li CtPrimitiveType pt = (CtPrimitiveType)type; 692*f1fbf3c2SXin Li exprType = MemberResolver.descToType(pt.getDescriptor()); 693*f1fbf3c2SXin Li arrayDim = dim; 694*f1fbf3c2SXin Li className = null; 695*f1fbf3c2SXin Li } 696*f1fbf3c2SXin Li else if (type.isArray()) 697*f1fbf3c2SXin Li try { 698*f1fbf3c2SXin Li setType(type.getComponentType(), dim + 1); 699*f1fbf3c2SXin Li } 700*f1fbf3c2SXin Li catch (NotFoundException e) { 701*f1fbf3c2SXin Li throw new CompileError("undefined type: " + type.getName()); 702*f1fbf3c2SXin Li } 703*f1fbf3c2SXin Li else { 704*f1fbf3c2SXin Li exprType = CLASS; 705*f1fbf3c2SXin Li arrayDim = dim; 706*f1fbf3c2SXin Li className = MemberResolver.javaToJvmName(type.getName()); 707*f1fbf3c2SXin Li } 708*f1fbf3c2SXin Li } 709*f1fbf3c2SXin Li 710*f1fbf3c2SXin Li /* Performs implicit coercion from exprType to type. 711*f1fbf3c2SXin Li */ doNumCast(CtClass type)712*f1fbf3c2SXin Li public void doNumCast(CtClass type) throws CompileError { 713*f1fbf3c2SXin Li if (arrayDim == 0 && !isRefType(exprType)) 714*f1fbf3c2SXin Li if (type instanceof CtPrimitiveType) { 715*f1fbf3c2SXin Li CtPrimitiveType pt = (CtPrimitiveType)type; 716*f1fbf3c2SXin Li atNumCastExpr(exprType, 717*f1fbf3c2SXin Li MemberResolver.descToType(pt.getDescriptor())); 718*f1fbf3c2SXin Li } 719*f1fbf3c2SXin Li else 720*f1fbf3c2SXin Li throw new CompileError("type mismatch"); 721*f1fbf3c2SXin Li } 722*f1fbf3c2SXin Li } 723