001/*
002 * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.
008 *
009 * This code is distributed in the hope that it will be useful, but WITHOUT
010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
011 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
012 * version 2 for more details (a copy is included in the LICENSE file that
013 * accompanied this code).
014 *
015 * You should have received a copy of the GNU General Public License version
016 * 2 along with this work; if not, write to the Free Software Foundation,
017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
018 *
019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
020 * or visit www.oracle.com if you need additional information or have any
021 * questions.
022 */
023package com.oracle.graal.virtual.phases.ea;
024
025import java.util.*;
026
027import com.oracle.graal.debug.*;
028
029import com.oracle.graal.nodes.*;
030import com.oracle.graal.nodes.java.*;
031import com.oracle.graal.nodes.virtual.*;
032import com.oracle.graal.virtual.nodes.*;
033
034/**
035 * This class describes the state of a virtual object while iterating over the graph. It describes
036 * the fields or array elements (called "entries") and the lock count if the object is still
037 * virtual. If the object was materialized, it contains the current materialized value.
038 */
039public class ObjectState {
040
041    public static final DebugMetric CREATE_ESCAPED_OBJECT_STATE = Debug.metric("CreateEscapeObjectState");
042    public static final DebugMetric GET_ESCAPED_OBJECT_STATE = Debug.metric("GetEscapeObjectState");
043
044    private ValueNode[] entries;
045    private ValueNode materializedValue;
046    private LockState locks;
047    private boolean ensureVirtualized;
048
049    private EscapeObjectState cachedState;
050
051    boolean copyOnWrite;
052
053    public ObjectState(ValueNode[] entries, List<MonitorIdNode> locks, boolean ensureVirtualized) {
054        this(entries, (LockState) null, ensureVirtualized);
055        for (int i = locks.size() - 1; i >= 0; i--) {
056            this.locks = new LockState(locks.get(i), this.locks);
057        }
058    }
059
060    public ObjectState(ValueNode[] entries, LockState locks, boolean ensureVirtualized) {
061        this.entries = entries;
062        this.locks = locks;
063        this.ensureVirtualized = ensureVirtualized;
064    }
065
066    public ObjectState(ValueNode materializedValue, LockState locks, boolean ensureVirtualized) {
067        assert materializedValue != null;
068        this.materializedValue = materializedValue;
069        this.locks = locks;
070        this.ensureVirtualized = ensureVirtualized;
071    }
072
073    private ObjectState(ObjectState other) {
074        entries = other.entries == null ? null : other.entries.clone();
075        materializedValue = other.materializedValue;
076        locks = other.locks;
077        cachedState = other.cachedState;
078        ensureVirtualized = other.ensureVirtualized;
079    }
080
081    public ObjectState cloneState() {
082        return new ObjectState(this);
083    }
084
085    public EscapeObjectState createEscapeObjectState(VirtualObjectNode virtual) {
086        GET_ESCAPED_OBJECT_STATE.increment();
087        if (cachedState == null) {
088            CREATE_ESCAPED_OBJECT_STATE.increment();
089            cachedState = isVirtual() ? new VirtualObjectState(virtual, entries) : new MaterializedObjectState(virtual, materializedValue);
090        }
091        return cachedState;
092
093    }
094
095    public boolean isVirtual() {
096        assert materializedValue == null ^ entries == null;
097        return materializedValue == null;
098    }
099
100    /**
101     * Users of this method are not allowed to change the entries of the returned array.
102     */
103    public ValueNode[] getEntries() {
104        assert isVirtual();
105        return entries;
106    }
107
108    public ValueNode getEntry(int index) {
109        assert isVirtual();
110        return entries[index];
111    }
112
113    public ValueNode getMaterializedValue() {
114        assert !isVirtual();
115        return materializedValue;
116    }
117
118    public void setEntry(int index, ValueNode value) {
119        assert isVirtual();
120        cachedState = null;
121        entries[index] = value;
122    }
123
124    public void escape(ValueNode materialized) {
125        assert isVirtual();
126        assert materialized != null;
127        materializedValue = materialized;
128        entries = null;
129        cachedState = null;
130        assert !isVirtual();
131    }
132
133    public void updateMaterializedValue(ValueNode value) {
134        assert !isVirtual();
135        assert value != null;
136        cachedState = null;
137        materializedValue = value;
138    }
139
140    public void addLock(MonitorIdNode monitorId) {
141        locks = new LockState(monitorId, locks);
142    }
143
144    public MonitorIdNode removeLock() {
145        try {
146            return locks.monitorId;
147        } finally {
148            locks = locks.next;
149        }
150    }
151
152    public LockState getLocks() {
153        return locks;
154    }
155
156    public boolean hasLocks() {
157        return locks != null;
158    }
159
160    public boolean locksEqual(ObjectState other) {
161        LockState a = locks;
162        LockState b = other.locks;
163        while (a != null && b != null && a.monitorId == b.monitorId) {
164            a = a.next;
165            b = b.next;
166        }
167        return a == null && b == null;
168    }
169
170    public void setEnsureVirtualized(boolean ensureVirtualized) {
171        this.ensureVirtualized = ensureVirtualized;
172    }
173
174    public boolean getEnsureVirtualized() {
175        return ensureVirtualized;
176    }
177
178    @Override
179    public String toString() {
180        StringBuilder str = new StringBuilder().append('{');
181        if (locks != null) {
182            str.append('l').append(locks).append(' ');
183        }
184        if (entries != null) {
185            for (int i = 0; i < entries.length; i++) {
186                str.append("entry").append(i).append('=').append(entries[i]).append(' ');
187            }
188        }
189        if (materializedValue != null) {
190            str.append("mat=").append(materializedValue);
191        }
192
193        return str.append('}').toString();
194    }
195
196    @Override
197    public int hashCode() {
198        final int prime = 31;
199        int result = 1;
200        result = prime * result + Arrays.hashCode(entries);
201        result = prime * result + (locks != null ? locks.monitorId.getLockDepth() : 0);
202        result = prime * result + ((materializedValue == null) ? 0 : materializedValue.hashCode());
203        return result;
204    }
205
206    @Override
207    public boolean equals(Object obj) {
208        if (this == obj) {
209            return true;
210        }
211        if (obj == null || getClass() != obj.getClass()) {
212            return false;
213        }
214        ObjectState other = (ObjectState) obj;
215        if (!Arrays.equals(entries, other.entries)) {
216            return false;
217        }
218        if (!locksEqual(other)) {
219            return false;
220        }
221        if (materializedValue == null) {
222            if (other.materializedValue != null) {
223                return false;
224            }
225        } else if (!materializedValue.equals(other.materializedValue)) {
226            return false;
227        }
228        return true;
229    }
230
231    public ObjectState share() {
232        copyOnWrite = true;
233        return this;
234    }
235}