package org.graalvm.compiler.virtual.phases.ea;
import java.util.Arrays;
import java.util.List;
import org.graalvm.compiler.debug.Debug;
import org.graalvm.compiler.debug.DebugCounter;
import org.graalvm.compiler.nodes.ValueNode;
import org.graalvm.compiler.nodes.java.MonitorIdNode;
import org.graalvm.compiler.nodes.virtual.EscapeObjectState;
import org.graalvm.compiler.nodes.virtual.LockState;
import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
import org.graalvm.compiler.virtual.nodes.MaterializedObjectState;
import org.graalvm.compiler.virtual.nodes.VirtualObjectState;
public class ObjectState {
public static final DebugCounter CREATE_ESCAPED_OBJECT_STATE = Debug.counter("CreateEscapeObjectState");
public static final DebugCounter GET_ESCAPED_OBJECT_STATE = Debug.counter("GetEscapeObjectState");
private ValueNode[] entries;
private ValueNode materializedValue;
private LockState locks;
private boolean ensureVirtualized;
private EscapeObjectState cachedState;
boolean copyOnWrite;
public ObjectState(ValueNode[] entries, List<MonitorIdNode> locks, boolean ensureVirtualized) {
this(entries, (LockState) null, ensureVirtualized);
for (int i = locks.size() - 1; i >= 0; i--) {
this.locks = new LockState(locks.get(i), this.locks);
}
}
public ObjectState(ValueNode[] entries, LockState locks, boolean ensureVirtualized) {
this.entries = entries;
this.locks = locks;
this.ensureVirtualized = ensureVirtualized;
}
public ObjectState(ValueNode materializedValue, LockState locks, boolean ensureVirtualized) {
assert materializedValue != null;
this.materializedValue = materializedValue;
this.locks = locks;
this.ensureVirtualized = ensureVirtualized;
}
private ObjectState(ObjectState other) {
entries = other.entries == null ? null : other.entries.clone();
materializedValue = other.materializedValue;
locks = other.locks;
cachedState = other.cachedState;
ensureVirtualized = other.ensureVirtualized;
}
public ObjectState cloneState() {
return new ObjectState(this);
}
public EscapeObjectState createEscapeObjectState(VirtualObjectNode virtual) {
GET_ESCAPED_OBJECT_STATE.increment();
if (cachedState == null) {
CREATE_ESCAPED_OBJECT_STATE.increment();
cachedState = isVirtual() ? new VirtualObjectState(virtual, entries) : new MaterializedObjectState(virtual, materializedValue);
}
return cachedState;
}
public boolean isVirtual() {
assert materializedValue == null ^ entries == null;
return materializedValue == null;
}
public ValueNode[] getEntries() {
assert isVirtual();
return entries;
}
public ValueNode getEntry(int index) {
assert isVirtual();
return entries[index];
}
public ValueNode getMaterializedValue() {
assert !isVirtual();
return materializedValue;
}
public void setEntry(int index, ValueNode value) {
assert isVirtual();
cachedState = null;
entries[index] = value;
}
public void escape(ValueNode materialized) {
assert isVirtual();
assert materialized != null;
materializedValue = materialized;
entries = null;
cachedState = null;
assert !isVirtual();
}
public void updateMaterializedValue(ValueNode value) {
assert !isVirtual();
assert value != null;
cachedState = null;
materializedValue = value;
}
public void addLock(MonitorIdNode monitorId) {
locks = new LockState(monitorId, locks);
}
public MonitorIdNode removeLock() {
try {
return locks.monitorId;
} finally {
locks = locks.next;
}
}
public LockState getLocks() {
return locks;
}
public boolean hasLocks() {
return locks != null;
}
public boolean locksEqual(ObjectState other) {
LockState a = locks;
LockState b = other.locks;
while (a != null && b != null && a.monitorId == b.monitorId) {
a = a.next;
b = b.next;
}
return a == null && b == null;
}
public void setEnsureVirtualized(boolean ensureVirtualized) {
this.ensureVirtualized = ensureVirtualized;
}
public boolean getEnsureVirtualized() {
return ensureVirtualized;
}
@Override
public String toString() {
StringBuilder str = new StringBuilder().append('{');
if (locks != null) {
str.append('l').append(locks).append(' ');
}
if (entries != null) {
for (int i = 0; i < entries.length; i++) {
str.append("entry").append(i).append('=').append(entries[i]).append(' ');
}
}
if (materializedValue != null) {
str.append("mat=").append(materializedValue);
}
return str.append('}').toString();
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + Arrays.hashCode(entries);
result = prime * result + (locks != null ? locks.monitorId.getLockDepth() : 0);
result = prime * result + ((materializedValue == null) ? 0 : materializedValue.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
ObjectState other = (ObjectState) obj;
if (!Arrays.equals(entries, other.entries)) {
return false;
}
if (!locksEqual(other)) {
return false;
}
if (materializedValue == null) {
if (other.materializedValue != null) {
return false;
}
} else if (!materializedValue.equals(other.materializedValue)) {
return false;
}
return true;
}
public ObjectState share() {
copyOnWrite = true;
return this;
}
}