43972
|
1 |
/*
|
|
2 |
* Copyright (c) 2012, 2016, 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 |
*/
|
|
23 |
package org.graalvm.compiler.hotspot.replacements;
|
|
24 |
|
46344
|
25 |
import static jdk.vm.ci.code.MemoryBarriers.STORE_LOAD;
|
43972
|
26 |
import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG;
|
|
27 |
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.arrayIndexScale;
|
|
28 |
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.cardTableShift;
|
|
29 |
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.dirtyCardValue;
|
|
30 |
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.g1CardQueueBufferOffset;
|
|
31 |
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.g1CardQueueIndexOffset;
|
|
32 |
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.g1SATBQueueBufferOffset;
|
|
33 |
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.g1SATBQueueIndexOffset;
|
|
34 |
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.g1SATBQueueMarkingOffset;
|
|
35 |
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.g1YoungCardValue;
|
|
36 |
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.registerAsWord;
|
|
37 |
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.verifyOop;
|
|
38 |
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.verifyOops;
|
|
39 |
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.wordSize;
|
|
40 |
import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.FREQUENT_PROBABILITY;
|
|
41 |
import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.LIKELY_PROBABILITY;
|
|
42 |
import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.NOT_FREQUENT_PROBABILITY;
|
|
43 |
import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.probability;
|
|
44 |
import static org.graalvm.compiler.replacements.SnippetTemplate.DEFAULT_REPLACER;
|
|
45 |
|
|
46 |
import org.graalvm.compiler.api.replacements.Snippet;
|
|
47 |
import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter;
|
46344
|
48 |
import org.graalvm.compiler.core.common.CompressEncoding;
|
43972
|
49 |
import org.graalvm.compiler.core.common.GraalOptions;
|
|
50 |
import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
|
46640
|
51 |
import org.graalvm.compiler.debug.DebugHandlersFactory;
|
43972
|
52 |
import org.graalvm.compiler.graph.Node.ConstantNodeParameter;
|
|
53 |
import org.graalvm.compiler.graph.Node.NodeIntrinsic;
|
|
54 |
import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
|
|
55 |
import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider;
|
|
56 |
import org.graalvm.compiler.hotspot.nodes.G1ArrayRangePostWriteBarrier;
|
|
57 |
import org.graalvm.compiler.hotspot.nodes.G1ArrayRangePreWriteBarrier;
|
|
58 |
import org.graalvm.compiler.hotspot.nodes.G1PostWriteBarrier;
|
|
59 |
import org.graalvm.compiler.hotspot.nodes.G1PreWriteBarrier;
|
|
60 |
import org.graalvm.compiler.hotspot.nodes.G1ReferentFieldReadBarrier;
|
|
61 |
import org.graalvm.compiler.hotspot.nodes.GraalHotSpotVMConfigNode;
|
46459
|
62 |
import org.graalvm.compiler.hotspot.nodes.HotSpotCompressionNode;
|
43972
|
63 |
import org.graalvm.compiler.hotspot.nodes.SerialArrayRangeWriteBarrier;
|
|
64 |
import org.graalvm.compiler.hotspot.nodes.SerialWriteBarrier;
|
46344
|
65 |
import org.graalvm.compiler.hotspot.nodes.VMErrorNode;
|
43972
|
66 |
import org.graalvm.compiler.nodes.NamedLocationIdentity;
|
48190
|
67 |
import org.graalvm.compiler.nodes.NodeView;
|
43972
|
68 |
import org.graalvm.compiler.nodes.StructuredGraph;
|
|
69 |
import org.graalvm.compiler.nodes.ValueNode;
|
|
70 |
import org.graalvm.compiler.nodes.extended.FixedValueAnchorNode;
|
|
71 |
import org.graalvm.compiler.nodes.extended.ForeignCallNode;
|
|
72 |
import org.graalvm.compiler.nodes.extended.MembarNode;
|
|
73 |
import org.graalvm.compiler.nodes.extended.NullCheckNode;
|
|
74 |
import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType;
|
|
75 |
import org.graalvm.compiler.nodes.memory.address.AddressNode;
|
|
76 |
import org.graalvm.compiler.nodes.memory.address.AddressNode.Address;
|
|
77 |
import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
|
|
78 |
import org.graalvm.compiler.nodes.spi.LoweringTool;
|
46459
|
79 |
import org.graalvm.compiler.nodes.type.NarrowOopStamp;
|
46344
|
80 |
import org.graalvm.compiler.options.OptionValues;
|
43972
|
81 |
import org.graalvm.compiler.replacements.Log;
|
|
82 |
import org.graalvm.compiler.replacements.SnippetCounter;
|
46344
|
83 |
import org.graalvm.compiler.replacements.SnippetCounter.Group;
|
43972
|
84 |
import org.graalvm.compiler.replacements.SnippetTemplate.AbstractTemplates;
|
|
85 |
import org.graalvm.compiler.replacements.SnippetTemplate.Arguments;
|
|
86 |
import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo;
|
|
87 |
import org.graalvm.compiler.replacements.Snippets;
|
|
88 |
import org.graalvm.compiler.replacements.nodes.DirectStoreNode;
|
|
89 |
import org.graalvm.compiler.word.Word;
|
46551
|
90 |
import org.graalvm.word.LocationIdentity;
|
|
91 |
import org.graalvm.word.Pointer;
|
46680
|
92 |
import org.graalvm.word.UnsignedWord;
|
46551
|
93 |
import org.graalvm.word.WordFactory;
|
43972
|
94 |
|
|
95 |
import jdk.vm.ci.code.Register;
|
|
96 |
import jdk.vm.ci.code.TargetDescription;
|
|
97 |
import jdk.vm.ci.meta.JavaKind;
|
|
98 |
|
|
99 |
public class WriteBarrierSnippets implements Snippets {
|
|
100 |
|
46344
|
101 |
static class Counters {
|
|
102 |
Counters(SnippetCounter.Group.Factory factory) {
|
|
103 |
Group countersWriteBarriers = factory.createSnippetCounterGroup("WriteBarriers");
|
|
104 |
serialWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "serialWriteBarrier", "Number of Serial Write Barriers");
|
|
105 |
g1AttemptedPreWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "g1AttemptedPreWriteBarrier", "Number of attempted G1 Pre Write Barriers");
|
|
106 |
g1EffectivePreWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "g1EffectivePreWriteBarrier", "Number of effective G1 Pre Write Barriers");
|
|
107 |
g1ExecutedPreWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "g1ExecutedPreWriteBarrier", "Number of executed G1 Pre Write Barriers");
|
|
108 |
g1AttemptedPostWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "g1AttemptedPostWriteBarrier", "Number of attempted G1 Post Write Barriers");
|
|
109 |
g1EffectiveAfterXORPostWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "g1EffectiveAfterXORPostWriteBarrier",
|
|
110 |
"Number of effective G1 Post Write Barriers (after passing the XOR test)");
|
|
111 |
g1EffectiveAfterNullPostWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "g1EffectiveAfterNullPostWriteBarrier",
|
|
112 |
"Number of effective G1 Post Write Barriers (after passing the NULL test)");
|
|
113 |
g1ExecutedPostWriteBarrierCounter = new SnippetCounter(countersWriteBarriers, "g1ExecutedPostWriteBarrier", "Number of executed G1 Post Write Barriers");
|
|
114 |
|
|
115 |
}
|
|
116 |
|
|
117 |
final SnippetCounter serialWriteBarrierCounter;
|
|
118 |
final SnippetCounter g1AttemptedPreWriteBarrierCounter;
|
|
119 |
final SnippetCounter g1EffectivePreWriteBarrierCounter;
|
|
120 |
final SnippetCounter g1ExecutedPreWriteBarrierCounter;
|
|
121 |
final SnippetCounter g1AttemptedPostWriteBarrierCounter;
|
|
122 |
final SnippetCounter g1EffectiveAfterXORPostWriteBarrierCounter;
|
|
123 |
final SnippetCounter g1EffectiveAfterNullPostWriteBarrierCounter;
|
|
124 |
final SnippetCounter g1ExecutedPostWriteBarrierCounter;
|
|
125 |
}
|
43972
|
126 |
|
|
127 |
public static final LocationIdentity GC_CARD_LOCATION = NamedLocationIdentity.mutable("GC-Card");
|
|
128 |
public static final LocationIdentity GC_LOG_LOCATION = NamedLocationIdentity.mutable("GC-Log");
|
|
129 |
public static final LocationIdentity GC_INDEX_LOCATION = NamedLocationIdentity.mutable("GC-Index");
|
|
130 |
|
46344
|
131 |
private static void serialWriteBarrier(Pointer ptr, Counters counters) {
|
|
132 |
counters.serialWriteBarrierCounter.inc();
|
43972
|
133 |
final long startAddress = GraalHotSpotVMConfigNode.cardTableAddress();
|
|
134 |
Word base = (Word) ptr.unsignedShiftRight(cardTableShift(INJECTED_VMCONFIG));
|
|
135 |
if (((int) startAddress) == startAddress && GraalHotSpotVMConfigNode.isCardTableAddressConstant()) {
|
|
136 |
base.writeByte((int) startAddress, (byte) 0, GC_CARD_LOCATION);
|
|
137 |
} else {
|
46459
|
138 |
base.writeByte(WordFactory.unsigned(startAddress), (byte) 0, GC_CARD_LOCATION);
|
43972
|
139 |
}
|
|
140 |
}
|
|
141 |
|
|
142 |
@Snippet
|
46344
|
143 |
public static void serialImpreciseWriteBarrier(Object object, @ConstantParameter Counters counters) {
|
|
144 |
serialWriteBarrier(Word.objectToTrackedPointer(object), counters);
|
43972
|
145 |
}
|
|
146 |
|
|
147 |
@Snippet
|
46344
|
148 |
public static void serialPreciseWriteBarrier(Address address, @ConstantParameter Counters counters) {
|
|
149 |
serialWriteBarrier(Word.fromAddress(address), counters);
|
43972
|
150 |
}
|
|
151 |
|
|
152 |
@Snippet
|
48861
|
153 |
public static void serialArrayRangeWriteBarrier(Address address, int length, @ConstantParameter int elementStride) {
|
43972
|
154 |
if (length == 0) {
|
|
155 |
return;
|
|
156 |
}
|
|
157 |
int cardShift = cardTableShift(INJECTED_VMCONFIG);
|
|
158 |
final long cardStart = GraalHotSpotVMConfigNode.cardTableAddress();
|
48861
|
159 |
long start = getPointerToFirstArrayElement(address, length, elementStride) >>> cardShift;
|
|
160 |
long end = getPointerToLastArrayElement(address, length, elementStride) >>> cardShift;
|
43972
|
161 |
long count = end - start + 1;
|
|
162 |
while (count-- > 0) {
|
|
163 |
DirectStoreNode.storeBoolean((start + cardStart) + count, false, JavaKind.Boolean);
|
|
164 |
}
|
|
165 |
}
|
|
166 |
|
|
167 |
@Snippet
|
|
168 |
public static void g1PreWriteBarrier(Address address, Object object, Object expectedObject, @ConstantParameter boolean doLoad, @ConstantParameter boolean nullCheck,
|
46344
|
169 |
@ConstantParameter Register threadRegister, @ConstantParameter boolean trace, @ConstantParameter Counters counters) {
|
43972
|
170 |
if (nullCheck) {
|
|
171 |
NullCheckNode.nullCheck(address);
|
|
172 |
}
|
|
173 |
Word thread = registerAsWord(threadRegister);
|
|
174 |
verifyOop(object);
|
|
175 |
Object fixedExpectedObject = FixedValueAnchorNode.getObject(expectedObject);
|
46459
|
176 |
Word field = Word.fromAddress(address);
|
43972
|
177 |
Pointer previousOop = Word.objectToTrackedPointer(fixedExpectedObject);
|
|
178 |
byte markingValue = thread.readByte(g1SATBQueueMarkingOffset(INJECTED_VMCONFIG));
|
|
179 |
int gcCycle = 0;
|
|
180 |
if (trace) {
|
46459
|
181 |
Pointer gcTotalCollectionsAddress = WordFactory.pointer(HotSpotReplacementsUtil.gcTotalCollectionsAddress(INJECTED_VMCONFIG));
|
|
182 |
gcCycle = (int) gcTotalCollectionsAddress.readLong(0);
|
43972
|
183 |
log(trace, "[%d] G1-Pre Thread %p Object %p\n", gcCycle, thread.rawValue(), Word.objectToTrackedPointer(object).rawValue());
|
|
184 |
log(trace, "[%d] G1-Pre Thread %p Expected Object %p\n", gcCycle, thread.rawValue(), Word.objectToTrackedPointer(fixedExpectedObject).rawValue());
|
|
185 |
log(trace, "[%d] G1-Pre Thread %p Field %p\n", gcCycle, thread.rawValue(), field.rawValue());
|
|
186 |
log(trace, "[%d] G1-Pre Thread %p Marking %d\n", gcCycle, thread.rawValue(), markingValue);
|
|
187 |
log(trace, "[%d] G1-Pre Thread %p DoLoad %d\n", gcCycle, thread.rawValue(), doLoad ? 1L : 0L);
|
|
188 |
}
|
46344
|
189 |
counters.g1AttemptedPreWriteBarrierCounter.inc();
|
43972
|
190 |
// If the concurrent marker is enabled, the barrier is issued.
|
|
191 |
if (probability(NOT_FREQUENT_PROBABILITY, markingValue != (byte) 0)) {
|
|
192 |
// If the previous value has to be loaded (before the write), the load is issued.
|
|
193 |
// The load is always issued except the cases of CAS and referent field.
|
|
194 |
if (probability(LIKELY_PROBABILITY, doLoad)) {
|
|
195 |
previousOop = Word.objectToTrackedPointer(field.readObject(0, BarrierType.NONE));
|
|
196 |
if (trace) {
|
|
197 |
log(trace, "[%d] G1-Pre Thread %p Previous Object %p\n ", gcCycle, thread.rawValue(), previousOop.rawValue());
|
|
198 |
verifyOop(previousOop.toObject());
|
|
199 |
}
|
|
200 |
}
|
46344
|
201 |
counters.g1EffectivePreWriteBarrierCounter.inc();
|
43972
|
202 |
// If the previous value is null the barrier should not be issued.
|
|
203 |
if (probability(FREQUENT_PROBABILITY, previousOop.notEqual(0))) {
|
46344
|
204 |
counters.g1ExecutedPreWriteBarrierCounter.inc();
|
43972
|
205 |
// If the thread-local SATB buffer is full issue a native call which will
|
|
206 |
// initialize a new one and add the entry.
|
|
207 |
Word indexAddress = thread.add(g1SATBQueueIndexOffset(INJECTED_VMCONFIG));
|
|
208 |
Word indexValue = indexAddress.readWord(0);
|
|
209 |
if (probability(FREQUENT_PROBABILITY, indexValue.notEqual(0))) {
|
|
210 |
Word bufferAddress = thread.readWord(g1SATBQueueBufferOffset(INJECTED_VMCONFIG));
|
|
211 |
Word nextIndex = indexValue.subtract(wordSize());
|
|
212 |
Word logAddress = bufferAddress.add(nextIndex);
|
|
213 |
// Log the object to be marked as well as update the SATB's buffer next index.
|
|
214 |
logAddress.writeWord(0, previousOop, GC_LOG_LOCATION);
|
|
215 |
indexAddress.writeWord(0, nextIndex, GC_INDEX_LOCATION);
|
|
216 |
} else {
|
|
217 |
g1PreBarrierStub(G1WBPRECALL, previousOop.toObject());
|
|
218 |
}
|
|
219 |
}
|
|
220 |
}
|
|
221 |
}
|
|
222 |
|
|
223 |
@Snippet
|
|
224 |
public static void g1PostWriteBarrier(Address address, Object object, Object value, @ConstantParameter boolean usePrecise, @ConstantParameter Register threadRegister,
|
46344
|
225 |
@ConstantParameter boolean trace, @ConstantParameter Counters counters) {
|
43972
|
226 |
Word thread = registerAsWord(threadRegister);
|
|
227 |
Object fixedValue = FixedValueAnchorNode.getObject(value);
|
|
228 |
verifyOop(object);
|
|
229 |
verifyOop(fixedValue);
|
|
230 |
validateObject(object, fixedValue);
|
|
231 |
Pointer oop;
|
|
232 |
if (usePrecise) {
|
|
233 |
oop = Word.fromAddress(address);
|
|
234 |
} else {
|
|
235 |
oop = Word.objectToTrackedPointer(object);
|
|
236 |
}
|
|
237 |
int gcCycle = 0;
|
|
238 |
if (trace) {
|
46459
|
239 |
Pointer gcTotalCollectionsAddress = WordFactory.pointer(HotSpotReplacementsUtil.gcTotalCollectionsAddress(INJECTED_VMCONFIG));
|
|
240 |
gcCycle = (int) gcTotalCollectionsAddress.readLong(0);
|
43972
|
241 |
log(trace, "[%d] G1-Post Thread: %p Object: %p\n", gcCycle, thread.rawValue(), Word.objectToTrackedPointer(object).rawValue());
|
|
242 |
log(trace, "[%d] G1-Post Thread: %p Field: %p\n", gcCycle, thread.rawValue(), oop.rawValue());
|
|
243 |
}
|
|
244 |
Pointer writtenValue = Word.objectToTrackedPointer(fixedValue);
|
|
245 |
// The result of the xor reveals whether the installed pointer crosses heap regions.
|
|
246 |
// In case it does the write barrier has to be issued.
|
|
247 |
final int logOfHeapRegionGrainBytes = GraalHotSpotVMConfigNode.logOfHeapRegionGrainBytes();
|
46680
|
248 |
UnsignedWord xorResult = (oop.xor(writtenValue)).unsignedShiftRight(logOfHeapRegionGrainBytes);
|
43972
|
249 |
|
|
250 |
// Calculate the address of the card to be enqueued to the
|
|
251 |
// thread local card queue.
|
46680
|
252 |
UnsignedWord cardBase = oop.unsignedShiftRight(cardTableShift(INJECTED_VMCONFIG));
|
43972
|
253 |
final long startAddress = GraalHotSpotVMConfigNode.cardTableAddress();
|
|
254 |
int displacement = 0;
|
|
255 |
if (((int) startAddress) == startAddress && GraalHotSpotVMConfigNode.isCardTableAddressConstant()) {
|
|
256 |
displacement = (int) startAddress;
|
|
257 |
} else {
|
46459
|
258 |
cardBase = cardBase.add(WordFactory.unsigned(startAddress));
|
43972
|
259 |
}
|
|
260 |
Word cardAddress = (Word) cardBase.add(displacement);
|
|
261 |
|
46344
|
262 |
counters.g1AttemptedPostWriteBarrierCounter.inc();
|
43972
|
263 |
if (probability(FREQUENT_PROBABILITY, xorResult.notEqual(0))) {
|
46344
|
264 |
counters.g1EffectiveAfterXORPostWriteBarrierCounter.inc();
|
43972
|
265 |
|
|
266 |
// If the written value is not null continue with the barrier addition.
|
|
267 |
if (probability(FREQUENT_PROBABILITY, writtenValue.notEqual(0))) {
|
|
268 |
byte cardByte = cardAddress.readByte(0, GC_CARD_LOCATION);
|
46344
|
269 |
counters.g1EffectiveAfterNullPostWriteBarrierCounter.inc();
|
43972
|
270 |
|
|
271 |
// If the card is already dirty, (hence already enqueued) skip the insertion.
|
|
272 |
if (probability(NOT_FREQUENT_PROBABILITY, cardByte != g1YoungCardValue(INJECTED_VMCONFIG))) {
|
|
273 |
MembarNode.memoryBarrier(STORE_LOAD, GC_CARD_LOCATION);
|
|
274 |
byte cardByteReload = cardAddress.readByte(0, GC_CARD_LOCATION);
|
|
275 |
if (probability(NOT_FREQUENT_PROBABILITY, cardByteReload != dirtyCardValue(INJECTED_VMCONFIG))) {
|
46459
|
276 |
log(trace, "[%d] G1-Post Thread: %p Card: %p \n", gcCycle, thread.rawValue(), WordFactory.unsigned((int) cardByte).rawValue());
|
43972
|
277 |
cardAddress.writeByte(0, (byte) 0, GC_CARD_LOCATION);
|
46344
|
278 |
counters.g1ExecutedPostWriteBarrierCounter.inc();
|
43972
|
279 |
|
|
280 |
// If the thread local card queue is full, issue a native call which will
|
|
281 |
// initialize a new one and add the card entry.
|
|
282 |
Word indexAddress = thread.add(g1CardQueueIndexOffset(INJECTED_VMCONFIG));
|
|
283 |
Word indexValue = thread.readWord(g1CardQueueIndexOffset(INJECTED_VMCONFIG));
|
|
284 |
if (probability(FREQUENT_PROBABILITY, indexValue.notEqual(0))) {
|
|
285 |
Word bufferAddress = thread.readWord(g1CardQueueBufferOffset(INJECTED_VMCONFIG));
|
|
286 |
Word nextIndex = indexValue.subtract(wordSize());
|
|
287 |
Word logAddress = bufferAddress.add(nextIndex);
|
|
288 |
// Log the object to be scanned as well as update
|
|
289 |
// the card queue's next index.
|
|
290 |
logAddress.writeWord(0, cardAddress, GC_LOG_LOCATION);
|
|
291 |
indexAddress.writeWord(0, nextIndex, GC_INDEX_LOCATION);
|
|
292 |
} else {
|
|
293 |
g1PostBarrierStub(G1WBPOSTCALL, cardAddress);
|
|
294 |
}
|
|
295 |
}
|
|
296 |
}
|
|
297 |
}
|
|
298 |
}
|
|
299 |
}
|
|
300 |
|
|
301 |
@Snippet
|
48861
|
302 |
public static void g1ArrayRangePreWriteBarrier(Address address, int length, @ConstantParameter int elementStride, @ConstantParameter Register threadRegister) {
|
43972
|
303 |
Word thread = registerAsWord(threadRegister);
|
|
304 |
byte markingValue = thread.readByte(g1SATBQueueMarkingOffset(INJECTED_VMCONFIG));
|
|
305 |
// If the concurrent marker is not enabled or the vector length is zero, return.
|
|
306 |
if (markingValue == (byte) 0 || length == 0) {
|
|
307 |
return;
|
|
308 |
}
|
|
309 |
Word bufferAddress = thread.readWord(g1SATBQueueBufferOffset(INJECTED_VMCONFIG));
|
|
310 |
Word indexAddress = thread.add(g1SATBQueueIndexOffset(INJECTED_VMCONFIG));
|
|
311 |
long indexValue = indexAddress.readWord(0).rawValue();
|
|
312 |
final int scale = arrayIndexScale(JavaKind.Object);
|
48861
|
313 |
long start = getPointerToFirstArrayElement(address, length, elementStride);
|
43972
|
314 |
|
48861
|
315 |
for (int i = 0; i < length; i++) {
|
|
316 |
Word arrElemPtr = WordFactory.pointer(start + i * scale);
|
|
317 |
Pointer oop = Word.objectToTrackedPointer(arrElemPtr.readObject(0, BarrierType.NONE));
|
43972
|
318 |
verifyOop(oop.toObject());
|
|
319 |
if (oop.notEqual(0)) {
|
|
320 |
if (indexValue != 0) {
|
|
321 |
indexValue = indexValue - wordSize();
|
46459
|
322 |
Word logAddress = bufferAddress.add(WordFactory.unsigned(indexValue));
|
43972
|
323 |
// Log the object to be marked as well as update the SATB's buffer next index.
|
|
324 |
logAddress.writeWord(0, oop, GC_LOG_LOCATION);
|
46459
|
325 |
indexAddress.writeWord(0, WordFactory.unsigned(indexValue), GC_INDEX_LOCATION);
|
43972
|
326 |
} else {
|
|
327 |
g1PreBarrierStub(G1WBPRECALL, oop.toObject());
|
|
328 |
}
|
|
329 |
}
|
|
330 |
}
|
|
331 |
}
|
|
332 |
|
|
333 |
@Snippet
|
48861
|
334 |
public static void g1ArrayRangePostWriteBarrier(Address address, int length, @ConstantParameter int elementStride, @ConstantParameter Register threadRegister) {
|
43972
|
335 |
if (length == 0) {
|
|
336 |
return;
|
|
337 |
}
|
|
338 |
Word thread = registerAsWord(threadRegister);
|
|
339 |
Word bufferAddress = thread.readWord(g1CardQueueBufferOffset(INJECTED_VMCONFIG));
|
|
340 |
Word indexAddress = thread.add(g1CardQueueIndexOffset(INJECTED_VMCONFIG));
|
|
341 |
long indexValue = thread.readWord(g1CardQueueIndexOffset(INJECTED_VMCONFIG)).rawValue();
|
|
342 |
|
|
343 |
int cardShift = cardTableShift(INJECTED_VMCONFIG);
|
|
344 |
final long cardStart = GraalHotSpotVMConfigNode.cardTableAddress();
|
48861
|
345 |
long start = getPointerToFirstArrayElement(address, length, elementStride) >>> cardShift;
|
|
346 |
long end = getPointerToLastArrayElement(address, length, elementStride) >>> cardShift;
|
43972
|
347 |
long count = end - start + 1;
|
|
348 |
|
|
349 |
while (count-- > 0) {
|
46459
|
350 |
Word cardAddress = WordFactory.unsigned((start + cardStart) + count);
|
43972
|
351 |
byte cardByte = cardAddress.readByte(0, GC_CARD_LOCATION);
|
|
352 |
// If the card is already dirty, (hence already enqueued) skip the insertion.
|
|
353 |
if (probability(NOT_FREQUENT_PROBABILITY, cardByte != g1YoungCardValue(INJECTED_VMCONFIG))) {
|
|
354 |
MembarNode.memoryBarrier(STORE_LOAD, GC_CARD_LOCATION);
|
|
355 |
byte cardByteReload = cardAddress.readByte(0, GC_CARD_LOCATION);
|
|
356 |
if (probability(NOT_FREQUENT_PROBABILITY, cardByteReload != dirtyCardValue(INJECTED_VMCONFIG))) {
|
|
357 |
cardAddress.writeByte(0, (byte) 0, GC_CARD_LOCATION);
|
|
358 |
// If the thread local card queue is full, issue a native call which will
|
|
359 |
// initialize a new one and add the card entry.
|
|
360 |
if (indexValue != 0) {
|
|
361 |
indexValue = indexValue - wordSize();
|
46459
|
362 |
Word logAddress = bufferAddress.add(WordFactory.unsigned(indexValue));
|
43972
|
363 |
// Log the object to be scanned as well as update
|
|
364 |
// the card queue's next index.
|
|
365 |
logAddress.writeWord(0, cardAddress, GC_LOG_LOCATION);
|
46459
|
366 |
indexAddress.writeWord(0, WordFactory.unsigned(indexValue), GC_INDEX_LOCATION);
|
43972
|
367 |
} else {
|
|
368 |
g1PostBarrierStub(G1WBPOSTCALL, cardAddress);
|
|
369 |
}
|
|
370 |
}
|
|
371 |
}
|
|
372 |
}
|
|
373 |
}
|
|
374 |
|
48861
|
375 |
private static long getPointerToFirstArrayElement(Address address, int length, int elementStride) {
|
|
376 |
long result = Word.fromAddress(address).rawValue();
|
|
377 |
if (elementStride < 0) {
|
|
378 |
// the address points to the place after the last array element
|
|
379 |
result = result + elementStride * length;
|
|
380 |
}
|
|
381 |
return result;
|
|
382 |
}
|
|
383 |
|
|
384 |
private static long getPointerToLastArrayElement(Address address, int length, int elementStride) {
|
|
385 |
long result = Word.fromAddress(address).rawValue();
|
|
386 |
if (elementStride < 0) {
|
|
387 |
// the address points to the place after the last array element
|
|
388 |
result = result + elementStride;
|
|
389 |
} else {
|
|
390 |
result = result + (length - 1) * elementStride;
|
|
391 |
}
|
|
392 |
return result;
|
|
393 |
}
|
|
394 |
|
43972
|
395 |
public static final ForeignCallDescriptor G1WBPRECALL = new ForeignCallDescriptor("write_barrier_pre", void.class, Object.class);
|
|
396 |
|
|
397 |
@NodeIntrinsic(ForeignCallNode.class)
|
|
398 |
private static native void g1PreBarrierStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Object object);
|
|
399 |
|
|
400 |
public static final ForeignCallDescriptor G1WBPOSTCALL = new ForeignCallDescriptor("write_barrier_post", void.class, Word.class);
|
|
401 |
|
|
402 |
@NodeIntrinsic(ForeignCallNode.class)
|
|
403 |
public static native void g1PostBarrierStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word card);
|
|
404 |
|
|
405 |
public static class Templates extends AbstractTemplates {
|
|
406 |
|
|
407 |
private final SnippetInfo serialImpreciseWriteBarrier = snippet(WriteBarrierSnippets.class, "serialImpreciseWriteBarrier", GC_CARD_LOCATION);
|
|
408 |
private final SnippetInfo serialPreciseWriteBarrier = snippet(WriteBarrierSnippets.class, "serialPreciseWriteBarrier", GC_CARD_LOCATION);
|
|
409 |
private final SnippetInfo serialArrayRangeWriteBarrier = snippet(WriteBarrierSnippets.class, "serialArrayRangeWriteBarrier");
|
|
410 |
private final SnippetInfo g1PreWriteBarrier = snippet(WriteBarrierSnippets.class, "g1PreWriteBarrier", GC_INDEX_LOCATION, GC_LOG_LOCATION);
|
|
411 |
private final SnippetInfo g1ReferentReadBarrier = snippet(WriteBarrierSnippets.class, "g1PreWriteBarrier", GC_INDEX_LOCATION, GC_LOG_LOCATION);
|
|
412 |
private final SnippetInfo g1PostWriteBarrier = snippet(WriteBarrierSnippets.class, "g1PostWriteBarrier", GC_CARD_LOCATION, GC_INDEX_LOCATION, GC_LOG_LOCATION);
|
|
413 |
private final SnippetInfo g1ArrayRangePreWriteBarrier = snippet(WriteBarrierSnippets.class, "g1ArrayRangePreWriteBarrier", GC_INDEX_LOCATION, GC_LOG_LOCATION);
|
|
414 |
private final SnippetInfo g1ArrayRangePostWriteBarrier = snippet(WriteBarrierSnippets.class, "g1ArrayRangePostWriteBarrier", GC_CARD_LOCATION, GC_INDEX_LOCATION, GC_LOG_LOCATION);
|
|
415 |
|
|
416 |
private final CompressEncoding oopEncoding;
|
46344
|
417 |
private final Counters counters;
|
43972
|
418 |
|
46640
|
419 |
public Templates(OptionValues options, Iterable<DebugHandlersFactory> factories, SnippetCounter.Group.Factory factory, HotSpotProviders providers, TargetDescription target,
|
|
420 |
CompressEncoding oopEncoding) {
|
|
421 |
super(options, factories, providers, providers.getSnippetReflection(), target);
|
43972
|
422 |
this.oopEncoding = oopEncoding;
|
46344
|
423 |
this.counters = new Counters(factory);
|
43972
|
424 |
}
|
|
425 |
|
|
426 |
public void lower(SerialWriteBarrier writeBarrier, LoweringTool tool) {
|
|
427 |
Arguments args;
|
|
428 |
if (writeBarrier.usePrecise()) {
|
|
429 |
args = new Arguments(serialPreciseWriteBarrier, writeBarrier.graph().getGuardsStage(), tool.getLoweringStage());
|
|
430 |
args.add("address", writeBarrier.getAddress());
|
|
431 |
} else {
|
|
432 |
args = new Arguments(serialImpreciseWriteBarrier, writeBarrier.graph().getGuardsStage(), tool.getLoweringStage());
|
|
433 |
OffsetAddressNode address = (OffsetAddressNode) writeBarrier.getAddress();
|
|
434 |
args.add("object", address.getBase());
|
|
435 |
}
|
46344
|
436 |
args.addConst("counters", counters);
|
46640
|
437 |
template(writeBarrier.getDebug(), args).instantiate(providers.getMetaAccess(), writeBarrier, DEFAULT_REPLACER, args);
|
43972
|
438 |
}
|
|
439 |
|
|
440 |
public void lower(SerialArrayRangeWriteBarrier arrayRangeWriteBarrier, LoweringTool tool) {
|
|
441 |
Arguments args = new Arguments(serialArrayRangeWriteBarrier, arrayRangeWriteBarrier.graph().getGuardsStage(), tool.getLoweringStage());
|
48861
|
442 |
args.add("address", arrayRangeWriteBarrier.getAddress());
|
43972
|
443 |
args.add("length", arrayRangeWriteBarrier.getLength());
|
48861
|
444 |
args.addConst("elementStride", arrayRangeWriteBarrier.getElementStride());
|
46640
|
445 |
template(arrayRangeWriteBarrier.getDebug(), args).instantiate(providers.getMetaAccess(), arrayRangeWriteBarrier, DEFAULT_REPLACER, args);
|
43972
|
446 |
}
|
|
447 |
|
|
448 |
public void lower(G1PreWriteBarrier writeBarrierPre, HotSpotRegistersProvider registers, LoweringTool tool) {
|
|
449 |
Arguments args = new Arguments(g1PreWriteBarrier, writeBarrierPre.graph().getGuardsStage(), tool.getLoweringStage());
|
|
450 |
AddressNode address = writeBarrierPre.getAddress();
|
|
451 |
args.add("address", address);
|
|
452 |
if (address instanceof OffsetAddressNode) {
|
|
453 |
args.add("object", ((OffsetAddressNode) address).getBase());
|
|
454 |
} else {
|
|
455 |
args.add("object", null);
|
|
456 |
}
|
|
457 |
|
|
458 |
ValueNode expected = writeBarrierPre.getExpectedObject();
|
48190
|
459 |
if (expected != null && expected.stamp(NodeView.DEFAULT) instanceof NarrowOopStamp) {
|
43972
|
460 |
assert oopEncoding != null;
|
46459
|
461 |
expected = HotSpotCompressionNode.uncompress(expected, oopEncoding);
|
43972
|
462 |
}
|
|
463 |
args.add("expectedObject", expected);
|
|
464 |
|
|
465 |
args.addConst("doLoad", writeBarrierPre.doLoad());
|
|
466 |
args.addConst("nullCheck", writeBarrierPre.getNullCheck());
|
|
467 |
args.addConst("threadRegister", registers.getThreadRegister());
|
46344
|
468 |
args.addConst("trace", traceBarrier(writeBarrierPre.graph()));
|
|
469 |
args.addConst("counters", counters);
|
46640
|
470 |
template(writeBarrierPre.getDebug(), args).instantiate(providers.getMetaAccess(), writeBarrierPre, DEFAULT_REPLACER, args);
|
43972
|
471 |
}
|
|
472 |
|
|
473 |
public void lower(G1ReferentFieldReadBarrier readBarrier, HotSpotRegistersProvider registers, LoweringTool tool) {
|
|
474 |
Arguments args = new Arguments(g1ReferentReadBarrier, readBarrier.graph().getGuardsStage(), tool.getLoweringStage());
|
|
475 |
AddressNode address = readBarrier.getAddress();
|
|
476 |
args.add("address", address);
|
|
477 |
if (address instanceof OffsetAddressNode) {
|
|
478 |
args.add("object", ((OffsetAddressNode) address).getBase());
|
|
479 |
} else {
|
|
480 |
args.add("object", null);
|
|
481 |
}
|
|
482 |
|
|
483 |
ValueNode expected = readBarrier.getExpectedObject();
|
48190
|
484 |
if (expected != null && expected.stamp(NodeView.DEFAULT) instanceof NarrowOopStamp) {
|
43972
|
485 |
assert oopEncoding != null;
|
46459
|
486 |
expected = HotSpotCompressionNode.uncompress(expected, oopEncoding);
|
43972
|
487 |
}
|
|
488 |
|
|
489 |
args.add("expectedObject", expected);
|
|
490 |
args.addConst("doLoad", readBarrier.doLoad());
|
|
491 |
args.addConst("nullCheck", false);
|
|
492 |
args.addConst("threadRegister", registers.getThreadRegister());
|
46344
|
493 |
args.addConst("trace", traceBarrier(readBarrier.graph()));
|
|
494 |
args.addConst("counters", counters);
|
46640
|
495 |
template(readBarrier.getDebug(), args).instantiate(providers.getMetaAccess(), readBarrier, DEFAULT_REPLACER, args);
|
43972
|
496 |
}
|
|
497 |
|
|
498 |
public void lower(G1PostWriteBarrier writeBarrierPost, HotSpotRegistersProvider registers, LoweringTool tool) {
|
|
499 |
StructuredGraph graph = writeBarrierPost.graph();
|
|
500 |
if (writeBarrierPost.alwaysNull()) {
|
|
501 |
graph.removeFixed(writeBarrierPost);
|
|
502 |
return;
|
|
503 |
}
|
|
504 |
Arguments args = new Arguments(g1PostWriteBarrier, graph.getGuardsStage(), tool.getLoweringStage());
|
|
505 |
AddressNode address = writeBarrierPost.getAddress();
|
|
506 |
args.add("address", address);
|
|
507 |
if (address instanceof OffsetAddressNode) {
|
|
508 |
args.add("object", ((OffsetAddressNode) address).getBase());
|
|
509 |
} else {
|
|
510 |
assert writeBarrierPost.usePrecise() : "found imprecise barrier that's not an object access " + writeBarrierPost;
|
|
511 |
args.add("object", null);
|
|
512 |
}
|
|
513 |
|
|
514 |
ValueNode value = writeBarrierPost.getValue();
|
48190
|
515 |
if (value.stamp(NodeView.DEFAULT) instanceof NarrowOopStamp) {
|
43972
|
516 |
assert oopEncoding != null;
|
46459
|
517 |
value = HotSpotCompressionNode.uncompress(value, oopEncoding);
|
43972
|
518 |
}
|
|
519 |
args.add("value", value);
|
|
520 |
|
|
521 |
args.addConst("usePrecise", writeBarrierPost.usePrecise());
|
|
522 |
args.addConst("threadRegister", registers.getThreadRegister());
|
46344
|
523 |
args.addConst("trace", traceBarrier(writeBarrierPost.graph()));
|
|
524 |
args.addConst("counters", counters);
|
46640
|
525 |
template(graph.getDebug(), args).instantiate(providers.getMetaAccess(), writeBarrierPost, DEFAULT_REPLACER, args);
|
43972
|
526 |
}
|
|
527 |
|
|
528 |
public void lower(G1ArrayRangePreWriteBarrier arrayRangeWriteBarrier, HotSpotRegistersProvider registers, LoweringTool tool) {
|
|
529 |
Arguments args = new Arguments(g1ArrayRangePreWriteBarrier, arrayRangeWriteBarrier.graph().getGuardsStage(), tool.getLoweringStage());
|
48861
|
530 |
args.add("address", arrayRangeWriteBarrier.getAddress());
|
43972
|
531 |
args.add("length", arrayRangeWriteBarrier.getLength());
|
48861
|
532 |
args.addConst("elementStride", arrayRangeWriteBarrier.getElementStride());
|
43972
|
533 |
args.addConst("threadRegister", registers.getThreadRegister());
|
46640
|
534 |
template(arrayRangeWriteBarrier.getDebug(), args).instantiate(providers.getMetaAccess(), arrayRangeWriteBarrier, DEFAULT_REPLACER, args);
|
43972
|
535 |
}
|
|
536 |
|
|
537 |
public void lower(G1ArrayRangePostWriteBarrier arrayRangeWriteBarrier, HotSpotRegistersProvider registers, LoweringTool tool) {
|
|
538 |
Arguments args = new Arguments(g1ArrayRangePostWriteBarrier, arrayRangeWriteBarrier.graph().getGuardsStage(), tool.getLoweringStage());
|
48861
|
539 |
args.add("address", arrayRangeWriteBarrier.getAddress());
|
43972
|
540 |
args.add("length", arrayRangeWriteBarrier.getLength());
|
48861
|
541 |
args.addConst("elementStride", arrayRangeWriteBarrier.getElementStride());
|
43972
|
542 |
args.addConst("threadRegister", registers.getThreadRegister());
|
46640
|
543 |
template(arrayRangeWriteBarrier.getDebug(), args).instantiate(providers.getMetaAccess(), arrayRangeWriteBarrier, DEFAULT_REPLACER, args);
|
43972
|
544 |
}
|
|
545 |
}
|
|
546 |
|
|
547 |
/**
|
|
548 |
* Log method of debugging purposes.
|
|
549 |
*/
|
|
550 |
public static void log(boolean enabled, String format, long value) {
|
|
551 |
if (enabled) {
|
|
552 |
Log.printf(format, value);
|
|
553 |
}
|
|
554 |
}
|
|
555 |
|
|
556 |
public static void log(boolean enabled, String format, long value1, long value2) {
|
|
557 |
if (enabled) {
|
|
558 |
Log.printf(format, value1, value2);
|
|
559 |
}
|
|
560 |
}
|
|
561 |
|
|
562 |
public static void log(boolean enabled, String format, long value1, long value2, long value3) {
|
|
563 |
if (enabled) {
|
|
564 |
Log.printf(format, value1, value2, value3);
|
|
565 |
}
|
|
566 |
}
|
|
567 |
|
46344
|
568 |
public static boolean traceBarrier(StructuredGraph graph) {
|
|
569 |
return GraalOptions.GCDebugStartCycle.getValue(graph.getOptions()) > 0 &&
|
46459
|
570 |
((int) ((Pointer) WordFactory.pointer(HotSpotReplacementsUtil.gcTotalCollectionsAddress(INJECTED_VMCONFIG))).readLong(0) > GraalOptions.GCDebugStartCycle.getValue(
|
|
571 |
graph.getOptions()));
|
43972
|
572 |
}
|
|
573 |
|
|
574 |
/**
|
|
575 |
* Validation helper method which performs sanity checks on write operations. The addresses of
|
|
576 |
* both the object and the value being written are checked in order to determine if they reside
|
|
577 |
* in a valid heap region. If an object is stale, an invalid access is performed in order to
|
|
578 |
* prematurely crash the VM and debug the stack trace of the faulty method.
|
|
579 |
*/
|
|
580 |
public static void validateObject(Object parent, Object child) {
|
|
581 |
if (verifyOops(INJECTED_VMCONFIG) && child != null && !validateOop(VALIDATE_OBJECT, parent, child)) {
|
|
582 |
log(true, "Verification ERROR, Parent: %p Child: %p\n", Word.objectToTrackedPointer(parent).rawValue(), Word.objectToTrackedPointer(child).rawValue());
|
46344
|
583 |
VMErrorNode.vmError("Verification ERROR, Parent: %p\n", Word.objectToTrackedPointer(parent).rawValue());
|
43972
|
584 |
}
|
|
585 |
}
|
|
586 |
|
|
587 |
public static final ForeignCallDescriptor VALIDATE_OBJECT = new ForeignCallDescriptor("validate_object", boolean.class, Word.class, Word.class);
|
|
588 |
|
|
589 |
@NodeIntrinsic(ForeignCallNode.class)
|
|
590 |
private static native boolean validateOop(@ConstantNodeParameter ForeignCallDescriptor descriptor, Object parent, Object object);
|
|
591 |
|
|
592 |
}
|