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