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