001/* 002 * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. 008 * 009 * This code is distributed in the hope that it will be useful, but WITHOUT 010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 011 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 012 * version 2 for more details (a copy is included in the LICENSE file that 013 * accompanied this code). 014 * 015 * You should have received a copy of the GNU General Public License version 016 * 2 along with this work; if not, write to the Free Software Foundation, 017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 018 * 019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 020 * or visit www.oracle.com if you need additional information or have any 021 * questions. 022 */ 023package com.oracle.graal.virtual.phases.ea; 024 025import java.util.*; 026 027import com.oracle.graal.nodes.*; 028import com.oracle.graal.nodes.calc.*; 029import com.oracle.graal.nodes.java.*; 030import com.oracle.graal.nodes.virtual.*; 031 032public abstract class PartialEscapeBlockState<T extends PartialEscapeBlockState<T>> extends EffectsBlockState<T> { 033 034 private static final ObjectState[] EMPTY_ARRAY = new ObjectState[0]; 035 036 private ObjectState[] objectStates; 037 038 private static class RefCount { 039 private int refCount = 1; 040 } 041 042 private RefCount arrayRefCount; 043 044 /** 045 * Final subclass of PartialEscapeBlockState, for performance and to make everything behave 046 * nicely with generics. 047 */ 048 public static final class Final extends PartialEscapeBlockState<Final> { 049 050 public Final() { 051 } 052 053 public Final(Final other) { 054 super(other); 055 } 056 } 057 058 protected PartialEscapeBlockState() { 059 objectStates = EMPTY_ARRAY; 060 arrayRefCount = new RefCount(); 061 } 062 063 protected PartialEscapeBlockState(PartialEscapeBlockState<T> other) { 064 super(other); 065 adoptAddObjectStates(other); 066 } 067 068 public ObjectState getObjectState(int object) { 069 ObjectState state = objectStates[object]; 070 assert state != null; 071 return state; 072 } 073 074 public ObjectState getObjectStateOptional(int object) { 075 return object >= objectStates.length ? null : objectStates[object]; 076 } 077 078 public ObjectState getObjectState(VirtualObjectNode object) { 079 ObjectState state = objectStates[object.getObjectId()]; 080 assert state != null; 081 return state; 082 } 083 084 public ObjectState getObjectStateOptional(VirtualObjectNode object) { 085 int id = object.getObjectId(); 086 return id >= objectStates.length ? null : objectStates[id]; 087 } 088 089 private ObjectState[] getObjectStateArrayForModification() { 090 if (arrayRefCount.refCount > 1) { 091 objectStates = objectStates.clone(); 092 arrayRefCount = new RefCount(); 093 } 094 return objectStates; 095 } 096 097 private ObjectState getObjectStateForModification(int object) { 098 ObjectState[] array = getObjectStateArrayForModification(); 099 ObjectState objectState = array[object]; 100 if (objectState.copyOnWrite) { 101 array[object] = objectState = objectState.cloneState(); 102 } 103 return objectState; 104 } 105 106 public void setEntry(int object, int entryIndex, ValueNode value) { 107 if (objectStates[object].getEntry(entryIndex) != value) { 108 getObjectStateForModification(object).setEntry(entryIndex, value); 109 } 110 } 111 112 public void escape(int object, ValueNode materialized) { 113 getObjectStateForModification(object).escape(materialized); 114 } 115 116 public void addLock(int object, MonitorIdNode monitorId) { 117 getObjectStateForModification(object).addLock(monitorId); 118 } 119 120 public MonitorIdNode removeLock(int object) { 121 return getObjectStateForModification(object).removeLock(); 122 } 123 124 public void setEnsureVirtualized(int object, boolean ensureVirtualized) { 125 if (objectStates[object].getEnsureVirtualized() != ensureVirtualized) { 126 getObjectStateForModification(object).setEnsureVirtualized(ensureVirtualized); 127 } 128 } 129 130 public void updateMaterializedValue(int object, ValueNode value) { 131 if (objectStates[object].getMaterializedValue() != value) { 132 getObjectStateForModification(object).updateMaterializedValue(value); 133 } 134 } 135 136 public void materializeBefore(FixedNode fixed, VirtualObjectNode virtual, GraphEffectList materializeEffects) { 137 PartialEscapeClosure.METRIC_MATERIALIZATIONS.increment(); 138 List<AllocatedObjectNode> objects = new ArrayList<>(2); 139 List<ValueNode> values = new ArrayList<>(8); 140 List<List<MonitorIdNode>> locks = new ArrayList<>(2); 141 List<ValueNode> otherAllocations = new ArrayList<>(2); 142 List<Boolean> ensureVirtual = new ArrayList<>(2); 143 materializeWithCommit(fixed, virtual, objects, locks, values, ensureVirtual, otherAllocations); 144 145 materializeEffects.add("materializeBefore", (graph, obsoleteNodes) -> { 146 for (ValueNode otherAllocation : otherAllocations) { 147 graph.addWithoutUnique(otherAllocation); 148 if (otherAllocation instanceof FixedWithNextNode) { 149 graph.addBeforeFixed(fixed, (FixedWithNextNode) otherAllocation); 150 } else { 151 assert otherAllocation instanceof FloatingNode; 152 } 153 } 154 if (!objects.isEmpty()) { 155 CommitAllocationNode commit; 156 if (fixed.predecessor() instanceof CommitAllocationNode) { 157 commit = (CommitAllocationNode) fixed.predecessor(); 158 } else { 159 commit = graph.add(new CommitAllocationNode()); 160 graph.addBeforeFixed(fixed, commit); 161 } 162 for (AllocatedObjectNode obj : objects) { 163 graph.addWithoutUnique(obj); 164 commit.getVirtualObjects().add(obj.getVirtualObject()); 165 obj.setCommit(commit); 166 } 167 commit.getValues().addAll(values); 168 for (List<MonitorIdNode> monitorIds : locks) { 169 commit.addLocks(monitorIds); 170 } 171 commit.getEnsureVirtual().addAll(ensureVirtual); 172 173 assert commit.usages().filter(AllocatedObjectNode.class).count() == commit.getUsageCount(); 174 List<AllocatedObjectNode> materializedValues = commit.usages().filter(AllocatedObjectNode.class).snapshot(); 175 for (int i = 0; i < commit.getValues().size(); i++) { 176 if (materializedValues.contains(commit.getValues().get(i))) { 177 commit.getValues().set(i, ((AllocatedObjectNode) commit.getValues().get(i)).getVirtualObject()); 178 } 179 } 180 } 181 }); 182 } 183 184 private void materializeWithCommit(FixedNode fixed, VirtualObjectNode virtual, List<AllocatedObjectNode> objects, List<List<MonitorIdNode>> locks, List<ValueNode> values, 185 List<Boolean> ensureVirtual, List<ValueNode> otherAllocations) { 186 ObjectState obj = getObjectState(virtual); 187 188 ValueNode[] entries = obj.getEntries(); 189 ValueNode representation = virtual.getMaterializedRepresentation(fixed, entries, obj.getLocks()); 190 escape(virtual.getObjectId(), representation); 191 obj = getObjectState(virtual); 192 PartialEscapeClosure.updateStatesForMaterialized(this, virtual, obj.getMaterializedValue()); 193 if (representation instanceof AllocatedObjectNode) { 194 objects.add((AllocatedObjectNode) representation); 195 locks.add(LockState.asList(obj.getLocks())); 196 ensureVirtual.add(obj.getEnsureVirtualized()); 197 int pos = values.size(); 198 while (values.size() < pos + entries.length) { 199 values.add(null); 200 } 201 for (int i = 0; i < entries.length; i++) { 202 if (entries[i] instanceof VirtualObjectNode) { 203 VirtualObjectNode entryVirtual = (VirtualObjectNode) entries[i]; 204 ObjectState entryObj = getObjectState(entryVirtual); 205 if (entryObj.isVirtual()) { 206 materializeWithCommit(fixed, entryVirtual, objects, locks, values, ensureVirtual, otherAllocations); 207 entryObj = getObjectState(entryVirtual); 208 } 209 values.set(pos + i, entryObj.getMaterializedValue()); 210 } else { 211 values.set(pos + i, entries[i]); 212 } 213 } 214 objectMaterialized(virtual, (AllocatedObjectNode) representation, values.subList(pos, pos + entries.length)); 215 } else { 216 VirtualUtil.trace("materialized %s as %s", virtual, representation); 217 otherAllocations.add(representation); 218 assert obj.getLocks() == null; 219 } 220 } 221 222 protected void objectMaterialized(VirtualObjectNode virtual, AllocatedObjectNode representation, List<ValueNode> values) { 223 VirtualUtil.trace("materialized %s as %s with values %s", virtual, representation, values); 224 } 225 226 public void addObject(int virtual, ObjectState state) { 227 ensureSize(virtual)[virtual] = state; 228 } 229 230 private ObjectState[] ensureSize(int objectId) { 231 if (objectStates.length <= objectId) { 232 objectStates = Arrays.copyOf(objectStates, Math.max(objectId * 2, 4)); 233 arrayRefCount.refCount--; 234 arrayRefCount = new RefCount(); 235 return objectStates; 236 } else { 237 return getObjectStateArrayForModification(); 238 } 239 } 240 241 public int getStateCount() { 242 return objectStates.length; 243 } 244 245 @Override 246 public String toString() { 247 return super.toString() + ", Object States: " + Arrays.toString(objectStates); 248 } 249 250 @Override 251 public boolean equivalentTo(T other) { 252 int length = Math.max(objectStates.length, other.getStateCount()); 253 for (int i = 0; i < length; i++) { 254 ObjectState left = getObjectStateOptional(i); 255 ObjectState right = other.getObjectStateOptional(i); 256 if (left != right) { 257 if (left == null || right == null) { 258 return false; 259 } 260 if (!left.equals(right)) { 261 return false; 262 } 263 } 264 } 265 return true; 266 } 267 268 protected static <K, V> boolean compareMaps(Map<K, V> left, Map<K, V> right) { 269 if (left.size() != right.size()) { 270 return false; 271 } 272 return compareMapsNoSize(left, right); 273 } 274 275 protected static <K, V> boolean compareMapsNoSize(Map<K, V> left, Map<K, V> right) { 276 if (left == right) { 277 return true; 278 } 279 for (Map.Entry<K, V> entry : right.entrySet()) { 280 K key = entry.getKey(); 281 V value = entry.getValue(); 282 assert value != null; 283 V otherValue = left.get(key); 284 if (otherValue != value && !value.equals(otherValue)) { 285 return false; 286 } 287 } 288 return true; 289 } 290 291 protected static <U, V> void meetMaps(Map<U, V> target, Map<U, V> source) { 292 Iterator<Map.Entry<U, V>> iter = target.entrySet().iterator(); 293 while (iter.hasNext()) { 294 Map.Entry<U, V> entry = iter.next(); 295 if (source.containsKey(entry.getKey())) { 296 assert source.get(entry.getKey()) == entry.getValue(); 297 } else { 298 iter.remove(); 299 } 300 } 301 } 302 303 public void resetObjectStates(int size) { 304 objectStates = new ObjectState[size]; 305 } 306 307 public static boolean identicalObjectStates(PartialEscapeBlockState<?>[] states) { 308 for (int i = 1; i < states.length; i++) { 309 if (states[0].objectStates != states[i].objectStates) { 310 return false; 311 } 312 } 313 return true; 314 } 315 316 public static boolean identicalObjectStates(PartialEscapeBlockState<?>[] states, int object) { 317 for (int i = 1; i < states.length; i++) { 318 if (states[0].objectStates[object] != states[i].objectStates[object]) { 319 return false; 320 } 321 } 322 return true; 323 } 324 325 public void adoptAddObjectStates(PartialEscapeBlockState<?> other) { 326 if (objectStates != null) { 327 arrayRefCount.refCount--; 328 } 329 objectStates = other.objectStates; 330 arrayRefCount = other.arrayRefCount; 331 332 if (arrayRefCount.refCount == 1) { 333 for (ObjectState state : objectStates) { 334 if (state != null) { 335 state.share(); 336 } 337 } 338 } 339 arrayRefCount.refCount++; 340 } 341}