1 15 16 package javassist.compiler; 17 18 import javassist.*; 19 import javassist.bytecode.*; 20 import javassist.compiler.ast.*; 21 22 24 25 public class JvstCodeGen extends MemberCodeGen { 26 String paramArrayName = null; 27 String paramListName = null; 28 CtClass[] paramTypeList = null; 29 private int paramVarBase = 0; private boolean useParam0 = false; private String param0Type = null; public static final String sigName = "$sig"; 33 public static final String dollarTypeName = "$type"; 34 public static final String clazzName = "$class"; 35 private CtClass dollarType = null; 36 CtClass returnType = null; 37 String returnCastName = null; 38 private String returnVarName = null; public static final String wrapperCastName = "$w"; 40 String proceedName = null; 41 public static final String cflowName = "$cflow"; 42 ProceedHandler procHandler = null; 44 public JvstCodeGen(Bytecode b, CtClass cc, ClassPool cp) { 45 super(b, cc, cp); 46 setTypeChecker(new JvstTypeChecker(cc, cp, this)); 47 } 48 49 51 private int indexOfParam1() { 52 return paramVarBase + (useParam0 ? 1 : 0); 53 } 54 55 60 public void setProceedHandler(ProceedHandler h, String name) { 61 proceedName = name; 62 procHandler = h; 63 } 64 65 68 public void addNullIfVoid() { 69 if (exprType == VOID) { 70 bytecode.addOpcode(ACONST_NULL); 71 exprType = CLASS; 72 arrayDim = 0; 73 className = jvmJavaLangObject; 74 } 75 } 76 77 80 public void atMember(Member mem) throws CompileError { 81 String name = mem.get(); 82 if (name.equals(paramArrayName)) { 83 compileParameterList(bytecode, paramTypeList, indexOfParam1()); 84 exprType = CLASS; 85 arrayDim = 1; 86 className = jvmJavaLangObject; 87 } 88 else if (name.equals(sigName)) { 89 bytecode.addLdc(Descriptor.ofMethod(returnType, paramTypeList)); 90 bytecode.addInvokestatic("javassist/runtime/Desc", "getParams", 91 "(Ljava/lang/String;)[Ljava/lang/Class;"); 92 exprType = CLASS; 93 arrayDim = 1; 94 className = "java/lang/Class"; 95 } 96 else if (name.equals(dollarTypeName)) { 97 if (dollarType == null) 98 throw new CompileError(dollarType + " is not available"); 99 100 bytecode.addLdc(Descriptor.of(dollarType)); 101 callGetType("getType"); 102 } 103 else if (name.equals(clazzName)) { 104 if (param0Type == null) 105 throw new CompileError(clazzName + " is not available"); 106 107 bytecode.addLdc(param0Type); 108 callGetType("getClazz"); 109 } 110 else 111 super.atMember(mem); 112 } 113 114 private void callGetType(String method) { 115 bytecode.addInvokestatic("javassist/runtime/Desc", method, 116 "(Ljava/lang/String;)Ljava/lang/Class;"); 117 exprType = CLASS; 118 arrayDim = 0; 119 className = "java/lang/Class"; 120 } 121 122 protected void atFieldAssign(Expr expr, int op, ASTree left, 123 ASTree right, boolean doDup) throws CompileError 124 { 125 if (left instanceof Member 126 && ((Member)left).get().equals(paramArrayName)) { 127 if (op != '=') 128 throw new CompileError("bad operator for " + paramArrayName); 129 130 right.accept(this); 131 if (arrayDim != 1 || exprType != CLASS) 132 throw new CompileError("invalid type for " + paramArrayName); 133 134 atAssignParamList(paramTypeList, bytecode); 135 if (!doDup) 136 bytecode.addOpcode(POP); 137 } 138 else 139 super.atFieldAssign(expr, op, left, right, doDup); 140 } 141 142 protected void atAssignParamList(CtClass[] params, Bytecode code) 143 throws CompileError 144 { 145 if (params == null) 146 return; 147 148 int varNo = indexOfParam1(); 149 int n = params.length; 150 for (int i = 0; i < n; ++i) { 151 code.addOpcode(DUP); 152 code.addIconst(i); 153 code.addOpcode(AALOAD); 154 compileUnwrapValue(params[i], code); 155 code.addStore(varNo, params[i]); 156 varNo += is2word(exprType, arrayDim) ? 2 : 1; 157 } 158 } 159 160 public void atCastExpr(CastExpr expr) throws CompileError { 161 ASTList classname = expr.getClassName(); 162 if (classname != null && expr.getArrayDim() == 0) { 163 ASTree p = classname.head(); 164 if (p instanceof Symbol && classname.tail() == null) { 165 String typename = ((Symbol)p).get(); 166 if (typename.equals(returnCastName)) { 167 atCastToRtype(expr); 168 return; 169 } 170 else if (typename.equals(wrapperCastName)) { 171 atCastToWrapper(expr); 172 return; 173 } 174 } 175 } 176 177 super.atCastExpr(expr); 178 } 179 180 184 protected void atCastToRtype(CastExpr expr) throws CompileError { 185 expr.getOprand().accept(this); 186 if (exprType == VOID || isRefType(exprType) || arrayDim > 0) 187 compileUnwrapValue(returnType, bytecode); 188 else if (returnType instanceof CtPrimitiveType) { 189 CtPrimitiveType pt = (CtPrimitiveType)returnType; 190 int destType = MemberResolver.descToType(pt.getDescriptor()); 191 atNumCastExpr(exprType, destType); 192 exprType = destType; 193 arrayDim = 0; 194 className = null; 195 } 196 else 197 throw new CompileError("invalid cast"); 198 } 199 200 protected void atCastToWrapper(CastExpr expr) throws CompileError { 201 expr.getOprand().accept(this); 202 if (isRefType(exprType) || arrayDim > 0) 203 return; 205 CtClass clazz = resolver.lookupClass(exprType, arrayDim, className); 206 if (clazz instanceof CtPrimitiveType) { 207 CtPrimitiveType pt = (CtPrimitiveType)clazz; 208 String wrapper = pt.getWrapperName(); 209 bytecode.addNew(wrapper); bytecode.addOpcode(DUP); if (pt.getDataSize() > 1) 212 bytecode.addOpcode(DUP2_X2); else 214 bytecode.addOpcode(DUP2_X1); 216 bytecode.addOpcode(POP2); bytecode.addInvokespecial(wrapper, "<init>", 218 "(" + pt.getDescriptor() + ")V"); 219 exprType = CLASS; 221 arrayDim = 0; 222 className = jvmJavaLangObject; 223 } 224 } 225 226 229 public void atCallExpr(CallExpr expr) throws CompileError { 230 ASTree method = expr.oprand1(); 231 if (method instanceof Member) { 232 String name = ((Member)method).get(); 233 if (procHandler != null && name.equals(proceedName)) { 234 procHandler.doit(this, bytecode, (ASTList)expr.oprand2()); 235 return; 236 } 237 else if (name.equals(cflowName)) { 238 atCflow((ASTList)expr.oprand2()); 239 return; 240 } 241 } 242 243 super.atCallExpr(expr); 244 } 245 246 248 protected void atCflow(ASTList cname) throws CompileError { 249 StringBuffer sbuf = new StringBuffer (); 250 if (cname == null || cname.tail() != null) 251 throw new CompileError("bad " + cflowName); 252 253 makeCflowName(sbuf, cname.head()); 254 String name = sbuf.toString(); 255 Object [] names = resolver.getClassPool().lookupCflow(name); 256 if (names == null) 257 throw new CompileError("no such a " + cflowName + ": " + name); 258 259 bytecode.addGetstatic((String )names[0], (String )names[1], 260 "Ljavassist/runtime/Cflow;"); 261 bytecode.addInvokevirtual("javassist.runtime.Cflow", 262 "value", "()I"); 263 exprType = INT; 264 arrayDim = 0; 265 className = null; 266 } 267 268 273 private static void makeCflowName(StringBuffer sbuf, ASTree name) 274 throws CompileError 275 { 276 if (name instanceof Symbol) { 277 sbuf.append(((Symbol)name).get()); 278 return; 279 } 280 else if (name instanceof Expr) { 281 Expr expr = (Expr)name; 282 if (expr.getOperator() == '.') { 283 makeCflowName(sbuf, expr.oprand1()); 284 sbuf.append('.'); 285 makeCflowName(sbuf, expr.oprand2()); 286 return; 287 } 288 } 289 290 throw new CompileError("bad " + cflowName); 291 } 292 293 296 public boolean isParamListName(ASTList args) { 297 if (paramTypeList != null 298 && args != null && args.tail() == null) { 299 ASTree left = args.head(); 300 return (left instanceof Member 301 && ((Member)left).get().equals(paramListName)); 302 } 303 else 304 return false; 305 } 306 307 315 316 public int getMethodArgsLength(ASTList args) { 317 String pname = paramListName; 318 int n = 0; 319 while (args != null) { 320 ASTree a = args.head(); 321 if (a instanceof Member && ((Member)a).get().equals(pname)) { 322 if (paramTypeList != null) 323 n += paramTypeList.length; 324 } 325 else 326 ++n; 327 328 args = args.tail(); 329 } 330 331 return n; 332 } 333 334 public void atMethodArgs(ASTList args, int[] types, int[] dims, 335 String [] cnames) throws CompileError { 336 CtClass[] params = paramTypeList; 337 String pname = paramListName; 338 int i = 0; 339 while (args != null) { 340 ASTree a = args.head(); 341 if (a instanceof Member && ((Member)a).get().equals(pname)) { 342 if (params != null) { 343 int n = params.length; 344 int regno = indexOfParam1(); 345 for (int k = 0; k < n; ++k) { 346 CtClass p = params[k]; 347 regno += bytecode.addLoad(regno, p); 348 setType(p); 349 types[i] = exprType; 350 dims[i] = arrayDim; 351 cnames[i] = className; 352 ++i; 353 } 354 } 355 } 356 else { 357 a.accept(this); 358 types[i] = exprType; 359 dims[i] = arrayDim; 360 cnames[i] = className; 361 ++i; 362 } 363 364 args = args.tail(); 365 } 366 } 367 368 392 393 395 void compileInvokeSpecial(ASTree target, String classname, 396 String methodname, String descriptor, 397 ASTList args) 398 throws CompileError 399 { 400 target.accept(this); 401 int nargs = getMethodArgsLength(args); 402 atMethodArgs(args, new int[nargs], new int[nargs], 403 new String [nargs]); 404 bytecode.addInvokespecial(classname, methodname, descriptor); 405 setReturnType(descriptor, false, false); 406 addNullIfVoid(); 407 } 408 409 412 protected void atReturnStmnt(Stmnt st) throws CompileError { 413 ASTree result = st.getLeft(); 414 if (result != null && returnType == CtClass.voidType) { 415 compileExpr(result); 416 if (is2word(exprType, arrayDim)) 417 bytecode.addOpcode(POP2); 418 else if (exprType != VOID) 419 bytecode.addOpcode(POP); 420 421 result = null; 422 } 423 424 atReturnStmnt2(result); 425 } 426 427 437 public int recordReturnType(CtClass type, String castName, 438 String resultName, SymbolTable tbl) throws CompileError 439 { 440 returnType = type; 441 returnCastName = castName; 442 returnVarName = resultName; 443 if (resultName == null) 444 return -1; 445 else { 446 int varNo = getMaxLocals(); 447 int locals = varNo + recordVar(type, resultName, varNo, tbl); 448 setMaxLocals(locals); 449 return varNo; 450 } 451 } 452 453 456 public void recordType(CtClass t) { 457 dollarType = t; 458 } 459 460 465 public int recordParams(CtClass[] params, boolean isStatic, 466 String prefix, String paramVarName, 467 String paramsName, SymbolTable tbl) 468 throws CompileError 469 { 470 return recordParams(params, isStatic, prefix, paramVarName, 471 paramsName, !isStatic, 0, getThisName(), tbl); 472 } 473 474 492 public int recordParams(CtClass[] params, boolean isStatic, 493 String prefix, String paramVarName, 494 String paramsName, boolean use0, 495 int paramBase, String target, 496 SymbolTable tbl) 497 throws CompileError 498 { 499 int varNo; 500 501 paramTypeList = params; 502 paramArrayName = paramVarName; 503 paramListName = paramsName; 504 paramVarBase = paramBase; 505 useParam0 = use0; 506 507 if (target != null) 508 param0Type = MemberResolver.jvmToJavaName(target); 509 510 inStaticMethod = isStatic; 511 varNo = paramBase; 512 if (use0) { 513 String varName = prefix + "0"; 514 Declarator decl 515 = new Declarator(CLASS, MemberResolver.javaToJvmName(target), 516 0, varNo++, new Symbol(varName)); 517 tbl.append(varName, decl); 518 } 519 520 for (int i = 0; i < params.length; ++i) 521 varNo += recordVar(params[i], prefix + (i + 1), varNo, tbl); 522 523 if (getMaxLocals() < varNo) 524 setMaxLocals(varNo); 525 526 return varNo; 527 } 528 529 535 public int recordVariable(CtClass type, String varName, SymbolTable tbl) 536 throws CompileError 537 { 538 if (varName == null) 539 return -1; 540 else { 541 int varNo = getMaxLocals(); 542 int locals = varNo + recordVar(type, varName, varNo, tbl); 543 setMaxLocals(locals); 544 return varNo; 545 } 546 } 547 548 private int recordVar(CtClass cc, String varName, int varNo, 549 SymbolTable tbl) throws CompileError 550 { 551 if (cc == CtClass.voidType) { 552 exprType = CLASS; 553 arrayDim = 0; 554 className = jvmJavaLangObject; 555 } 556 else 557 setType(cc); 558 559 Declarator decl 560 = new Declarator(exprType, className, arrayDim, 561 varNo, new Symbol(varName)); 562 tbl.append(varName, decl); 563 return is2word(exprType, arrayDim) ? 2 : 1; 564 } 565 566 573 public void recordVariable(String typeDesc, String varName, int varNo, 574 SymbolTable tbl) throws CompileError 575 { 576 char c; 577 int dim = 0; 578 while ((c = typeDesc.charAt(dim)) == '[') 579 ++dim; 580 581 int type = MemberResolver.descToType(c); 582 String cname = null; 583 if (type == CLASS) { 584 if (dim == 0) 585 cname = typeDesc.substring(1, typeDesc.length() - 1); 586 else 587 cname = typeDesc.substring(dim + 1, typeDesc.length() - 1); 588 } 589 590 Declarator decl 591 = new Declarator(type, cname, dim, varNo, new Symbol(varName)); 592 tbl.append(varName, decl); 593 } 594 595 604 public static int compileParameterList(Bytecode code, 605 CtClass[] params, int regno) { 606 if (params == null) { 607 code.addIconst(0); code.addAnewarray(javaLangObject); return 1; 610 } 611 else { 612 CtClass[] args = new CtClass[1]; 613 int n = params.length; 614 code.addIconst(n); code.addAnewarray(javaLangObject); for (int i = 0; i < n; ++i) { 617 code.addOpcode(Bytecode.DUP); code.addIconst(i); if (params[i].isPrimitive()) { 620 CtPrimitiveType pt = (CtPrimitiveType)params[i]; 621 String wrapper = pt.getWrapperName(); 622 code.addNew(wrapper); code.addOpcode(Bytecode.DUP); int s = code.addLoad(regno, pt); regno += s; 626 args[0] = pt; 627 code.addInvokespecial(wrapper, "<init>", 628 Descriptor.ofMethod(CtClass.voidType, args)); 629 } 631 else { 632 code.addAload(regno); ++regno; 634 } 635 636 code.addOpcode(Bytecode.AASTORE); } 638 639 return 8; 640 } 641 } 642 643 protected void compileUnwrapValue(CtClass type, Bytecode code) 644 throws CompileError 645 { 646 if (type == CtClass.voidType) { 647 addNullIfVoid(); 648 return; 649 } 650 651 if (exprType == VOID) 652 throw new CompileError("invalid type for " + returnCastName); 653 654 if (type instanceof CtPrimitiveType) { 655 CtPrimitiveType pt = (CtPrimitiveType)type; 656 String wrapper = pt.getWrapperName(); 658 code.addCheckcast(wrapper); 659 code.addInvokevirtual(wrapper, pt.getGetMethodName(), 660 pt.getGetMethodDescriptor()); 661 setType(type); 662 } 663 else { 664 code.addCheckcast(type); 665 setType(type); 666 } 667 } 668 669 672 public void setType(CtClass type) throws CompileError { 673 setType(type, 0); 674 } 675 676 private void setType(CtClass type, int dim) throws CompileError { 677 if (type.isPrimitive()) { 678 CtPrimitiveType pt = (CtPrimitiveType)type; 679 exprType = MemberResolver.descToType(pt.getDescriptor()); 680 arrayDim = dim; 681 className = null; 682 } 683 else if (type.isArray()) 684 try { 685 setType(type.getComponentType(), dim + 1); 686 } 687 catch (NotFoundException e) { 688 throw new CompileError("undefined type: " + type.getName()); 689 } 690 else { 691 exprType = CLASS; 692 arrayDim = dim; 693 className = MemberResolver.javaToJvmName(type.getName()); 694 } 695 } 696 697 699 public void doNumCast(CtClass type) throws CompileError { 700 if (arrayDim == 0 && !isRefType(exprType)) 701 if (type instanceof CtPrimitiveType) { 702 CtPrimitiveType pt = (CtPrimitiveType)type; 703 atNumCastExpr(exprType, 704 MemberResolver.descToType(pt.getDescriptor())); 705 } 706 else 707 throw new CompileError("type mismatch"); 708 } 709 } 710 | Popular Tags |