changeset 22273:e8dc090e167f

keep "ensureVirtual" flag for objects during escape analysis
author Lukas Stadler <lukas.stadler@oracle.com>
date Tue, 21 Jul 2015 14:14:41 +0200
parents e4efc2b03eb4
children b6d504612b3f
files graal/com.oracle.graal.api.directives/src/com/oracle/graal/api/directives/GraalDirectives.java graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PEAAssertionsTest.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Virtualizable.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizerTool.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/CommitAllocationNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/EnsureVirtualizedNode.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StandardGraphBuilderPlugins.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BasicObjectCloneNode.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/MaterializeFrameNode.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/NewFrameNode.java graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ObjectState.java graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeBlockState.java graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java
diffstat 17 files changed, 394 insertions(+), 29 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.api.directives/src/com/oracle/graal/api/directives/GraalDirectives.java	Tue Jul 21 14:09:39 2015 +0200
+++ b/graal/com.oracle.graal.api.directives/src/com/oracle/graal/api/directives/GraalDirectives.java	Tue Jul 21 14:14:41 2015 +0200
@@ -283,4 +283,17 @@
         }
         return value;
     }
+
+    /**
+     * Ensures that the given object will be virtual (escape analyzed) at all points that are
+     * dominated by the current position.
+     */
+    public static void ensureVirtualized(@SuppressWarnings("unused") Object object) {
+    }
+
+    /**
+     * Ensures that the given object will be virtual at the current position.
+     */
+    public static void ensureVirtualizedHere(@SuppressWarnings("unused") Object object) {
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PEAAssertionsTest.java	Tue Jul 21 14:14:41 2015 +0200
@@ -0,0 +1,235 @@
+/*
+ * Copyright (c) 2015, 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.graal.compiler.test.ea;
+
+import jdk.internal.jvmci.code.*;
+
+import org.junit.*;
+
+import com.oracle.graal.api.directives.*;
+import com.oracle.graal.compiler.test.*;
+
+public class PEAAssertionsTest extends GraalCompilerTest {
+
+    public static Object field;
+
+    public static void snippet1(int i) {
+        Integer object = new Integer(i);
+        GraalDirectives.ensureVirtualized(object);
+    }
+
+    @Test
+    public void test1() {
+        test("snippet1", 1);
+    }
+
+    public static void snippet2(int i) {
+        Integer object = new Integer(i);
+        GraalDirectives.ensureVirtualized(object);
+        field = object; // assert here
+    }
+
+    @Test(expected = SourceStackTrace.class)
+    public void test2() {
+        test("snippet2", 1);
+    }
+
+    public static void snippet3(int i) {
+        Integer object = new Integer(i);
+        field = object;
+        GraalDirectives.ensureVirtualized(object); // assert here
+    }
+
+    @Test(expected = SourceStackTrace.class)
+    public void test3() {
+        test("snippet3", 1);
+    }
+
+    public static void snippetHere1(int i) {
+        Integer object = new Integer(i);
+        GraalDirectives.ensureVirtualizedHere(object);
+    }
+
+    @Test
+    public void testHere1() {
+        test("snippetHere1", 1);
+    }
+
+    public static void snippetHere2(int i) {
+        Integer object = new Integer(i);
+        GraalDirectives.ensureVirtualizedHere(object);
+        field = object;
+    }
+
+    @Test
+    public void testHere2() {
+        test("snippetHere2", 1);
+    }
+
+    public static void snippetHere3(int i) {
+        Integer object = new Integer(i);
+        field = object;
+        GraalDirectives.ensureVirtualizedHere(object); // assert here
+    }
+
+    @Test(expected = SourceStackTrace.class)
+    public void testHere3() {
+        test("snippetHere3", 1);
+    }
+
+    public static void snippetBoxing1(int i) {
+        Integer object = i;
+        GraalDirectives.ensureVirtualizedHere(object); // assert here
+    }
+
+    @Test(expected = SourceStackTrace.class)
+    public void testBoxing1() {
+        test("snippetBoxing1", 1);
+    }
+
+    public static void snippetBoxing2(int i) {
+        Integer object = i;
+        GraalDirectives.ensureVirtualized(object); // assert here
+        field = object;
+    }
+
+    @Test(expected = SourceStackTrace.class)
+    public void testBoxing2() {
+        test("snippetBoxing2", 1);
+    }
+
+    public static void snippetControlFlow1(boolean b, int i) {
+        Integer object = new Integer(i);
+        if (b) {
+            GraalDirectives.ensureVirtualized(object);
+        }
+        field = object;
+    }
+
+    @Test
+    public void testControlFlow1() {
+        test("snippetControlFlow1", true, 1);
+    }
+
+    public static void snippetControlFlow2(boolean b, int i) {
+        Integer object = new Integer(i);
+        if (b) {
+            GraalDirectives.ensureVirtualized(object);
+        } else {
+            GraalDirectives.ensureVirtualized(object);
+        }
+        field = object; // assert here
+    }
+
+    @Test(expected = SourceStackTrace.class)
+    public void testControlFlow2() {
+        test("snippetControlFlow2", true, 1);
+    }
+
+    public static void snippetControlFlow3(boolean b, int i) {
+        Integer object = new Integer(i);
+        GraalDirectives.ensureVirtualized(object);
+        if (b) {
+            field = 1;
+        } else {
+            field = 2;
+        }
+        field = object; // assert here
+    }
+
+    @Test(expected = SourceStackTrace.class)
+    public void testControlFlow3() {
+        test("snippetControlFlow3", true, 1);
+    }
+
+    public static void snippetControlFlow4(boolean b, int i) {
+        Integer object = new Integer(i);
+        if (b) {
+            field = object;
+        } else {
+            field = 2;
+        }
+        GraalDirectives.ensureVirtualized(object); // assert here
+    }
+
+    @Test(expected = SourceStackTrace.class)
+    public void testControlFlow4() {
+        test("snippetControlFlow4", true, 1);
+    }
+
+    public static void snippetControlFlow5(boolean b, int i) {
+        Integer object = new Integer(i);
+        if (b) {
+            field = object;
+        } else {
+            field = 2;
+        }
+        GraalDirectives.ensureVirtualizedHere(object); // assert here
+    }
+
+    @Test(expected = SourceStackTrace.class)
+    public void testControlFlow5() {
+        test("snippetControlFlow5", true, 1);
+    }
+
+    public static final class TestClass {
+        Object a;
+        Object b;
+    }
+
+    public static void snippetIndirect1(boolean b, int i) {
+        Integer object = new Integer(i);
+        TestClass t = new TestClass();
+        t.a = object;
+        GraalDirectives.ensureVirtualized(object);
+
+        if (b) {
+            field = t; // assert here
+        } else {
+            field = 2;
+        }
+    }
+
+    @Test(expected = SourceStackTrace.class)
+    public void testIndirect1() {
+        test("snippetIndirect1", true, 1);
+    }
+
+    public static void snippetIndirect2(boolean b, int i) {
+        Integer object = new Integer(i);
+        TestClass t = new TestClass();
+        t.a = object;
+        GraalDirectives.ensureVirtualized(t);
+
+        if (b) {
+            field = object;
+        } else {
+            field = 2;
+        }
+    }
+
+    @Test
+    public void testIndirect2() {
+        test("snippetIndirect2", true, 1);
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java	Tue Jul 21 14:09:39 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java	Tue Jul 21 14:14:41 2015 +0200
@@ -82,7 +82,7 @@
         VirtualBoxingNode newVirtual = new VirtualBoxingNode(type, boxingKind);
         assert newVirtual.getFields().length == 1;
 
-        tool.createVirtualObject(newVirtual, new ValueNode[]{v}, Collections.<MonitorIdNode> emptyList());
+        tool.createVirtualObject(newVirtual, new ValueNode[]{v}, Collections.<MonitorIdNode> emptyList(), false);
         tool.replaceWithVirtual(newVirtual);
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java	Tue Jul 21 14:09:39 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java	Tue Jul 21 14:14:41 2015 +0200
@@ -84,7 +84,7 @@
                     state[i] = defaultForKind;
                 }
                 VirtualObjectNode virtualObject = createVirtualArrayNode(constantLength);
-                tool.createVirtualObject(virtualObject, state, Collections.<MonitorIdNode> emptyList());
+                tool.createVirtualObject(virtualObject, state, Collections.<MonitorIdNode> emptyList(), false);
                 tool.replaceWithVirtual(virtualObject);
             }
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java	Tue Jul 21 14:09:39 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java	Tue Jul 21 14:14:41 2015 +0200
@@ -79,7 +79,7 @@
             for (int i = 0; i < state.length; i++) {
                 state[i] = defaultFieldValue(fields[i]);
             }
-            tool.createVirtualObject(virtualObject, state, Collections.<MonitorIdNode> emptyList());
+            tool.createVirtualObject(virtualObject, state, Collections.<MonitorIdNode> emptyList(), false);
             tool.replaceWithVirtual(virtualObject);
         }
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Virtualizable.java	Tue Jul 21 14:09:39 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Virtualizable.java	Tue Jul 21 14:14:41 2015 +0200
@@ -52,6 +52,10 @@
         public abstract MonitorIdNode removeLock();
 
         public abstract ValueNode getMaterializedValue();
+
+        public abstract void setEnsureVirtualized(boolean ensureVirtualized);
+
+        public abstract boolean getEnsureVirtualized();
     }
 
     /**
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizerTool.java	Tue Jul 21 14:09:39 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizerTool.java	Tue Jul 21 14:14:41 2015 +0200
@@ -67,8 +67,9 @@
      * @param virtualObject the new virtual object.
      * @param entryState the initial state of the virtual object's fields.
      * @param locks the initial locking depths.
+     * @param ensureVirtualized true if this object needs to stay virtual
      */
-    void createVirtualObject(VirtualObjectNode virtualObject, ValueNode[] entryState, List<MonitorIdNode> locks);
+    void createVirtualObject(VirtualObjectNode virtualObject, ValueNode[] entryState, List<MonitorIdNode> locks, boolean ensureVirtualized);
 
     /**
      * Queries the current state of the given value: if it is virtualized (thread-local and the
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/CommitAllocationNode.java	Tue Jul 21 14:09:39 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/CommitAllocationNode.java	Tue Jul 21 14:14:41 2015 +0200
@@ -36,10 +36,12 @@
 public final class CommitAllocationNode extends FixedWithNextNode implements VirtualizableAllocation, Lowerable, Simplifiable {
 
     public static final NodeClass<CommitAllocationNode> TYPE = NodeClass.create(CommitAllocationNode.class);
+
     @Input NodeInputList<VirtualObjectNode> virtualObjects = new NodeInputList<>(this);
     @Input NodeInputList<ValueNode> values = new NodeInputList<>(this);
     @Input(InputType.Association) NodeInputList<MonitorIdNode> locks = new NodeInputList<>(this);
     protected ArrayList<Integer> lockIndexes = new ArrayList<>(Arrays.asList(0));
+    protected ArrayList<Boolean> ensureVirtual = new ArrayList<>();
 
     public CommitAllocationNode() {
         super(TYPE, StampFactory.forVoid());
@@ -57,6 +59,10 @@
         return locks.subList(lockIndexes.get(objIndex), lockIndexes.get(objIndex + 1));
     }
 
+    public List<Boolean> getEnsureVirtual() {
+        return ensureVirtual;
+    }
+
     @Override
     public boolean verify() {
         assertTrue(virtualObjects.size() + 1 == lockIndexes.size(), "lockIndexes size doesn't match " + virtualObjects + ", " + lockIndexes);
@@ -66,11 +72,17 @@
             valueCount += virtual.entryCount();
         }
         assertTrue(values.size() == valueCount, "values size doesn't match");
+        assertTrue(virtualObjects.size() == ensureVirtual.size(), "ensureVirtual size doesn't match");
         return super.verify();
     }
 
     @Override
     public void lower(LoweringTool tool) {
+        for (int i = 0; i < virtualObjects.size(); i++) {
+            if (ensureVirtual.get(i)) {
+                EnsureVirtualizedNode.ensureVirtualFailure(this, virtualObjects.get(i).stamp());
+            }
+        }
         tool.getLowerer().lower(this, tool);
     }
 
@@ -90,7 +102,7 @@
         for (int i = 0; i < virtualObjects.size(); i++) {
             VirtualObjectNode virtualObject = virtualObjects.get(i);
             int entryCount = virtualObject.entryCount();
-            tool.createVirtualObject(virtualObject, values.subList(pos, pos + entryCount).toArray(new ValueNode[entryCount]), getLocks(i));
+            tool.createVirtualObject(virtualObject, values.subList(pos, pos + entryCount).toArray(new ValueNode[entryCount]), getLocks(i), ensureVirtual.get(i));
             pos += entryCount;
         }
         tool.delete();
@@ -166,6 +178,7 @@
             List<VirtualObjectNode> newVirtualObjects = new ArrayList<>(usedCount);
             List<MonitorIdNode> newLocks = new ArrayList<>(usedCount);
             ArrayList<Integer> newLockIndexes = new ArrayList<>(usedCount + 1);
+            ArrayList<Boolean> newEnsureVirtual = new ArrayList<>(usedCount);
             newLockIndexes.add(0);
             List<ValueNode> newValues = new ArrayList<>();
             int valuePos = 0;
@@ -176,6 +189,7 @@
                     newLocks.addAll(getLocks(objIndex));
                     newLockIndexes.add(newLocks.size());
                     newValues.addAll(values.subList(valuePos, valuePos + virtualObject.entryCount()));
+                    newEnsureVirtual.add(ensureVirtual.get(objIndex));
                 }
                 valuePos += virtualObject.entryCount();
             }
@@ -186,6 +200,7 @@
             values.clear();
             values.addAll(newValues);
             lockIndexes = newLockIndexes;
+            ensureVirtual = newEnsureVirtual;
         }
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/EnsureVirtualizedNode.java	Tue Jul 21 14:14:41 2015 +0200
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2015, 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.graal.nodes.virtual;
+
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodeinfo.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.util.*;
+
+@NodeInfo
+public final class EnsureVirtualizedNode extends FixedWithNextNode implements Virtualizable, Lowerable {
+
+    public static final NodeClass<EnsureVirtualizedNode> TYPE = NodeClass.create(EnsureVirtualizedNode.class);
+
+    @Input ValueNode object;
+    private final boolean localOnly;
+
+    public EnsureVirtualizedNode(ValueNode object, boolean localOnly) {
+        super(TYPE, StampFactory.forVoid());
+        this.object = object;
+        this.localOnly = localOnly;
+    }
+
+    public void virtualize(VirtualizerTool tool) {
+        State state = tool.getObjectState(object);
+        if (state != null && state.getState() == EscapeState.Virtual) {
+            if (state.getVirtualObject() instanceof VirtualBoxingNode) {
+                Throwable exception = new VerificationError("ensureVirtual is not valid for boxing objects: %s", state.getVirtualObject().type().getName());
+                throw GraphUtil.approxSourceException(this, exception);
+            }
+            if (!localOnly) {
+                state.setEnsureVirtualized(true);
+            }
+            tool.delete();
+        }
+    }
+
+    public void lower(LoweringTool tool) {
+        ensureVirtualFailure(this, object.stamp());
+    }
+
+    public static void ensureVirtualFailure(Node location, Stamp stamp) {
+        Throwable exception = new VerificationError("Object should not be materialized (stamp=%s):", stamp);
+        throw GraphUtil.approxSourceException(location, exception);
+    }
+}
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StandardGraphBuilderPlugins.java	Tue Jul 21 14:09:39 2015 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StandardGraphBuilderPlugins.java	Tue Jul 21 14:14:41 2015 +0200
@@ -46,6 +46,7 @@
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.util.*;
+import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.replacements.nodes.*;
 import com.oracle.graal.replacements.nodes.arithmetic.*;
 
@@ -663,6 +664,19 @@
                 return true;
             }
         });
+
+        r.register1("ensureVirtualized", Object.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object) {
+                b.add(new EnsureVirtualizedNode(object, false));
+                return true;
+            }
+        });
+        r.register1("ensureVirtualizedHere", Object.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object) {
+                b.add(new EnsureVirtualizedNode(object, true));
+                return true;
+            }
+        });
     }
 
     private static void registerJMHBlackholePlugins(InvocationPlugins plugins) {
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BasicObjectCloneNode.java	Tue Jul 21 14:09:39 2015 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BasicObjectCloneNode.java	Tue Jul 21 14:14:41 2015 +0200
@@ -66,7 +66,7 @@
     /*
      * Looks at the given stamp and determines if it is an exact type (or can be assumed to be an
      * exact type) and if it is a cloneable type.
-     *
+     * 
      * If yes, then the exact type is returned, otherwise it returns null.
      */
     protected static ResolvedJavaType getConcreteType(Stamp stamp, Assumptions assumptions, MetaAccessProvider metaAccess) {
@@ -99,7 +99,7 @@
                     newEntryState[i] = originalState.getEntry(i);
                 }
                 VirtualObjectNode newVirtual = originalVirtual.duplicate();
-                tool.createVirtualObject(newVirtual, newEntryState, Collections.<MonitorIdNode> emptyList());
+                tool.createVirtualObject(newVirtual, newEntryState, Collections.<MonitorIdNode> emptyList(), false);
                 tool.replaceWithVirtual(newVirtual);
             }
         } else {
@@ -120,7 +120,7 @@
                     state[i] = loads[i] = new LoadFieldNode(obj, fields[i]);
                     tool.addNode(loads[i]);
                 }
