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
26 package sun.tools.asm;
27
28 import sun.tools.java.*;
29 import java.util.Enumeration;
30 import java.io.IOException;
31 import java.io.DataOutputStream;
32 import java.io.PrintStream;
33 import java.util.Vector;
34 // JCOV
35 import sun.tools.javac.*;
36 import java.io.File;
37 import java.io.BufferedInputStream;
38 import java.io.DataInputStream;
39 import java.io.FileInputStream;
40 import java.io.FileNotFoundException;
41 import java.io.FileOutputStream;
42 import 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 */
54 public final
55 class 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 */
add(Instruction inst)69 public void add(Instruction inst) {
70 if (inst != null) {
71 last.next = inst;
72 last = inst;
73 }
74 }
add(long where, int opc)75 public void add(long where, int opc) {
76 add(new Instruction(where, opc, null));
77 }
add(long where, int opc, Object obj)78 public void add(long where, int opc, Object obj) {
79 add(new Instruction(where, opc, obj));
80 }
81 // JCOV
add(long where, int opc, Object obj, boolean flagCondInverted)82 public void add(long where, int opc, Object obj, boolean flagCondInverted) {
83 add(new Instruction(where, opc, obj, flagCondInverted));
84 }
85
add(boolean flagNoCovered, long where, int opc, Object obj)86 public void add(boolean flagNoCovered, long where, int opc, Object obj) {
87 add(new Instruction(flagNoCovered, where, opc, obj));
88 }
89
add(long where, int opc, boolean flagNoCovered)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 */
optimize(Environment env, Label lbl)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 */
eliminate()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 */
optimize(Environment env)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 */
collect(Environment env, MemberDefinition field, ConstantPool tab)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 = (Vector<MemberDefinition>)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 */
balance(Label lbl, int depth)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 */
write(Environment env, DataOutputStream out, MemberDefinition field, ConstantPool tab)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 = (Vector<MemberDefinition>)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 */
writeExceptions(Environment env, DataOutputStream out, ConstantPool tab, Instruction first, Instruction last)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 */
writeCoverageTable(Environment env, ClassDefinition c, DataOutputStream out, ConstantPool tab, long whereField)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(new Integer(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
addNativeToJcovTab(Environment env, ClassDefinition c)617 public void addNativeToJcovTab(Environment env, ClassDefinition c) {
618 JcovClassCountArray[CT_METHOD]++;
619 }
620
621 /*
622 * Create class jcov element
623 */
624
createClassJcovElement(Environment env, ClassDefinition c)625 private 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
GenVecJCov(Environment env, ClassDefinition c, long Time)652 public 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
GenJCov(Environment env)676 public 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 */
writeLineNumberTable(Environment env, DataOutputStream out, ConstantPool tab)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 */
flowFields(Environment env, Label lbl, MemberDefinition locals[])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 */
writeLocalVariableTable(Environment env, MemberDefinition field, DataOutputStream out, ConstantPool tab)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 = (Vector<MemberDefinition>)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 = (Vector<MemberDefinition>)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 */
empty()950 public boolean empty() {
951 return first == last;
952 }
953
954 /**
955 * Print the byte codes
956 */
listing(PrintStream out)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