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