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 }