001: /* Copyright (C) 2004 - 2007 db4objects Inc. http://www.db4o.com
002:
003: This file is part of the db4o open source object database.
004:
005: db4o is free software; you can redistribute it and/or modify it under
006: the terms of version 2 of the GNU General Public License as published
007: by the Free Software Foundation and as clarified by db4objects' GPL
008: interpretation policy, available at
009: http://www.db4o.com/about/company/legalpolicies/gplinterpretation/
010: Alternatively you can write to db4objects, Inc., 1900 S Norfolk Street,
011: Suite 350, San Mateo, CA 94403, USA.
012:
013: db4o is distributed in the hope that it will be useful, but WITHOUT ANY
014: WARRANTY; without even the implied warranty of MERCHANTABILITY or
015: FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
016: for more details.
017:
018: You should have received a copy of the GNU General Public License along
019: with this program; if not, write to the Free Software Foundation, Inc.,
020: 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
021: package EDU.purdue.cs.bloat.inline;
022:
023: import java.util.*;
024:
025: import EDU.purdue.cs.bloat.editor.*;
026:
027: /**
028: * Used to keep track of the height of the stack. As instructions are visited,
029: * the height of the stack is adjusted accordingly.
030: */
031: public class StackHeightCounter extends InstructionAdapter {
032: public static boolean DEBUG = false;
033:
034: private int height; // Current stack height
035:
036: private HashMap labelHeights; // Maps labels to their heights as Integers
037:
038: private MethodEditor method; // Method whose height we're computing
039:
040: Set tryCatches; // TryCatches active at current instruction
041:
042: private static void db(final String s) {
043: if (StackHeightCounter.DEBUG) {
044: System.out.println(s);
045: }
046: }
047:
048: public StackHeightCounter(final MethodEditor method) {
049: this .method = method;
050: this .height = 0;
051: this .labelHeights = new HashMap();
052: this .tryCatches = new HashSet();
053: }
054:
055: /**
056: * Returns the current height of the stack.
057: */
058: public int height() {
059: return (this .height);
060: }
061:
062: /**
063: * Handles a Label. Special provisions must be made for labels that catch
064: * exceptions.
065: */
066: public void handle(final Label label) {
067: final Integer labelHeight = (Integer) labelHeights.get(label);
068: if (labelHeight != null) {
069: height = labelHeight.intValue();
070: }
071:
072: // If this label begins an exception handler, then start it off
073: // with a new stack with one element (the exception object) on it.
074: final Iterator tryCatches = method.tryCatches().iterator();
075: while (tryCatches.hasNext()) {
076: final TryCatch tc = (TryCatch) tryCatches.next();
077: if (tc.handler().equals(label)) {
078: label.setStartsBlock(true);
079: height = 1;
080: break;
081: }
082:
083: if (tc.start().equals(label)) {
084: // If this block starts a protected region make note of the
085: // TryCatch block
086: this .tryCatches.add(tc);
087: }
088:
089: if (tc.end().equals(label)) {
090: // If this block ends a protected region, remove it from the
091: // tryCatches list
092: this .tryCatches.remove(tc);
093: }
094: }
095: }
096:
097: /**
098: * Handles an instruction. Special provisions must be made to handle jumps,
099: * switches, throws, and returns.
100: */
101: public void handle(final Instruction inst) {
102: inst.visit(this );
103:
104: if (inst.isJump()) {
105: final Label target = (Label) inst.operand();
106: target.setStartsBlock(true);
107: final Integer targetHeight = (Integer) labelHeights
108: .get(target);
109: if (targetHeight != null) {
110: if (targetHeight.intValue() != height) {
111: // Make sure stack heights match
112: StackHeightCounter.db("Stack height mismatch ("
113: + targetHeight.intValue() + " != " + height
114: + ") at " + inst);
115: }
116:
117: } else {
118: labelHeights.put(target, new Integer(height));
119: }
120:
121: } else if (inst.isSwitch()) {
122: // Propagate height to all targets
123: final Switch sw = (Switch) inst.operand();
124: final Label defaultTarget = sw.defaultTarget();
125: defaultTarget.setStartsBlock(true);
126: final Integer dTargetHeight = (Integer) labelHeights
127: .get(defaultTarget);
128: if (dTargetHeight != null) {
129: if (dTargetHeight.intValue() != height) {
130: // Make sure stack heights match
131: StackHeightCounter.db("Stack height mismatch ("
132: + dTargetHeight.intValue() + " != "
133: + height + ") at " + inst);
134: }
135: } else {
136: labelHeights.put(defaultTarget, new Integer(height));
137: }
138:
139: final Label[] targets = sw.targets();
140: for (int t = 0; t < targets.length; t++) {
141: final Label target = targets[t];
142: target.setStartsBlock(true);
143: final Integer targetHeight = (Integer) labelHeights
144: .get(target);
145: if (targetHeight != null) {
146: if (targetHeight.intValue() != height) {
147: // Make sure stack heights match
148: StackHeightCounter.db("Stack height mismatch ("
149: + targetHeight.intValue() + " != "
150: + height + ") at " + inst);
151: }
152: } else {
153: labelHeights.put(target, new Integer(height));
154: }
155: }
156:
157: } else if (inst.isJsr()) {
158: // We have to account for the return address being pushed on the
159: // stack. Let's ignore the fact that someday in the future
160: // subroutines may push stuff on the stack. M'kay?
161: final Label subroutine = (Label) inst.operand();
162: subroutine.setStartsBlock(true);
163: final Integer subHeight = (Integer) labelHeights
164: .get(subroutine);
165: if (subHeight != null) {
166: if (subHeight.intValue() != height + 1) {
167: StackHeightCounter
168: .db("Stack height mismatch at subroutine ("
169: + subHeight.intValue() + " != "
170: + (height + 1) + ") at " + inst);
171: }
172:
173: } else {
174: labelHeights.put(subroutine, new Integer(height + 1));
175: }
176:
177: } else if (inst.isThrow() || inst.isReturn()) {
178: // Clear the stack
179: height = 0;
180: }
181: }
182:
183: /**
184: * Simulates the effect of "backing up" over an instruction.
185: */
186: public void unhandle(final Instruction inst) {
187: // Temporarily negate the stack height, perform the normal handle,
188: // and then negate the stack height again.
189: this .height = -this .height;
190: this .handle(inst);
191: this .height = -this .height;
192: }
193:
194: /**
195: * Returns the set of <tt>TryCatch</tt> objects for the protected region
196: * that the current instruction may be in.
197: */
198: public Set tryCatches() {
199: return (this .tryCatches);
200: }
201:
202: public void visit_ldc(final Instruction inst) {
203: final Object operand = inst.operand();
204:
205: if ((operand instanceof Long) || (operand instanceof Double)) {
206: height += 2;
207:
208: } else {
209: height += 1;
210: }
211: }
212:
213: public void visit_iload(final Instruction inst) {
214: height += 1;
215: }
216:
217: public void visit_lload(final Instruction inst) {
218: height += 2;
219: }
220:
221: public void visit_fload(final Instruction inst) {
222: height += 1;
223: }
224:
225: public void visit_dload(final Instruction inst) {
226: height += 2;
227: }
228:
229: public void visit_aload(final Instruction inst) {
230: height += 1;
231: }
232:
233: public void visit_iaload(final Instruction inst) {
234: height -= 1;
235: }
236:
237: public void visit_laload(final Instruction inst) {
238: height -= 0;
239: }
240:
241: public void visit_faload(final Instruction inst) {
242: height -= 1;
243: }
244:
245: public void visit_daload(final Instruction inst) {
246: height -= 0;
247: }
248:
249: public void visit_aaload(final Instruction inst) {
250: height -= 1;
251: }
252:
253: public void visit_baload(final Instruction inst) {
254: height -= 1;
255: }
256:
257: public void visit_caload(final Instruction inst) {
258: height -= 1;
259: }
260:
261: public void visit_saload(final Instruction inst) {
262: height -= 1;
263: }
264:
265: public void visit_istore(final Instruction inst) {
266: height -= 1;
267: }
268:
269: public void visit_lstore(final Instruction inst) {
270: height -= 2;
271: }
272:
273: public void visit_fstore(final Instruction inst) {
274: height -= 1;
275: }
276:
277: public void visit_dstore(final Instruction inst) {
278: height -= 2;
279: }
280:
281: public void visit_astore(final Instruction inst) {
282: height -= 1;
283: }
284:
285: public void visit_iastore(final Instruction inst) {
286: height -= 3;
287: }
288:
289: public void visit_lastore(final Instruction inst) {
290: height -= 4;
291: }
292:
293: public void visit_fastore(final Instruction inst) {
294: height -= 3;
295: }
296:
297: public void visit_dastore(final Instruction inst) {
298: height -= 4;
299: }
300:
301: public void visit_aastore(final Instruction inst) {
302: height -= 3;
303: }
304:
305: public void visit_bastore(final Instruction inst) {
306: height -= 3;
307: }
308:
309: public void visit_castore(final Instruction inst) {
310: height -= 3;
311: }
312:
313: public void visit_sastore(final Instruction inst) {
314: height -= 3;
315: }
316:
317: public void visit_pop(final Instruction inst) {
318: height -= 1;
319: }
320:
321: public void visit_pop2(final Instruction inst) {
322: height -= 2;
323: }
324:
325: public void visit_dup(final Instruction inst) {
326: height += 1;
327: }
328:
329: public void visit_dup_x1(final Instruction inst) {
330: height += 1;
331: }
332:
333: public void visit_dup_x2(final Instruction inst) {
334: height += 1;
335: }
336:
337: public void visit_dup2(final Instruction inst) {
338: height += 2;
339: }
340:
341: public void visit_dup2_x1(final Instruction inst) {
342: height += 2;
343: }
344:
345: public void visit_dup2_x2(final Instruction inst) {
346: height += 2;
347: }
348:
349: public void visit_iadd(final Instruction inst) {
350: height -= 1;
351: }
352:
353: public void visit_ladd(final Instruction inst) {
354: height -= 2;
355: }
356:
357: public void visit_fadd(final Instruction inst) {
358: height -= 1;
359: }
360:
361: public void visit_dadd(final Instruction inst) {
362: height -= 2;
363: }
364:
365: public void visit_isub(final Instruction inst) {
366: height -= 1;
367: }
368:
369: public void visit_lsub(final Instruction inst) {
370: height -= 2;
371: }
372:
373: public void visit_fsub(final Instruction inst) {
374: height -= 1;
375: }
376:
377: public void visit_dsub(final Instruction inst) {
378: height -= 2;
379: }
380:
381: public void visit_imul(final Instruction inst) {
382: height -= 1;
383: }
384:
385: public void visit_lmul(final Instruction inst) {
386: height -= 2;
387: }
388:
389: public void visit_fmul(final Instruction inst) {
390: height -= 1;
391: }
392:
393: public void visit_dmul(final Instruction inst) {
394: height -= 2;
395: }
396:
397: public void visit_idiv(final Instruction inst) {
398: height -= 1;
399: }
400:
401: public void visit_ldiv(final Instruction inst) {
402: height -= 2;
403: }
404:
405: public void visit_fdiv(final Instruction inst) {
406: height -= 1;
407: }
408:
409: public void visit_ddiv(final Instruction inst) {
410: height -= 2;
411: }
412:
413: public void visit_irem(final Instruction inst) {
414: height -= 1;
415: }
416:
417: public void visit_lrem(final Instruction inst) {
418: height -= 2;
419: }
420:
421: public void visit_frem(final Instruction inst) {
422: height -= 1;
423: }
424:
425: public void visit_drem(final Instruction inst) {
426: height -= 2;
427: }
428:
429: public void visit_ishl(final Instruction inst) {
430: height -= 1;
431: }
432:
433: public void visit_lshl(final Instruction inst) {
434: height -= 1;
435: }
436:
437: public void visit_ishr(final Instruction inst) {
438: height -= 1;
439: }
440:
441: public void visit_lshr(final Instruction inst) {
442: height -= 1;
443: }
444:
445: public void visit_iushr(final Instruction inst) {
446: height -= 1;
447: }
448:
449: public void visit_lushr(final Instruction inst) {
450: // Yes, it's only -1. The long and the int index are popped off
451: // and the shifted value is pushed. Net loss of 1.
452: height -= 1;
453: }
454:
455: public void visit_iand(final Instruction inst) {
456: height -= 1;
457: }
458:
459: public void visit_land(final Instruction inst) {
460: height -= 2;
461: }
462:
463: public void visit_ior(final Instruction inst) {
464: height -= 1;
465: }
466:
467: public void visit_lor(final Instruction inst) {
468: height -= 2;
469: }
470:
471: public void visit_ixor(final Instruction inst) {
472: height -= 1;
473: }
474:
475: public void visit_lxor(final Instruction inst) {
476: height -= 2;
477: }
478:
479: public void visit_i2l(final Instruction inst) {
480: height += 1;
481: }
482:
483: public void visit_i2d(final Instruction inst) {
484: height += 1;
485: }
486:
487: public void visit_l2i(final Instruction inst) {
488: height -= 1;
489: }
490:
491: public void visit_l2f(final Instruction inst) {
492: height -= 1;
493: }
494:
495: public void visit_f2l(final Instruction inst) {
496: height += 1;
497: }
498:
499: public void visit_f2d(final Instruction inst) {
500: height += 1;
501: }
502:
503: public void visit_d2i(final Instruction inst) {
504: height -= 1;
505: }
506:
507: public void visit_d2f(final Instruction inst) {
508: height -= 1;
509: }
510:
511: public void visit_lcmp(final Instruction inst) {
512: height -= 3;
513: }
514:
515: public void visit_fcmpl(final Instruction inst) {
516: height -= 1;
517: }
518:
519: public void visit_fcmpg(final Instruction inst) {
520: height -= 1;
521: }
522:
523: public void visit_dcmpl(final Instruction inst) {
524: height -= 3;
525: }
526:
527: public void visit_dcmpg(final Instruction inst) {
528: height -= 3;
529: }
530:
531: public void visit_ifeq(final Instruction inst) {
532: height -= 1;
533: }
534:
535: public void visit_ifne(final Instruction inst) {
536: height -= 1;
537: }
538:
539: public void visit_iflt(final Instruction inst) {
540: height -= 1;
541: }
542:
543: public void visit_ifge(final Instruction inst) {
544: height -= 1;
545: }
546:
547: public void visit_ifgt(final Instruction inst) {
548: height -= 1;
549: }
550:
551: public void visit_ifle(final Instruction inst) {
552: height -= 1;
553: }
554:
555: public void visit_if_icmpeq(final Instruction inst) {
556: height -= 2;
557: }
558:
559: public void visit_if_icmpne(final Instruction inst) {
560: height -= 2;
561: }
562:
563: public void visit_if_icmplt(final Instruction inst) {
564: height -= 2;
565: }
566:
567: public void visit_if_icmpge(final Instruction inst) {
568: height -= 2;
569: }
570:
571: public void visit_if_icmpgt(final Instruction inst) {
572: height -= 2;
573: }
574:
575: public void visit_if_icmple(final Instruction inst) {
576: height -= 2;
577: }
578:
579: public void visit_if_acmpeq(final Instruction inst) {
580: height -= 2;
581: }
582:
583: public void visit_if_acmpne(final Instruction inst) {
584: height -= 2;
585: }
586:
587: public void visit_jsr(final Instruction inst) {
588: // Even though the jsr instruction itself pushes the return
589: // address onto the stack, we don't want to account for that
590: // here. It is already taken care of in the handle method. This
591: // way the label following the jsr (the return site) will have the
592: // stack height it had before the call. Once again, we do not
593: // account for the possibility of the jsr modifying the height of
594: // the stack.
595: height += 0;
596: }
597:
598: public void visit_switch(final Instruction inst) {
599: height -= 1;
600: }
601:
602: public void visit_ireturn(final Instruction inst) {
603: height = 0;
604: }
605:
606: public void visit_lreturn(final Instruction inst) {
607: height = 0;
608: }
609:
610: public void visit_freturn(final Instruction inst) {
611: height = 0;
612: }
613:
614: public void visit_dreturn(final Instruction inst) {
615: height = 0;
616: }
617:
618: public void visit_areturn(final Instruction inst) {
619: height = 0;
620: }
621:
622: public void visit_return(final Instruction inst) {
623: height = 0;
624: }
625:
626: public void visit_getstatic(final Instruction inst) {
627: final Type type = ((MemberRef) inst.operand()).nameAndType()
628: .type();
629: height += type.stackHeight();
630: }
631:
632: public void visit_putstatic(final Instruction inst) {
633: final Type type = ((MemberRef) inst.operand()).nameAndType()
634: .type();
635: height -= type.stackHeight();
636: }
637:
638: public void visit_putstatic_nowb(final Instruction inst) {
639: final Type type = ((MemberRef) inst.operand()).nameAndType()
640: .type();
641: height -= type.stackHeight();
642: }
643:
644: public void visit_getfield(final Instruction inst) {
645: final Type type = ((MemberRef) inst.operand()).nameAndType()
646: .type();
647: height += type.stackHeight() - 1;
648: }
649:
650: public void visit_putfield(final Instruction inst) {
651: final Type type = ((MemberRef) inst.operand()).nameAndType()
652: .type();
653: height -= type.stackHeight() + 1;
654: }
655:
656: public void visit_putfield_nowb(final Instruction inst) {
657: final Type type = ((MemberRef) inst.operand()).nameAndType()
658: .type();
659: height -= type.stackHeight() + 1;
660: }
661:
662: public void visit_invokevirtual(final Instruction inst) {
663: final MemberRef method = (MemberRef) inst.operand();
664: final Type type = method.nameAndType().type();
665:
666: height += type.returnType().stackHeight() - type.stackHeight()
667: - 1;
668: }
669:
670: public void visit_invokespecial(final Instruction inst) {
671: final MemberRef method = (MemberRef) inst.operand();
672: final Type type = method.nameAndType().type();
673:
674: height += type.returnType().stackHeight() - type.stackHeight()
675: - 1;
676: }
677:
678: public void visit_invokestatic(final Instruction inst) {
679: final MemberRef method = (MemberRef) inst.operand();
680: final Type type = method.nameAndType().type();
681:
682: height += type.returnType().stackHeight() - type.stackHeight();
683: }
684:
685: public void visit_invokeinterface(final Instruction inst) {
686: final MemberRef method = (MemberRef) inst.operand();
687: final Type type = method.nameAndType().type();
688:
689: height += type.returnType().stackHeight() - type.stackHeight()
690: - 1;
691:
692: }
693:
694: public void visit_new(final Instruction inst) {
695: height += 1;
696: }
697:
698: public void visit_monitorenter(final Instruction inst) {
699: height -= 1;
700: }
701:
702: public void visit_monitorexit(final Instruction inst) {
703: height -= 1;
704: }
705:
706: public void visit_multianewarray(final Instruction inst) {
707: final MultiArrayOperand operand = (MultiArrayOperand) inst
708: .operand();
709: final int dim = operand.dimensions();
710:
711: height += 1 - dim;
712: }
713:
714: public void visit_ifnull(final Instruction inst) {
715: height -= 1;
716: }
717:
718: public void visit_ifnonnull(final Instruction inst) {
719: height -= 1;
720: }
721:
722: public void visit_aswizzle(final Instruction inst) {
723: height -= 2;
724: }
725:
726: public void visit_aswrange(final Instruction inst) {
727: height -= 3;
728: }
729:
730: /**
731: * Returns a clone of this <tt>StackHeightCounter</tt>
732: */
733: public Object clone() {
734: final StackHeightCounter clone = new StackHeightCounter(
735: this .method);
736: clone.height = this .height;
737: clone.labelHeights = (HashMap) this.labelHeights.clone();
738: return (clone);
739: }
740: }
|