comparison graal/com.oracle.graal.java/src/com/oracle/graal/java/HIRFrameStateBuilder.java @ 19535:97b35083d49d

Reduce casting in AbstractBytecodeParser. Consolidate asserts in HIRFrameStateBuilder.
author Thomas Wuerthinger <thomas.wuerthinger@oracle.com>
date Sun, 22 Feb 2015 15:19:54 +0100
parents 9525e4d5b385
children 2c3ea61e8b65
comparison
equal deleted inserted replaced
19534:50b19dc35c66 19535:97b35083d49d
1 /* 1 /*
2 * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. 2 * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 * 4 *
5 * This code is free software; you can redistribute it and/or modify it 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 6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. 7 * published by the Free Software Foundation.
29 29
30 import com.oracle.graal.api.code.*; 30 import com.oracle.graal.api.code.*;
31 import com.oracle.graal.api.meta.*; 31 import com.oracle.graal.api.meta.*;
32 import com.oracle.graal.compiler.common.type.*; 32 import com.oracle.graal.compiler.common.type.*;
33 import com.oracle.graal.debug.*; 33 import com.oracle.graal.debug.*;
34 import com.oracle.graal.java.BciBlockMapping.*;
34 import com.oracle.graal.java.GraphBuilderPlugin.ParameterPlugin; 35 import com.oracle.graal.java.GraphBuilderPlugin.ParameterPlugin;
35 import com.oracle.graal.nodeinfo.*; 36 import com.oracle.graal.nodeinfo.*;
36 import com.oracle.graal.nodes.*; 37 import com.oracle.graal.nodes.*;
37 import com.oracle.graal.nodes.calc.*; 38 import com.oracle.graal.nodes.calc.*;
38 import com.oracle.graal.nodes.java.*; 39 import com.oracle.graal.nodes.java.*;
39 import com.oracle.graal.nodes.util.*; 40 import com.oracle.graal.nodes.util.*;
40 41
41 public class HIRFrameStateBuilder extends AbstractFrameStateBuilder<ValueNode, HIRFrameStateBuilder> { 42 public final class HIRFrameStateBuilder {
42 43
43 private static final ValueNode[] EMPTY_ARRAY = new ValueNode[0]; 44 private static final ValueNode[] EMPTY_ARRAY = new ValueNode[0];
44 private static final MonitorIdNode[] EMPTY_MONITOR_ARRAY = new MonitorIdNode[0]; 45 private static final MonitorIdNode[] EMPTY_MONITOR_ARRAY = new MonitorIdNode[0];
46
47 protected final ResolvedJavaMethod method;
48 protected int stackSize;
49 protected final ValueNode[] locals;
50 protected final ValueNode[] stack;
51 protected ValueNode[] lockedObjects;
52
53 /**
54 * Specifies if asserting type checks are enabled.
55 */
56 protected final boolean checkTypes;
57
58 /**
59 * @see BytecodeFrame#rethrowException
60 */
61 protected boolean rethrowException;
45 62
46 private MonitorIdNode[] monitorIds; 63 private MonitorIdNode[] monitorIds;
47 private final StructuredGraph graph; 64 private final StructuredGraph graph;
48 private final Supplier<FrameState> outerFrameStateSupplier; 65 private final Supplier<FrameState> outerFrameStateSupplier;
49 66
52 * 69 *
53 * @param method the method whose frame is simulated 70 * @param method the method whose frame is simulated
54 * @param graph the target graph of Graal nodes created by the builder 71 * @param graph the target graph of Graal nodes created by the builder
55 */ 72 */
56 public HIRFrameStateBuilder(ResolvedJavaMethod method, StructuredGraph graph, boolean checkTypes, Supplier<FrameState> outerFrameStateSupplier) { 73 public HIRFrameStateBuilder(ResolvedJavaMethod method, StructuredGraph graph, boolean checkTypes, Supplier<FrameState> outerFrameStateSupplier) {
57 super(method, checkTypes); 74 this.method = method;
75 this.locals = allocateArray(method.getMaxLocals());
76 this.stack = allocateArray(Math.max(1, method.getMaxStackSize()));
77 this.lockedObjects = allocateArray(0);
78 this.checkTypes = checkTypes;
58 79
59 assert graph != null; 80 assert graph != null;
60 81
61 this.monitorIds = EMPTY_MONITOR_ARRAY; 82 this.monitorIds = EMPTY_MONITOR_ARRAY;
62 this.graph = graph; 83 this.graph = graph;
63 this.outerFrameStateSupplier = outerFrameStateSupplier; 84 this.outerFrameStateSupplier = outerFrameStateSupplier;
64 } 85 }
65 86
66 public final void initializeFromArgumentsArray(ValueNode[] arguments) { 87 public void initializeFromArgumentsArray(ValueNode[] arguments) {
67 88
68 int javaIndex = 0; 89 int javaIndex = 0;
69 int index = 0; 90 int index = 0;
70 if (!method.isStatic()) { 91 if (!method.isStatic()) {
71 // set the receiver 92 // set the receiver
80 javaIndex += arguments[index].getKind().getSlotCount(); 101 javaIndex += arguments[index].getKind().getSlotCount();
81 index++; 102 index++;
82 } 103 }
83 } 104 }
84 105
85 public final void initializeForMethodStart(boolean eagerResolve, ParameterPlugin parameterPlugin) { 106 public void initializeForMethodStart(boolean eagerResolve, ParameterPlugin parameterPlugin) {
86 107
87 int javaIndex = 0; 108 int javaIndex = 0;
88 int index = 0; 109 int index = 0;
89 if (!method.isStatic()) { 110 if (!method.isStatic()) {
90 // add the receiver 111 // add the receiver
126 index++; 147 index++;
127 } 148 }
128 } 149 }
129 150
130 private HIRFrameStateBuilder(HIRFrameStateBuilder other) { 151 private HIRFrameStateBuilder(HIRFrameStateBuilder other) {
131 super(other); 152 this.method = other.method;
153 this.stackSize = other.stackSize;
154 this.locals = other.locals.clone();
155 this.stack = other.stack.clone();
156 this.lockedObjects = other.lockedObjects.length == 0 ? other.lockedObjects : other.lockedObjects.clone();
157 this.rethrowException = other.rethrowException;
158 this.checkTypes = other.checkTypes;
159
160 assert locals.length == method.getMaxLocals();
161 assert stack.length == Math.max(1, method.getMaxStackSize());
162
132 assert other.graph != null; 163 assert other.graph != null;
133 graph = other.graph; 164 graph = other.graph;
134 monitorIds = other.monitorIds.length == 0 ? other.monitorIds : other.monitorIds.clone(); 165 monitorIds = other.monitorIds.length == 0 ? other.monitorIds : other.monitorIds.clone();
135 this.outerFrameStateSupplier = other.outerFrameStateSupplier; 166 this.outerFrameStateSupplier = other.outerFrameStateSupplier;
136 167
137 assert locals.length == method.getMaxLocals(); 168 assert locals.length == method.getMaxLocals();
138 assert stack.length == Math.max(1, method.getMaxStackSize()); 169 assert stack.length == Math.max(1, method.getMaxStackSize());
139 assert lockedObjects.length == monitorIds.length; 170 assert lockedObjects.length == monitorIds.length;
140 } 171 }
141 172
142 @Override 173 private static ValueNode[] allocateArray(int length) {
143 protected ValueNode[] allocateArray(int length) {
144 return length == 0 ? EMPTY_ARRAY : new ValueNode[length]; 174 return length == 0 ? EMPTY_ARRAY : new ValueNode[length];
145 } 175 }
146 176
147 @Override 177 @Override
148 public String toString() { 178 public String toString() {
173 outerFrameState = outerFrameStateSupplier.get(); 203 outerFrameState = outerFrameStateSupplier.get();
174 } 204 }
175 return graph.add(new FrameState(outerFrameState, method, bci, locals, stack, stackSize, lockedObjects, Arrays.asList(monitorIds), rethrowException, false)); 205 return graph.add(new FrameState(outerFrameState, method, bci, locals, stack, stackSize, lockedObjects, Arrays.asList(monitorIds), rethrowException, false));
176 } 206 }
177 207
178 @Override
179 public HIRFrameStateBuilder copy() { 208 public HIRFrameStateBuilder copy() {
180 return new HIRFrameStateBuilder(this); 209 return new HIRFrameStateBuilder(this);
181 } 210 }
182 211
183 @Override
184 public boolean isCompatibleWith(HIRFrameStateBuilder other) { 212 public boolean isCompatibleWith(HIRFrameStateBuilder other) {
185 assert method.equals(other.method) && graph == other.graph && localsSize() == other.localsSize() : "Can only compare frame states of the same method"; 213 assert method.equals(other.method) && graph == other.graph && localsSize() == other.localsSize() : "Can only compare frame states of the same method";
186 assert lockedObjects.length == monitorIds.length && other.lockedObjects.length == other.monitorIds.length : "mismatch between lockedObjects and monitorIds"; 214 assert lockedObjects.length == monitorIds.length && other.lockedObjects.length == other.monitorIds.length : "mismatch between lockedObjects and monitorIds";
187 215
188 if (stackSize() != other.stackSize()) { 216 if (stackSize() != other.stackSize()) {
378 } 406 }
379 407
380 /** 408 /**
381 * @return the current lock depth 409 * @return the current lock depth
382 */ 410 */
383 @Override
384 public int lockDepth() { 411 public int lockDepth() {
385 assert lockedObjects.length == monitorIds.length; 412 assert lockedObjects.length == monitorIds.length;
386 return lockedObjects.length; 413 return lockedObjects.length;
387 } 414 }
388 415
403 return true; 430 return true;
404 } 431 }
405 } 432 }
406 return false; 433 return false;
407 } 434 }
435
436 public void clearNonLiveLocals(BciBlock block, LocalLiveness liveness, boolean liveIn) {
437 /*
438 * (lstadler) if somebody is tempted to remove/disable this clearing code: it's possible to
439 * remove it for normal compilations, but not for OSR compilations - otherwise dead object
440 * slots at the OSR entry aren't cleared. it is also not enough to rely on PiNodes with
441 * Kind.Illegal, because the conflicting branch might not have been parsed.
442 */
443 if (liveness == null) {
444 return;
445 }
446 if (liveIn) {
447 for (int i = 0; i < locals.length; i++) {
448 if (!liveness.localIsLiveIn(block, i)) {
449 locals[i] = null;
450 }
451 }
452 } else {
453 for (int i = 0; i < locals.length; i++) {
454 if (!liveness.localIsLiveOut(block, i)) {
455 locals[i] = null;
456 }
457 }
458 }
459 }
460
461 /**
462 * @see BytecodeFrame#rethrowException
463 */
464 public boolean rethrowException() {
465 return rethrowException;
466 }
467
468 /**
469 * @see BytecodeFrame#rethrowException
470 */
471 public void setRethrowException(boolean b) {
472 rethrowException = b;
473 }
474
475 /**
476 * Returns the size of the local variables.
477 *
478 * @return the size of the local variables
479 */
480 public int localsSize() {
481 return locals.length;
482 }
483
484 /**
485 * Gets the current size (height) of the stack.
486 */
487 public int stackSize() {
488 return stackSize;
489 }
490
491 /**
492 * Gets the value in the local variables at the specified index, without any sanity checking.
493 *
494 * @param i the index into the locals
495 * @return the instruction that produced the value for the specified local
496 */
497 public ValueNode localAt(int i) {
498 return locals[i];
499 }
500
501 /**
502 * Get the value on the stack at the specified stack index.
503 *
504 * @param i the index into the stack, with {@code 0} being the bottom of the stack
505 * @return the instruction at the specified position in the stack
506 */
507 public ValueNode stackAt(int i) {
508 return stack[i];
509 }
510
511 /**
512 * Gets the value in the lock at the specified index, without any sanity checking.
513 *
514 * @param i the index into the lock
515 * @return the instruction that produced the value for the specified lock
516 */
517 public ValueNode lockAt(int i) {
518 return lockedObjects[i];
519 }
520
521 public void storeLock(int i, ValueNode lock) {
522 lockedObjects[i] = lock;
523 }
524
525 /**
526 * Loads the local variable at the specified index, checking that the returned value is non-null
527 * and that two-stack values are properly handled.
528 *
529 * @param i the index of the local variable to load
530 * @return the instruction that produced the specified local
531 */
532 public ValueNode loadLocal(int i) {
533 ValueNode x = locals[i];
534 assert assertLoadLocal(i, x);
535 return x;
536 }
537
538 private boolean assertLoadLocal(int i, ValueNode x) {
539 assert x != null : i;
540 assert !checkTypes || (x.getKind().getSlotCount() == 1 || locals[i + 1] == null);
541 assert !checkTypes || (i == 0 || locals[i - 1] == null || locals[i - 1].getKind().getSlotCount() == 1);
542 return true;
543 }
544
545 /**
546 * Stores a given local variable at the specified index. If the value occupies two slots, then
547 * the next local variable index is also overwritten.
548 *
549 * @param i the index at which to store
550 * @param x the instruction which produces the value for the local
551 */
552 public void storeLocal(int i, ValueNode x) {
553 assert assertStoreLocal(x);
554 locals[i] = x;
555 if (x != null && x.getKind().needsTwoSlots()) {
556 // if this is a double word, then kill i+1
557 locals[i + 1] = null;
558 }
559 if (x != null && i > 0) {
560 ValueNode p = locals[i - 1];
561 if (p != null && p.getKind().needsTwoSlots()) {
562 // if there was a double word at i - 1, then kill it
563 locals[i - 1] = null;
564 }
565 }
566 }
567
568 private boolean assertStoreLocal(ValueNode x) {
569 assert x == null || !checkTypes || (x.getKind() != Kind.Void && x.getKind() != Kind.Illegal) : "unexpected value: " + x;
570 return true;
571 }
572
573 public void storeStack(int i, ValueNode x) {
574 assert assertStoreStack(i, x);
575 stack[i] = x;
576 }
577
578 private boolean assertStoreStack(int i, ValueNode x) {
579 assert x == null || (stack[i] == null || x.getKind() == stack[i].getKind()) : "Method does not handle changes from one-slot to two-slot values or non-alive values";
580 return true;
581 }
582
583 /**
584 * Pushes an instruction onto the stack with the expected type.
585 *
586 * @param kind the type expected for this instruction
587 * @param x the instruction to push onto the stack
588 */
589 public void push(Kind kind, ValueNode x) {
590 assert assertPush(kind, x);
591 xpush(x);
592 if (kind.needsTwoSlots()) {
593 xpush(null);
594 }
595 }
596
597 private boolean assertPush(Kind kind, ValueNode x) {
598 assert !checkTypes || (x.getKind() != Kind.Void && x.getKind() != Kind.Illegal);
599 assert x != null && (!checkTypes || x.getKind() == kind);
600 return true;
601 }
602
603 /**
604 * Pushes a value onto the stack without checking the type.
605 *
606 * @param x the instruction to push onto the stack
607 */
608 public void xpush(ValueNode x) {
609 assert assertXpush(x);
610 stack[stackSize++] = x;
611 }
612
613 private boolean assertXpush(ValueNode x) {
614 assert !checkTypes || (x == null || (x.getKind() != Kind.Void && x.getKind() != Kind.Illegal));
615 return true;
616 }
617
618 /**
619 * Pushes a value onto the stack and checks that it is an int.
620 *
621 * @param x the instruction to push onto the stack
622 */
623 public void ipush(ValueNode x) {
624 assert assertInt(x);
625 xpush(x);
626 }
627
628 /**
629 * Pushes a value onto the stack and checks that it is a float.
630 *
631 * @param x the instruction to push onto the stack
632 */
633 public void fpush(ValueNode x) {
634 assert assertFloat(x);
635 xpush(x);
636 }
637
638 /**
639 * Pushes a value onto the stack and checks that it is an object.
640 *
641 * @param x the instruction to push onto the stack
642 */
643 public void apush(ValueNode x) {
644 assert assertObject(x);
645 xpush(x);
646 }
647
648 /**
649 * Pushes a value onto the stack and checks that it is a long.
650 *
651 * @param x the instruction to push onto the stack
652 */
653 public void lpush(ValueNode x) {
654 assert assertLong(x);
655 xpush(x);
656 xpush(null);
657 }
658
659 /**
660 * Pushes a value onto the stack and checks that it is a double.
661 *
662 * @param x the instruction to push onto the stack
663 */
664 public void dpush(ValueNode x) {
665 assert assertDouble(x);
666 xpush(x);
667 xpush(null);
668 }
669
670 public void pushReturn(Kind kind, ValueNode x) {
671 if (kind != Kind.Void) {
672 push(kind.getStackKind(), x);
673 }
674 }
675
676 /**
677 * Pops an instruction off the stack with the expected type.
678 *
679 * @param kind the expected type
680 * @return the instruction on the top of the stack
681 */
682 public ValueNode pop(Kind kind) {
683 if (kind.needsTwoSlots()) {
684 xpop();
685 }
686 assert assertPop(kind);
687 return xpop();
688 }
689
690 private boolean assertPop(Kind kind) {
691 assert kind != Kind.Void;
692 ValueNode x = xpeek();
693 assert x != null && (!checkTypes || x.getKind() == kind);
694 return true;
695 }
696
697 /**
698 * Pops a value off of the stack without checking the type.
699 *
700 * @return x the instruction popped off the stack
701 */
702 public ValueNode xpop() {
703 return stack[--stackSize];
704 }
705
706 private ValueNode xpeek() {
707 return stack[stackSize - 1];
708 }
709
710 /**
711 * Pops a value off of the stack and checks that it is an int.
712 *
713 * @return x the instruction popped off the stack
714 */
715 public ValueNode ipop() {
716 assert assertIntPeek();
717 return xpop();
718 }
719
720 /**
721 * Pops a value off of the stack and checks that it is a float.
722 *
723 * @return x the instruction popped off the stack
724 */
725 public ValueNode fpop() {
726 assert assertFloatPeek();
727 return xpop();
728 }
729
730 /**
731 * Pops a value off of the stack and checks that it is an object.
732 *
733 * @return x the instruction popped off the stack
734 */
735 public ValueNode apop() {
736 assert assertObjectPeek();
737 return xpop();
738 }
739
740 /**
741 * Pops a value off of the stack and checks that it is a long.
742 *
743 * @return x the instruction popped off the stack
744 */
745 public ValueNode lpop() {
746 assert assertHighPeek();
747 xpop();
748 assert assertLongPeek();
749 return xpop();
750 }
751
752 /**
753 * Pops a value off of the stack and checks that it is a double.
754 *
755 * @return x the instruction popped off the stack
756 */
757 public ValueNode dpop() {
758 assert assertHighPeek();
759 xpop();
760 assert assertDoublePeek();
761 return xpop();
762 }
763
764 /**
765 * Pop the specified number of slots off of this stack and return them as an array of
766 * instructions.
767 *
768 * @return an array containing the arguments off of the stack
769 */
770 public ValueNode[] popArguments(int argSize) {
771 ValueNode[] result = allocateArray(argSize);
772 int newStackSize = stackSize;
773 for (int i = argSize - 1; i >= 0; i--) {
774 newStackSize--;
775 if (stack[newStackSize] == null) {
776 /* Two-slot value. */
777 newStackSize--;
778 assert stack[newStackSize].getKind().needsTwoSlots();
779 } else {
780 assert !checkTypes || (stack[newStackSize].getKind().getSlotCount() == 1);
781 }
782 result[i] = stack[newStackSize];
783 }
784 stackSize = newStackSize;
785 return result;
786 }
787
788 /**
789 * Peeks an element from the operand stack.
790 *
791 * @param argumentNumber The number of the argument, relative from the top of the stack (0 =
792 * top). Long and double arguments only count as one argument, i.e., null-slots are
793 * ignored.
794 * @return The peeked argument.
795 */
796 public ValueNode peek(int argumentNumber) {
797 int idx = stackSize() - 1;
798 for (int i = 0; i < argumentNumber; i++) {
799 if (stackAt(idx) == null) {
800 idx--;
801 assert stackAt(idx).getKind().needsTwoSlots();
802 }
803 idx--;
804 }
805 return stackAt(idx);
806 }
807
808 /**
809 * Clears all values on this stack.
810 */
811 public void clearStack() {
812 stackSize = 0;
813 }
814
815 private boolean assertLongPeek() {
816 return assertLong(xpeek());
817 }
818
819 private static boolean assertLong(ValueNode x) {
820 assert x != null && (x.getKind() == Kind.Long);
821 return true;
822 }
823
824 private boolean assertIntPeek() {
825 return assertInt(xpeek());
826 }
827
828 private static boolean assertInt(ValueNode x) {
829 assert x != null && (x.getKind() == Kind.Int);
830 return true;
831 }
832
833 private boolean assertFloatPeek() {
834 return assertFloat(xpeek());
835 }
836
837 private static boolean assertFloat(ValueNode x) {
838 assert x != null && (x.getKind() == Kind.Float);
839 return true;
840 }
841
842 private boolean assertObjectPeek() {
843 return assertObject(xpeek());
844 }
845
846 private boolean assertObject(ValueNode x) {
847 assert x != null && (!checkTypes || (x.getKind() == Kind.Object));
848 return true;
849 }
850
851 private boolean assertDoublePeek() {
852 return assertDouble(xpeek());
853 }
854
855 private static boolean assertDouble(ValueNode x) {
856 assert x != null && (x.getKind() == Kind.Double);
857 return true;
858 }
859
860 private boolean assertHighPeek() {
861 assert xpeek() == null;
862 return true;
863 }
408 } 864 }