1 /* 2 * Copyright (c) 2011, 2014, 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.Arrays; 26 import java.util.List; 27 28 import org.graalvm.compiler.debug.Debug; 29 import org.graalvm.compiler.debug.DebugCounter; 30 import org.graalvm.compiler.nodes.ValueNode; 31 import org.graalvm.compiler.nodes.java.MonitorIdNode; 32 import org.graalvm.compiler.nodes.virtual.EscapeObjectState; 33 import org.graalvm.compiler.nodes.virtual.LockState; 34 import org.graalvm.compiler.nodes.virtual.VirtualObjectNode; 35 import org.graalvm.compiler.virtual.nodes.MaterializedObjectState; 36 import org.graalvm.compiler.virtual.nodes.VirtualObjectState; 37 38 /** 39 * This class describes the state of a virtual object while iterating over the graph. It describes 40 * the fields or array elements (called "entries") and the lock count if the object is still 41 * virtual. If the object was materialized, it contains the current materialized value. 42 */ 43 public class ObjectState { 44 45 public static final DebugCounter CREATE_ESCAPED_OBJECT_STATE = Debug.counter("CreateEscapeObjectState"); 46 public static final DebugCounter GET_ESCAPED_OBJECT_STATE = Debug.counter("GetEscapeObjectState"); 47 48 private ValueNode[] entries; 49 private ValueNode materializedValue; 50 private LockState locks; 51 private boolean ensureVirtualized; 52 53 private EscapeObjectState cachedState; 54 55 boolean copyOnWrite; 56 57 public ObjectState(ValueNode[] entries, List<MonitorIdNode> locks, boolean ensureVirtualized) { 58 this(entries, (LockState) null, ensureVirtualized); 59 for (int i = locks.size() - 1; i >= 0; i--) { 60 this.locks = new LockState(locks.get(i), this.locks); 61 } 62 } 63 64 public ObjectState(ValueNode[] entries, LockState locks, boolean ensureVirtualized) { 65 this.entries = entries; 66 this.locks = locks; 67 this.ensureVirtualized = ensureVirtualized; 68 } 69 70 public ObjectState(ValueNode materializedValue, LockState locks, boolean ensureVirtualized) { 71 assert materializedValue != null; 72 this.materializedValue = materializedValue; 73 this.locks = locks; 74 this.ensureVirtualized = ensureVirtualized; 75 } 76 77 private ObjectState(ObjectState other) { 78 entries = other.entries == null ? null : other.entries.clone(); 79 materializedValue = other.materializedValue; 80 locks = other.locks; 81 cachedState = other.cachedState; 82 ensureVirtualized = other.ensureVirtualized; 83 } 84 85 public ObjectState cloneState() { 86 return new ObjectState(this); 87 } 88 89 public EscapeObjectState createEscapeObjectState(VirtualObjectNode virtual) { 90 GET_ESCAPED_OBJECT_STATE.increment(); 91 if (cachedState == null) { 92 CREATE_ESCAPED_OBJECT_STATE.increment(); 93 cachedState = isVirtual() ? new VirtualObjectState(virtual, entries) : new MaterializedObjectState(virtual, materializedValue); 94 } 95 return cachedState; 96 97 } 98 99 public boolean isVirtual() { 100 assert materializedValue == null ^ entries == null; 101 return materializedValue == null; 102 } 103 104 /** 105 * Users of this method are not allowed to change the entries of the returned array. 106 */ 107 public ValueNode[] getEntries() { 108 assert isVirtual(); 109 return entries; 110 } 111 112 public ValueNode getEntry(int index) { 113 assert isVirtual(); 114 return entries[index]; 115 } 116 117 public ValueNode getMaterializedValue() { 118 assert !isVirtual(); 119 return materializedValue; 120 } 121 122 public void setEntry(int index, ValueNode value) { 123 assert isVirtual(); 124 cachedState = null; 125 entries[index] = value; 126 } 127 128 public void escape(ValueNode materialized) { 129 assert isVirtual(); 130 assert materialized != null; 131 materializedValue = materialized; 132 entries = null; 133 cachedState = null; 134 assert !isVirtual(); 135 } 136 137 public void updateMaterializedValue(ValueNode value) { 138 assert !isVirtual(); 139 assert value != null; 140 cachedState = null; 141 materializedValue = value; 142 } 143 144 public void addLock(MonitorIdNode monitorId) { 145 locks = new LockState(monitorId, locks); 146 } 147 148 public MonitorIdNode removeLock() { 149 try { 150 return locks.monitorId; 151 } finally { 152 locks = locks.next; 153 } 154 } 155 156 public LockState getLocks() { 157 return locks; 158 } 159 160 public boolean hasLocks() { 161 return locks != null; 162 } 163 164 public boolean locksEqual(ObjectState other) { 165 LockState a = locks; 166 LockState b = other.locks; 167 while (a != null && b != null && a.monitorId == b.monitorId) { 168 a = a.next; 169 b = b.next; 170 } 171 return a == null && b == null; 172 } 173 174 public void setEnsureVirtualized(boolean ensureVirtualized) { 175 this.ensureVirtualized = ensureVirtualized; 176 } 177 178 public boolean getEnsureVirtualized() { 179 return ensureVirtualized; 180 } 181 182 @Override 183 public String toString() { 184 StringBuilder str = new StringBuilder().append('{'); 185 if (locks != null) { 186 str.append('l').append(locks).append(' '); 187 } 188 if (entries != null) { 189 for (int i = 0; i < entries.length; i++) { 190 str.append("entry").append(i).append('=').append(entries[i]).append(' '); 191 } 192 } 193 if (materializedValue != null) { 194 str.append("mat=").append(materializedValue); 195 } 196 197 return str.append('}').toString(); 198 } 199 200 @Override 201 public int hashCode() { 202 final int prime = 31; 203 int result = 1; 204 result = prime * result + Arrays.hashCode(entries); 205 result = prime * result + (locks != null ? locks.monitorId.getLockDepth() : 0); 206 result = prime * result + ((materializedValue == null) ? 0 : materializedValue.hashCode()); 207 return result; 208 } 209 210 @Override 211 public boolean equals(Object obj) { 212 if (this == obj) { 213 return true; 214 } 215 if (obj == null || getClass() != obj.getClass()) { 216 return false; 217 } 218 ObjectState other = (ObjectState) obj; 219 if (!Arrays.equals(entries, other.entries)) { 220 return false; 221 } 222 if (!locksEqual(other)) { 223 return false; 224 } 225 if (materializedValue == null) { 226 if (other.materializedValue != null) { 227 return false; 228 } 229 } else if (!materializedValue.equals(other.materializedValue)) { 230 return false; 231 } 232 return true; 233 } 234 235 public ObjectState share() { 236 copyOnWrite = true; 237 return this; 238 } 239 }