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.debug.DebugContext;
  29 import org.graalvm.compiler.nodes.FieldLocationIdentity;
  30 import org.graalvm.compiler.nodes.ValueNode;
  31 import org.graalvm.compiler.nodes.virtual.AllocatedObjectNode;
  32 import org.graalvm.compiler.nodes.virtual.VirtualInstanceNode;
  33 import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
  34 import org.graalvm.compiler.options.OptionValues;
  35 import org.graalvm.util.EconomicMap;
  36 import org.graalvm.util.Equivalence;
  37 import org.graalvm.word.LocationIdentity;
  38 
  39 import jdk.vm.ci.meta.JavaKind;
  40 
  41 public final class PEReadEliminationBlockState extends PartialEscapeBlockState<PEReadEliminationBlockState> {
  42 
  43     final EconomicMap<ReadCacheEntry, ValueNode> readCache;
  44 
  45     static final class ReadCacheEntry {
  46 
  47         public final LocationIdentity identity;
  48         public final ValueNode object;
  49         public final int index;
  50         public final JavaKind kind;
  51 
  52         ReadCacheEntry(LocationIdentity identity, ValueNode object, int index, JavaKind kind) {
  53             this.identity = identity;
  54             this.object = object;
  55             this.index = index;
  56             this.kind = kind;
  57         }
  58 
  59         @Override
  60         public int hashCode() {
  61             int result = 31 + ((identity == null) ? 0 : identity.hashCode());
  62             result = 31 * result + ((object == null) ? 0 : System.identityHashCode(object));
  63             result = 31 * result + kind.ordinal();
  64             return result * 31 + index;
  65         }
  66 
  67         @Override
  68         public boolean equals(Object obj) {
  69             if (!(obj instanceof ReadCacheEntry)) {
  70                 return false;
  71             }
  72             ReadCacheEntry other = (ReadCacheEntry) obj;
  73             return identity.equals(other.identity) && object == other.object && index == other.index && kind == other.kind;
  74         }
  75 
  76         @Override
  77         public String toString() {
  78             return index == -1 ? (object + ":" + kind + "<" + identity + ">") : (object + "[" + index + "]:" + kind + "<" + identity + ">");
  79         }
  80     }
  81 
  82     public PEReadEliminationBlockState(OptionValues options, DebugContext debug) {
  83         super(options, debug);
  84         readCache = EconomicMap.create(Equivalence.DEFAULT);
  85     }
  86 
  87     public PEReadEliminationBlockState(PEReadEliminationBlockState other) {
  88         super(other);
  89         readCache = EconomicMap.create(Equivalence.DEFAULT, other.readCache);
  90     }
  91 
  92     @Override
  93     public String toString() {
  94         return super.toString() + " " + readCache;
  95     }
  96 
  97     @Override
  98     protected void objectMaterialized(VirtualObjectNode virtual, AllocatedObjectNode representation, List<ValueNode> values) {
  99         if (virtual instanceof VirtualInstanceNode) {
 100             VirtualInstanceNode instance = (VirtualInstanceNode) virtual;
 101             for (int i = 0; i < instance.entryCount(); i++) {
 102                 readCache.put(new ReadCacheEntry(new FieldLocationIdentity(instance.field(i)), representation, -1, instance.field(i).getJavaKind()), values.get(i));
 103             }
 104         }
 105     }
 106 
 107     @Override
 108     public boolean equivalentTo(PEReadEliminationBlockState other) {
 109         if (!isSubMapOf(readCache, other.readCache)) {
 110             return false;
 111         }
 112         return super.equivalentTo(other);
 113     }
 114 
 115     public void addReadCache(ValueNode object, LocationIdentity identity, int index, JavaKind kind, ValueNode value, PartialEscapeClosure<?> closure) {
 116         ValueNode cacheObject;
 117         ObjectState obj = closure.getObjectState(this, object);
 118         if (obj != null) {
 119             assert !obj.isVirtual();
 120             cacheObject = obj.getMaterializedValue();
 121         } else {
 122             cacheObject = object;
 123         }
 124         readCache.put(new ReadCacheEntry(identity, cacheObject, index, kind), value);
 125     }
 126 
 127     public ValueNode getReadCache(ValueNode object, LocationIdentity identity, int index, JavaKind kind, PartialEscapeClosure<?> closure) {
 128         ValueNode cacheObject;
 129         ObjectState obj = closure.getObjectState(this, object);
 130         if (obj != null) {
 131             assert !obj.isVirtual() : object;
 132             cacheObject = obj.getMaterializedValue();
 133         } else {
 134             cacheObject = object;
 135         }
 136         ValueNode cacheValue = readCache.get(new ReadCacheEntry(identity, cacheObject, index, kind));
 137         obj = closure.getObjectState(this, cacheValue);
 138         if (obj != null) {
 139             assert !obj.isVirtual();
 140             cacheValue = obj.getMaterializedValue();
 141         } else {
 142             // assert !scalarAliases.containsKey(cacheValue);
 143             cacheValue = closure.getScalarAlias(cacheValue);
 144         }
 145         return cacheValue;
 146     }
 147 
 148     public void killReadCache() {
 149         readCache.clear();
 150     }
 151 
 152     public void killReadCache(LocationIdentity identity, int index) {
 153         Iterator<ReadCacheEntry> iter = readCache.getKeys().iterator();
 154         while (iter.hasNext()) {
 155             ReadCacheEntry entry = iter.next();
 156             if (entry.identity.equals(identity) && (index == -1 || entry.index == -1 || index == entry.index)) {
 157                 iter.remove();
 158             }
 159         }
 160     }
 161 
 162     public EconomicMap<ReadCacheEntry, ValueNode> getReadCache() {
 163         return readCache;
 164     }
 165 }