WriteBarrierAdditionPhase.java revision 12968:4d8a004e5c6d
1/*
2 * Copyright (c) 2013, 2015, 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.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23package org.graalvm.compiler.hotspot.phases;
24
25import org.graalvm.compiler.debug.GraalError;
26import org.graalvm.compiler.graph.Node;
27import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
28import org.graalvm.compiler.hotspot.nodes.G1ArrayRangePostWriteBarrier;
29import org.graalvm.compiler.hotspot.nodes.G1ArrayRangePreWriteBarrier;
30import org.graalvm.compiler.hotspot.nodes.G1PostWriteBarrier;
31import org.graalvm.compiler.hotspot.nodes.G1PreWriteBarrier;
32import org.graalvm.compiler.hotspot.nodes.G1ReferentFieldReadBarrier;
33import org.graalvm.compiler.hotspot.nodes.SerialArrayRangeWriteBarrier;
34import org.graalvm.compiler.hotspot.nodes.SerialWriteBarrier;
35import org.graalvm.compiler.nodes.StructuredGraph;
36import org.graalvm.compiler.nodes.ValueNode;
37import org.graalvm.compiler.nodes.extended.ArrayRangeWriteNode;
38import org.graalvm.compiler.nodes.java.AbstractCompareAndSwapNode;
39import org.graalvm.compiler.nodes.java.LoweredAtomicReadAndWriteNode;
40import org.graalvm.compiler.nodes.memory.FixedAccessNode;
41import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType;
42import org.graalvm.compiler.nodes.memory.ReadNode;
43import org.graalvm.compiler.nodes.memory.WriteNode;
44import org.graalvm.compiler.nodes.memory.address.AddressNode;
45import org.graalvm.compiler.nodes.type.StampTool;
46import org.graalvm.compiler.phases.Phase;
47
48public class WriteBarrierAdditionPhase extends Phase {
49
50    private GraalHotSpotVMConfig config;
51
52    public WriteBarrierAdditionPhase(GraalHotSpotVMConfig config) {
53        this.config = config;
54    }
55
56    @Override
57    protected void run(StructuredGraph graph) {
58        for (Node n : graph.getNodes()) {
59            if (n instanceof ReadNode) {
60                addReadNodeBarriers((ReadNode) n, graph);
61            } else if (n instanceof WriteNode) {
62                addWriteNodeBarriers((WriteNode) n, graph);
63            } else if (n instanceof LoweredAtomicReadAndWriteNode) {
64                LoweredAtomicReadAndWriteNode loweredAtomicReadAndWriteNode = (LoweredAtomicReadAndWriteNode) n;
65                addAtomicReadWriteNodeBarriers(loweredAtomicReadAndWriteNode, graph);
66            } else if (n instanceof AbstractCompareAndSwapNode) {
67                addCASBarriers((AbstractCompareAndSwapNode) n, graph);
68            } else if (n instanceof ArrayRangeWriteNode) {
69                ArrayRangeWriteNode node = (ArrayRangeWriteNode) n;
70                if (node.isObjectArray()) {
71                    addArrayRangeBarriers(node, graph);
72                }
73            }
74        }
75    }
76
77    private void addReadNodeBarriers(ReadNode node, StructuredGraph graph) {
78        if (node.getBarrierType() == BarrierType.PRECISE) {
79            assert config.useG1GC;
80            G1ReferentFieldReadBarrier barrier = graph.add(new G1ReferentFieldReadBarrier(node.getAddress(), node, false));
81            graph.addAfterFixed(node, barrier);
82        } else {
83            assert node.getBarrierType() == BarrierType.NONE : "Non precise read barrier has been attached to read node.";
84        }
85    }
86
87    protected static void addG1PreWriteBarrier(FixedAccessNode node, AddressNode address, ValueNode value, boolean doLoad, boolean nullCheck, StructuredGraph graph) {
88        G1PreWriteBarrier preBarrier = graph.add(new G1PreWriteBarrier(address, value, doLoad, nullCheck));
89        preBarrier.setStateBefore(node.stateBefore());
90        node.setNullCheck(false);
91        node.setStateBefore(null);
92        graph.addBeforeFixed(node, preBarrier);
93    }
94
95    protected void addG1PostWriteBarrier(FixedAccessNode node, AddressNode address, ValueNode value, boolean precise, StructuredGraph graph) {
96        final boolean alwaysNull = StampTool.isPointerAlwaysNull(value);
97        graph.addAfterFixed(node, graph.add(new G1PostWriteBarrier(address, value, precise, alwaysNull)));
98    }
99
100    protected void addSerialPostWriteBarrier(FixedAccessNode node, AddressNode address, ValueNode value, boolean precise, StructuredGraph graph) {
101        final boolean alwaysNull = StampTool.isPointerAlwaysNull(value);
102        if (alwaysNull) {
103            // Serial barrier isn't needed for null value
104            return;
105        }
106        graph.addAfterFixed(node, graph.add(new SerialWriteBarrier(address, precise)));
107    }
108
109    private void addWriteNodeBarriers(WriteNode node, StructuredGraph graph) {
110        BarrierType barrierType = node.getBarrierType();
111        switch (barrierType) {
112            case NONE:
113                // nothing to do
114                break;
115            case IMPRECISE:
116            case PRECISE:
117                boolean precise = barrierType == BarrierType.PRECISE;
118                if (config.useG1GC) {
119                    if (!node.getLocationIdentity().isInit()) {
120                        addG1PreWriteBarrier(node, node.getAddress(), null, true, node.getNullCheck(), graph);
121                    }
122                    addG1PostWriteBarrier(node, node.getAddress(), node.value(), precise, graph);
123                } else {
124                    addSerialPostWriteBarrier(node, node.getAddress(), node.value(), precise, graph);
125                }
126                break;
127            default:
128                throw new GraalError("unexpected barrier type: " + barrierType);
129        }
130    }
131
132    private void addAtomicReadWriteNodeBarriers(LoweredAtomicReadAndWriteNode node, StructuredGraph graph) {
133        BarrierType barrierType = node.getBarrierType();
134        switch (barrierType) {
135            case NONE:
136                // nothing to do
137                break;
138            case IMPRECISE:
139            case PRECISE:
140                boolean precise = barrierType == BarrierType.PRECISE;
141                if (config.useG1GC) {
142                    addG1PreWriteBarrier(node, node.getAddress(), null, true, node.getNullCheck(), graph);
143                    addG1PostWriteBarrier(node, node.getAddress(), node.getNewValue(), precise, graph);
144                } else {
145                    addSerialPostWriteBarrier(node, node.getAddress(), node.getNewValue(), precise, graph);
146                }
147                break;
148            default:
149                throw new GraalError("unexpected barrier type: " + barrierType);
150        }
151    }
152
153    private void addCASBarriers(AbstractCompareAndSwapNode node, StructuredGraph graph) {
154        BarrierType barrierType = node.getBarrierType();
155        switch (barrierType) {
156            case NONE:
157                // nothing to do
158                break;
159            case IMPRECISE:
160            case PRECISE:
161                boolean precise = barrierType == BarrierType.PRECISE;
162                if (config.useG1GC) {
163                    addG1PreWriteBarrier(node, node.getAddress(), node.getExpectedValue(), false, false, graph);
164                    addG1PostWriteBarrier(node, node.getAddress(), node.getNewValue(), precise, graph);
165                } else {
166                    addSerialPostWriteBarrier(node, node.getAddress(), node.getNewValue(), precise, graph);
167                }
168                break;
169            default:
170                throw new GraalError("unexpected barrier type: " + barrierType);
171        }
172    }
173
174    private void addArrayRangeBarriers(ArrayRangeWriteNode node, StructuredGraph graph) {
175        if (config.useG1GC) {
176            if (!node.isInitialization()) {
177                G1ArrayRangePreWriteBarrier g1ArrayRangePreWriteBarrier = graph.add(new G1ArrayRangePreWriteBarrier(node.getArray(), node.getIndex(), node.getLength()));
178                graph.addBeforeFixed(node, g1ArrayRangePreWriteBarrier);
179            }
180            G1ArrayRangePostWriteBarrier g1ArrayRangePostWriteBarrier = graph.add(new G1ArrayRangePostWriteBarrier(node.getArray(), node.getIndex(), node.getLength()));
181            graph.addAfterFixed(node, g1ArrayRangePostWriteBarrier);
182        } else {
183            SerialArrayRangeWriteBarrier serialArrayRangeWriteBarrier = graph.add(new SerialArrayRangeWriteBarrier(node.getArray(), node.getIndex(), node.getLength()));
184            graph.addAfterFixed(node, serialArrayRangeWriteBarrier);
185        }
186    }
187
188    @Override
189    public boolean checkContract() {
190        return false;
191    }
192}
193