blob: f05e6d015eaa9fdf5cc7849dddcabb73c48b3120 [file] [log] [blame]
/*
* Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
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;
/**
* This class describes the state of a virtual object while iterating over the graph. It describes
* the fields or array elements (called "entries") and the lock count if the object is still
* virtual. If the object was materialized, it contains the current materialized value.
*/
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;
}
/**
* Users of this method are not allowed to change the entries of the returned array.
*/
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;
}
}