comparison doc/design/graal_compiler.tex @ 2682:c5739b99762a

New field store / guard / frame state example.
author Thomas Wuerthinger <thomas@wuerthinger.net>
date Mon, 16 May 2011 17:26:31 +0200
parents 07aa0a31fffb
children c866126a8df3
comparison
equal deleted inserted replaced
2679:07aa0a31fffb 2682:c5739b99762a
199 This is opposite to the approach taken in the server compiler, where control flow and data flow edges point in the same direction. 199 This is opposite to the approach taken in the server compiler, where control flow and data flow edges point in the same direction.
200 The advantage that we see in our approach is that there is no need for projection nodes in case of control flow splits. 200 The advantage that we see in our approach is that there is no need for projection nodes in case of control flow splits.
201 An \texttt{If} instruction can directly point to its true and false successors without any intermediate nodes. 201 An \texttt{If} instruction can directly point to its true and false successors without any intermediate nodes.
202 This makes the graph more compact and simplifies graph traversal. 202 This makes the graph more compact and simplifies graph traversal.
203 203
204 Listing \ref{lst:cfg2} shows an example Java program with an if statement where both paths do not contain any instruction with side effects. 204 Listing~\ref{lst:cfg2} shows an example Java program with an if statement where both paths do not contain any instruction with side effects.
205 The \texttt{If} instruction can directly point its true and false successors to a \texttt{Merge} instruction. 205 The \texttt{If} instruction can directly point its true and false successors to a \texttt{Merge} instruction.
206 A \texttt{Phi} node that selects the appropriate value is appended to the \texttt{Merge} instruction. 206 A \texttt{Phi} node that selects the appropriate value is appended to the \texttt{Merge} instruction.
207 The \texttt{Return} instruction then has a data dependency on the \texttt{Phi} node. 207 The \texttt{Return} instruction then has a data dependency on the \texttt{Phi} node.
208 208
209 \begin{lstlisting}[label=lst:cfg2, caption=Control flow in the graph, captionpos=b] 209 \begin{lstlisting}[label=lst:cfg2, caption=Control flow in the graph., captionpos=b]
210 if (condition) { return 0; } 210 if (condition) { return 0; }
211 else { return 1; } 211 else { return 1; }
212 \end{lstlisting} 212 \end{lstlisting}
213 213
214 \begin{figure}[h] 214 \begin{figure}[h]
246 246
247 There are only two kinds of instruction that need explicit exception edges, because they are the only instructions that can throw exceptions in compiled code: \texttt{Throw} instructions and \texttt{Invoke} instructions. 247 There are only two kinds of instruction that need explicit exception edges, because they are the only instructions that can throw exceptions in compiled code: \texttt{Throw} instructions and \texttt{Invoke} instructions.
248 They are modelled as instructions with an additional control flow continuation that points to an \texttt{ExceptionDispatch} instruction. 248 They are modelled as instructions with an additional control flow continuation that points to an \texttt{ExceptionDispatch} instruction.
249 The exception dispatch instruction decides based on the type of the exception object whether the control should flow to the catch handler or to another exception dispatch. 249 The exception dispatch instruction decides based on the type of the exception object whether the control should flow to the catch handler or to another exception dispatch.
250 If there is no catch handler in the currently compiled method, then the control flows into the \texttt{Unwind} instruction that handles the exception by forwarding it to the caller. 250 If there is no catch handler in the currently compiled method, then the control flows into the \texttt{Unwind} instruction that handles the exception by forwarding it to the caller.
251 Listing \ref{lst:exc1} shows an example Java program with nested try blocks and Figure \ref{fig:exc1} shows the corresponding compiler graph. 251 Listing~\ref{lst:exc1} shows an example Java program with nested try blocks and Figure \ref{fig:exc1} shows the corresponding compiler graph.
252 252
253 \begin{lstlisting}[label=lst:exc1, caption=Exception dispatch in the compiler graph, captionpos=b] 253 \begin{lstlisting}[label=lst:exc1, caption=Exception dispatch in the compiler graph., captionpos=b]
254 try { m1(); 254 try { m1();
255 try { m2(); 255 try { m2();
256 } catch(ExtendedException e) { ... } 256 } catch(ExtendedException e) { ... }
257 m3(); 257 m3();
258 throw exception; 258 throw exception;
324 324
325 \subsection{Loop Phis} 325 \subsection{Loop Phis}
326 Data flow in loops is modelled with special phi nodes at the beginning and the end of the loop. 326 Data flow in loops is modelled with special phi nodes at the beginning and the end of the loop.
327 The \nodename{LoopEnd} instruction merges every value that flows into the next loop iteration in associated \nodename{LoopEndPhi} nodes. 327 The \nodename{LoopEnd} instruction merges every value that flows into the next loop iteration in associated \nodename{LoopEndPhi} nodes.
328 A corresponding \nodename{LoopBeginPhi} node that is associated with the loop header has a control flow dependency on the \nodename{LoopEndPhi} node. 328 A corresponding \nodename{LoopBeginPhi} node that is associated with the loop header has a control flow dependency on the \nodename{LoopEndPhi} node.
329 Listing \ref{lst:loop} shows a simple counting loop that is used as an example in the rest of this section. 329 Listing~\ref{lst:loop} shows a simple counting loop that is used as an example in the rest of this section.
330 Figure \ref{fig:loop2} shows how the loop is modelled immediately after building the graph. 330 Figure~\ref{fig:loop2} shows how the loop is modelled immediately after building the graph.
331 331
332 \begin{lstlisting}[label=lst:loop, caption=Loop example, captionpos=b] 332 \begin{lstlisting}[label=lst:loop, caption=Loop example that counts from 0 to n-1., captionpos=b]
333 for(int i=0; i<n; ++i) { } 333 for(int i=0; i<n; ++i) { }
334 \end{lstlisting} 334 \end{lstlisting}
335 335
336 \begin{figure}[h] 336 \begin{figure}[h]
337 \centering 337 \centering
490 490
491 Within the graph a frame state is represented as a node that is attached to the instruction that caused it to be generated using a control dependency (see Figure~\ref{fig:fs1}). 491 Within the graph a frame state is represented as a node that is attached to the instruction that caused it to be generated using a control dependency (see Figure~\ref{fig:fs1}).
492 Frame states also have data dependencies on the contents of the state: the local variables and the expression stack. 492 Frame states also have data dependencies on the contents of the state: the local variables and the expression stack.
493 493
494 The frame state at the method beginning does not have to be explicitely in the graph, because it can always be reconstructed at a later stage. 494 The frame state at the method beginning does not have to be explicitely in the graph, because it can always be reconstructed at a later stage.
495 We save the frame state at control flow merges if there is at least one frame state on any control flow path after the immediate dominator. 495 We save the frame state at control flow merges if there is at least one frame state on any control flow path between a node and its immediate dominator.
496 496
497 497
498 \begin{figure}[h] 498 \begin{figure}[h]
499 \centering 499 \centering
500 \begin{digraphenv}{scale=0.5}{fs1} 500 \begin{digraphenv}{scale=0.5}{fs1}
514 \caption{Simple example using two frame states.} 514 \caption{Simple example using two frame states.}
515 \label{fig:fs1} 515 \label{fig:fs1}
516 \end{figure} 516 \end{figure}
517 517
518 518
519 A deoptimization node needs a valid frame state that specifies the location and state where the interpreter should continue.
520 The algorithm for constructing frame states makes sure that every possible location in the graph has a well-defined frame state that can be used by a deoptimization instruction.
521 Therefore, there are no direct links between the deoptimization instruction and its frame state thus allowing the deoptimization instructions to move freely around.
522
523 \subsection{Partial Escape Analysis}
524
525 A partial escape analysis can help to further reduce the number of frame states.
526 A field or array store does not create a new frame state, when the object that is modified did not have a chance to escape between its creation and the store.
527
528 Listing~\ref{lst:escape1} shows an example of a method that creates two \texttt{Point} objects, connects them, and returns them.
529 The object allocation of the first \texttt{Point} object does not need a frame state.
530 We can always reexecute the \texttt{NEW} bytecode again in the interpreter.
531 The \texttt{Point} object allocated by the compiler will then simply disappear after the next garbage collection.
532 The following field store is a thread-local memory store, because the \texttt{Point} object did not have any chance to escape.
533 Same applies to the assignment of the \texttt{next} field and the third field assignment.
534 Therefore, the whole method \texttt{getPoint} does not need an explicit frame state, because at any time during execution of this method, we can deoptimize and continue execution in the interpreter at the first bytecode of the method.
535
536 \begin{lstlisting}[label=lst:escape1, caption=Example method that needs no frame state., captionpos=b]
537 void getPoint() {
538 Point p = new Point();
539 p.x = 1;
540 p.next = new Point();
541 p.next.x = 2;
542 return p;
543 }
544 \end{lstlisting}
545
546 The reduction of frame states makes it easier for the compiler to perform memory optimizations like memory access coalescing.
547 We believe that this reduction on frame states is the key to effective vectorization and other compiler optimizations where compilers of compilers of unmanaged languages have advantages.
548
519 \subsection{Guards} 549 \subsection{Guards}
520 A guard is a node that deoptimizes based on a conditional expression. 550 A guard is a node that deoptimizes based on a conditional expression.
521 Guards are not attached to a certain frame state, they can move around freely and will always use the correct frame state when the nodes are scheduled (i.e., the last emitted frame state). 551 Guards are not attached to a certain frame state, they can move around freely and will always use the correct frame state when the nodes are scheduled (i.e., the last emitted frame state).
522 The node that is guarded by the deoptimization has a data dependency on the guard, and the guard in turn has a data dependency on the condition and on the most distant node that is postdominated by the guarded node. 552 The node that is guarded by the deoptimization has a data dependency on the guard and the guard in turn has a data dependency on the condition.
523 553 A guard must not be moved above any \texttt{If} nodes.
524 In the example of Figure~\ref{fig:guard1}, the second load is guarded by a guard, because its receiver might be null (the receiver of the first load is assumed to be non-null). 554 Therefore, we use \texttt{Anchor} instructions after a control flow split and a data dependency from the guard to this anchor.
525 The guard is anchored to the control split, because as soon as this node is executed, the second load must be executed as well. 555 The anchor is the most distant instruction that is postdominated by the guarded instruction and the guard can be scheduled anywhere between those two nodes.
526 In the final schedule, the guard can be placed before or after the first load. 556 This ensures maximum flexibility for the guard instruction and guarantees that we only deoptimize if the control flow would have reached the guarded instruction (without taking exceptions into account).
557
558 To illustrate the strengths of this approach, we show the graph for the Java code snippet shown in \ref{lst:guard1}.
559 The example looks artificial, but in case of method inlining, this is a pattern that is not unlikely to be present in a normal Java program.
560 Figure \ref{fig:guard0} shows the compiler graph for the example method after graph building.
561 The field stores are both represented by a single instruction and the null check that is implicitely incorporated in the field store.
562
563 \begin{lstlisting}[label=lst:guard1, caption=Example method that demonstrates the strengths of modelling the guards explicitely., captionpos=b]
564 void init(Point p) {
565 if (p != null) {
566 p.x = 0;
567 }
568 p.y = 0;
569 }
570 \end{lstlisting}
571
572 \begin{figure}[h]
573 \centering
574 \begin{digraphenv}{scale=0.5}{guard0}
575 \textnode{entry}{Entry}
576 \nodesplit{if}{If}
577 \node{merge}{Merge}
578 \node{return}{Return}
579 \node{cmpnull}{NonNull}
580 \textnode{p}{p}
581 \textnode{const0}{0}
582 \nodebisplit{store1}{FieldStore x}
583 \nodebisplit{store2}{FieldStore y}
584 \nodeframestate{fs1}{FrameState}
585 \nodeframestate{fs2}{FrameState}
586 \datalabel{store1:in1}{p}
587 \datalabel{store2:in1}{p}
588 \datalabel{store1:in2}{const0}
589 \datalabel{store2:in2}{const0}
590 \control{entry}{if}
591 \data{if}{cmpnull}
592 \controllabel{if:succ1}{merge}
593 \controllabel{if:succ2}{store1}
594 \controllabel{store1:succ1}{merge}
595 \controllabel{store1:succ2}{fs1}
596 \control{merge}{store2}
597 \controllabel{store2:succ1}{return}
598 \controllabel{store2:succ2}{fs2}
599 \data{cmpnull}{p}
600 \end{digraphenv}
601 \caption{Initial graph with the two field stores.}
602 \label{fig:guard0}
603 \end{figure}
604
605 Figure~\ref{fig:guard1} shows the example graph at a later compilation phase when the field store instructions are lowered to memory store instructions and explicitely modelled null check guards.
606 The guards are attached to anchor instructions that delimit their possible schedule.
607 The first guard must not be moved outside the \texttt{if} block; the second guard may be moved before the \texttt{If} instruction, because at this point it is already guaranteed that the second store is executed.
527 608
528 \begin{figure}[h] 609 \begin{figure}[h]
529 \centering 610 \centering
530 \begin{digraphenv}{scale=0.5}{guard1} 611 \begin{digraphenv}{scale=0.5}{guard1}
612 \textnode{entry}{Entry}
613 \node{anchor1}{Anchor}
614 \node{anchor2}{Anchor}
531 \nodesplit{if}{If} 615 \nodesplit{if}{If}
532 nop [shape=plaintext, label="..."]
533 \controllabel{if:succ1}{nop}
534 %
535 \node{split2}{Anchor}
536 \controllabel{if:succ2}{split2}
537 \nodebi{load1}{MemLoad}
538 \control{split2}{load1}
539 \nodebi{load2}{MemLoad}
540 \control{load1}{load2}
541 \control{load2}{merge}
542 \node{merge}{Merge} 616 \node{merge}{Merge}
543 \control{nop}{merge} 617 \node{return}{Return}
544 % 618 \node{cmpnull}{NonNull}
545 \nodeconst{o1}{obj1} 619 \textnode{p}{p}
546 \nodeconst{o2}{obj2} 620 \textnode{const0}{0}
547 \datalabel{load1:in2}{o1} 621 \nodeguard{guard1}{Guard}
548 \datalabel{load2:in2}{o2} 622 \nodeguard{guard2}{Guard}
549 \nodeguard{guard}{Guard} 623 \nodetrisplit{store1}{MemStore 16 (int)}
550 \node{cmpnull}{IsNull} 624 \nodetrisplit{store2}{MemStore 20 (int)}
551 \data{cmpnull}{o2} 625 \nodeframestate{fs1}{FrameState}
552 \datalabel{guard:in2}{cmpnull} 626 \nodeframestate{fs2}{FrameState}
553 \datalabel{load2:in1}{guard} 627 \data{store1:in1}{p}
554 \datalabel{guard:in1}{split2} 628 \data{store2:in1}{p}
629 \data{store1:in2}{const0}
630 \data{store2:in2}{const0}
631 \data{store1:in3}{guard1}
632 \data{store2:in3}{guard2}
633 \data{guard1:in1}{anchor2}
634 \data{guard2:in1}{anchor1}
635 \data{guard1:in2}{cmpnull}
636 \data{guard2:in2}{cmpnull}
637 \control{entry}{anchor1}
638 \control{anchor1}{if}
639 \data{if}{cmpnull}
640 \controllabel{if:succ1}{merge}
641 \controllabel{if:succ2}{anchor2}
642 \control{anchor2}{store1}
643 \controllabel{store1:succ1}{merge}
644 \controllabel{store1:succ2}{fs1}
645 \control{merge}{store2}
646 \controllabel{store2:succ1}{return}
647 \controllabel{store2:succ2}{fs2}
648 \data{cmpnull}{p}
555 \end{digraphenv} 649 \end{digraphenv}
556 \caption{A load guarded by a null check guard.} 650 \caption{A load guarded by a null check guard.}
557 \label{fig:guard1} 651 \label{fig:guard1}
558 \end{figure} 652 \end{figure}
559 653
560 A guard can be used to remove branches that have a very low execution frequency and replace them with a conditional jump to deoptimization. 654 The first guard can be easily removed, because it is guarded by an \texttt{If} instruction that checks the same condition.
561 655 Therefore we can remove the guard and the anchor from the graph and this gives us the graph shown in Figure \ref{fig:guard2}.
562 In the example of Figure~\ref{fig:guard2}, an \texttt{If} instruction was replaced by an anchor and a guard. 656
563 The anchor takes the place of the \texttt{If} instruction in the control flow, and is connected to the guard. 657 There is another optimization for guard instructions: If two guards that are anchored to the true and false branch of the same \texttt{If} instruction have the same condition, they can be merged, so that the resulting guard is anchored at the most distant node of which the \texttt{If} instruction is a postdominator.
564 The guard is now anchored to the most distant node of which the \texttt{If} instruction was a postdominator. 658
565 659
566 \begin{figure}[h] 660 \begin{figure}[h]
567 \centering 661 \centering
568 \begin{digraphenv}{scale=0.5}{guard2} 662 \begin{digraphenv}{scale=0.5}{guard2}
569 start [shape=plaintext, label="..."] 663 \textnode{entry}{Entry}
570 start2 [shape=plaintext, label=""] 664 \node{anchor1}{Anchor}
571 start3 [shape=plaintext, label=""] 665 \nodesplit{if}{If}
572 \control{start}{guard} 666 \node{merge}{Merge}
573 \node{anchor}{Anchor} 667 \node{return}{Return}
574 \nodebi{load1}{MemLoad} 668 \node{cmpnull}{NonNull}
575 \control{anchor}{load1} 669 \textnode{p}{p}
576 \control{load1}{nop} 670 \textnode{const0}{0}
577 nop [shape=plaintext, label="..."] 671 \nodeguard{guard2}{Guard}
578 % 672 \nodetrisplit{store1}{MemStore 16 (int)}
579 \nodeguard{guard}{Guard} 673 \nodetrisplit{store2}{MemStore 20 (int)}
580 \datalabel{guard:in1}{start2} 674 \nodeframestate{fs1}{FrameState}
581 \datalabel{guard:in2}{start3} 675 \nodeframestate{fs2}{FrameState}
582 \data{anchor}{guard} 676 \data{store1:in1}{p}
583 \end{digraphenv} 677 \data{store2:in1}{p}
584 \caption{A guard that is fixed to the control flow using an anchor instruction.} 678 \data{store1:in2}{const0}
679 \data{store2:in2}{const0}
680 \data{store2:in3}{guard2}
681 \data{guard2:in1}{anchor1}
682 \data{guard2:in2}{cmpnull}
683 \control{entry}{anchor1}
684 \control{anchor1}{if}
685 \data{if}{cmpnull}
686 \controllabel{if:succ1}{merge}
687 \controllabel{if:succ2}{store1}
688 \controllabel{store1:succ1}{merge}
689 \controllabel{store1:succ2}{fs1}
690 \control{merge}{store2}
691 \controllabel{store2:succ1}{return}
692 \controllabel{store2:succ2}{fs2}
693 \data{cmpnull}{p}
694 \end{digraphenv}
695 \caption{After removing redundant guards.}
585 \label{fig:guard2} 696 \label{fig:guard2}
697 \end{figure}
698
699 The remaining guard can now be moved above the \texttt{If} condition and be used to eliminate the need for the \texttt{If} node.
700 From this point on, the guard can however no longer be moved below the first memory store.
701 We use a control dependency from the guard to the field store to express this condition.
702 The link between the second store and the guard and the control flow merge instruction is no longer necessary.
703
704 \begin{figure}[h]
705 \centering
706 \begin{digraphenv}{scale=0.5}{guard3}
707 \textnode{entry}{Entry}
708 \node{anchor1}{Anchor}
709 \node{return}{Return}
710 \node{cmpnull}{NonNull}
711 \textnode{p}{p}
712 \textnode{const0}{0}
713 \nodeguard{guard2}{Guard}
714 \nodetrisplit{store1}{MemStore 16 (int)}
715 \nodetrisplit{store2}{MemStore 20 (int)}
716 \nodeframestate{fs1}{FrameState}
717 \nodeframestate{fs2}{FrameState}
718 \data{store1:in1}{p}
719 \data{store2:in1}{p}
720 \data{store1:in2}{const0}
721 \data{store2:in2}{const0}
722 \data{store2:in3}{guard2}
723 \data{guard2:in1}{anchor1}
724 \data{guard2:in2}{cmpnull}
725 \control{guard2}{store1}
726 \control{entry}{anchor1}
727 \control{anchor1}{store1}
728 \controllabel{store1:succ2}{fs1}
729 \control{store1}{store2}
730 \controllabel{store2:succ1}{return}
731 \controllabel{store2:succ2}{fs2}
732 \data{cmpnull}{p}
733 \end{digraphenv}
734 \caption{After eliminating an if with a guard.}
735 \label{fig:guard3}
586 \end{figure} 736 \end{figure}
587 737
588 At some point during the compilation, guards need to be fixed, which means that appropriate data and control dependencies will be inserted so that they cannot move outside the scope of the associated frame state. 738 At some point during the compilation, guards need to be fixed, which means that appropriate data and control dependencies will be inserted so that they cannot move outside the scope of the associated frame state.
589 This will generate deoptimization-free zones that can be targeted by the most aggressive optimizations. 739 This will generate deoptimization-free zones that can be targeted by the most aggressive optimizations.
590 A simple algorithm for this removal of frame states would be to move all guards as far upwards as possible. 740 A simple algorithm for this removal of frame states would be to move all guards as far upwards as possible and then the guards are fixed using anchor nodes.
591 Multiple guards with the same condition and anchor can be merged (see Figure~\ref{fig:guard3}). 741 In our example, the guard is already fixed, so there is no deoptimization point that uses any of the memory store frame states.
592 742 Therefore we can delete the frame states from the graph (see Figure \ref{fig:guard4}).
593 \begin{figure}[h] 743
594 \centering 744 \begin{figure}[h]
595 \begin{digraphenv}{scale=0.5}{guard3} 745 \centering
596 \nodesplit{if}{If} 746 \begin{digraphenv}{scale=0.5}{guard4}
597 nop [shape=plaintext, label="..."] 747 \textnode{entry}{Entry}
598 \controllabel{if:succ1}{nop} 748 \node{anchor1}{Anchor}
599 % 749 \node{return}{Return}
600 \node{split2}{Anchor} 750 \node{cmpnull}{NonNull}
601 \controllabel{if:succ2}{split2} 751 \textnode{p}{p}
602 \nodebi{load1}{MemLoad} 752 \textnode{const0}{0}
603 \control{split2}{load1} 753 \nodeguard{guard2}{Guard}
604 \nodebi{load2}{MemLoad} 754 \nodetrisplit{store1}{MemStore 16 (int)}
605 \control{load1}{load2} 755 \nodetrisplit{store2}{MemStore 20 (int)}
606 \control{load2}{merge} 756 \data{store1:in1}{p}
607 \node{merge}{Merge} 757 \data{store2:in1}{p}
608 \control{nop}{merge} 758 \data{store1:in2}{const0}
609 % 759 \data{store2:in2}{const0}
610 \nodeconst{o}{obj} 760 \data{store2:in3}{guard2}
611 \datalabel{load1:in2}{o} 761 \data{guard2:in1}{anchor1}
612 \datalabel{load2:in2}{o} 762 \data{guard2:in2}{cmpnull}
613 \nodeguard{guard}{Guard} 763 \control{guard2}{store1}
614 \node{cmpnull}{IsNull} 764 \control{entry}{anchor1}
615 \data{cmpnull}{o} 765 \control{anchor1}{store1}
616 \datalabel{guard:in2}{cmpnull} 766 \control{store1}{store2}
617 \datalabel{load2:in1}{guard} 767 \controllabel{store2:succ1}{return}
618 \datalabel{load1:in1}{guard} 768 \data{cmpnull}{p}
619 \datalabel{guard:in1}{split2} 769 \end{digraphenv}
620 \end{digraphenv} 770 \caption{After removing the frame states.}
621 \caption{Two loads using the same guard.} 771 \label{fig:guard4}
622 \label{fig:guard3} 772 \end{figure}
623 \end{figure} 773
624 774 Now we can use memory coalescing to combine the two stores without frame state to adjacent locations in the same object.
625 Also, if two guards that are anchored to the true and false branch of the same \texttt{If} instruction have the same condition, they can be merged, so that the resulting guard is anchored at the most distant node of which the \texttt{If} instruction is a postdominator. 775 This is only possible if the first store does not have a frame state.
776 Figure \ref{fig:guard5} shows the resulting graph.
777
778
779 \begin{figure}[h]
780 \centering
781 \begin{digraphenv}{scale=0.5}{guard5}
782 \textnode{entry}{Entry}
783 \node{anchor1}{Anchor}
784 \node{return}{Return}
785 \node{cmpnull}{NonNull}
786 \textnode{p}{p}
787 \textnode{const0}{0}
788 \nodeguard{guard2}{Guard}
789 \nodetrisplit{store1}{MemStore 16 (long)}
790 \data{store1:in1}{p}
791 \data{store1:in2}{const0}
792 \data{guard2:in1}{anchor1}
793 \data{guard2:in2}{cmpnull}
794 \control{guard2}{store1}
795 \control{entry}{anchor1}
796 \control{anchor1}{store1}
797 \controllabel{store1:succ1}{return}
798 \data{cmpnull}{p}
799 \end{digraphenv}
800 \caption{After coalescing the two memory stores.}
801 \label{fig:guard5}
802 \end{figure}
803
804 A memory store that immediately follows a null check guard instruction on the same object, can be combined into a store with an implicit null check (that deoptimizes instead of throwing the exception).
805 Therefore, we can remove the guard again and also the anchor is no longer necessary.
806 Figure~\ref{fig:guard6} shows now that fully optimized graph that is generated for Listing~\ref{lst:guard1}.
807
808 \begin{figure}[h]
809 \centering
810 \begin{digraphenv}{scale=0.5}{guard6}
811 \textnode{entry}{Entry}
812 \node{return}{Return}
813 \textnode{p}{p}
814 \textnode{const0}{0}
815 \nodetrisplit{store1}{DeoptimizingMemStore 16 (long)}
816 \data{store1:in1}{p}
817 \data{store1:in2}{const0}
818 \control{entry}{store1}
819 \controllabel{store1:succ1}{return}
820 \end{digraphenv}
821 \caption{Fully optimized method.}
822 \label{fig:guard6}
823 \end{figure}
824
626 825
627 \section{Conclusions} 826 \section{Conclusions}
628 \label{sec:conclusions} 827 \label{sec:conclusions}
629 This document sketched the strategy for the Graph compiler. 828 This document sketched the strategy for the Graph compiler.
630 We already reached M1 (as defined in Section~\ref{sec:mile}) and have the following plans for M2 to M4: 829 We already reached M1 (as defined in Section~\ref{sec:mile}) and have the following plans for M2 to M4: