1 /*
2  * Copyright (c) 2011, 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 
24 
25 package org.graalvm.compiler.virtual.phases.ea;
26 
27 import java.util.Iterator;
28 import java.util.List;
29 
30 import jdk.internal.vm.compiler.collections.EconomicMap;
31 import jdk.internal.vm.compiler.collections.Equivalence;
32 import org.graalvm.compiler.core.common.type.IntegerStamp;
33 import org.graalvm.compiler.core.common.type.Stamp;
34 import org.graalvm.compiler.debug.DebugContext;
35 import org.graalvm.compiler.nodes.FieldLocationIdentity;
36 import org.graalvm.compiler.nodes.NodeView;
37 import org.graalvm.compiler.nodes.ValueNode;
38 import org.graalvm.compiler.nodes.virtual.AllocatedObjectNode;
39 import org.graalvm.compiler.nodes.virtual.VirtualInstanceNode;
40 import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
41 import org.graalvm.compiler.options.OptionValues;
42 import jdk.internal.vm.compiler.word.LocationIdentity;
43 
44 import jdk.vm.ci.meta.JavaKind;
45 
46 public final class PEReadEliminationBlockState extends PartialEscapeBlockState<PEReadEliminationBlockState> {
47 
48     final EconomicMap<ReadCacheEntry, ValueNode> readCache;
49 
50     static final class ReadCacheEntry {
51 
52         public final LocationIdentity identity;
53         public final ValueNode object;
54         public final int index;
55         public final JavaKind kind;
56 
57         /* This flag does not affect hashCode or equals implementations. */
58         public final boolean overflowAccess;
59 
ReadCacheEntry(LocationIdentity identity, ValueNode object, int index, JavaKind kind, boolean overflowAccess)60         ReadCacheEntry(LocationIdentity identity, ValueNode object, int index, JavaKind kind, boolean overflowAccess) {
61             this.identity = identity;
62             this.object = object;
63             this.index = index;
64             this.kind = kind;
65             this.overflowAccess = overflowAccess;
66         }
67 
68         @Override
hashCode()69         public int hashCode() {
70             int result = 31 + ((identity == null) ? 0 : identity.hashCode());
71             result = 31 * result + ((object == null) ? 0 : System.identityHashCode(object));
72             result = 31 * result + kind.ordinal();
73             return result * 31 + index;
74         }
75 
76         @Override
equals(Object obj)77         public boolean equals(Object obj) {
78             if (!(obj instanceof ReadCacheEntry)) {
79                 return false;
80             }
81             ReadCacheEntry other = (ReadCacheEntry) obj;
82             return identity.equals(other.identity) && object == other.object && index == other.index && kind == other.kind;
83         }
84 
85         @Override
toString()86         public String toString() {
87             return index == -1 ? (object + ":" + kind + "<" + identity + ">") : (object + "[" + index + "]:" + kind + "<" + identity + ">");
88         }
89     }
90 
PEReadEliminationBlockState(OptionValues options, DebugContext debug)91     public PEReadEliminationBlockState(OptionValues options, DebugContext debug) {
92         super(options, debug);
93         readCache = EconomicMap.create(Equivalence.DEFAULT);
94     }
95 
PEReadEliminationBlockState(PEReadEliminationBlockState other)96     public PEReadEliminationBlockState(PEReadEliminationBlockState other) {
97         super(other);
98         readCache = EconomicMap.create(Equivalence.DEFAULT, other.readCache);
99     }
100 
101     @Override
toString()102     public String toString() {
103         return super.toString() + " " + readCache;
104     }
105 
stampToJavaKind(Stamp stamp)106     private static JavaKind stampToJavaKind(Stamp stamp) {
107         if (stamp instanceof IntegerStamp) {
108             switch (((IntegerStamp) stamp).getBits()) {
109                 case 1:
110                     return JavaKind.Boolean;
111                 case 8:
112                     return JavaKind.Byte;
113                 case 16:
114                     return ((IntegerStamp) stamp).isPositive() ? JavaKind.Char : JavaKind.Short;
115                 case 32:
116                     return JavaKind.Int;
117                 case 64:
118                     return JavaKind.Long;
119                 default:
120                     throw new IllegalArgumentException("unexpected IntegerStamp " + stamp);
121             }
122         } else {
123             return stamp.getStackKind();
124         }
125     }
126 
127     @Override
objectMaterialized(VirtualObjectNode virtual, AllocatedObjectNode representation, List<ValueNode> values)128     protected void objectMaterialized(VirtualObjectNode virtual, AllocatedObjectNode representation, List<ValueNode> values) {
129         if (virtual instanceof VirtualInstanceNode) {
130             VirtualInstanceNode instance = (VirtualInstanceNode) virtual;
131             for (int i = 0; i < instance.entryCount(); i++) {
132                 JavaKind declaredKind = instance.field(i).getJavaKind();
133                 if (declaredKind == stampToJavaKind(values.get(i).stamp(NodeView.DEFAULT))) {
134                     // We won't cache unaligned field writes upon instantiation unless we add
135                     // support for non-array objects in PEReadEliminationClosure.processUnsafeLoad.
136                     readCache.put(new ReadCacheEntry(new FieldLocationIdentity(instance.field(i)), representation, -1, declaredKind, false), values.get(i));
137                 }
138             }
139         }
140     }
141 
142     @Override
equivalentTo(PEReadEliminationBlockState other)143     public boolean equivalentTo(PEReadEliminationBlockState other) {
144         if (!isSubMapOf(readCache, other.readCache)) {
145             return false;
146         }
147         return super.equivalentTo(other);
148     }
149 
addReadCache(ValueNode object, LocationIdentity identity, int index, JavaKind kind, boolean overflowAccess, ValueNode value, PartialEscapeClosure<?> closure)150     public void addReadCache(ValueNode object, LocationIdentity identity, int index, JavaKind kind, boolean overflowAccess, ValueNode value, PartialEscapeClosure<?> closure) {
151         ValueNode cacheObject;
152         ObjectState obj = closure.getObjectState(this, object);
153         if (obj != null) {
154             assert !obj.isVirtual();
155             cacheObject = obj.getMaterializedValue();
156         } else {
157             cacheObject = object;
158         }
159         readCache.put(new ReadCacheEntry(identity, cacheObject, index, kind, overflowAccess), value);
160     }
161 
getReadCache(ValueNode object, LocationIdentity identity, int index, JavaKind kind, PartialEscapeClosure<?> closure)162     public ValueNode getReadCache(ValueNode object, LocationIdentity identity, int index, JavaKind kind, PartialEscapeClosure<?> closure) {
163         ValueNode cacheObject;
164         ObjectState obj = closure.getObjectState(this, object);
165         if (obj != null) {
166             assert !obj.isVirtual() : object;
167             cacheObject = obj.getMaterializedValue();
168         } else {
169             cacheObject = object;
170         }
171         ValueNode cacheValue = readCache.get(new ReadCacheEntry(identity, cacheObject, index, kind, false));
172         obj = closure.getObjectState(this, cacheValue);
173         if (obj != null) {
174             assert !obj.isVirtual();
175             cacheValue = obj.getMaterializedValue();
176         } else {
177             // assert !scalarAliases.containsKey(cacheValue);
178             cacheValue = closure.getScalarAlias(cacheValue);
179         }
180         return cacheValue;
181     }
182 
killReadCache()183     public void killReadCache() {
184         readCache.clear();
185     }
186 
killReadCache(LocationIdentity identity, int index)187     public void killReadCache(LocationIdentity identity, int index) {
188         Iterator<ReadCacheEntry> iter = readCache.getKeys().iterator();
189         while (iter.hasNext()) {
190             ReadCacheEntry entry = iter.next();
191             if (entry.identity.equals(identity) && (index == -1 || entry.index == -1 || index == entry.index || entry.overflowAccess)) {
192                 iter.remove();
193             }
194         }
195     }
196 
getReadCache()197     public EconomicMap<ReadCacheEntry, ValueNode> getReadCache() {
198         return readCache;
199     }
200 }
201