blob: 15d59ec58198f12b554f480f16e877e927f446f0 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1994-2003 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any 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 SourceClassList = new Vector();
95
96 static Vector 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 e = sw.tab.elements() ; e.hasMoreElements();) {
181 optimize(env, (Label)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 e = td.catches.elements() ; e.hasMoreElements();) {
190 CatchData cd = (CatchData)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 if (field.getArguments() != null) {
241 for (Enumeration e = field.getArguments().elements() ; e.hasMoreElements() ;) {
242 MemberDefinition f = (MemberDefinition)e.nextElement();
243 tab.put(f.getName().toString());
244 tab.put(f.getType().getTypeSignature());
245 }
246 }
247 }
248
249 // Collect constants from the instructions
250 for (Instruction inst = first ; inst != null ; inst = inst.next) {
251 inst.collect(tab);
252 }
253 }
254
255 /**
256 * Determine stack size, count local variables
257 */
258 void balance(Label lbl, int depth) {
259 for (Instruction inst = lbl ; inst != null ; inst = inst.next) {
260 //Environment.debugOutput(inst.toString() + ": " + depth + " => " +
261 // (depth + inst.balance()));
262 depth += inst.balance();
263 if (depth < 0) {
264 throw new CompilerError("stack under flow: " + inst.toString() + " = " + depth);
265 }
266 if (depth > maxdepth) {
267 maxdepth = depth;
268 }
269 switch (inst.opc) {
270 case opc_label:
271 lbl = (Label)inst;
272 if (inst.pc == REACHED) {
273 if (lbl.depth != depth) {
274 throw new CompilerError("stack depth error " +
275 depth + "/" + lbl.depth +
276 ": " + inst.toString());
277 }
278 return;
279 }
280 lbl.pc = REACHED;
281 lbl.depth = depth;
282 break;
283
284 case opc_ifeq:
285 case opc_ifne:
286 case opc_ifgt:
287 case opc_ifge:
288 case opc_iflt:
289 case opc_ifle:
290 case opc_if_icmpeq:
291 case opc_if_icmpne:
292 case opc_if_icmpgt:
293 case opc_if_icmpge:
294 case opc_if_icmplt:
295 case opc_if_icmple:
296 case opc_if_acmpeq:
297 case opc_if_acmpne:
298 case opc_ifnull:
299 case opc_ifnonnull:
300 balance((Label)inst.value, depth);
301 break;
302
303 case opc_goto:
304 balance((Label)inst.value, depth);
305 return;
306
307 case opc_jsr:
308 balance((Label)inst.value, depth + 1);
309 break;
310
311 case opc_ret:
312 case opc_return:
313 case opc_ireturn:
314 case opc_lreturn:
315 case opc_freturn:
316 case opc_dreturn:
317 case opc_areturn:
318 case opc_athrow:
319 return;
320
321 case opc_iload:
322 case opc_fload:
323 case opc_aload:
324 case opc_istore:
325 case opc_fstore:
326 case opc_astore: {
327 int v = ((inst.value instanceof Number)
328 ? ((Number)inst.value).intValue()
329 : ((LocalVariable)inst.value).slot) + 1;
330 if (v > maxvar)
331 maxvar = v;
332 break;
333 }
334
335 case opc_lload:
336 case opc_dload:
337 case opc_lstore:
338 case opc_dstore: {
339 int v = ((inst.value instanceof Number)
340 ? ((Number)inst.value).intValue()
341 : ((LocalVariable)inst.value).slot) + 2;
342 if (v > maxvar)
343 maxvar = v;
344 break;
345 }
346
347 case opc_iinc: {
348 int v = ((int[])inst.value)[0] + 1;
349 if (v > maxvar)
350 maxvar = v + 1;
351 break;
352 }
353
354 case opc_tableswitch:
355 case opc_lookupswitch: {
356 SwitchData sw = (SwitchData)inst.value;
357 balance(sw.defaultLabel, depth);
358 for (Enumeration e = sw.tab.elements() ; e.hasMoreElements();) {
359 balance((Label)e.nextElement(), depth);
360 }
361 return;
362 }
363
364 case opc_try: {
365 TryData td = (TryData)inst.value;
366 for (Enumeration e = td.catches.elements() ; e.hasMoreElements();) {
367 CatchData cd = (CatchData)e.nextElement();
368 balance(cd.getLabel(), depth + 1);
369 }
370 break;
371 }
372 }
373 }
374 }
375
376 /**
377 * Generate code
378 */
379 public void write(Environment env, DataOutputStream out,
380 MemberDefinition field, ConstantPool tab)
381 throws IOException {
382 //listing(System.out);
383
384 if ((field != null) && field.getArguments() != null) {
385 int sum = 0;
386 Vector v = field.getArguments();
387 for (Enumeration e = v.elements(); e.hasMoreElements(); ) {
388 MemberDefinition f = ((MemberDefinition)e.nextElement());
389 sum += f.getType().stackSize();
390 }
391 maxvar = sum;
392 }
393
394 // Make sure the stack balances. Also calculate maxvar and maxstack
395 try {
396 balance(first, 0);
397 } catch (CompilerError e) {
398 System.out.println("ERROR: " + e);
399 listing(System.out);
400 throw e;
401 }
402
403 // Assign PCs
404 int pc = 0, nexceptions = 0;
405 for (Instruction inst = first ; inst != null ; inst = inst.next) {
406 inst.pc = pc;
407 int sz = inst.size(tab);
408 if (pc<65536 && (pc+sz)>=65536) {
409 env.error(inst.where, "warn.method.too.long");
410 }
411 pc += sz;
412
413 if (inst.opc == opc_try) {
414 nexceptions += ((TryData)inst.value).catches.size();
415 }
416 }
417
418 // Write header
419 out.writeShort(maxdepth);
420 out.writeShort(maxvar);
421 out.writeInt(maxpc = pc);
422
423 // Generate code
424 for (Instruction inst = first.next ; inst != null ; inst = inst.next) {
425 inst.write(out, tab);
426 }
427
428 // write exceptions
429 out.writeShort(nexceptions);
430 if (nexceptions > 0) {
431 //listing(System.out);
432 writeExceptions(env, out, tab, first, last);
433 }
434 }
435
436 /**
437 * Write the exceptions table
438 */
439 void writeExceptions(Environment env, DataOutputStream out, ConstantPool tab, Instruction first, Instruction last) throws IOException {
440 for (Instruction inst = first ; inst != last.next ; inst = inst.next) {
441 if (inst.opc == opc_try) {
442 TryData td = (TryData)inst.value;
443 writeExceptions(env, out, tab, inst.next, td.getEndLabel());
444 for (Enumeration e = td.catches.elements() ; e.hasMoreElements();) {
445 CatchData cd = (CatchData)e.nextElement();
446 //System.out.println("EXCEPTION: " + env.getSource() + ", pc=" + inst.pc + ", end=" + td.getEndLabel().pc + ", hdl=" + cd.getLabel().pc + ", tp=" + cd.getType());
447 out.writeShort(inst.pc);
448 out.writeShort(td.getEndLabel().pc);
449 out.writeShort(cd.getLabel().pc);
450 if (cd.getType() != null) {
451 out.writeShort(tab.index(cd.getType()));
452 } else {
453 out.writeShort(0);
454 }
455 }
456 inst = td.getEndLabel();
457 }
458 }
459 }
460
461//JCOV
462 /**
463 * Write the coverage table
464 */
465 public void writeCoverageTable(Environment env, ClassDefinition c, DataOutputStream out, ConstantPool tab, long whereField) throws IOException {
466 Vector TableLot = new Vector(); /* Coverage table */
467 boolean begseg = false;
468 boolean begmeth = false;
469 long whereClass = ((SourceClass)c).getWhere();
470 Vector whereTry = new Vector();
471 int numberTry = 0;
472 int count = 0;
473
474 for (Instruction inst = first ; inst != null ; inst = inst.next) {
475 long n = (inst.where >> WHEREOFFSETBITS);
476 if (n > 0 && inst.opc != opc_label) {
477 if (!begmeth) {
478 if ( whereClass == inst.where)
479 TableLot.addElement(new Cover(CT_FIKT_METHOD, whereField, inst.pc));
480 else
481 TableLot.addElement(new Cover(CT_METHOD, whereField, inst.pc));
482 count++;
483 begmeth = true;
484 }
485 if (!begseg && !inst.flagNoCovered ) {
486 boolean findTry = false;
487 for (Enumeration e = whereTry.elements(); e.hasMoreElements();) {
488 if ( ((Long)(e.nextElement())).longValue() == inst.where) {
489 findTry = true;
490 break;
491 }
492 }
493 if (!findTry) {
494 TableLot.addElement(new Cover(CT_BLOCK, inst.where, inst.pc));
495 count++;
496 begseg = true;
497 }
498 }
499 }
500 switch (inst.opc) {
501 case opc_label:
502 begseg = false;
503 break;
504 case opc_ifeq:
505 case opc_ifne:
506 case opc_ifnull:
507 case opc_ifnonnull:
508 case opc_ifgt:
509 case opc_ifge:
510 case opc_iflt:
511 case opc_ifle:
512 case opc_if_icmpeq:
513 case opc_if_icmpne:
514 case opc_if_icmpgt:
515 case opc_if_icmpge:
516 case opc_if_icmplt:
517 case opc_if_icmple:
518 case opc_if_acmpeq:
519 case opc_if_acmpne: {
520 if ( inst.flagCondInverted ) {
521 TableLot.addElement(new Cover(CT_BRANCH_TRUE, inst.where, inst.pc));
522 TableLot.addElement(new Cover(CT_BRANCH_FALSE, inst.where, inst.pc));
523 } else {
524 TableLot.addElement(new Cover(CT_BRANCH_FALSE, inst.where, inst.pc));
525 TableLot.addElement(new Cover(CT_BRANCH_TRUE, inst.where, inst.pc));
526 }
527 count += 2;
528 begseg = false;
529 break;
530 }
531
532 case opc_goto: {
533 begseg = false;
534 break;
535 }
536
537 case opc_ret:
538 case opc_return:
539 case opc_ireturn:
540 case opc_lreturn:
541 case opc_freturn:
542 case opc_dreturn:
543 case opc_areturn:
544 case opc_athrow: {
545 break;
546 }
547
548 case opc_try: {
549 whereTry.addElement(new Long(inst.where));
550 begseg = false;
551 break;
552 }
553
554 case opc_tableswitch: {
555 SwitchData sw = (SwitchData)inst.value;
556 for (int i = sw.minValue; i <= sw.maxValue; i++) {
557 TableLot.addElement(new Cover(CT_CASE, sw.whereCase(new Integer(i)), inst.pc));
558 count++;
559 }
560 if (!sw.getDefault()) {
561 TableLot.addElement(new Cover(CT_SWITH_WO_DEF, inst.where, inst.pc));
562 count++;
563 } else {
564 TableLot.addElement(new Cover(CT_CASE, sw.whereCase("default"), inst.pc));
565 count++;
566 }
567 begseg = false;
568 break;
569 }
570 case opc_lookupswitch: {
571 SwitchData sw = (SwitchData)inst.value;
572 for (Enumeration e = sw.sortedKeys(); e.hasMoreElements() ; ) {
573 Integer v = (Integer)e.nextElement();
574 TableLot.addElement(new Cover(CT_CASE, sw.whereCase(v), inst.pc));
575 count++;
576 }
577 if (!sw.getDefault()) {
578 TableLot.addElement(new Cover(CT_SWITH_WO_DEF, inst.where, inst.pc));
579 count++;
580 } else {
581 TableLot.addElement(new Cover(CT_CASE, sw.whereCase("default"), inst.pc));
582 count++;
583 }
584 begseg = false;
585 break;
586 }
587 }
588 }
589 Cover Lot;
590 long ln, pos;
591
592 out.writeShort(count);
593 for (int i = 0; i < count; i++) {
594 Lot = (Cover)TableLot.elementAt(i);
595 ln = (Lot.Addr >> WHEREOFFSETBITS);
596 pos = (Lot.Addr << (64 - WHEREOFFSETBITS)) >> (64 - WHEREOFFSETBITS);
597 out.writeShort(Lot.NumCommand);
598 out.writeShort(Lot.Type);
599 out.writeInt((int)ln);
600 out.writeInt((int)pos);
601
602 if ( !(Lot.Type == CT_CASE && Lot.Addr == 0) ) {
603 JcovClassCountArray[Lot.Type]++;
604 }
605 }
606
607 }
608
609/*
610 * Increase count of methods for native methods
611 */
612
613public void addNativeToJcovTab(Environment env, ClassDefinition c) {
614 JcovClassCountArray[CT_METHOD]++;
615}
616
617/*
618 * Create class jcov element
619 */
620
621private String createClassJcovElement(Environment env, ClassDefinition c) {
622 String SourceClass = (Type.mangleInnerType((c.getClassDeclaration()).getName())).toString();
623 String ConvSourceClass;
624 String classJcovLine;
625
626 SourceClassList.addElement(SourceClass);
627 ConvSourceClass = SourceClass.replace('.', '/');
628 classJcovLine = JcovClassLine + ConvSourceClass;
629
630 classJcovLine = classJcovLine + " [";
631 String blank = "";
632
633 for (int i = 0; i < arrayModifiers.length; i++ ) {
634 if ((c.getModifiers() & arrayModifiers[i]) != 0) {
635 classJcovLine = classJcovLine + blank + opNames[arrayModifiersOpc[i]];
636 blank = " ";
637 }
638 }
639 classJcovLine = classJcovLine + "]";
640
641 return classJcovLine;
642}
643
644/*
645 * generate coverage data
646 */
647
648public void GenVecJCov(Environment env, ClassDefinition c, long Time) {
649 String SourceFile = ((SourceClass)c).getAbsoluteName();
650
651 TmpCovTable.addElement(createClassJcovElement(env, c));
652 TmpCovTable.addElement(JcovSrcfileLine + SourceFile);
653 TmpCovTable.addElement(JcovTimestampLine + Time);
654 TmpCovTable.addElement(JcovDataLine + "A"); // data format
655 TmpCovTable.addElement(JcovHeadingLine);
656
657 for (int i = CT_FIRST_KIND; i <= CT_LAST_KIND; i++) {
658 if (JcovClassCountArray[i] != 0) {
659 TmpCovTable.addElement(new String(i + "\t" + JcovClassCountArray[i]));
660 JcovClassCountArray[i] = 0;
661 }
662 }
663}
664
665
666/*
667 * generate file of coverage data
668 */
669
670public void GenJCov(Environment env) {
671
672 try {
673 File outFile = env.getcovFile();
674 if( outFile.exists()) {
675 DataInputStream JCovd = new DataInputStream(
676 new BufferedInputStream(
677 new FileInputStream(outFile)));
678 String CurrLine = null;
679 boolean first = true;
680 String Class;
681
682 CurrLine = JCovd.readLine();
683 if ((CurrLine != null) && CurrLine.startsWith(JcovMagicLine)) {
684 // this is a good Jcov file
685
686 while((CurrLine = JCovd.readLine()) != null ) {
687 if ( CurrLine.startsWith(JcovClassLine) ) {
688 first = true;
689 for(Enumeration e = SourceClassList.elements(); e.hasMoreElements();) {
690 String clsName = CurrLine.substring(JcovClassLine.length());
691 int idx = clsName.indexOf(' ');
692
693 if (idx != -1) {
694 clsName = clsName.substring(0, idx);
695 }
696 Class = (String)e.nextElement();
697 if ( Class.compareTo(clsName) == 0) {
698 first = false;
699 break;
700 }
701 }
702 }
703 if (first) // re-write old class
704 TmpCovTable.addElement(CurrLine);
705 }
706 }
707 JCovd.close();
708 }
709 PrintStream CovFile = new PrintStream(new DataOutputStream(new FileOutputStream(outFile)));
710 CovFile.println(JcovMagicLine);
711 for(Enumeration e = TmpCovTable.elements(); e.hasMoreElements();) {
712 CovFile.println(e.nextElement());
713 }
714 CovFile.close();
715 }
716 catch (FileNotFoundException e) {
717 System.out.println("ERROR: " + e);
718 }
719 catch (IOException e) {
720 System.out.println("ERROR: " + e);
721 }
722}
723// end JCOV
724
725
726 /**
727 * Write the linenumber table
728 */
729 public void writeLineNumberTable(Environment env, DataOutputStream out, ConstantPool tab) throws IOException {
730 long ln = -1;
731 int count = 0;
732
733 for (Instruction inst = first ; inst != null ; inst = inst.next) {
734 long n = (inst.where >> WHEREOFFSETBITS);
735 if ((n > 0) && (ln != n)) {
736 ln = n;
737 count++;
738 }
739 }
740
741 ln = -1;
742 out.writeShort(count);
743 for (Instruction inst = first ; inst != null ; inst = inst.next) {
744 long n = (inst.where >> WHEREOFFSETBITS);
745 if ((n > 0) && (ln != n)) {
746 ln = n;
747 out.writeShort(inst.pc);
748 out.writeShort((int)ln);
749 //System.out.println("pc = " + inst.pc + ", ln = " + ln);
750 }
751 }
752 }
753
754 /**
755 * Figure out when registers contain a legal value. This is done
756 * using a simple data flow algorithm. This information is later used
757 * to generate the local variable table.
758 */
759 void flowFields(Environment env, Label lbl, MemberDefinition locals[]) {
760 if (lbl.locals != null) {
761 // Been here before. Erase any conflicts.
762 MemberDefinition f[] = lbl.locals;
763 for (int i = 0 ; i < maxvar ; i++) {
764 if (f[i] != locals[i]) {
765 f[i] = null;
766 }
767 }
768 return;
769 }
770
771 // Remember the set of active registers at this point
772 lbl.locals = new MemberDefinition[maxvar];
773 System.arraycopy(locals, 0, lbl.locals, 0, maxvar);
774
775 MemberDefinition newlocals[] = new MemberDefinition[maxvar];
776 System.arraycopy(locals, 0, newlocals, 0, maxvar);
777 locals = newlocals;
778
779 for (Instruction inst = lbl.next ; inst != null ; inst = inst.next) {
780 switch (inst.opc) {
781 case opc_istore: case opc_istore_0: case opc_istore_1:
782 case opc_istore_2: case opc_istore_3:
783 case opc_fstore: case opc_fstore_0: case opc_fstore_1:
784 case opc_fstore_2: case opc_fstore_3:
785 case opc_astore: case opc_astore_0: case opc_astore_1:
786 case opc_astore_2: case opc_astore_3:
787 case opc_lstore: case opc_lstore_0: case opc_lstore_1:
788 case opc_lstore_2: case opc_lstore_3:
789 case opc_dstore: case opc_dstore_0: case opc_dstore_1:
790 case opc_dstore_2: case opc_dstore_3:
791 if (inst.value instanceof LocalVariable) {
792 LocalVariable v = (LocalVariable)inst.value;
793 locals[v.slot] = v.field;
794 }
795 break;
796
797 case opc_label:
798 flowFields(env, (Label)inst, locals);
799 return;
800
801 case opc_ifeq: case opc_ifne: case opc_ifgt:
802 case opc_ifge: case opc_iflt: case opc_ifle:
803 case opc_if_icmpeq: case opc_if_icmpne: case opc_if_icmpgt:
804 case opc_if_icmpge: case opc_if_icmplt: case opc_if_icmple:
805 case opc_if_acmpeq: case opc_if_acmpne:
806 case opc_ifnull: case opc_ifnonnull:
807 case opc_jsr:
808 flowFields(env, (Label)inst.value, locals);
809 break;
810
811 case opc_goto:
812 flowFields(env, (Label)inst.value, locals);
813 return;
814
815 case opc_return: case opc_ireturn: case opc_lreturn:
816 case opc_freturn: case opc_dreturn: case opc_areturn:
817 case opc_athrow: case opc_ret:
818 return;
819
820 case opc_tableswitch:
821 case opc_lookupswitch: {
822 SwitchData sw = (SwitchData)inst.value;
823 flowFields(env, sw.defaultLabel, locals);
824 for (Enumeration e = sw.tab.elements() ; e.hasMoreElements();) {
825 flowFields(env, (Label)e.nextElement(), locals);
826 }
827 return;
828 }
829
830 case opc_try: {
831 Vector catches = ((TryData)inst.value).catches;
832 for (Enumeration e = catches.elements(); e.hasMoreElements();) {
833 CatchData cd = (CatchData)e.nextElement();
834 flowFields(env, cd.getLabel(), locals);
835 }
836 break;
837 }
838 }
839 }
840 }
841
842 /**
843 * Write the local variable table. The necessary constants have already been
844 * added to the constant table by the collect() method. The flowFields method
845 * is used to determine which variables are alive at each pc.
846 */
847 public void writeLocalVariableTable(Environment env, MemberDefinition field, DataOutputStream out, ConstantPool tab) throws IOException {
848 MemberDefinition locals[] = new MemberDefinition[maxvar];
849 int i = 0;
850
851 // Initialize arguments
852 if ((field != null) && (field.getArguments() != null)) {
853 int reg = 0;
854 Vector v = field.getArguments();
855 for (Enumeration e = v.elements(); e.hasMoreElements(); ) {
856 MemberDefinition f = ((MemberDefinition)e.nextElement());
857 locals[reg] = f;
858 reg += f.getType().stackSize();
859 }
860 }
861
862 flowFields(env, first, locals);
863 LocalVariableTable lvtab = new LocalVariableTable();
864
865 // Initialize arguments again
866 for (i = 0; i < maxvar; i++)
867 locals[i] = null;
868 if ((field != null) && (field.getArguments() != null)) {
869 int reg = 0;
870 Vector v = field.getArguments();
871 for (Enumeration e = v.elements(); e.hasMoreElements(); ) {
872 MemberDefinition f = ((MemberDefinition)e.nextElement());
873 locals[reg] = f;
874 lvtab.define(f, reg, 0, maxpc);
875 reg += f.getType().stackSize();
876 }
877 }
878
879 int pcs[] = new int[maxvar];
880
881 for (Instruction inst = first ; inst != null ; inst = inst.next) {
882 switch (inst.opc) {
883 case opc_istore: case opc_istore_0: case opc_istore_1:
884 case opc_istore_2: case opc_istore_3: case opc_fstore:
885 case opc_fstore_0: case opc_fstore_1: case opc_fstore_2:
886 case opc_fstore_3:
887 case opc_astore: case opc_astore_0: case opc_astore_1:
888 case opc_astore_2: case opc_astore_3:
889 case opc_lstore: case opc_lstore_0: case opc_lstore_1:
890 case opc_lstore_2: case opc_lstore_3:
891 case opc_dstore: case opc_dstore_0: case opc_dstore_1:
892 case opc_dstore_2: case opc_dstore_3:
893 if (inst.value instanceof LocalVariable) {
894 LocalVariable v = (LocalVariable)inst.value;
895 int pc = (inst.next != null) ? inst.next.pc : inst.pc;
896 if (locals[v.slot] != null) {
897 lvtab.define(locals[v.slot], v.slot, pcs[v.slot], pc);
898 }
899 pcs[v.slot] = pc;
900 locals[v.slot] = v.field;
901 }
902 break;
903
904 case opc_label: {
905 // flush previous labels
906 for (i = 0 ; i < maxvar ; i++) {
907 if (locals[i] != null) {
908 lvtab.define(locals[i], i, pcs[i], inst.pc);
909 }
910 }
911 // init new labels
912 int pc = inst.pc;
913 MemberDefinition[] labelLocals = ((Label)inst).locals;
914 if (labelLocals == null) { // unreachable code??
915 for (i = 0; i < maxvar; i++)
916 locals[i] = null;
917 } else {
918 System.arraycopy(labelLocals, 0, locals, 0, maxvar);
919 }
920 for (i = 0 ; i < maxvar ; i++) {
921 pcs[i] = pc;
922 }
923 break;
924 }
925 }
926 }
927
928 // flush remaining labels
929 for (i = 0 ; i < maxvar ; i++) {
930 if (locals[i] != null) {
931 lvtab.define(locals[i], i, pcs[i], maxpc);
932 }
933 }
934
935 // write the local variable table
936 lvtab.write(env, out, tab);
937 }
938
939 /**
940 * Return true if empty
941 */
942 public boolean empty() {
943 return first == last;
944 }
945
946 /**
947 * Print the byte codes
948 */
949 public void listing(PrintStream out) {
950 out.println("-- listing --");
951 for (Instruction inst = first ; inst != null ; inst = inst.next) {
952 out.println(inst.toString());
953 }
954 }
955}