1 /*
2  * Copyright (c) 2011, 2019, 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 
24 
25 package org.graalvm.compiler.virtual.phases.ea;
26 
27 import java.util.Iterator;
28 
29 import jdk.internal.vm.compiler.collections.EconomicMap;
30 import jdk.internal.vm.compiler.collections.Equivalence;
31 import org.graalvm.compiler.nodes.ValueNode;
32 import jdk.internal.vm.compiler.word.LocationIdentity;
33 
34 /**
35  * This class maintains a set of known values, identified by base object, locations and offset.
36  */
37 public final class ReadEliminationBlockState extends EffectsBlockState<ReadEliminationBlockState> {
38 
39     final EconomicMap<CacheEntry<?>, ValueNode> readCache;
40 
41     abstract static class CacheEntry<T> {
42 
43         public final ValueNode object;
44         public final T identity;
45 
CacheEntry(ValueNode object, T identity)46         CacheEntry(ValueNode object, T identity) {
47             this.object = object;
48             this.identity = identity;
49         }
50 
duplicateWithObject(ValueNode newObject)51         public abstract CacheEntry<T> duplicateWithObject(ValueNode newObject);
52 
53         @Override
hashCode()54         public int hashCode() {
55             int result = 31 + ((identity == null) ? 0 : identity.hashCode());
56             return 31 * result + ((object == null) ? 0 : object.hashCode());
57         }
58 
59         @Override
equals(Object obj)60         public boolean equals(Object obj) {
61             if (!(obj instanceof CacheEntry<?>)) {
62                 return false;
63             }
64             CacheEntry<?> other = (CacheEntry<?>) obj;
65             return identity.equals(other.identity) && object == other.object;
66         }
67 
68         @Override
toString()69         public String toString() {
70             return object + ":" + identity;
71         }
72 
conflicts(LocationIdentity other)73         public abstract boolean conflicts(LocationIdentity other);
74 
getIdentity()75         public abstract LocationIdentity getIdentity();
76     }
77 
78     static final class LoadCacheEntry extends CacheEntry<LocationIdentity> {
79 
LoadCacheEntry(ValueNode object, LocationIdentity identity)80         LoadCacheEntry(ValueNode object, LocationIdentity identity) {
81             super(object, identity);
82         }
83 
84         @Override
duplicateWithObject(ValueNode newObject)85         public CacheEntry<LocationIdentity> duplicateWithObject(ValueNode newObject) {
86             return new LoadCacheEntry(newObject, identity);
87         }
88 
89         @Override
conflicts(LocationIdentity other)90         public boolean conflicts(LocationIdentity other) {
91             return identity.equals(other);
92         }
93 
94         @Override
getIdentity()95         public LocationIdentity getIdentity() {
96             return identity;
97         }
98     }
99 
100     /**
101      * CacheEntry describing an Unsafe memory reference. The memory location and the location
102      * identity are separate so both must be considered when looking for optimizable memory
103      * accesses.
104      */
105     static final class UnsafeLoadCacheEntry extends CacheEntry<ValueNode> {
106 
107         private final LocationIdentity locationIdentity;
108 
UnsafeLoadCacheEntry(ValueNode object, ValueNode location, LocationIdentity locationIdentity)109         UnsafeLoadCacheEntry(ValueNode object, ValueNode location, LocationIdentity locationIdentity) {
110             super(object, location);
111             assert locationIdentity != null;
112             this.locationIdentity = locationIdentity;
113         }
114 
115         @Override
duplicateWithObject(ValueNode newObject)116         public CacheEntry<ValueNode> duplicateWithObject(ValueNode newObject) {
117             return new UnsafeLoadCacheEntry(newObject, identity, locationIdentity);
118         }
119 
120         @Override
conflicts(LocationIdentity other)121         public boolean conflicts(LocationIdentity other) {
122             return locationIdentity.equals(other);
123         }
124 
125         @Override
hashCode()126         public int hashCode() {
127             return 31 * super.hashCode() + locationIdentity.hashCode();
128         }
129 
130         @Override
equals(Object obj)131         public boolean equals(Object obj) {
132             if (obj instanceof UnsafeLoadCacheEntry) {
133                 UnsafeLoadCacheEntry other = (UnsafeLoadCacheEntry) obj;
134                 return super.equals(other) && locationIdentity.equals(other.locationIdentity);
135             }
136             return false;
137         }
138 
139         @Override
getIdentity()140         public LocationIdentity getIdentity() {
141             return locationIdentity;
142         }
143 
144         @Override
toString()145         public String toString() {
146             return "UNSAFE:" + super.toString() + " location:" + locationIdentity;
147         }
148     }
149 
ReadEliminationBlockState()150     public ReadEliminationBlockState() {
151         readCache = EconomicMap.create(Equivalence.DEFAULT);
152     }
153 
ReadEliminationBlockState(ReadEliminationBlockState other)154     public ReadEliminationBlockState(ReadEliminationBlockState other) {
155         super(other);
156         readCache = EconomicMap.create(Equivalence.DEFAULT, other.readCache);
157     }
158 
159     @Override
toString()160     public String toString() {
161         return super.toString() + " " + readCache;
162     }
163 
164     @Override
equivalentTo(ReadEliminationBlockState other)165     public boolean equivalentTo(ReadEliminationBlockState other) {
166         return isSubMapOf(readCache, other.readCache);
167     }
168 
addCacheEntry(CacheEntry<?> identifier, ValueNode value)169     public void addCacheEntry(CacheEntry<?> identifier, ValueNode value) {
170         readCache.put(identifier, value);
171     }
172 
getCacheEntry(CacheEntry<?> identifier)173     public ValueNode getCacheEntry(CacheEntry<?> identifier) {
174         return readCache.get(identifier);
175     }
176 
killReadCache()177     public void killReadCache() {
178         readCache.clear();
179     }
180 
killReadCache(LocationIdentity identity)181     public void killReadCache(LocationIdentity identity) {
182         Iterator<CacheEntry<?>> iterator = readCache.getKeys().iterator();
183         while (iterator.hasNext()) {
184             CacheEntry<?> entry = iterator.next();
185             if (entry.conflicts(identity)) {
186                 iterator.remove();
187             }
188         }
189     }
190 
getReadCache()191     public EconomicMap<CacheEntry<?>, ValueNode> getReadCache() {
192         return readCache;
193     }
194 }
195