1/* 2 * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26package sun.tools.asm; 27 28import sun.tools.java.*; 29import java.util.Enumeration; 30import java.io.IOException; 31import java.io.DataOutputStream; 32import java.io.PrintStream; 33import java.util.Vector; 34// JCOV 35import sun.tools.javac.*; 36import java.io.File; 37import java.io.BufferedInputStream; 38import java.io.DataInputStream; 39import java.io.FileInputStream; 40import java.io.FileNotFoundException; 41import java.io.FileOutputStream; 42import java.lang.String; 43// end JCOV 44 45/** 46 * This class is used to assemble the bytecode instructions for a method. 47 * 48 * WARNING: The contents of this source file are not part of any 49 * supported API. Code that depends on them does so at its own risk: 50 * they are subject to change or removal without notice. 51 * 52 * @author Arthur van Hoff 53 */ 54public final 55class Assembler implements Constants { 56 static final int NOTREACHED = 0; 57 static final int REACHED = 1; 58 static final int NEEDED = 2; 59 60 Label first = new Label(); 61 Instruction last = first; 62 int maxdepth; 63 int maxvar; 64 int maxpc; 65 66 /** 67 * Add an instruction 68 */ 69 public void add(Instruction inst) { 70 if (inst != null) { 71 last.next = inst; 72 last = inst; 73 } 74 } 75 public void add(long where, int opc) { 76 add(new Instruction(where, opc, null)); 77 } 78 public void add(long where, int opc, Object obj) { 79 add(new Instruction(where, opc, obj)); 80 } 81// JCOV 82 public void add(long where, int opc, Object obj, boolean flagCondInverted) { 83 add(new Instruction(where, opc, obj, flagCondInverted)); 84 } 85 86 public void add(boolean flagNoCovered, long where, int opc, Object obj) { 87 add(new Instruction(flagNoCovered, where, opc, obj)); 88 } 89 90 public void add(long where, int opc, boolean flagNoCovered) { 91 add(new Instruction(where, opc, flagNoCovered)); 92 } 93 94 static Vector<String> SourceClassList = new Vector<>(); 95 96 static Vector<String> TmpCovTable = new Vector<>(); 97 98 static int[] JcovClassCountArray = new int[CT_LAST_KIND + 1]; 99 100 static String JcovMagicLine = "JCOV-DATA-FILE-VERSION: 2.0"; 101 static String JcovClassLine = "CLASS: "; 102 static String JcovSrcfileLine = "SRCFILE: "; 103 static String JcovTimestampLine = "TIMESTAMP: "; 104 static String JcovDataLine = "DATA: "; 105 static String JcovHeadingLine = "#kind\tcount"; 106 107 static int[] arrayModifiers = 108 {M_PUBLIC, M_PRIVATE, M_PROTECTED, M_ABSTRACT, M_FINAL, M_INTERFACE}; 109 static int[] arrayModifiersOpc = 110 {PUBLIC, PRIVATE, PROTECTED, ABSTRACT, FINAL, INTERFACE}; 111//end JCOV 112 113 /** 114 * Optimize instructions and mark those that can be reached 115 */ 116 void optimize(Environment env, Label lbl) { 117 lbl.pc = REACHED; 118 119 for (Instruction inst = lbl.next ; inst != null ; inst = inst.next) { 120 switch (inst.pc) { 121 case NOTREACHED: 122 inst.optimize(env); 123 inst.pc = REACHED; 124 break; 125 case REACHED: 126 return; 127 case NEEDED: 128 break; 129 } 130 131 switch (inst.opc) { 132 case opc_label: 133 case opc_dead: 134 if (inst.pc == REACHED) { 135 inst.pc = NOTREACHED; 136 } 137 break; 138 139 case opc_ifeq: 140 case opc_ifne: 141 case opc_ifgt: 142 case opc_ifge: 143 case opc_iflt: 144 case opc_ifle: 145 case opc_if_icmpeq: 146 case opc_if_icmpne: 147 case opc_if_icmpgt: 148 case opc_if_icmpge: 149 case opc_if_icmplt: 150 case opc_if_icmple: 151 case opc_if_acmpeq: 152 case opc_if_acmpne: 153 case opc_ifnull: 154 case opc_ifnonnull: 155 optimize(env, (Label)inst.value); 156 break; 157 158 case opc_goto: 159 optimize(env, (Label)inst.value); 160 return; 161 162 case opc_jsr: 163 optimize(env, (Label)inst.value); 164 break; 165 166 case opc_ret: 167 case opc_return: 168 case opc_ireturn: 169 case opc_lreturn: 170 case opc_freturn: 171 case opc_dreturn: 172 case opc_areturn: 173 case opc_athrow: 174 return; 175 176 case opc_tableswitch: 177 case opc_lookupswitch: { 178 SwitchData sw = (SwitchData)inst.value; 179 optimize(env, sw.defaultLabel); 180 for (Enumeration<Label> e = sw.tab.elements() ; e.hasMoreElements();) { 181 optimize(env, e.nextElement()); 182 } 183 return; 184 } 185 186 case opc_try: { 187 TryData td = (TryData)inst.value; 188 td.getEndLabel().pc = NEEDED; 189 for (Enumeration<CatchData> e = td.catches.elements() ; e.hasMoreElements();) { 190 CatchData cd = e.nextElement(); 191 optimize(env, cd.getLabel()); 192 } 193 break; 194 } 195 } 196 } 197 } 198 199 /** 200 * Eliminate instructions that are not reached 201 */ 202 boolean eliminate() { 203 boolean change = false; 204 Instruction prev = first; 205 206 for (Instruction inst = first.next ; inst != null ; inst = inst.next) { 207 if (inst.pc != NOTREACHED) { 208 prev.next = inst; 209 prev = inst; 210 inst.pc = NOTREACHED; 211 } else { 212 change = true; 213 } 214 } 215 first.pc = NOTREACHED; 216 prev.next = null; 217 return change; 218 } 219 220 /** 221 * Optimize the byte codes 222 */ 223 public void optimize(Environment env) { 224 //listing(System.out); 225 do { 226 // Figure out which instructions are reached 227 optimize(env, first); 228 229 // Eliminate instructions that are not reached 230 } while (eliminate() && env.opt()); 231 } 232 233 /** 234 * Collect all constants into the constant table 235 */ 236 public void collect(Environment env, MemberDefinition field, ConstantPool tab) { 237 // Collect constants for arguments only 238 // if a local variable table is generated 239 if ((field != null) && env.debug_vars()) { 240 @SuppressWarnings("unchecked") 241 Vector<MemberDefinition> v = field.getArguments(); 242 if (v != null) { 243 for (Enumeration<MemberDefinition> e = v.elements() ; e.hasMoreElements() ;) { 244 MemberDefinition f = e.nextElement(); 245 tab.put(f.getName().toString()); 246 tab.put(f.getType().getTypeSignature()); 247 } 248 } 249 } 250 251 // Collect constants from the instructions 252 for (Instruction inst = first ; inst != null ; inst = inst.next) { 253 inst.collect(tab); 254 } 255 } 256 257 /** 258 * Determine stack size, count local variables 259 */ 260 void balance(Label lbl, int depth) { 261 for (Instruction inst = lbl ; inst != null ; inst = inst.next) { 262 //Environment.debugOutput(inst.toString() + ": " + depth + " => " + 263 // (depth + inst.balance())); 264 depth += inst.balance(); 265 if (depth < 0) { 266 throw new CompilerError("stack under flow: " + inst.toString() + " = " + depth); 267 } 268 if (depth > maxdepth) { 269 maxdepth = depth; 270 } 271 switch (inst.opc) { 272 case opc_label: 273 lbl = (Label)inst; 274 if (inst.pc == REACHED) { 275 if (lbl.depth != depth) { 276 throw new CompilerError("stack depth error " + 277 depth + "/" + lbl.depth + 278 ": " + inst.toString()); 279 } 280 return; 281 } 282 lbl.pc = REACHED; 283 lbl.depth = depth; 284 break; 285 286 case opc_ifeq: 287 case opc_ifne: 288 case opc_ifgt: 289 case opc_ifge: 290 case opc_iflt: 291 case opc_ifle: 292 case opc_if_icmpeq: 293 case opc_if_icmpne: 294 case opc_if_icmpgt: 295 case opc_if_icmpge: 296 case opc_if_icmplt: 297 case opc_if_icmple: 298 case opc_if_acmpeq: 299 case opc_if_acmpne: 300 case opc_ifnull: 301 case opc_ifnonnull: 302 balance((Label)inst.value, depth); 303 break; 304 305 case opc_goto: 306 balance((Label)inst.value, depth); 307 return; 308 309 case opc_jsr: 310 balance((Label)inst.value, depth + 1); 311 break; 312 313 case opc_ret: 314 case opc_return: 315 case opc_ireturn: 316 case opc_lreturn: 317 case opc_freturn: 318 case opc_dreturn: 319 case opc_areturn: 320 case opc_athrow: 321 return; 322 323 case opc_iload: 324 case opc_fload: 325 case opc_aload: 326 case opc_istore: 327 case opc_fstore: 328 case opc_astore: { 329 int v = ((inst.value instanceof Number) 330 ? ((Number)inst.value).intValue() 331 : ((LocalVariable)inst.value).slot) + 1; 332 if (v > maxvar) 333 maxvar = v; 334 break; 335 } 336 337 case opc_lload: 338 case opc_dload: 339 case opc_lstore: 340 case opc_dstore: { 341 int v = ((inst.value instanceof Number) 342 ? ((Number)inst.value).intValue() 343 : ((LocalVariable)inst.value).slot) + 2; 344 if (v > maxvar) 345 maxvar = v; 346 break; 347 } 348 349 case opc_iinc: { 350 int v = ((int[])inst.value)[0] + 1; 351 if (v > maxvar) 352 maxvar = v + 1; 353 break; 354 } 355 356 case opc_tableswitch: 357 case opc_lookupswitch: { 358 SwitchData sw = (SwitchData)inst.value; 359 balance(sw.defaultLabel, depth); 360 for (Enumeration<Label> e = sw.tab.elements() ; e.hasMoreElements();) { 361 balance(e.nextElement(), depth); 362 } 363 return; 364 } 365 366 case opc_try: { 367 TryData td = (TryData)inst.value; 368 for (Enumeration<CatchData> e = td.catches.elements() ; e.hasMoreElements();) { 369 CatchData cd = e.nextElement(); 370 balance(cd.getLabel(), depth + 1); 371 } 372 break; 373 } 374 } 375 } 376 } 377 378 /** 379 * Generate code 380 */ 381 public void write(Environment env, DataOutputStream out, 382 MemberDefinition field, ConstantPool tab) 383 throws IOException { 384 //listing(System.out); 385 386 if ((field != null) && field.getArguments() != null) { 387 int sum = 0; 388 @SuppressWarnings("unchecked") 389 Vector<MemberDefinition> v = field.getArguments(); 390 for (Enumeration<MemberDefinition> e = v.elements(); e.hasMoreElements(); ) { 391 MemberDefinition f = e.nextElement(); 392 sum += f.getType().stackSize(); 393 } 394 maxvar = sum; 395 } 396 397 // Make sure the stack balances. Also calculate maxvar and maxstack 398 try { 399 balance(first, 0); 400 } catch (CompilerError e) { 401 System.out.println("ERROR: " + e); 402 listing(System.out); 403 throw e; 404 } 405 406 // Assign PCs 407 int pc = 0, nexceptions = 0; 408 for (Instruction inst = first ; inst != null ; inst = inst.next) { 409 inst.pc = pc; 410 int sz = inst.size(tab); 411 if (pc<65536 && (pc+sz)>=65536) { 412 env.error(inst.where, "warn.method.too.long"); 413 } 414 pc += sz; 415 416 if (inst.opc == opc_try) { 417 nexceptions += ((TryData)inst.value).catches.size(); 418 } 419 } 420 421 // Write header 422 out.writeShort(maxdepth); 423 out.writeShort(maxvar); 424 out.writeInt(maxpc = pc); 425 426 // Generate code 427 for (Instruction inst = first.next ; inst != null ; inst = inst.next) { 428 inst.write(out, tab); 429 } 430 431 // write exceptions 432 out.writeShort(nexceptions); 433 if (nexceptions > 0) { 434 //listing(System.out); 435 writeExceptions(env, out, tab, first, last); 436 } 437 } 438 439 /** 440 * Write the exceptions table 441 */ 442 void writeExceptions(Environment env, DataOutputStream out, ConstantPool tab, Instruction first, Instruction last) throws IOException { 443 for (Instruction inst = first ; inst != last.next ; inst = inst.next) { 444 if (inst.opc == opc_try) { 445 TryData td = (TryData)inst.value; 446 writeExceptions(env, out, tab, inst.next, td.getEndLabel()); 447 for (Enumeration<CatchData> e = td.catches.elements() ; e.hasMoreElements();) { 448 CatchData cd = e.nextElement(); 449 //System.out.println("EXCEPTION: " + env.getSource() + ", pc=" + inst.pc + ", end=" + td.getEndLabel().pc + ", hdl=" + cd.getLabel().pc + ", tp=" + cd.getType()); 450 out.writeShort(inst.pc); 451 out.writeShort(td.getEndLabel().pc); 452 out.writeShort(cd.getLabel().pc); 453 if (cd.getType() != null) { 454 out.writeShort(tab.index(cd.getType())); 455 } else { 456 out.writeShort(0); 457 } 458 } 459 inst = td.getEndLabel(); 460 } 461 } 462 } 463 464//JCOV 465 /** 466 * Write the coverage table 467 */ 468 public void writeCoverageTable(Environment env, ClassDefinition c, DataOutputStream out, ConstantPool tab, long whereField) throws IOException { 469 Vector<Cover> TableLot = new Vector<>(); /* Coverage table */ 470 boolean begseg = false; 471 boolean begmeth = false; 472 @SuppressWarnings("deprecation") 473 long whereClass = ((SourceClass)c).getWhere(); 474 Vector<Long> whereTry = new Vector<>(); 475 int numberTry = 0; 476 int count = 0; 477 478 for (Instruction inst = first ; inst != null ; inst = inst.next) { 479 long n = (inst.where >> WHEREOFFSETBITS); 480 if (n > 0 && inst.opc != opc_label) { 481 if (!begmeth) { 482 if ( whereClass == inst.where) 483 TableLot.addElement(new Cover(CT_FIKT_METHOD, whereField, inst.pc)); 484 else 485 TableLot.addElement(new Cover(CT_METHOD, whereField, inst.pc)); 486 count++; 487 begmeth = true; 488 } 489 if (!begseg && !inst.flagNoCovered ) { 490 boolean findTry = false; 491 for (Enumeration<Long> e = whereTry.elements(); e.hasMoreElements();) { 492 if (e.nextElement().longValue() == inst.where) { 493 findTry = true; 494 break; 495 } 496 } 497 if (!findTry) { 498 TableLot.addElement(new Cover(CT_BLOCK, inst.where, inst.pc)); 499 count++; 500 begseg = true; 501 } 502 } 503 } 504 switch (inst.opc) { 505 case opc_label: 506 begseg = false; 507 break; 508 case opc_ifeq: 509 case opc_ifne: 510 case opc_ifnull: 511 case opc_ifnonnull: 512 case opc_ifgt: 513 case opc_ifge: 514 case opc_iflt: 515 case opc_ifle: 516 case opc_if_icmpeq: 517 case opc_if_icmpne: 518 case opc_if_icmpgt: 519 case opc_if_icmpge: 520 case opc_if_icmplt: 521 case opc_if_icmple: 522 case opc_if_acmpeq: 523 case opc_if_acmpne: { 524 if ( inst.flagCondInverted ) { 525 TableLot.addElement(new Cover(CT_BRANCH_TRUE, inst.where, inst.pc)); 526 TableLot.addElement(new Cover(CT_BRANCH_FALSE, inst.where, inst.pc)); 527 } else { 528 TableLot.addElement(new Cover(CT_BRANCH_FALSE, inst.where, inst.pc)); 529 TableLot.addElement(new Cover(CT_BRANCH_TRUE, inst.where, inst.pc)); 530 } 531 count += 2; 532 begseg = false; 533 break; 534 } 535 536 case opc_goto: { 537 begseg = false; 538 break; 539 } 540 541 case opc_ret: 542 case opc_return: 543 case opc_ireturn: 544 case opc_lreturn: 545 case opc_freturn: 546 case opc_dreturn: 547 case opc_areturn: 548 case opc_athrow: { 549 break; 550 } 551 552 case opc_try: { 553 whereTry.addElement(Long.valueOf(inst.where)); 554 begseg = false; 555 break; 556 } 557 558 case opc_tableswitch: { 559 SwitchData sw = (SwitchData)inst.value; 560 for (int i = sw.minValue; i <= sw.maxValue; i++) { 561 TableLot.addElement(new Cover(CT_CASE, sw.whereCase(i), inst.pc)); 562 count++; 563 } 564 if (!sw.getDefault()) { 565 TableLot.addElement(new Cover(CT_SWITH_WO_DEF, inst.where, inst.pc)); 566 count++; 567 } else { 568 TableLot.addElement(new Cover(CT_CASE, sw.whereCase("default"), inst.pc)); 569 count++; 570 } 571 begseg = false; 572 break; 573 } 574 case opc_lookupswitch: { 575 SwitchData sw = (SwitchData)inst.value; 576 for (Enumeration<Integer> e = sw.sortedKeys(); e.hasMoreElements() ; ) { 577 Integer v = e.nextElement(); 578 TableLot.addElement(new Cover(CT_CASE, sw.whereCase(v), inst.pc)); 579 count++; 580 } 581 if (!sw.getDefault()) { 582 TableLot.addElement(new Cover(CT_SWITH_WO_DEF, inst.where, inst.pc)); 583 count++; 584 } else { 585 TableLot.addElement(new Cover(CT_CASE, sw.whereCase("default"), inst.pc)); 586 count++; 587 } 588 begseg = false; 589 break; 590 } 591 } 592 } 593 Cover Lot; 594 long ln, pos; 595 596 out.writeShort(count); 597 for (int i = 0; i < count; i++) { 598 Lot = TableLot.elementAt(i); 599 ln = (Lot.Addr >> WHEREOFFSETBITS); 600 pos = (Lot.Addr << (64 - WHEREOFFSETBITS)) >> (64 - WHEREOFFSETBITS); 601 out.writeShort(Lot.NumCommand); 602 out.writeShort(Lot.Type); 603 out.writeInt((int)ln); 604 out.writeInt((int)pos); 605 606 if ( !(Lot.Type == CT_CASE && Lot.Addr == 0) ) { 607 JcovClassCountArray[Lot.Type]++; 608 } 609 } 610 611 } 612 613/* 614 * Increase count of methods for native methods 615 */ 616 617public void addNativeToJcovTab(Environment env, ClassDefinition c) { 618 JcovClassCountArray[CT_METHOD]++; 619} 620 621/* 622 * Create class jcov element 623 */ 624 625private String createClassJcovElement(Environment env, ClassDefinition c) { 626 String SourceClass = (Type.mangleInnerType((c.getClassDeclaration()).getName())).toString(); 627 String ConvSourceClass; 628 String classJcovLine; 629 630 SourceClassList.addElement(SourceClass); 631 ConvSourceClass = SourceClass.replace('.', '/'); 632 classJcovLine = JcovClassLine + ConvSourceClass; 633 634 classJcovLine = classJcovLine + " ["; 635 String blank = ""; 636 637 for (int i = 0; i < arrayModifiers.length; i++ ) { 638 if ((c.getModifiers() & arrayModifiers[i]) != 0) { 639 classJcovLine = classJcovLine + blank + opNames[arrayModifiersOpc[i]]; 640 blank = " "; 641 } 642 } 643 classJcovLine = classJcovLine + "]"; 644 645 return classJcovLine; 646} 647 648/* 649 * generate coverage data 650 */ 651 652public void GenVecJCov(Environment env, ClassDefinition c, long Time) { 653 @SuppressWarnings("deprecation") 654 String SourceFile = ((SourceClass)c).getAbsoluteName(); 655 656 TmpCovTable.addElement(createClassJcovElement(env, c)); 657 TmpCovTable.addElement(JcovSrcfileLine + SourceFile); 658 TmpCovTable.addElement(JcovTimestampLine + Time); 659 TmpCovTable.addElement(JcovDataLine + "A"); // data format 660 TmpCovTable.addElement(JcovHeadingLine); 661 662 for (int i = CT_FIRST_KIND; i <= CT_LAST_KIND; i++) { 663 if (JcovClassCountArray[i] != 0) { 664 TmpCovTable.addElement(new String(i + "\t" + JcovClassCountArray[i])); 665 JcovClassCountArray[i] = 0; 666 } 667 } 668} 669 670 671/* 672 * generate file of coverage data 673 */ 674 675@SuppressWarnings("deprecation") // for JCovd.readLine() calls 676public void GenJCov(Environment env) { 677 678 try { 679 File outFile = env.getcovFile(); 680 if( outFile.exists()) { 681 DataInputStream JCovd = new DataInputStream( 682 new BufferedInputStream( 683 new FileInputStream(outFile))); 684 String CurrLine = null; 685 boolean first = true; 686 String Class; 687 688 CurrLine = JCovd.readLine(); 689 if ((CurrLine != null) && CurrLine.startsWith(JcovMagicLine)) { 690 // this is a good Jcov file 691 692 while((CurrLine = JCovd.readLine()) != null ) { 693 if ( CurrLine.startsWith(JcovClassLine) ) { 694 first = true; 695 for(Enumeration<String> e = SourceClassList.elements(); e.hasMoreElements();) { 696 String clsName = CurrLine.substring(JcovClassLine.length()); 697 int idx = clsName.indexOf(' '); 698 699 if (idx != -1) { 700 clsName = clsName.substring(0, idx); 701 } 702 Class = e.nextElement(); 703 if ( Class.compareTo(clsName) == 0) { 704 first = false; 705 break; 706 } 707 } 708 } 709 if (first) // re-write old class 710 TmpCovTable.addElement(CurrLine); 711 } 712 } 713 JCovd.close(); 714 } 715 PrintStream CovFile = new PrintStream(new DataOutputStream(new FileOutputStream(outFile))); 716 CovFile.println(JcovMagicLine); 717 for(Enumeration<String> e = TmpCovTable.elements(); e.hasMoreElements();) { 718 CovFile.println(e.nextElement()); 719 } 720 CovFile.close(); 721 } 722 catch (FileNotFoundException e) { 723 System.out.println("ERROR: " + e); 724 } 725 catch (IOException e) { 726 System.out.println("ERROR: " + e); 727 } 728} 729// end JCOV 730 731 732 /** 733 * Write the linenumber table 734 */ 735 public void writeLineNumberTable(Environment env, DataOutputStream out, ConstantPool tab) throws IOException { 736 long ln = -1; 737 int count = 0; 738 739 for (Instruction inst = first ; inst != null ; inst = inst.next) { 740 long n = (inst.where >> WHEREOFFSETBITS); 741 if ((n > 0) && (ln != n)) { 742 ln = n; 743 count++; 744 } 745 } 746 747 ln = -1; 748 out.writeShort(count); 749 for (Instruction inst = first ; inst != null ; inst = inst.next) { 750 long n = (inst.where >> WHEREOFFSETBITS); 751 if ((n > 0) && (ln != n)) { 752 ln = n; 753 out.writeShort(inst.pc); 754 out.writeShort((int)ln); 755 //System.out.println("pc = " + inst.pc + ", ln = " + ln); 756 } 757 } 758 } 759 760 /** 761 * Figure out when registers contain a legal value. This is done 762 * using a simple data flow algorithm. This information is later used 763 * to generate the local variable table. 764 */ 765 void flowFields(Environment env, Label lbl, MemberDefinition locals[]) { 766 if (lbl.locals != null) { 767 // Been here before. Erase any conflicts. 768 MemberDefinition f[] = lbl.locals; 769 for (int i = 0 ; i < maxvar ; i++) { 770 if (f[i] != locals[i]) { 771 f[i] = null; 772 } 773 } 774 return; 775 } 776 777 // Remember the set of active registers at this point 778 lbl.locals = new MemberDefinition[maxvar]; 779 System.arraycopy(locals, 0, lbl.locals, 0, maxvar); 780 781 MemberDefinition newlocals[] = new MemberDefinition[maxvar]; 782 System.arraycopy(locals, 0, newlocals, 0, maxvar); 783 locals = newlocals; 784 785 for (Instruction inst = lbl.next ; inst != null ; inst = inst.next) { 786 switch (inst.opc) { 787 case opc_istore: case opc_istore_0: case opc_istore_1: 788 case opc_istore_2: case opc_istore_3: 789 case opc_fstore: case opc_fstore_0: case opc_fstore_1: 790 case opc_fstore_2: case opc_fstore_3: 791 case opc_astore: case opc_astore_0: case opc_astore_1: 792 case opc_astore_2: case opc_astore_3: 793 case opc_lstore: case opc_lstore_0: case opc_lstore_1: 794 case opc_lstore_2: case opc_lstore_3: 795 case opc_dstore: case opc_dstore_0: case opc_dstore_1: 796 case opc_dstore_2: case opc_dstore_3: 797 if (inst.value instanceof LocalVariable) { 798 LocalVariable v = (LocalVariable)inst.value; 799 locals[v.slot] = v.field; 800 } 801 break; 802 803 case opc_label: 804 flowFields(env, (Label)inst, locals); 805 return; 806 807 case opc_ifeq: case opc_ifne: case opc_ifgt: 808 case opc_ifge: case opc_iflt: case opc_ifle: 809 case opc_if_icmpeq: case opc_if_icmpne: case opc_if_icmpgt: 810 case opc_if_icmpge: case opc_if_icmplt: case opc_if_icmple: 811 case opc_if_acmpeq: case opc_if_acmpne: 812 case opc_ifnull: case opc_ifnonnull: 813 case opc_jsr: 814 flowFields(env, (Label)inst.value, locals); 815 break; 816 817 case opc_goto: 818 flowFields(env, (Label)inst.value, locals); 819 return; 820 821 case opc_return: case opc_ireturn: case opc_lreturn: 822 case opc_freturn: case opc_dreturn: case opc_areturn: 823 case opc_athrow: case opc_ret: 824 return; 825 826 case opc_tableswitch: 827 case opc_lookupswitch: { 828 SwitchData sw = (SwitchData)inst.value; 829 flowFields(env, sw.defaultLabel, locals); 830 for (Enumeration<Label> e = sw.tab.elements() ; e.hasMoreElements();) { 831 flowFields(env, e.nextElement(), locals); 832 } 833 return; 834 } 835 836 case opc_try: { 837 Vector<CatchData> catches = ((TryData)inst.value).catches; 838 for (Enumeration<CatchData> e = catches.elements(); e.hasMoreElements();) { 839 CatchData cd = e.nextElement(); 840 flowFields(env, cd.getLabel(), locals); 841 } 842 break; 843 } 844 } 845 } 846 } 847 848 /** 849 * Write the local variable table. The necessary constants have already been 850 * added to the constant table by the collect() method. The flowFields method 851 * is used to determine which variables are alive at each pc. 852 */ 853 public void writeLocalVariableTable(Environment env, MemberDefinition field, DataOutputStream out, ConstantPool tab) throws IOException { 854 MemberDefinition locals[] = new MemberDefinition[maxvar]; 855 int i = 0; 856 857 // Initialize arguments 858 if ((field != null) && (field.getArguments() != null)) { 859 int reg = 0; 860 @SuppressWarnings("unchecked") 861 Vector<MemberDefinition> v = field.getArguments(); 862 for (Enumeration<MemberDefinition> e = v.elements(); e.hasMoreElements(); ) { 863 MemberDefinition f = e.nextElement(); 864 locals[reg] = f; 865 reg += f.getType().stackSize(); 866 } 867 } 868 869 flowFields(env, first, locals); 870 LocalVariableTable lvtab = new LocalVariableTable(); 871 872 // Initialize arguments again 873 for (i = 0; i < maxvar; i++) 874 locals[i] = null; 875 if ((field != null) && (field.getArguments() != null)) { 876 int reg = 0; 877 @SuppressWarnings("unchecked") 878 Vector<MemberDefinition> v = field.getArguments(); 879 for (Enumeration<MemberDefinition> e = v.elements(); e.hasMoreElements(); ) { 880 MemberDefinition f = e.nextElement(); 881 locals[reg] = f; 882 lvtab.define(f, reg, 0, maxpc); 883 reg += f.getType().stackSize(); 884 } 885 } 886 887 int pcs[] = new int[maxvar]; 888 889 for (Instruction inst = first ; inst != null ; inst = inst.next) { 890 switch (inst.opc) { 891 case opc_istore: case opc_istore_0: case opc_istore_1: 892 case opc_istore_2: case opc_istore_3: case opc_fstore: 893 case opc_fstore_0: case opc_fstore_1: case opc_fstore_2: 894 case opc_fstore_3: 895 case opc_astore: case opc_astore_0: case opc_astore_1: 896 case opc_astore_2: case opc_astore_3: 897 case opc_lstore: case opc_lstore_0: case opc_lstore_1: 898 case opc_lstore_2: case opc_lstore_3: 899 case opc_dstore: case opc_dstore_0: case opc_dstore_1: 900 case opc_dstore_2: case opc_dstore_3: 901 if (inst.value instanceof LocalVariable) { 902 LocalVariable v = (LocalVariable)inst.value; 903 int pc = (inst.next != null) ? inst.next.pc : inst.pc; 904 if (locals[v.slot] != null) { 905 lvtab.define(locals[v.slot], v.slot, pcs[v.slot], pc); 906 } 907 pcs[v.slot] = pc; 908 locals[v.slot] = v.field; 909 } 910 break; 911 912 case opc_label: { 913 // flush previous labels 914 for (i = 0 ; i < maxvar ; i++) { 915 if (locals[i] != null) { 916 lvtab.define(locals[i], i, pcs[i], inst.pc); 917 } 918 } 919 // init new labels 920 int pc = inst.pc; 921 MemberDefinition[] labelLocals = ((Label)inst).locals; 922 if (labelLocals == null) { // unreachable code?? 923 for (i = 0; i < maxvar; i++) 924 locals[i] = null; 925 } else { 926 System.arraycopy(labelLocals, 0, locals, 0, maxvar); 927 } 928 for (i = 0 ; i < maxvar ; i++) { 929 pcs[i] = pc; 930 } 931 break; 932 } 933 } 934 } 935 936 // flush remaining labels 937 for (i = 0 ; i < maxvar ; i++) { 938 if (locals[i] != null) { 939 lvtab.define(locals[i], i, pcs[i], maxpc); 940 } 941 } 942 943 // write the local variable table 944 lvtab.write(env, out, tab); 945 } 946 947 /** 948 * Return true if empty 949 */ 950 public boolean empty() { 951 return first == last; 952 } 953 954 /** 955 * Print the byte codes 956 */ 957 public void listing(PrintStream out) { 958 out.println("-- listing --"); 959 for (Instruction inst = first ; inst != null ; inst = inst.next) { 960 out.println(inst.toString()); 961 } 962 } 963} 964