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