< prev index next >

src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/VirtualizerToolImpl.java

Print this page

        

@@ -28,22 +28,26 @@
 
 import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
 import org.graalvm.compiler.debug.DebugContext;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodes.ConstantNode;
 import org.graalvm.compiler.nodes.FixedNode;
 import org.graalvm.compiler.nodes.FixedWithNextNode;
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.calc.FloatingNode;
+import org.graalvm.compiler.nodes.calc.UnpackEndianHalfNode;
 import org.graalvm.compiler.nodes.java.MonitorIdNode;
 import org.graalvm.compiler.nodes.spi.LoweringProvider;
 import org.graalvm.compiler.nodes.spi.VirtualizerTool;
+import org.graalvm.compiler.nodes.virtual.VirtualInstanceNode;
 import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
 import org.graalvm.compiler.options.OptionValues;
 
 import jdk.vm.ci.meta.Assumptions;
 import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.JavaConstant;
 import jdk.vm.ci.meta.JavaKind;
 import jdk.vm.ci.meta.MetaAccessProvider;
 
 /**
  * Forwards calls from {@link VirtualizerTool} to the actual {@link PartialEscapeBlockState}.

@@ -56,10 +60,11 @@
     private final PartialEscapeClosure<?> closure;
     private final Assumptions assumptions;
     private final OptionValues options;
     private final DebugContext debug;
     private final LoweringProvider loweringProvider;
+    private ConstantNode illegalConstant;
 
     VirtualizerToolImpl(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, ConstantFieldProvider constantFieldProvider, PartialEscapeClosure<?> closure,
                     Assumptions assumptions, OptionValues options, DebugContext debug, LoweringProvider loweringProvider) {
         this.metaAccess = metaAccess;
         this.constantReflection = constantReflection;

@@ -123,21 +128,85 @@
     public ValueNode getEntry(VirtualObjectNode virtualObject, int index) {
         return state.getObjectState(virtualObject).getEntry(index);
     }
 
     @Override
-    public void setVirtualEntry(VirtualObjectNode virtual, int index, ValueNode value, boolean unsafe) {
+    public boolean setVirtualEntry(VirtualObjectNode virtual, int index, ValueNode value, JavaKind theAccessKind, long offset) {
         ObjectState obj = state.getObjectState(virtual);
         assert obj.isVirtual() : "not virtual: " + obj;
         ValueNode newValue;
+        JavaKind entryKind = virtual.entryKind(index);
+        JavaKind accessKind = theAccessKind != null ? theAccessKind : entryKind;
         if (value == null) {
             newValue = null;
         } else {
             newValue = closure.getAliasAndResolve(state, value);
-            assert unsafe || obj.getEntry(index) == null || obj.getEntry(index).getStackKind() == newValue.getStackKind() || (isObjectEntry(obj.getEntry(index)) && isObjectEntry(newValue));
         }
+        getDebug().log(DebugContext.DETAILED_LEVEL, "Setting entry %d in virtual object %s %s results in %s", index, virtual.getObjectId(), virtual, state.getObjectState(virtual.getObjectId()));
+        ValueNode oldValue = getEntry(virtual, index);
+        boolean canVirtualize = entryKind == accessKind || (entryKind == accessKind.getStackKind() && virtual instanceof VirtualInstanceNode);
+        if (!canVirtualize) {
+            if (entryKind == JavaKind.Long && oldValue.getStackKind() == newValue.getStackKind() && oldValue.getStackKind().isPrimitive()) {
+                /*
+                 * Special case: If the entryKind is long, allow arbitrary kinds as long as a value
+                 * of the same kind is already there. This can only happen if some other node
+                 * initialized the entry with a value of a different kind. One example where this
+                 * happens is the Truffle NewFrameNode.
+                 */
+                getDebug().log(DebugContext.DETAILED_LEVEL, "virtualizing %s with primitive of kind %s in long entry ", current, oldValue.getStackKind());
+                canVirtualize = true;
+            } else if (entryKind == JavaKind.Int && (accessKind == JavaKind.Long || accessKind == JavaKind.Double) && offset % 8 == 0) {
+                /*
+                 * Special case: Allow storing a single long or double value into two consecutive
+                 * int slots.
+                 */
+                int nextIndex = virtual.entryIndexForOffset(offset + 4, JavaKind.Int);
+                if (nextIndex != -1) {
+                    canVirtualize = true;
+                    assert nextIndex == index + 1 : "expected to be sequential";
+                    getDebug().log(DebugContext.DETAILED_LEVEL, "virtualizing %s for double word stored in two ints", current);
+                }
+            }
+        }
+
+        if (canVirtualize) {
+            getDebug().log(DebugContext.DETAILED_LEVEL, "virtualizing %s for entryKind %s and access kind %s", current, entryKind, accessKind);
         state.setEntry(virtual.getObjectId(), index, newValue);
+            if (entryKind == JavaKind.Int) {
+                if (accessKind.needsTwoSlots()) {
+                    // Storing double word value two int slots
+                    assert virtual.entryKind(index + 1) == JavaKind.Int;
+                    state.setEntry(virtual.getObjectId(), index + 1, getIllegalConstant());
+                } else if (oldValue.getStackKind() == JavaKind.Double || oldValue.getStackKind() == JavaKind.Long) {
+                    // Splitting double word constant by storing over it with an int
+                    getDebug().log(DebugContext.DETAILED_LEVEL, "virtualizing %s producing second half of double word value %s", current, oldValue);
+                    ValueNode secondHalf = UnpackEndianHalfNode.create(oldValue, false);
+                    addNode(secondHalf);
+                    state.setEntry(virtual.getObjectId(), index + 1, secondHalf);
+                }
+            }
+            if (oldValue.isConstant() && oldValue.asConstant().equals(JavaConstant.forIllegal())) {
+                // Storing into second half of double, so replace previous value
+                ValueNode previous = getEntry(virtual, index - 1);
+                getDebug().log(DebugContext.DETAILED_LEVEL, "virtualizing %s producing first half of double word value %s", current, previous);
+                ValueNode firstHalf = UnpackEndianHalfNode.create(previous, true);
+                addNode(firstHalf);
+                state.setEntry(virtual.getObjectId(), index - 1, firstHalf);
+            }
+            return true;
+        }
+        // Should only occur if there are mismatches between the entry and access kind
+        assert entryKind != accessKind;
+        return false;
+    }
+
+    private ValueNode getIllegalConstant() {
+        if (illegalConstant == null) {
+            illegalConstant = ConstantNode.forConstant(JavaConstant.forIllegal(), getMetaAccessProvider());
+            addNode(illegalConstant);
+        }
+        return illegalConstant;
     }
 
     @Override
     public void setEnsureVirtualized(VirtualObjectNode virtualObject, boolean ensureVirtualized) {
         int id = virtualObject.getObjectId();

@@ -147,14 +216,10 @@
     @Override
     public boolean getEnsureVirtualized(VirtualObjectNode virtualObject) {
         return state.getObjectState(virtualObject).getEnsureVirtualized();
     }
 
-    private static boolean isObjectEntry(ValueNode value) {
-        return value.getStackKind() == JavaKind.Object || value instanceof VirtualObjectNode;
-    }
-
     @Override
     public void replaceWithVirtual(VirtualObjectNode virtual) {
         closure.addVirtualAlias(virtual, current);
         effects.deleteNode(current);
         deleted = true;
< prev index next >