-                tool.createVirtualObject(newVirtual, state, Collections.<MonitorIdNode> emptyList());
+                tool.createVirtualObject(newVirtual, state, Collections.<MonitorIdNode> emptyList(), false);
                 tool.replaceWithVirtual(newVirtual);
             }
         }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/MaterializeFrameNode.java	Tue Jul 21 14:09:39 2015 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/MaterializeFrameNode.java	Tue Jul 21 14:14:41 2015 +0200
@@ -25,7 +25,6 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.truffle.api.frame.*;
 
 /**
  * Intrinsic node for materializing a Truffle frame.
@@ -44,7 +43,4 @@
     public ValueNode getFrame() {
         return frame;
     }
-
-    @NodeIntrinsic
-    public static native MaterializedFrame materialize(VirtualFrame frame);
 }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/NewFrameNode.java	Tue Jul 21 14:09:39 2015 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/NewFrameNode.java	Tue Jul 21 14:14:41 2015 +0200
@@ -182,12 +182,12 @@
             graph().getAssumptions().record(new AssumptionValidAssumption((OptimizedAssumption) frameDescriptor.getVersion()));
         }
 
-        tool.createVirtualObject(virtualFrameObjectArray, objectArrayEntryState, Collections.<MonitorIdNode> emptyList());
+        tool.createVirtualObject(virtualFrameObjectArray, objectArrayEntryState, Collections.<MonitorIdNode> emptyList(), false);
         if (virtualFramePrimitiveArray != null) {
-            tool.createVirtualObject(virtualFramePrimitiveArray, primitiveArrayEntryState, Collections.<MonitorIdNode> emptyList());
+            tool.createVirtualObject(virtualFramePrimitiveArray, primitiveArrayEntryState, Collections.<MonitorIdNode> emptyList(), false);
         }
         if (virtualFrameTagArray != null) {
-            tool.createVirtualObject(virtualFrameTagArray, tagArrayEntryState, Collections.<MonitorIdNode> emptyList());
+            tool.createVirtualObject(virtualFrameTagArray, tagArrayEntryState, Collections.<MonitorIdNode> emptyList(), false);
         }
 
         assert frameFields.length == 5 || frameFields.length == 3;
@@ -202,7 +202,7 @@
         if (tagsField != null) {
             frameEntryState[frameFieldList.indexOf(tagsField)] = virtualFrameTagArray;
         }
-        tool.createVirtualObject(virtualFrame, frameEntryState, Collections.<MonitorIdNode> emptyList());
+        tool.createVirtualObject(virtualFrame, frameEntryState, Collections.<MonitorIdNode> emptyList(), false);
         tool.replaceWithVirtual(virtualFrame);
     }
 
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ObjectState.java	Tue Jul 21 14:09:39 2015 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ObjectState.java	Tue Jul 21 14:14:41 2015 +0200
@@ -49,28 +49,31 @@
     private ValueNode[] entries;
     private ValueNode materializedValue;
     private LockState locks;
+    private boolean ensureVirtualized;
 
     private EscapeObjectState cachedState;
 
-    public ObjectState(VirtualObjectNode virtual, ValueNode[] entries, EscapeState state, List<MonitorIdNode> locks) {
-        this(virtual, entries, state, (LockState) null);
+    public ObjectState(VirtualObjectNode virtual, ValueNode[] entries, EscapeState state, List<MonitorIdNode> locks, boolean ensureVirtualized) {
+        this(virtual, entries, state, (LockState) null, ensureVirtualized);
         for (int i = locks.size() - 1; i >= 0; i--) {
             this.locks = new LockState(locks.get(i), this.locks);
         }
     }
 
-    public ObjectState(VirtualObjectNode virtual, ValueNode[] entries, EscapeState state, LockState locks) {
+    public ObjectState(VirtualObjectNode virtual, ValueNode[] entries, EscapeState state, LockState locks, boolean ensureVirtualized) {
         this.virtual = virtual;
         this.entries = entries;
         this.state = state;
         this.locks = locks;
+        this.ensureVirtualized = ensureVirtualized;
     }
 
-    public ObjectState(VirtualObjectNode virtual, ValueNode materializedValue, EscapeState state, LockState locks) {
+    public ObjectState(VirtualObjectNode virtual, ValueNode materializedValue, EscapeState state, LockState locks, boolean ensureVirtualized) {
         this.virtual = virtual;
         this.materializedValue = materializedValue;
         this.state = state;
         this.locks = locks;
+        this.ensureVirtualized = ensureVirtualized;
     }
 
     private ObjectState(ObjectState other) {
@@ -80,6 +83,7 @@
         locks = other.locks;
         state = other.state;
         cachedState = other.cachedState;
+        ensureVirtualized = other.ensureVirtualized;
     }
 
     public ObjectState cloneState() {
@@ -185,6 +189,16 @@
     }
 
     @Override
+    public void setEnsureVirtualized(boolean ensureVirtualized) {
+        this.ensureVirtualized = ensureVirtualized;
+    }
+
+    @Override
+    public boolean getEnsureVirtualized() {
+        return ensureVirtualized;
+    }
+
+    @Override
     public String toString() {
         StringBuilder str = new StringBuilder().append('{');
         if (locks != null) {
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeBlockState.java	Tue Jul 21 14:09:39 2015 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeBlockState.java	Tue Jul 21 14:14:41 2015 +0200
@@ -74,7 +74,8 @@
         List<ValueNode> values = new ArrayList<>(8);
         List<List<MonitorIdNode>> locks = new ArrayList<>(2);
         List<ValueNode> otherAllocations = new ArrayList<>(2);
-        materializeWithCommit(fixed, virtual, objects, locks, values, otherAllocations, state);
+        List<Boolean> ensureVirtual = new ArrayList<>(2);
+        materializeWithCommit(fixed, virtual, objects, locks, values, ensureVirtual, otherAllocations, state);
 
         materializeEffects.add("materializeBefore", (graph, obsoleteNodes) -> {
             for (ValueNode otherAllocation : otherAllocations) {
@@ -102,6 +103,7 @@
                 for (List<MonitorIdNode> monitorIds : locks) {
                     commit.addLocks(monitorIds);
                 }
+                commit.getEnsureVirtual().addAll(ensureVirtual);
 
                 assert commit.usages().filter(AllocatedObjectNode.class).count() == commit.getUsageCount();
                 List<AllocatedObjectNode> materializedValues = commit.usages().filter(AllocatedObjectNode.class).snapshot();
@@ -115,7 +117,7 @@
     }
 
     private void materializeWithCommit(FixedNode fixed, VirtualObjectNode virtual, List<AllocatedObjectNode> objects, List<List<MonitorIdNode>> locks, List<ValueNode> values,
-                    List<ValueNode> otherAllocations, EscapeState state) {
+                    List<Boolean> ensureVirtual, List<ValueNode> otherAllocations, EscapeState state) {
         ObjectState obj = getObjectState(virtual);
 
         ValueNode[] entries = obj.getEntries();
@@ -125,6 +127,7 @@
         if (representation instanceof AllocatedObjectNode) {
             objects.add((AllocatedObjectNode) representation);
             locks.add(LockState.asList(obj.getLocks()));
+            ensureVirtual.add(obj.getEnsureVirtualized());
             int pos = values.size();
             while (values.size() < pos + entries.length) {
                 values.add(null);
@@ -133,7 +136,7 @@
                 if (entries[i] instanceof VirtualObjectNode) {
                     ObjectState entryObj = getObjectState((VirtualObjectNode) entries[i]);
                     if (entryObj.isVirtual()) {
-                        materializeWithCommit(fixed, entryObj.getVirtualObject(), objects, locks, values, otherAllocations, state);
+                        materializeWithCommit(fixed, entryObj.getVirtualObject(), objects, locks, values, ensureVirtual, otherAllocations, state);
                     }
                     values.set(pos + i, entryObj.getMaterializedValue());
                 } else {
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Tue Jul 21 14:09:39 2015 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Tue Jul 21 14:14:41 2015 +0200
@@ -562,7 +562,7 @@
                         materialized |= mergeObjectStates(object, objStates, states);
                     } else {
                         if (uniqueMaterializedValue != null) {
-                            newState.addObject(object, new ObjectState(object, uniqueMaterializedValue, EscapeState.Materialized, null));
+                            newState.addObject(object, new ObjectState(object, uniqueMaterializedValue, EscapeState.Materialized, null, false));
                         } else {
                             PhiNode materializedValuePhi = getPhi(object, StampFactory.forKind(Kind.Object));
                             mergeEffects.addFloatingNode(materializedValuePhi, "materializedPhi");
@@ -574,7 +574,7 @@
                                 }
                                 setPhiInput(materializedValuePhi, i, obj.getMaterializedValue());
                             }
-                            newState.addObject(object, new ObjectState(object, materializedValuePhi, EscapeState.Materialized, null));
+                            newState.addObject(object, new ObjectState(object, materializedValuePhi, EscapeState.Materialized, null, false));
                         }
                     }
                 }
@@ -615,6 +615,7 @@
          */
         private boolean mergeObjectStates(VirtualObjectNode object, ObjectState[] objStates, List<BlockT> blockStates) {
             boolean compatible = true;
+            boolean ensureVirtual = true;
             ValueNode[] values = objStates[0].getEntries().clone();
 
             // determine all entries that have a two-slot value
@@ -622,6 +623,7 @@
             outer: for (int i = 0; i < objStates.length; i++) {
                 ValueNode[] entries = objStates[i].getEntries();
                 int valueIndex = 0;
+                ensureVirtual &= objStates[i].getEnsureVirtualized();
                 while (valueIndex < values.length) {
                     Kind otherKind = entries[valueIndex].getKind();
                     Kind entryKind = object.entryKind(valueIndex);
@@ -705,7 +707,7 @@
                         values[i] = phi;
                     }
                 }
-                newState.addObject(object, new ObjectState(object, values, EscapeState.Virtual, objStates[0].getLocks()));
+                newState.addObject(object, new ObjectState(object, values, EscapeState.Virtual, objStates[0].getLocks(), ensureVirtual));
                 return materialized;
             } else {
                 // not compatible: materialize in all predecessors
@@ -716,7 +718,7 @@
                     ensureMaterialized(blockStates.get(i), obj, predecessor.getEndNode(), blockEffects.get(predecessor), METRIC_MATERIALIZATIONS_MERGE);
                     setPhiInput(materializedValuePhi, i, obj.getMaterializedValue());
                 }
