1 /* 2 * Copyright (c) 2011, 2017, 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.CounterKey; 29 import org.graalvm.compiler.debug.DebugContext; 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 import jdk.vm.ci.meta.JavaConstant; 39 40 /** 41 * This class describes the state of a virtual object while iterating over the graph. It describes 42 * the fields or array elements (called "entries") and the lock count if the object is still 43 * virtual. If the object was materialized, it contains the current materialized value. 44 */ 45 public class ObjectState { 46 47 public static final CounterKey CREATE_ESCAPED_OBJECT_STATE = DebugContext.counter("CreateEscapeObjectState"); 48 public static final CounterKey GET_ESCAPED_OBJECT_STATE = DebugContext.counter("GetEscapeObjectState"); 49 50 private ValueNode[] entries; 51 private ValueNode materializedValue; 52 private LockState locks; 53 private boolean ensureVirtualized; 54 55 private EscapeObjectState cachedState; 56 57 /** 58 * ObjectStates are duplicated lazily, if this field is true then the state needs to be copied 59 * before it is modified. 60 */ 61 boolean copyOnWrite; 62 63 public ObjectState(ValueNode[] entries, List<MonitorIdNode> locks, boolean ensureVirtualized) { 64 this(entries, (LockState) null, ensureVirtualized); 65 for (int i = locks.size() - 1; i >= 0; i--) { 66 this.locks = new LockState(locks.get(i), this.locks); 67 } 68 } 69 70 public ObjectState(ValueNode[] entries, LockState locks, boolean ensureVirtualized) { 71 assert checkIllegalValues(entries); 72 this.entries = entries; 73 this.locks = locks; 74 this.ensureVirtualized = ensureVirtualized; 75 } 76 77 public ObjectState(ValueNode materializedValue, LockState locks, boolean ensureVirtualized) { 78 assert materializedValue != null; 79 this.materializedValue = materializedValue; 80 this.locks = locks; 81 this.ensureVirtualized = ensureVirtualized; 82 } 83 84 private ObjectState(ObjectState other) { 85 entries = other.entries == null ? null : other.entries.clone(); 86 materializedValue = other.materializedValue; 87 locks = other.locks; 88 cachedState = other.cachedState; 89 ensureVirtualized = other.ensureVirtualized; 90 } 91 92 public ObjectState cloneState() { 93 return new ObjectState(this); 94 } 95 96 /** 97 * Ensure that if an {@link JavaConstant#forIllegal() illegal value} is seen that the previous 98 * value is a double word value. 99 */ 100 public static boolean checkIllegalValues(ValueNode[] values) { 101 if (values != null) { 102 for (int v = 1; v < values.length; v++) { 103 checkIllegalValue(values, v); 104 } 105 } 106 return true; 107 } 108 109 /** 110 * Ensure that if an {@link JavaConstant#forIllegal() illegal value} is seen that the previous 111 * value is a double word value. 112 */ 113 public static boolean checkIllegalValue(ValueNode[] values, int v) { 114 if (v > 0 && values[v].isConstant() && values[v].asConstant().equals(JavaConstant.forIllegal())) { 115 assert values[v - 1].getStackKind().needsTwoSlots(); 116 } 117 return true; 118 } 119 120 public EscapeObjectState createEscapeObjectState(DebugContext debug, VirtualObjectNode virtual) { 121 GET_ESCAPED_OBJECT_STATE.increment(debug); 122 if (cachedState == null) { 123 CREATE_ESCAPED_OBJECT_STATE.increment(debug); 124 if (isVirtual()) { 125 /* 126 * Clear out entries that are default values anyway. 127 * 128 * TODO: this should be propagated into ObjectState.entries, but that will take some 129 * more refactoring. 130 */ 131 ValueNode[] newEntries = entries.clone(); 132 for (int i = 0; i < newEntries.length; i++) { 133 if (newEntries[i].asJavaConstant() == JavaConstant.defaultForKind(virtual.entryKind(i).getStackKind())) { 134 newEntries[i] = null; 135 } 136 } 137 cachedState = new VirtualObjectState(virtual, newEntries); 138 } else { 139 cachedState = new MaterializedObjectState(virtual, materializedValue); 140 } 141 } 142 return cachedState; 143 144 } 145 146 public boolean isVirtual() { 147 assert materializedValue == null ^ entries == null; 148 return materializedValue == null; 149 } 150 151 /** 152 * Users of this method are not allowed to change the entries of the returned array. 153 */ 154 public ValueNode[] getEntries() { 155 assert isVirtual(); 156 return entries; 157 } 158 159 public ValueNode getEntry(int index) { 160 assert isVirtual(); 161 return entries[index]; 162 } 163 164 public ValueNode getMaterializedValue() { 165 assert !isVirtual(); 166 return materializedValue; 167 } 168 169 public void setEntry(int index, ValueNode value) { 170 assert isVirtual(); 171 cachedState = null; 172 entries[index] = value; 173 } 174 175 public void escape(ValueNode materialized) { 176 assert isVirtual(); 177 assert materialized != null; 178 materializedValue = materialized; 179 entries = null; 180 cachedState = null; 181 assert !isVirtual(); 182 } 183 184 public void updateMaterializedValue(ValueNode value) { 185 assert !isVirtual(); 186 assert value != null; 187 cachedState = null; 188 materializedValue = value; 189 } 190 191 public void addLock(MonitorIdNode monitorId) { 192 locks = new LockState(monitorId, locks); 193 } 194 195 public MonitorIdNode removeLock() { 196 try { 197 return locks.monitorId; 198 } finally { 199 locks = locks.next; 200 } 201 } 202 203 public LockState getLocks() { 204 return locks; 205 } 206 207 public boolean hasLocks() { 208 return locks != null; 209 } 210 211 public boolean locksEqual(ObjectState other) { 212 LockState a = locks; 213 LockState b = other.locks; 214 while (a != null && b != null && a.monitorId == b.monitorId) { 215 a = a.next; 216 b = b.next; 217 } 218 return a == null && b == null; 219 } 220 221 public void setEnsureVirtualized(boolean ensureVirtualized) { 222 this.ensureVirtualized = ensureVirtualized; 223 } 224 225 public boolean getEnsureVirtualized() { 226 return ensureVirtualized; 227 } 228 229 @Override 230 public String toString() { 231 StringBuilder str = new StringBuilder().append('{'); 232 if (locks != null) { 233 str.append('l').append(locks).append(' '); 234 } 235 if (entries != null) { 236 for (int i = 0; i < entries.length; i++) { 237 str.append("entry").append(i).append('=').append(entries[i]).append(' '); 238 } 239 } 240 if (materializedValue != null) { 241 str.append("mat=").append(materializedValue); 242 } 243 244 return str.append('}').toString(); 245 } 246 247 @Override 248 public int hashCode() { 249 final int prime = 31; 250 int result = 1; 251 result = prime * result + Arrays.hashCode(entries); 252 result = prime * result + (locks != null ? locks.monitorId.getLockDepth() : 0); 253 result = prime * result + ((materializedValue == null) ? 0 : materializedValue.hashCode()); 254 return result; 255 } 256 257 @Override 258 public boolean equals(Object obj) { 259 if (this == obj) { 260 return true; 261 } 262 if (obj == null || getClass() != obj.getClass()) { 263 return false; 264 } 265 ObjectState other = (ObjectState) obj; 266 if (!Arrays.equals(entries, other.entries)) { 267 return false; 268 } 269 if (!locksEqual(other)) { 270 return false; 271 } 272 if (materializedValue == null) { 273 if (other.materializedValue != null) { 274 return false; 275 } 276 } else if (!materializedValue.equals(other.materializedValue)) { 277 return false; 278 } 279 return true; 280 } 281 282 public ObjectState share() { 283 copyOnWrite = true; 284 return this; 285 } 286 }