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