-                newState.addObject(object, new ObjectState(object, materializedValuePhi, EscapeState.Materialized, null));
+                newState.addObject(object, new ObjectState(object, materializedValuePhi, EscapeState.Materialized, null, false));
                 return true;
             }
         }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java	Tue Jul 21 14:09:39 2015 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java	Tue Jul 21 14:14:41 2015 +0200
@@ -151,7 +151,7 @@
     }
 
     @Override
-    public void createVirtualObject(VirtualObjectNode virtualObject, ValueNode[] entryState, List<MonitorIdNode> locks) {
+    public void createVirtualObject(VirtualObjectNode virtualObject, ValueNode[] entryState, List<MonitorIdNode> locks, boolean ensureVirtualized) {
         VirtualUtil.trace("{{%s}} ", current);
         if (!virtualObject.isAlive()) {
             effects.addFloatingNode(virtualObject, "newVirtualObject");
@@ -166,7 +166,7 @@
                 }
             }
         }
-        state.addObject(virtualObject, new ObjectState(virtualObject, entryState, EscapeState.Virtual, locks));
+        state.addObject(virtualObject, new ObjectState(virtualObject, entryState, EscapeState.Virtual, locks, ensureVirtualized));
         closure.addAndMarkAlias(virtualObject, virtualObject);
         PartialEscapeClosure.METRIC_ALLOCATION_REMOVED.increment();
     }