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.virtual.phases.ea;
24
25 import static org.graalvm.compiler.core.common.GraalOptions.ReadEliminationMaxLoopVisits;
26 import static org.graalvm.compiler.nodes.NamedLocationIdentity.ARRAY_LENGTH_LOCATION;
27
28 import java.util.EnumMap;
29 import java.util.Iterator;
30 import java.util.List;
31
32 import org.graalvm.compiler.core.common.cfg.Loop;
33 import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
34 import org.graalvm.compiler.graph.Node;
35 import org.graalvm.compiler.nodes.AbstractBeginNode;
36 import org.graalvm.compiler.nodes.FieldLocationIdentity;
37 import org.graalvm.compiler.nodes.FixedNode;
38 import org.graalvm.compiler.nodes.FixedWithNextNode;
39 import org.graalvm.compiler.nodes.LoopBeginNode;
40 import org.graalvm.compiler.nodes.LoopExitNode;
41 import org.graalvm.compiler.nodes.NamedLocationIdentity;
42 import org.graalvm.compiler.nodes.PhiNode;
43 import org.graalvm.compiler.nodes.ProxyNode;
44 import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult;
45 import org.graalvm.compiler.nodes.ValueNode;
46 import org.graalvm.compiler.nodes.ValueProxyNode;
47 import org.graalvm.compiler.nodes.cfg.Block;
48 import org.graalvm.compiler.nodes.extended.RawLoadNode;
49 import org.graalvm.compiler.nodes.extended.RawStoreNode;
50 import org.graalvm.compiler.nodes.extended.UnboxNode;
51 import org.graalvm.compiler.nodes.java.ArrayLengthNode;
52 import org.graalvm.compiler.nodes.java.LoadFieldNode;
53 import org.graalvm.compiler.nodes.java.LoadIndexedNode;
113 } else if (node instanceof UnboxNode) {
114 return processUnbox((UnboxNode) node, state, effects);
115 } else if (node instanceof RawLoadNode) {
116 return processUnsafeLoad((RawLoadNode) node, state, effects);
117 } else if (node instanceof RawStoreNode) {
118 return processUnsafeStore((RawStoreNode) node, state, effects);
119 } else if (node instanceof MemoryCheckpoint.Single) {
120 COUNTER_MEMORYCHECKPOINT.increment(node.getDebug());
121 LocationIdentity identity = ((MemoryCheckpoint.Single) node).getLocationIdentity();
122 processIdentity(state, identity);
123 } else if (node instanceof MemoryCheckpoint.Multi) {
124 COUNTER_MEMORYCHECKPOINT.increment(node.getDebug());
125 for (LocationIdentity identity : ((MemoryCheckpoint.Multi) node).getLocationIdentities()) {
126 processIdentity(state, identity);
127 }
128 }
129
130 return false;
131 }
132
133 private boolean processStore(FixedNode store, ValueNode object, LocationIdentity identity, int index, ValueNode value, PEReadEliminationBlockState state, GraphEffectList effects) {
134 ValueNode unproxiedObject = GraphUtil.unproxify(object);
135 ValueNode cachedValue = state.getReadCache(object, identity, index, this);
136
137 ValueNode finalValue = getScalarAlias(value);
138 boolean result = false;
139 if (GraphUtil.unproxify(finalValue) == GraphUtil.unproxify(cachedValue)) {
140 effects.deleteNode(store);
141 result = true;
142 }
143 state.killReadCache(identity, index);
144 state.addReadCache(unproxiedObject, identity, index, finalValue, this);
145 return result;
146 }
147
148 private boolean processLoad(FixedNode load, ValueNode object, LocationIdentity identity, int index, PEReadEliminationBlockState state, GraphEffectList effects) {
149 ValueNode unproxiedObject = GraphUtil.unproxify(object);
150 ValueNode cachedValue = state.getReadCache(unproxiedObject, identity, index, this);
151 if (cachedValue != null) {
152 if (!load.stamp().isCompatible(cachedValue.stamp())) {
153 /*
154 * Can either be the first field of a two slot write to a one slot field which would
155 * have a non compatible stamp or the second load which will see Illegal.
156 */
157 assert load.stamp().getStackKind() == JavaKind.Int && (cachedValue.stamp().getStackKind() == JavaKind.Long || cachedValue.getStackKind() == JavaKind.Double ||
158 cachedValue.getStackKind() == JavaKind.Illegal) : "Can only allow different stack kind two slot marker writes on one slot fields.";
159 return false;
160 } else {
161 // perform the read elimination
162 effects.replaceAtUsages(load, cachedValue, load);
163 addScalarAlias(load, cachedValue);
164 return true;
165 }
166 } else {
167 state.addReadCache(unproxiedObject, identity, index, load, this);
168 return false;
169 }
170 }
171
172 private boolean processUnsafeLoad(RawLoadNode load, PEReadEliminationBlockState state, GraphEffectList effects) {
173 if (load.offset().isConstant()) {
174 ResolvedJavaType type = StampTool.typeOrNull(load.object());
175 if (type != null && type.isArray()) {
176 long offset = load.offset().asJavaConstant().asLong();
177 int index = VirtualArrayNode.entryIndexForOffset(offset, load.accessKind(), type.getComponentType(), Integer.MAX_VALUE);
178 ValueNode object = GraphUtil.unproxify(load.object());
179 LocationIdentity location = NamedLocationIdentity.getArrayLocation(type.getComponentType().getJavaKind());
180 ValueNode cachedValue = state.getReadCache(object, location, index, this);
181 if (cachedValue != null && load.stamp().isCompatible(cachedValue.stamp())) {
182 effects.replaceAtUsages(load, cachedValue, load);
183 addScalarAlias(load, cachedValue);
184 return true;
185 } else {
186 state.addReadCache(object, location, index, load, this);
187 }
188 }
189 }
190 return false;
191 }
192
193 private boolean processUnsafeStore(RawStoreNode store, PEReadEliminationBlockState state, GraphEffectList effects) {
194 ResolvedJavaType type = StampTool.typeOrNull(store.object());
195 if (type != null && type.isArray()) {
196 LocationIdentity location = NamedLocationIdentity.getArrayLocation(type.getComponentType().getJavaKind());
197 if (store.offset().isConstant()) {
198 long offset = store.offset().asJavaConstant().asLong();
199 int index = VirtualArrayNode.entryIndexForOffset(offset, store.accessKind(), type.getComponentType(), Integer.MAX_VALUE);
200 return processStore(store, store.object(), location, index, store.value(), state, effects);
201 } else {
202 processIdentity(state, location);
203 }
204 } else {
205 state.killReadCache();
206 }
207 return false;
208 }
209
210 private boolean processArrayLength(ArrayLengthNode length, PEReadEliminationBlockState state, GraphEffectList effects) {
211 return processLoad(length, length.array(), ARRAY_LENGTH_LOCATION, -1, state, effects);
212 }
213
214 private boolean processStoreField(StoreFieldNode store, PEReadEliminationBlockState state, GraphEffectList effects) {
215 if (store.isVolatile()) {
216 state.killReadCache();
217 return false;
218 }
219 return processStore(store, store.object(), new FieldLocationIdentity(store.field()), -1, store.value(), state, effects);
220 }
221
222 private boolean processLoadField(LoadFieldNode load, PEReadEliminationBlockState state, GraphEffectList effects) {
223 if (load.isVolatile()) {
224 state.killReadCache();
225 return false;
226 }
227 return processLoad(load, load.object(), new FieldLocationIdentity(load.field()), -1, state, effects);
228 }
229
230 private boolean processStoreIndexed(StoreIndexedNode store, PEReadEliminationBlockState state, GraphEffectList effects) {
231 LocationIdentity arrayLocation = NamedLocationIdentity.getArrayLocation(store.elementKind());
232 if (store.index().isConstant()) {
233 int index = ((JavaConstant) store.index().asConstant()).asInt();
234 return processStore(store, store.array(), arrayLocation, index, store.value(), state, effects);
235 } else {
236 state.killReadCache(arrayLocation, -1);
237 }
238 return false;
239 }
240
241 private boolean processLoadIndexed(LoadIndexedNode load, PEReadEliminationBlockState state, GraphEffectList effects) {
242 if (load.index().isConstant()) {
243 int index = ((JavaConstant) load.index().asConstant()).asInt();
244 LocationIdentity arrayLocation = NamedLocationIdentity.getArrayLocation(load.elementKind());
245 return processLoad(load, load.array(), arrayLocation, index, state, effects);
246 }
247 return false;
248 }
249
250 private boolean processUnbox(UnboxNode unbox, PEReadEliminationBlockState state, GraphEffectList effects) {
251 return processLoad(unbox, unbox.getValue(), UNBOX_LOCATIONS.get(unbox.getBoxingKind()), -1, state, effects);
252 }
253
254 private static void processIdentity(PEReadEliminationBlockState state, LocationIdentity identity) {
255 if (identity.isAny()) {
256 state.killReadCache();
257 } else {
258 state.killReadCache(identity, -1);
259 }
260 }
261
262 @SuppressWarnings("unchecked")
263 @Override
264 protected void processInitialLoopState(Loop<Block> loop, PEReadEliminationBlockState initialState) {
265 super.processInitialLoopState(loop, initialState);
266
267 if (!initialState.getReadCache().isEmpty()) {
268 EconomicMap<ValueNode, Pair<ValueNode, Object>> firstValueSet = null;
269 for (PhiNode phi : ((LoopBeginNode) loop.getHeader().getBeginNode()).phis()) {
270 ValueNode firstValue = phi.valueAt(0);
271 if (firstValue != null && phi.getStackKind().isObject()) {
273 if (firstValueSet == null) {
274 firstValueSet = EconomicMap.create(Equivalence.IDENTITY_WITH_SYSTEM_HASHCODE);
275 }
276 Pair<ValueNode, Object> pair = Pair.create(unproxified, firstValueSet.get(unproxified));
277 firstValueSet.put(unproxified, pair);
278 }
279 }
280
281 if (firstValueSet != null) {
282 ReadCacheEntry[] entries = new ReadCacheEntry[initialState.getReadCache().size()];
283 int z = 0;
284 for (ReadCacheEntry entry : initialState.getReadCache().getKeys()) {
285 entries[z++] = entry;
286 }
287
288 for (ReadCacheEntry entry : entries) {
289 ValueNode object = entry.object;
290 if (object != null) {
291 Pair<ValueNode, Object> pair = firstValueSet.get(object);
292 while (pair != null) {
293 initialState.addReadCache(pair.getLeft(), entry.identity, entry.index, initialState.getReadCache().get(entry), this);
294 pair = (Pair<ValueNode, Object>) pair.getRight();
295 }
296 }
297 }
298 }
299 }
300 }
301
302 @Override
303 protected void processLoopExit(LoopExitNode exitNode, PEReadEliminationBlockState initialState, PEReadEliminationBlockState exitState, GraphEffectList effects) {
304 super.processLoopExit(exitNode, initialState, exitState, effects);
305
306 if (exitNode.graph().hasValueProxies()) {
307 MapCursor<ReadCacheEntry, ValueNode> entry = exitState.getReadCache().getEntries();
308 while (entry.advance()) {
309 if (initialState.getReadCache().get(entry.getKey()) != entry.getValue()) {
310 ValueNode value = exitState.getReadCache(entry.getKey().object, entry.getKey().identity, entry.getKey().index, this);
311 assert value != null : "Got null from read cache, entry's value:" + entry.getValue();
312 if (!(value instanceof ProxyNode) || ((ProxyNode) value).proxyPoint() != exitNode) {
313 ProxyNode proxy = new ValueProxyNode(value, exitNode);
314 effects.addFloatingNode(proxy, "readCacheProxy");
315 exitState.getReadCache().put(entry.getKey(), proxy);
316 }
317 }
318 }
319 }
320 }
321
322 @Override
323 protected PEReadEliminationBlockState cloneState(PEReadEliminationBlockState other) {
324 return new PEReadEliminationBlockState(other);
325 }
326
327 @Override
328 protected MergeProcessor createMergeProcessor(Block merge) {
329 return new ReadEliminationMergeProcessor(merge);
330 }
349 ValueNode value = cursor.getValue();
350 boolean phi = false;
351 for (int i = 1; i < states.size(); i++) {
352 ValueNode otherValue = states.get(i).readCache.get(key);
353 // e.g. unsafe loads / stores with different access kinds have different stamps
354 // although location, object and offset are the same, in this case we cannot
355 // create a phi nor can we set a common value
356 if (otherValue == null || !value.stamp().isCompatible(otherValue.stamp())) {
357 value = null;
358 phi = false;
359 break;
360 }
361 if (!phi && otherValue != value) {
362 phi = true;
363 }
364 }
365 if (phi) {
366 PhiNode phiNode = getPhi(key, value.stamp().unrestricted());
367 mergeEffects.addFloatingNode(phiNode, "mergeReadCache");
368 for (int i = 0; i < states.size(); i++) {
369 ValueNode v = states.get(i).getReadCache(key.object, key.identity, key.index, PEReadEliminationClosure.this);
370 assert phiNode.stamp().isCompatible(v.stamp()) : "Cannot create read elimination phi for inputs with incompatible stamps.";
371 setPhiInput(phiNode, i, v);
372 }
373 newState.readCache.put(key, phiNode);
374 } else if (value != null) {
375 newState.readCache.put(key, value);
376 }
377 }
378 /*
379 * For object phis, see if there are known reads on all predecessors, for which we could
380 * create new phis.
381 */
382 for (PhiNode phi : getPhis()) {
383 if (phi.getStackKind() == JavaKind.Object) {
384 for (ReadCacheEntry entry : states.get(0).readCache.getKeys()) {
385 if (entry.object == getPhiValueAt(phi, 0)) {
386 mergeReadCachePhi(phi, entry.identity, entry.index, states);
387 }
388 }
389 }
390 }
391 }
392
393 private void mergeReadCachePhi(PhiNode phi, LocationIdentity identity, int index, List<PEReadEliminationBlockState> states) {
394 ValueNode[] values = new ValueNode[states.size()];
395 values[0] = states.get(0).getReadCache(getPhiValueAt(phi, 0), identity, index, PEReadEliminationClosure.this);
396 if (values[0] != null) {
397 for (int i = 1; i < states.size(); i++) {
398 ValueNode value = states.get(i).getReadCache(getPhiValueAt(phi, i), identity, index, PEReadEliminationClosure.this);
399 // e.g. unsafe loads / stores with same identity and different access kinds see
400 // mergeReadCache(states)
401 if (value == null || !values[i - 1].stamp().isCompatible(value.stamp())) {
402 return;
403 }
404 values[i] = value;
405 }
406
407 PhiNode phiNode = getPhi(new ReadCacheEntry(identity, phi, index), values[0].stamp().unrestricted());
408 mergeEffects.addFloatingNode(phiNode, "mergeReadCachePhi");
409 for (int i = 0; i < values.length; i++) {
410 setPhiInput(phiNode, i, values[i]);
411 }
412 newState.readCache.put(new ReadCacheEntry(identity, phi, index), phiNode);
413 }
414 }
415 }
416
417 @Override
418 protected void processKilledLoopLocations(Loop<Block> loop, PEReadEliminationBlockState initialState, PEReadEliminationBlockState mergedStates) {
419 assert initialState != null;
420 assert mergedStates != null;
421 if (initialState.readCache.size() > 0) {
422 LoopKillCache loopKilledLocations = loopLocationKillCache.get(loop);
423 // we have fully processed this loop the first time, remember to cache it the next time
424 // it is visited
425 if (loopKilledLocations == null) {
426 loopKilledLocations = new LoopKillCache(1/* 1.visit */);
427 loopLocationKillCache.put(loop, loopKilledLocations);
428 } else {
429 AbstractBeginNode beginNode = loop.getHeader().getBeginNode();
430 OptionValues options = beginNode.getOptions();
431 if (loopKilledLocations.visits() > ReadEliminationMaxLoopVisits.getValue(options)) {
432 // we have processed the loop too many times, kill all locations so the inner
|
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.virtual.phases.ea;
24
25 import static org.graalvm.compiler.core.common.GraalOptions.ReadEliminationMaxLoopVisits;
26 import static org.graalvm.compiler.nodes.NamedLocationIdentity.ARRAY_LENGTH_LOCATION;
27
28 import java.util.EnumMap;
29 import java.util.Iterator;
30 import java.util.List;
31
32 import org.graalvm.compiler.core.common.cfg.Loop;
33 import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
34 import org.graalvm.compiler.core.common.type.Stamp;
35 import org.graalvm.compiler.graph.Node;
36 import org.graalvm.compiler.nodes.AbstractBeginNode;
37 import org.graalvm.compiler.nodes.FieldLocationIdentity;
38 import org.graalvm.compiler.nodes.FixedNode;
39 import org.graalvm.compiler.nodes.FixedWithNextNode;
40 import org.graalvm.compiler.nodes.LoopBeginNode;
41 import org.graalvm.compiler.nodes.LoopExitNode;
42 import org.graalvm.compiler.nodes.NamedLocationIdentity;
43 import org.graalvm.compiler.nodes.PhiNode;
44 import org.graalvm.compiler.nodes.ProxyNode;
45 import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult;
46 import org.graalvm.compiler.nodes.ValueNode;
47 import org.graalvm.compiler.nodes.ValueProxyNode;
48 import org.graalvm.compiler.nodes.cfg.Block;
49 import org.graalvm.compiler.nodes.extended.RawLoadNode;
50 import org.graalvm.compiler.nodes.extended.RawStoreNode;
51 import org.graalvm.compiler.nodes.extended.UnboxNode;
52 import org.graalvm.compiler.nodes.java.ArrayLengthNode;
53 import org.graalvm.compiler.nodes.java.LoadFieldNode;
54 import org.graalvm.compiler.nodes.java.LoadIndexedNode;
114 } else if (node instanceof UnboxNode) {
115 return processUnbox((UnboxNode) node, state, effects);
116 } else if (node instanceof RawLoadNode) {
117 return processUnsafeLoad((RawLoadNode) node, state, effects);
118 } else if (node instanceof RawStoreNode) {
119 return processUnsafeStore((RawStoreNode) node, state, effects);
120 } else if (node instanceof MemoryCheckpoint.Single) {
121 COUNTER_MEMORYCHECKPOINT.increment(node.getDebug());
122 LocationIdentity identity = ((MemoryCheckpoint.Single) node).getLocationIdentity();
123 processIdentity(state, identity);
124 } else if (node instanceof MemoryCheckpoint.Multi) {
125 COUNTER_MEMORYCHECKPOINT.increment(node.getDebug());
126 for (LocationIdentity identity : ((MemoryCheckpoint.Multi) node).getLocationIdentities()) {
127 processIdentity(state, identity);
128 }
129 }
130
131 return false;
132 }
133
134 private boolean processStore(FixedNode store, ValueNode object, LocationIdentity identity, int index, JavaKind kind, ValueNode value, PEReadEliminationBlockState state, GraphEffectList effects) {
135 ValueNode unproxiedObject = GraphUtil.unproxify(object);
136 ValueNode cachedValue = state.getReadCache(object, identity, index, kind, this);
137
138 ValueNode finalValue = getScalarAlias(value);
139 boolean result = false;
140 if (GraphUtil.unproxify(finalValue) == GraphUtil.unproxify(cachedValue)) {
141 effects.deleteNode(store);
142 result = true;
143 }
144 state.killReadCache(identity, index);
145 state.addReadCache(unproxiedObject, identity, index, kind, finalValue, this);
146 return result;
147 }
148
149 private boolean processLoad(FixedNode load, ValueNode object, LocationIdentity identity, int index, JavaKind kind, PEReadEliminationBlockState state, GraphEffectList effects) {
150 ValueNode unproxiedObject = GraphUtil.unproxify(object);
151 ValueNode cachedValue = state.getReadCache(unproxiedObject, identity, index, kind, this);
152 if (cachedValue != null) {
153 Stamp loadStamp = load.stamp();
154 Stamp cachedValueStamp = cachedValue.stamp();
155 if (!loadStamp.isCompatible(cachedValueStamp)) {
156 /*
157 * Can either be the first field of a two slot write to a one slot field which would
158 * have a non compatible stamp or the second load which will see Illegal.
159 */
160 assert load.stamp().getStackKind() == JavaKind.Int && (cachedValue.stamp().getStackKind() == JavaKind.Long || cachedValue.getStackKind() == JavaKind.Double ||
161 cachedValue.getStackKind() == JavaKind.Illegal) : "Can only allow different stack kind two slot marker writes on one slot fields.";
162 return false;
163 } else {
164 // perform the read elimination
165 effects.replaceAtUsages(load, cachedValue, load);
166 addScalarAlias(load, cachedValue);
167 return true;
168 }
169 } else {
170 state.addReadCache(unproxiedObject, identity, index, kind, load, this);
171 return false;
172 }
173 }
174
175 private boolean processUnsafeLoad(RawLoadNode load, PEReadEliminationBlockState state, GraphEffectList effects) {
176 if (load.offset().isConstant()) {
177 ResolvedJavaType type = StampTool.typeOrNull(load.object());
178 if (type != null && type.isArray()) {
179 long offset = load.offset().asJavaConstant().asLong();
180 int index = VirtualArrayNode.entryIndexForOffset(offset, load.accessKind(), type.getComponentType(), Integer.MAX_VALUE);
181 ValueNode object = GraphUtil.unproxify(load.object());
182 LocationIdentity location = NamedLocationIdentity.getArrayLocation(type.getComponentType().getJavaKind());
183 ValueNode cachedValue = state.getReadCache(object, location, index, load.accessKind(), this);
184 if (cachedValue != null && load.stamp().isCompatible(cachedValue.stamp())) {
185 effects.replaceAtUsages(load, cachedValue, load);
186 addScalarAlias(load, cachedValue);
187 return true;
188 } else {
189 state.addReadCache(object, location, index, load.accessKind(), load, this);
190 }
191 }
192 }
193 return false;
194 }
195
196 private boolean processUnsafeStore(RawStoreNode store, PEReadEliminationBlockState state, GraphEffectList effects) {
197 ResolvedJavaType type = StampTool.typeOrNull(store.object());
198 if (type != null && type.isArray()) {
199 LocationIdentity location = NamedLocationIdentity.getArrayLocation(type.getComponentType().getJavaKind());
200 if (store.offset().isConstant()) {
201 long offset = store.offset().asJavaConstant().asLong();
202 int index = VirtualArrayNode.entryIndexForOffset(offset, store.accessKind(), type.getComponentType(), Integer.MAX_VALUE);
203 return processStore(store, store.object(), location, index, store.accessKind(), store.value(), state, effects);
204 } else {
205 processIdentity(state, location);
206 }
207 } else {
208 state.killReadCache();
209 }
210 return false;
211 }
212
213 private boolean processArrayLength(ArrayLengthNode length, PEReadEliminationBlockState state, GraphEffectList effects) {
214 return processLoad(length, length.array(), ARRAY_LENGTH_LOCATION, -1, JavaKind.Int, state, effects);
215 }
216
217 private boolean processStoreField(StoreFieldNode store, PEReadEliminationBlockState state, GraphEffectList effects) {
218 if (store.isVolatile()) {
219 state.killReadCache();
220 return false;
221 }
222 return processStore(store, store.object(), new FieldLocationIdentity(store.field()), -1, store.field().getJavaKind(), store.value(), state, effects);
223 }
224
225 private boolean processLoadField(LoadFieldNode load, PEReadEliminationBlockState state, GraphEffectList effects) {
226 if (load.isVolatile()) {
227 state.killReadCache();
228 return false;
229 }
230 return processLoad(load, load.object(), new FieldLocationIdentity(load.field()), -1, load.field().getJavaKind(), state, effects);
231 }
232
233 private boolean processStoreIndexed(StoreIndexedNode store, PEReadEliminationBlockState state, GraphEffectList effects) {
234 LocationIdentity arrayLocation = NamedLocationIdentity.getArrayLocation(store.elementKind());
235 if (store.index().isConstant()) {
236 int index = ((JavaConstant) store.index().asConstant()).asInt();
237 return processStore(store, store.array(), arrayLocation, index, store.elementKind(), store.value(), state, effects);
238 } else {
239 state.killReadCache(arrayLocation, -1);
240 }
241 return false;
242 }
243
244 private boolean processLoadIndexed(LoadIndexedNode load, PEReadEliminationBlockState state, GraphEffectList effects) {
245 if (load.index().isConstant()) {
246 int index = ((JavaConstant) load.index().asConstant()).asInt();
247 LocationIdentity arrayLocation = NamedLocationIdentity.getArrayLocation(load.elementKind());
248 return processLoad(load, load.array(), arrayLocation, index, load.elementKind(), state, effects);
249 }
250 return false;
251 }
252
253 private boolean processUnbox(UnboxNode unbox, PEReadEliminationBlockState state, GraphEffectList effects) {
254 return processLoad(unbox, unbox.getValue(), UNBOX_LOCATIONS.get(unbox.getBoxingKind()), -1, unbox.getBoxingKind(), state, effects);
255 }
256
257 private static void processIdentity(PEReadEliminationBlockState state, LocationIdentity identity) {
258 if (identity.isAny()) {
259 state.killReadCache();
260 } else {
261 state.killReadCache(identity, -1);
262 }
263 }
264
265 @SuppressWarnings("unchecked")
266 @Override
267 protected void processInitialLoopState(Loop<Block> loop, PEReadEliminationBlockState initialState) {
268 super.processInitialLoopState(loop, initialState);
269
270 if (!initialState.getReadCache().isEmpty()) {
271 EconomicMap<ValueNode, Pair<ValueNode, Object>> firstValueSet = null;
272 for (PhiNode phi : ((LoopBeginNode) loop.getHeader().getBeginNode()).phis()) {
273 ValueNode firstValue = phi.valueAt(0);
274 if (firstValue != null && phi.getStackKind().isObject()) {
276 if (firstValueSet == null) {
277 firstValueSet = EconomicMap.create(Equivalence.IDENTITY_WITH_SYSTEM_HASHCODE);
278 }
279 Pair<ValueNode, Object> pair = Pair.create(unproxified, firstValueSet.get(unproxified));
280 firstValueSet.put(unproxified, pair);
281 }
282 }
283
284 if (firstValueSet != null) {
285 ReadCacheEntry[] entries = new ReadCacheEntry[initialState.getReadCache().size()];
286 int z = 0;
287 for (ReadCacheEntry entry : initialState.getReadCache().getKeys()) {
288 entries[z++] = entry;
289 }
290
291 for (ReadCacheEntry entry : entries) {
292 ValueNode object = entry.object;
293 if (object != null) {
294 Pair<ValueNode, Object> pair = firstValueSet.get(object);
295 while (pair != null) {
296 initialState.addReadCache(pair.getLeft(), entry.identity, entry.index, entry.kind, initialState.getReadCache().get(entry), this);
297 pair = (Pair<ValueNode, Object>) pair.getRight();
298 }
299 }
300 }
301 }
302 }
303 }
304
305 @Override
306 protected void processLoopExit(LoopExitNode exitNode, PEReadEliminationBlockState initialState, PEReadEliminationBlockState exitState, GraphEffectList effects) {
307 super.processLoopExit(exitNode, initialState, exitState, effects);
308
309 if (exitNode.graph().hasValueProxies()) {
310 MapCursor<ReadCacheEntry, ValueNode> entry = exitState.getReadCache().getEntries();
311 while (entry.advance()) {
312 if (initialState.getReadCache().get(entry.getKey()) != entry.getValue()) {
313 ValueNode value = exitState.getReadCache(entry.getKey().object, entry.getKey().identity, entry.getKey().index, entry.getKey().kind, this);
314 assert value != null : "Got null from read cache, entry's value:" + entry.getValue();
315 if (!(value instanceof ProxyNode) || ((ProxyNode) value).proxyPoint() != exitNode) {
316 ProxyNode proxy = new ValueProxyNode(value, exitNode);
317 effects.addFloatingNode(proxy, "readCacheProxy");
318 exitState.getReadCache().put(entry.getKey(), proxy);
319 }
320 }
321 }
322 }
323 }
324
325 @Override
326 protected PEReadEliminationBlockState cloneState(PEReadEliminationBlockState other) {
327 return new PEReadEliminationBlockState(other);
328 }
329
330 @Override
331 protected MergeProcessor createMergeProcessor(Block merge) {
332 return new ReadEliminationMergeProcessor(merge);
333 }
352 ValueNode value = cursor.getValue();
353 boolean phi = false;
354 for (int i = 1; i < states.size(); i++) {
355 ValueNode otherValue = states.get(i).readCache.get(key);
356 // e.g. unsafe loads / stores with different access kinds have different stamps
357 // although location, object and offset are the same, in this case we cannot
358 // create a phi nor can we set a common value
359 if (otherValue == null || !value.stamp().isCompatible(otherValue.stamp())) {
360 value = null;
361 phi = false;
362 break;
363 }
364 if (!phi && otherValue != value) {
365 phi = true;
366 }
367 }
368 if (phi) {
369 PhiNode phiNode = getPhi(key, value.stamp().unrestricted());
370 mergeEffects.addFloatingNode(phiNode, "mergeReadCache");
371 for (int i = 0; i < states.size(); i++) {
372 ValueNode v = states.get(i).getReadCache(key.object, key.identity, key.index, key.kind, PEReadEliminationClosure.this);
373 assert phiNode.stamp().isCompatible(v.stamp()) : "Cannot create read elimination phi for inputs with incompatible stamps.";
374 setPhiInput(phiNode, i, v);
375 }
376 newState.readCache.put(key, phiNode);
377 } else if (value != null) {
378 newState.readCache.put(key, value);
379 }
380 }
381 /*
382 * For object phis, see if there are known reads on all predecessors, for which we could
383 * create new phis.
384 */
385 for (PhiNode phi : getPhis()) {
386 if (phi.getStackKind() == JavaKind.Object) {
387 for (ReadCacheEntry entry : states.get(0).readCache.getKeys()) {
388 if (entry.object == getPhiValueAt(phi, 0)) {
389 mergeReadCachePhi(phi, entry.identity, entry.index, entry.kind, states);
390 }
391 }
392 }
393 }
394 }
395
396 private void mergeReadCachePhi(PhiNode phi, LocationIdentity identity, int index, JavaKind kind, List<PEReadEliminationBlockState> states) {
397 ValueNode[] values = new ValueNode[states.size()];
398 values[0] = states.get(0).getReadCache(getPhiValueAt(phi, 0), identity, index, kind, PEReadEliminationClosure.this);
399 if (values[0] != null) {
400 for (int i = 1; i < states.size(); i++) {
401 ValueNode value = states.get(i).getReadCache(getPhiValueAt(phi, i), identity, index, kind, PEReadEliminationClosure.this);
402 // e.g. unsafe loads / stores with same identity and different access kinds see
403 // mergeReadCache(states)
404 if (value == null || !values[i - 1].stamp().isCompatible(value.stamp())) {
405 return;
406 }
407 values[i] = value;
408 }
409
410 PhiNode phiNode = getPhi(new ReadCacheEntry(identity, phi, index, kind), values[0].stamp().unrestricted());
411 mergeEffects.addFloatingNode(phiNode, "mergeReadCachePhi");
412 for (int i = 0; i < values.length; i++) {
413 setPhiInput(phiNode, i, values[i]);
414 }
415 newState.readCache.put(new ReadCacheEntry(identity, phi, index, kind), phiNode);
416 }
417 }
418 }
419
420 @Override
421 protected void processKilledLoopLocations(Loop<Block> loop, PEReadEliminationBlockState initialState, PEReadEliminationBlockState mergedStates) {
422 assert initialState != null;
423 assert mergedStates != null;
424 if (initialState.readCache.size() > 0) {
425 LoopKillCache loopKilledLocations = loopLocationKillCache.get(loop);
426 // we have fully processed this loop the first time, remember to cache it the next time
427 // it is visited
428 if (loopKilledLocations == null) {
429 loopKilledLocations = new LoopKillCache(1/* 1.visit */);
430 loopLocationKillCache.put(loop, loopKilledLocations);
431 } else {
432 AbstractBeginNode beginNode = loop.getHeader().getBeginNode();
433 OptionValues options = beginNode.getOptions();
434 if (loopKilledLocations.visits() > ReadEliminationMaxLoopVisits.getValue(options)) {
435 // we have processed the loop too many times, kill all locations so the inner
|