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