diff graal/com.oracle.jvmci.code/src/com/oracle/jvmci/code/VirtualObject.java @ 21556:48c1ebd24120

renamed com.oracle.graal.api[meta|code] modules to com.oracle.jvmci.[meta|code] (JBS:GRAAL-53)
author Doug Simon <doug.simon@oracle.com>
date Wed, 27 May 2015 00:36:16 +0200
parents graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/VirtualObject.java@082417ac43e4
children f5b549811bac
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.jvmci.code/src/com/oracle/jvmci/code/VirtualObject.java	Wed May 27 00:36:16 2015 +0200
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 2010, 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 com.oracle.jvmci.code;
+
+import com.oracle.jvmci.meta.ResolvedJavaField;
+import com.oracle.jvmci.meta.JavaValue;
+import com.oracle.jvmci.meta.Kind;
+import com.oracle.jvmci.meta.AbstractValue;
+import com.oracle.jvmci.meta.Value;
+import com.oracle.jvmci.meta.ResolvedJavaType;
+import com.oracle.jvmci.meta.LIRKind;
+import java.util.*;
+
+
+/**
+ * An instance of this class represents an object whose allocation was removed by escape analysis.
+ * The information stored in the {@link VirtualObject} is used during deoptimization to recreate the
+ * object.
+ */
+public final class VirtualObject extends AbstractValue implements JavaValue {
+
+    private final ResolvedJavaType type;
+    private Value[] values;
+    private final int id;
+
+    /**
+     * Creates a new {@link VirtualObject} for the given type, with the given fields. If
+     * {@code type} is an instance class then {@code values} provides the values for the fields
+     * returned by {@link ResolvedJavaType#getInstanceFields(boolean) getInstanceFields(true)}. If
+     * {@code type} is an array then the length of the values array determines the reallocated array
+     * length.
+     *
+     * @param type the type of the object whose allocation was removed during compilation. This can
+     *            be either an instance of an array type.
+     * @param values an array containing all the values to be stored into the object when it is
+     *            recreated
+     * @param id a unique id that identifies the object within the debug information for one
+     *            position in the compiled code.
+     * @return a new {@link VirtualObject} instance.
+     */
+    public static VirtualObject get(ResolvedJavaType type, Value[] values, int id) {
+        return new VirtualObject(type, values, id);
+    }
+
+    private VirtualObject(ResolvedJavaType type, Value[] values, int id) {
+        super(LIRKind.reference(Kind.Object));
+        this.type = type;
+        this.values = values;
+        this.id = id;
+    }
+
+    private static StringBuilder appendValue(StringBuilder buf, Value value, Set<VirtualObject> visited) {
+        if (value instanceof VirtualObject) {
+            VirtualObject vo = (VirtualObject) value;
+            buf.append("vobject:").append(vo.type.toJavaName(false)).append(':').append(vo.id);
+            if (!visited.contains(vo)) {
+                visited.add(vo);
+                buf.append('{');
+                if (vo.values == null) {
+                    buf.append("<uninitialized>");
+                } else {
+                    if (vo.type.isArray()) {
+                        for (int i = 0; i < vo.values.length; i++) {
+                            if (i != 0) {
+                                buf.append(',');
+                            }
+                            buf.append(i).append('=');
+                            appendValue(buf, vo.values[i], visited);
+                        }
+                    } else {
+                        ResolvedJavaField[] fields = vo.type.getInstanceFields(true);
+                        assert fields.length == vo.values.length : vo.type + ", fields=" + Arrays.toString(fields) + ", values=" + Arrays.toString(vo.values);
+                        for (int i = 0; i < vo.values.length; i++) {
+                            if (i != 0) {
+                                buf.append(',');
+                            }
+                            buf.append(fields[i].getName()).append('=');
+                            appendValue(buf, vo.values[i], visited);
+                        }
+                    }
+                }
+                buf.append('}');
+            }
+        } else {
+            buf.append(value);
+        }
+        return buf;
+    }
+
+    @Override
+    public String toString() {
+        Set<VirtualObject> visited = Collections.newSetFromMap(new IdentityHashMap<VirtualObject, Boolean>());
+        return appendValue(new StringBuilder(), this, visited).toString();
+    }
+
+    /**
+     * Returns the type of the object whose allocation was removed during compilation. This can be
+     * either an instance of an array type.
+     */
+    public ResolvedJavaType getType() {
+        return type;
+    }
+
+    /**
+     * Returns an array containing all the values to be stored into the object when it is recreated.
+     */
+    public Value[] getValues() {
+        return values;
+    }
+
+    /**
+     * Returns the unique id that identifies the object within the debug information for one
+     * position in the compiled code.
+     */
+    public int getId() {
+        return id;
+    }
+
+    private static boolean checkValues(ResolvedJavaType type, Value[] values) {
+        if (values != null) {
+            if (!type.isArray()) {
+                ResolvedJavaField[] fields = type.getInstanceFields(true);
+                int fieldIndex = 0;
+                for (int i = 0; i < values.length; i++) {
+                    ResolvedJavaField field = fields[fieldIndex++];
+                    Kind valKind = values[i].getKind().getStackKind();
+                    if (field.getKind() == Kind.Object) {
+                        assert values[i].getLIRKind().isReference(0) : field + ": " + valKind + " != " + field.getKind();
+                    } else {
+                        if ((valKind == Kind.Double || valKind == Kind.Long) && field.getKind() == Kind.Int) {
+                            assert fields[fieldIndex].getKind() == Kind.Int;
+                            fieldIndex++;
+                        } else {
+                            assert valKind == field.getKind().getStackKind() : field + ": " + valKind + " != " + field.getKind();
+                        }
+                    }
+                }
+                assert fields.length == fieldIndex : type + ": fields=" + Arrays.toString(fields) + ", field values=" + Arrays.toString(values);
+            } else {
+                Kind componentKind = type.getComponentType().getKind().getStackKind();
+                if (componentKind == Kind.Object) {
+                    for (int i = 0; i < values.length; i++) {
+                        assert values[i].getLIRKind().isReference(0) : values[i].getKind() + " != " + componentKind;
+                    }
+                } else {
+                    for (int i = 0; i < values.length; i++) {
+                        assert values[i].getKind() == componentKind || componentKind.getBitCount() >= values[i].getKind().getBitCount() ||
+                                        (componentKind == Kind.Int && values[i].getKind().getBitCount() >= Kind.Int.getBitCount()) : values[i].getKind() + " != " + componentKind;
+                    }
+                }
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Overwrites the current set of values with a new one.
+     *
+     * @param values an array containing all the values to be stored into the object when it is
+     *            recreated.
+     */
+    public void setValues(Value[] values) {
+        assert checkValues(type, values);
+        this.values = values;
+    }
+
+    @Override
+    public int hashCode() {
+        return getLIRKind().hashCode() + type.hashCode();
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o == this) {
+            return true;
+        }
+        if (o instanceof VirtualObject) {
+            VirtualObject l = (VirtualObject) o;
+            if (!l.type.equals(type) || l.values.length != values.length) {
+                return false;
+            }
+            for (int i = 0; i < values.length; i++) {
+                /*
+                 * Virtual objects can form cycles. Calling equals() could therefore lead to
+                 * infinite recursion.
+                 */
+                if (!same(values[i], l.values[i])) {
+                    return false;
+                }
+            }
+            return true;
+        }
+        return false;
+    }
+
+    private static boolean same(Object o1, Object o2) {
+        return o1 == o2;
+    }
+}