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.trans;
022:
023: import java.util.*;
024:
025: import EDU.purdue.cs.bloat.editor.*;
026: import EDU.purdue.cs.bloat.util.*;
027:
028: /**
029: * Performs some peephole optimizations such as loads and stores and removes
030: * unreachable instructions.
031: */
032: public class Peephole implements Opcode {
033: public static boolean DEBUG = false;
034:
035: /**
036: * Perform peephole optimizations on the bytecodes in a method. Peephole
037: * optimizations look at two consecutive instructions and try to perform
038: * some simple optimization. For instance, a push followed by a pop is
039: * uninteresting, so both of those instructions can be removed.
040: *
041: * <p>
042: *
043: * After the peephole optimizations are performed a final phase removes
044: * instructions that are not reachable. These instructions reside in basic
045: * blocks whose starting label is never jumped to.
046: */
047: public static void transform(final MethodEditor method) {
048: if (Peephole.DEBUG) {
049: System.out.println("Peephole optimizing " + method);
050: }
051:
052: // Map between labels and the instruction that they label
053: final Map targets = new HashMap();
054:
055: final LinkedList jumps = new LinkedList(); // Jump instructions
056:
057: Instruction next = null;
058: Instruction nextInst = null;
059:
060: final List code = method.code();
061:
062: // Go backwards so we can eliminate redundant loads and stores
063: // in one pass. During the pass collect the locations of labels.
064:
065: CODE: for (int i = code.size() - 1; i >= 0; i--) {
066: final Object ce = code.get(i);
067:
068: if (ce instanceof Label) {
069: if (nextInst != null) {
070: targets.put(ce, nextInst);
071: }
072:
073: next = null;
074:
075: } else if (ce instanceof Instruction) {
076: final Instruction inst = (Instruction) ce;
077:
078: Filter peep = null;
079:
080: // Have we seen a label that starts a block? (i.e. is a target)
081: boolean seenLabel = false;
082:
083: if (inst.isGoto()) {
084: // Look at the instructions following the goto. If an
085: // instruction follows and no label (that starts a block)
086: // has been seen, the instruction is dead and can be
087: // removed. If the target of the goto follows the goto
088: // instruction, the goto is useless and is removed.
089:
090: final Label target = (Label) inst.operand();
091:
092: for (int j = i + 1; j < code.size(); j++) {
093: final Object t = code.get(j);
094:
095: // Replace
096: // goto L
097: // L: inst
098: // with
099: // L: inst
100: //
101: if (t instanceof Label) {
102: if (((Label) t).startsBlock()) {
103: seenLabel = true;
104: }
105:
106: if (target.equals(t)) {
107: code.remove(i);
108: next = null;
109: nextInst = null;
110: continue CODE;
111: }
112:
113: continue;
114: }
115:
116: // Replace
117: // goto L
118: // this is unreachable
119: // M: inst (M is a different label from L!)
120: // with
121: // goto L
122: // M: inst
123: //
124: if (t instanceof Instruction) {
125: if (seenLabel) {
126: break;
127: }
128:
129: code.remove(j);
130: j--;
131: }
132: }
133: }
134:
135: if (inst.isGoto() || inst.isSwitch()) {
136: jumps.add(inst);
137: }
138:
139: // Performs some peephole optimizations using the filter
140: // method that returns an instance of the Filter class. The
141: // filter method looks at two consecutive instructions and
142: // determines whether or not something about them can be
143: // changed. For instance, if a push is followed by a pop,
144: // both instructions are useless and can be eliminated. The
145: // contents of the Filter object represents the effects of the
146: // peephole optimization.
147: if (next != null) {
148: peep = Peephole.filter(inst, next);
149: }
150:
151: if (peep != null) {
152: if (ClassEditor.DEBUG) {
153: if (peep.replace.length == 0) {
154: System.out.println("eliminate "
155: + code.get(i) + "-"
156: + code.get(i + 1));
157:
158: } else {
159: System.out.println("replace " + code.get(i)
160: + "-" + code.get(i + 1));
161: System.out.println(" with");
162: for (int j = 0; j < peep.replace.length; j++) {
163: System.out.println(" "
164: + peep.replace[j]);
165: }
166: }
167: }
168:
169: // Remove old instructions
170: code.remove(i + 1);
171: code.remove(i);
172:
173: // Add new instructions resulting from peephole
174: // optimizations
175: for (int j = peep.replace.length - 1; j >= 0; j--) {
176: code.add(i, peep.replace[j]);
177: }
178:
179: if ((i < code.size())
180: && (code.get(i) instanceof Instruction)) {
181: next = (Instruction) code.get(i);
182:
183: } else {
184: // No more instructions, or next thing is a label
185: next = null;
186: }
187:
188: } else {
189: // Filter didn't find any peephole optimizations, skip to
190: // next pair of instructions.
191: next = inst;
192: }
193:
194: nextInst = next;
195: }
196: }
197:
198: // Replace the target of jumps to gotos with the goto target.
199: // Replace gotos to unconditional jumps with the unconditional jump.
200: while (!jumps.isEmpty()) {
201: final Instruction inst = (Instruction) jumps.removeFirst();
202:
203: Instruction target;
204:
205: if (inst.isGoto()) {
206: target = (Instruction) targets.get(inst.operand());
207:
208: if (target != null) {
209: if (target.isGoto()
210: && !target.operand().equals(inst.operand())) {
211:
212: if (ClassEditor.DEBUG) {
213: System.out.println("replace " + inst);
214: }
215:
216: inst.setOperand(target.operand());
217:
218: if (ClassEditor.DEBUG) {
219: System.out.println(" with " + inst);
220: }
221:
222: jumps.add(inst);
223:
224: } else if (target.isSwitch() || target.isReturn()
225: || target.isThrow()) {
226:
227: if (ClassEditor.DEBUG) {
228: System.out.println("replace " + inst);
229: }
230:
231: inst.setOpcodeClass(target.opcodeClass());
232: inst.setOperand(target.operand());
233:
234: if (ClassEditor.DEBUG) {
235: System.out.println(" with " + inst);
236: }
237: }
238: }
239: }
240: }
241:
242: // Remove unreachable code.
243: Peephole.removeUnreachable(method, code);
244:
245: if (ClassEditor.DEBUG) {
246: System.out
247: .println("END PEEPHOLE---------------------------------");
248: }
249: }
250:
251: /**
252: * Iterate over the code in the method and determine which labels begin
253: * blocks that are reachable. The code in blocks that are not reachable is
254: * removed.
255: */
256: // TODO: Currently, ALL ret targets are marked reachable from a
257: // single ret. Correct this by looking at the local variables.
258: private static void removeUnreachable(final MethodEditor method,
259: final List code) {
260: // Maps Labels to their instruction position
261: final Map labelPos = new HashMap();
262:
263: // Collect all the ret targets.
264: Iterator iter = code.iterator();
265: int i = 0;
266:
267: while (iter.hasNext()) {
268: final Object ce = iter.next();
269:
270: if (ce instanceof Label) {
271: labelPos.put(ce, new Integer(i));
272: }
273:
274: i++;
275: }
276:
277: // Visit the blocks depth-first.
278:
279: // Stack of Labels that begin blocks that have been visited
280: final Set visited = new HashSet();
281:
282: // Stack of Labels that begin blocks that have not been visited
283: final Stack stack = new Stack();
284:
285: Label label; // Current label
286:
287: if (code.size() > 0) {
288: // Start with the label of the first block
289: label = (Label) code.get(0);
290: visited.add(label);
291: stack.push(label);
292: }
293:
294: final Iterator e = method.tryCatches().iterator();
295:
296: while (e.hasNext()) {
297: // All exception handlers are considered to be live
298: final TryCatch tc = (TryCatch) e.next();
299: visited.add(tc.handler());
300: stack.push(tc.handler());
301: }
302:
303: while (!stack.isEmpty()) {
304: label = (Label) stack.pop();
305:
306: final Integer labelIndex = (Integer) labelPos.get(label);
307: Assert.isTrue(labelIndex != null, "Index of " + label
308: + " not found");
309:
310: i = labelIndex.intValue();
311: final ListIterator blockIter = code.listIterator(i + 1);
312:
313: while (blockIter.hasNext()) {
314: // Iterate over the code in the block. If we encounter
315: // instructions that change execution (i.e. go to another
316: // block), add the Label of the target of the jump to the
317: // stack if it is not already present.
318:
319: final Object ce = blockIter.next();
320: i++;
321:
322: if (ce instanceof Instruction) {
323: final Instruction inst = (Instruction) ce;
324:
325: if (inst.isReturn() || inst.isThrow()) {
326: // We've reached the end of the block, but we don't know
327: // which block will be executed next.
328: break;
329:
330: } else if (inst.isConditionalJump() || inst.isJsr()) {
331: // We've reached the end of the block, add the Label of
332: // the next block to be executed to the list. It's a
333: // conditional jump, so don't break. The rest of the
334: // code
335: // in the block is not necessarily dead.
336:
337: label = (Label) inst.operand();
338:
339: if (!visited.contains(label)) {
340: visited.add(label);
341: stack.push(label);
342: }
343:
344: // Fall through.
345:
346: } else if (inst.isGoto()) {
347: // Add next block to work list.
348:
349: label = (Label) inst.operand();
350:
351: if (!visited.contains(label)) {
352: visited.add(label);
353: stack.push(label);
354: }
355:
356: break;
357:
358: } else if (inst.isRet()) {
359: // The ret targets were handled by the jsr.
360: break;
361:
362: } else if (inst.isSwitch()) {
363: // A switch. Add all possible targets of the switch to
364: // the worklist.
365:
366: final Switch sw = (Switch) inst.operand();
367:
368: label = sw.defaultTarget();
369:
370: if (!visited.contains(label)) {
371: visited.add(label);
372: stack.push(label);
373: }
374:
375: final Label[] targets = sw.targets();
376:
377: for (int j = 0; j < targets.length; j++) {
378: label = targets[j];
379:
380: if (!visited.contains(label)) {
381: visited.add(label);
382: stack.push(label);
383: }
384: }
385:
386: break;
387: }
388:
389: } else if (ce instanceof Label) {
390: label = (Label) ce;
391: visited.add(label);
392: }
393: }
394: }
395:
396: boolean reachable = false;
397:
398: iter = code.iterator();
399:
400: // Remove unreachable instructions
401: while (iter.hasNext()) {
402: final Object ce = iter.next();
403:
404: if (ce instanceof Label) {
405: reachable = visited.contains(ce);
406: // Don't remove unreachable labels, only instructions.
407:
408: } else if (!reachable) {
409: if (ClassEditor.DEBUG) {
410: System.out.println("Removing unreachable " + ce);
411: }
412:
413: iter.remove();
414: }
415: }
416: }
417:
418: /**
419: * Filter represents a set of instructions that result from a peephole
420: * optimizations. For instance, when uninteresting instructions are removed,
421: * a Filter object with an empty "replace" array will be returned by the
422: * below filter method.
423: */
424: static class Filter {
425: Instruction[] replace;
426:
427: Filter() {
428: this .replace = new Instruction[0];
429: }
430:
431: Filter(final Instruction replace) {
432: this .replace = new Instruction[] { replace };
433: }
434:
435: Filter(final Instruction replace1, final Instruction replace2) {
436: this .replace = new Instruction[] { replace1, replace2 };
437: }
438: }
439:
440: /**
441: * Filter a pair of instructions. That is, do a peephole optimization on two
442: * consecutive instructions. For instance, if a push is followed by a pop,
443: * both instructions can be eliminated. The <tt>Filter</tt> object that is
444: * returned specifies what instruction(s), if any, should replace the two
445: * instructions that are the parameters to this method.
446: *
447: * @param first
448: * The first instruction.
449: * @param second
450: * The second instruction.
451: * @return A list of instructions to replace the two instructions with, or
452: * null, if the instructions should be left as is.
453: */
454: private static Filter filter(final Instruction first,
455: final Instruction second) {
456: switch (second.opcodeClass()) {
457:
458: // swap means nothing if it's after a dup.
459: // (goodbye means nothing when it's all for show
460: // so stop pretending you've somewhere else to go.)
461:
462: case opcx_swap:
463: // Elminate swap-swap
464: if (first.opcodeClass() == Opcode.opcx_swap) {
465: return new Filter();
466: }
467: // swap means nothing if it's after a dup.
468: // (goodbye means nothing when it's all for show
469: // so stop pretending you've somewhere else to go.)
470: if (first.opcodeClass() == Opcode.opcx_dup) {
471: return new Filter(first);
472: }
473: break;
474:
475: // Eliminate push-pop.
476: case opcx_pop:
477: // Eliminate push-pop.
478:
479: switch (first.opcodeClass()) {
480: case opcx_ldc:
481: // Make sure things being popped off is not wide (we're
482: // dealing with a pop not a pop2).
483: Assert.isTrue(!(first.operand() instanceof Long)
484: && !(first.operand() instanceof Double),
485: "Cannot pop a 2-word operand");
486: // Fall through.
487:
488: case opcx_iload:
489: case opcx_fload:
490: case opcx_aload:
491: case opcx_dup:
492: // Eliminate the load and the pop.
493: return new Filter();
494:
495: case opcx_dup_x1:
496: // Replace dup_x1-pop with swap
497: // (As if this is really likely to happen ;) <-- Nate made a
498: // joke!
499: return new Filter(new Instruction(Opcode.opcx_swap));
500: }
501: break;
502:
503: case opcx_pop2:
504: switch (first.opcodeClass()) {
505: case opcx_ldc:
506: Assert.isTrue((first.operand() instanceof Long)
507: || (first.operand() instanceof Double),
508: "Cannot pop2 a 1-word operand");
509: // Fall through.
510:
511: case opcx_lload:
512: case opcx_dload:
513: case opcx_dup2:
514: // Eliminate push and pop
515: return new Filter();
516: }
517: break;
518:
519: case opcx_istore:
520: // Eliminate load-store to same location.
521:
522: if (first.opcodeClass() == Opcode.opcx_iload) {
523: if (first.operand().equals(second.operand())) {
524: return new Filter();
525: }
526: }
527: break;
528:
529: case opcx_fstore:
530: if (first.opcodeClass() == Opcode.opcx_fload) {
531: if (first.operand().equals(second.operand())) {
532: return new Filter();
533: }
534: }
535: break;
536:
537: case opcx_astore:
538: if (first.opcodeClass() == Opcode.opcx_aload) {
539: if (first.operand().equals(second.operand())) {
540: return new Filter();
541: }
542: }
543: break;
544:
545: case opcx_lstore:
546: if (first.opcodeClass() == Opcode.opcx_lload) {
547: if (first.operand().equals(second.operand())) {
548: return new Filter();
549: }
550: }
551: break;
552:
553: case opcx_dstore:
554: if (first.opcodeClass() == Opcode.opcx_dload) {
555: if (first.operand().equals(second.operand())) {
556: return new Filter();
557: }
558: }
559: break;
560:
561: case opcx_ireturn:
562: case opcx_freturn:
563: case opcx_areturn:
564: case opcx_lreturn:
565: case opcx_dreturn:
566: // Replace store-return with return. Remember that upon return
567: // all local variables revert to their pre-call values, so any
568: // stores are destroyed.
569:
570: switch (first.opcodeClass()) {
571: case opcx_istore:
572: case opcx_fstore:
573: case opcx_astore:
574: case opcx_lstore:
575: case opcx_dstore:
576: return new Filter(second);
577: }
578: break;
579:
580: case opcx_iadd:
581: // Replace ineg-iadd with isub
582:
583: if (first.opcodeClass() == Opcode.opcx_ineg) {
584: return new Filter(new Instruction(Opcode.opcx_isub));
585: }
586: break;
587:
588: case opcx_isub:
589: // Replace ineg-isub with iadd
590:
591: if (first.opcodeClass() == Opcode.opcx_ineg) {
592: return new Filter(new Instruction(Opcode.opcx_iadd));
593: }
594: break;
595:
596: case opcx_ladd:
597: // Replace lneg-ladd with lsub
598:
599: if (first.opcodeClass() == Opcode.opcx_lneg) {
600: return new Filter(new Instruction(Opcode.opcx_lsub));
601: }
602: break;
603:
604: case opcx_lsub:
605: // Replace lneg-lsub with ladd
606:
607: if (first.opcodeClass() == Opcode.opcx_lneg) {
608: return new Filter(new Instruction(Opcode.opcx_ladd));
609: }
610: break;
611:
612: case opcx_if_icmpeq:
613: // Replace ldc 0-if_icmpeq with ifeq
614:
615: if (first.opcodeClass() == Opcode.opcx_ldc) {
616: final Object op = first.operand();
617: if (op instanceof Integer) {
618: if (((Integer) op).intValue() == 0) {
619: return new Filter(new Instruction(
620: Opcode.opcx_ifeq, second.operand()));
621: }
622: }
623: }
624: break;
625:
626: case opcx_if_icmpne:
627: // Replace ldc 0-if_icmpne with ifne
628:
629: if (first.opcodeClass() == Opcode.opcx_ldc) {
630: final Object op = first.operand();
631: if (op instanceof Integer) {
632: if (((Integer) op).intValue() == 0) {
633: return new Filter(new Instruction(
634: Opcode.opcx_ifne, second.operand()));
635: }
636: }
637: }
638: break;
639:
640: case opcx_if_icmplt:
641: // Replace ldc 0-if_icmplt with iflt
642:
643: if (first.opcodeClass() == Opcode.opcx_ldc) {
644: final Object op = first.operand();
645: if (op instanceof Integer) {
646: if (((Integer) op).intValue() == 0) {
647: return new Filter(new Instruction(
648: Opcode.opcx_iflt, second.operand()));
649: }
650: }
651: }
652: break;
653:
654: case opcx_if_icmpge:
655: // Replace ldc 0-if_icmpge with ifge
656:
657: if (first.opcodeClass() == Opcode.opcx_ldc) {
658: final Object op = first.operand();
659: if (op instanceof Integer) {
660: if (((Integer) op).intValue() == 0) {
661: return new Filter(new Instruction(
662: Opcode.opcx_ifge, second.operand()));
663: }
664: }
665: }
666: break;
667:
668: case opcx_if_icmpgt:
669: // Replace ldc 0-if_icmpgt with ifgt
670:
671: if (first.opcodeClass() == Opcode.opcx_ldc) {
672: final Object op = first.operand();
673: if (op instanceof Integer) {
674: if (((Integer) op).intValue() == 0) {
675: return new Filter(new Instruction(
676: Opcode.opcx_ifgt, second.operand()));
677: }
678: }
679: }
680: break;
681:
682: case opcx_if_icmple:
683: // Replace ldc 0-if_icmple with ifle
684:
685: if (first.opcodeClass() == Opcode.opcx_ldc) {
686: final Object op = first.operand();
687: if (op instanceof Integer) {
688: if (((Integer) op).intValue() == 0) {
689: return new Filter(new Instruction(
690: Opcode.opcx_ifle, second.operand()));
691: }
692: }
693: }
694: break;
695:
696: case opcx_if_acmpeq:
697: // Replace ldc null-if_acmpeq with ifnull
698:
699: if (first.opcodeClass() == Opcode.opcx_ldc) {
700: if (first.operand() == null) {
701: return new Filter(new Instruction(
702: Opcode.opcx_ifnull, second.operand()));
703: }
704: }
705: break;
706:
707: case opcx_if_acmpne:
708: // Replace ldc null-if_acmpne with ifnonnull
709:
710: if (first.opcodeClass() == Opcode.opcx_ldc) {
711: if (first.operand() == null) {
712: return new Filter(new Instruction(
713: Opcode.opcx_ifnonnull, second.operand()));
714: }
715: }
716: break;
717:
718: case opcx_ifeq:
719: // Replace ldc 0-ifeq with goto and eliminate ldc !0-ifeq
720:
721: if (first.opcodeClass() == Opcode.opcx_ldc) {
722: final Object op = first.operand();
723: if (op instanceof Integer) {
724: if (((Integer) op).intValue() == 0) {
725: return new Filter(new Instruction(
726: Opcode.opcx_goto, second.operand()));
727: } else {
728: return new Filter();
729: }
730: }
731: }
732: break;
733:
734: case opcx_ifne:
735: // Replace ldc !0-ifne with goto and eliminate ldc 0-ifne
736:
737: if (first.opcodeClass() == Opcode.opcx_ldc) {
738: final Object op = first.operand();
739: if (op instanceof Integer) {
740: if (((Integer) op).intValue() != 0) {
741: return new Filter(new Instruction(
742: Opcode.opcx_goto, second.operand()));
743: } else {
744: return new Filter();
745: }
746: }
747: }
748: break;
749:
750: case opcx_iflt:
751: // Replace ldc <0-iflt with goto and eliminate ldc >=0-iflt
752:
753: if (first.opcodeClass() == Opcode.opcx_ldc) {
754: final Object op = first.operand();
755: if (op instanceof Integer) {
756: if (((Integer) op).intValue() < 0) {
757: return new Filter(new Instruction(
758: Opcode.opcx_goto, second.operand()));
759: } else {
760: return new Filter();
761: }
762: }
763: }
764: break;
765:
766: case opcx_ifge:
767: // Replace ldc >=0-ifge with goto and eliminate ldc <0-ifge
768:
769: if (first.opcodeClass() == Opcode.opcx_ldc) {
770: final Object op = first.operand();
771: if (op instanceof Integer) {
772: if (((Integer) op).intValue() >= 0) {
773: return new Filter(new Instruction(
774: Opcode.opcx_goto, second.operand()));
775: } else {
776: return new Filter();
777: }
778: }
779: }
780: break;
781:
782: case opcx_ifgt:
783: // Replace ldc >0-ifgt with goto and eliminate ldc <=0-ifgt
784:
785: if (first.opcodeClass() == Opcode.opcx_ldc) {
786: final Object op = first.operand();
787: if (op instanceof Integer) {
788: if (((Integer) op).intValue() > 0) {
789: return new Filter(new Instruction(
790: Opcode.opcx_goto, second.operand()));
791: } else {
792: return new Filter();
793: }
794: }
795: }
796: break;
797:
798: case opcx_ifle:
799: // Replace ldc <=0-ifle with goto and eliminate ldc >0-ifle
800:
801: if (first.opcodeClass() == Opcode.opcx_ldc) {
802: final Object op = first.operand();
803: if (op instanceof Integer) {
804: if (((Integer) op).intValue() <= 0) {
805: return new Filter(new Instruction(
806: Opcode.opcx_goto, second.operand()));
807: } else {
808: return new Filter();
809: }
810: }
811: }
812: break;
813: }
814:
815: switch (second.opcodeClass()) {
816: // Replace store-store to same location with pop-store.
817:
818: case opcx_istore:
819: case opcx_fstore:
820: case opcx_astore:
821: case opcx_lstore:
822: case opcx_dstore:
823: switch (first.opcodeClass()) {
824: case opcx_istore:
825: case opcx_fstore:
826: case opcx_astore:
827: if (first.operand().equals(second.operand())) {
828: return new Filter(new Instruction(Opcode.opcx_pop),
829: first);
830: }
831: break;
832: case opcx_lstore:
833: case opcx_dstore:
834: if (first.operand().equals(second.operand())) {
835: return new Filter(
836: new Instruction(Opcode.opcx_pop2), first);
837: }
838: break;
839: }
840: break;
841: }
842:
843: switch (second.opcodeClass()) {
844: // Replace store-load with dup-store.
845: // Replace load-load with load-dup.
846: case opcx_iload:
847: if (first.opcodeClass() == Opcode.opcx_istore) {
848: if (first.operand().equals(second.operand())) {
849: return new Filter(new Instruction(Opcode.opcx_dup),
850: first);
851: }
852: }
853: if (first.opcodeClass() == Opcode.opcx_iload) {
854: if (first.operand().equals(second.operand())) {
855: return new Filter(first, new Instruction(
856: Opcode.opcx_dup));
857: }
858: }
859: break;
860:
861: case opcx_fload:
862: if (first.opcodeClass() == Opcode.opcx_fstore) {
863: if (first.operand().equals(second.operand())) {
864: return new Filter(new Instruction(Opcode.opcx_dup),
865: first);
866: }
867: }
868: if (first.opcodeClass() == Opcode.opcx_fload) {
869: if (first.operand().equals(second.operand())) {
870: return new Filter(first, new Instruction(
871: Opcode.opcx_dup));
872: }
873: }
874: break;
875:
876: case opcx_aload:
877: if (first.opcodeClass() == Opcode.opcx_astore) {
878: if (first.operand().equals(second.operand())) {
879: return new Filter(new Instruction(Opcode.opcx_dup),
880: first);
881: }
882: }
883: if (first.opcodeClass() == Opcode.opcx_aload) {
884: if (first.operand().equals(second.operand())) {
885: return new Filter(first, new Instruction(
886: Opcode.opcx_dup));
887: }
888: }
889: break;
890:
891: case opcx_lload:
892: if (first.opcodeClass() == Opcode.opcx_lstore) {
893: if (first.operand().equals(second.operand())) {
894: return new Filter(
895: new Instruction(Opcode.opcx_dup2), first);
896: }
897: }
898: if (first.opcodeClass() == Opcode.opcx_lload) {
899: if (first.operand().equals(second.operand())) {
900: return new Filter(first, new Instruction(
901: Opcode.opcx_dup2));
902: }
903: }
904: break;
905:
906: case opcx_dload:
907: if (first.opcodeClass() == Opcode.opcx_dstore) {
908: if (first.operand().equals(second.operand())) {
909: return new Filter(
910: new Instruction(Opcode.opcx_dup2), first);
911: }
912: }
913: if (first.opcodeClass() == Opcode.opcx_dload) {
914: if (first.operand().equals(second.operand())) {
915: return new Filter(first, new Instruction(
916: Opcode.opcx_dup2));
917: }
918: }
919: break;
920: }
921:
922: return null;
923: }
924: }
|