changeset 7764:cff55cdeea48

implement Object.clone snippets and macro node
author Lukas Stadler <lukas.stadler@jku.at>
date Fri, 08 Feb 2013 11:14:15 +0100
parents ebba355f5605
children f20c2b1f5289
files graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ObjectCloneNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ObjectCloneSnippets.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ObjectSubstitutions.java graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java
diffstat 5 files changed, 297 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Fri Feb 08 10:41:09 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Fri Feb 08 11:14:15 2013 +0100
@@ -350,6 +350,9 @@
         if (GraalOptions.IntrinsifyArrayCopy) {
             installer.installSnippets(ArrayCopySnippets.class);
         }
+        if (GraalOptions.IntrinsifyObjectClone) {
+            installer.installSnippets(ObjectCloneSnippets.class);
+        }
 
         installer.installSnippets(CheckCastSnippets.class);
         installer.installSnippets(InstanceOfSnippets.class);
@@ -705,7 +708,7 @@
             assert loadHub.kind() == wordKind;
             LocationNode location = LocationNode.create(LocationNode.FINAL_LOCATION, wordKind, config.hubOffset, graph);
             ValueNode object = loadHub.object();
-            assert !object.isConstant();
+            assert !object.isConstant() || object.asConstant().isNull();
             ValueNode guard = tool.createNullCheckGuard(object);
             ReadNode hub = graph.add(new ReadNode(object, location, StampFactory.forKind(wordKind())));
             hub.dependencies().add(guard);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ObjectCloneNode.java	Fri Feb 08 11:14:15 2013 +0100
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2013, 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.hotspot.snippets;
+
+import java.lang.reflect.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.virtual.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.common.*;
+import com.oracle.graal.snippets.nodes.*;
+
+public class ObjectCloneNode extends MacroNode implements VirtualizableAllocation, ArrayLengthProvider {
+
+    public ObjectCloneNode(Invoke invoke) {
+        super(invoke);
+    }
+
+    @Override
+    public boolean inferStamp() {
+        return updateStamp(getObject().stamp());
+    }
+
+    private ValueNode getObject() {
+        return arguments.get(0);
+    }
+
+    private Method selectSnippetMethod(LoweringTool tool) {
+        ResolvedJavaType type = getObject().objectStamp().type();
+        if (type.isArray()) {
+            return ObjectCloneSnippets.arrayCloneMethod;
+        } else if (type.isAssignableFrom(tool.getRuntime().lookupJavaType(Object[].class))) {
+            // arrays are assignable to Object, Cloneable and Serializable
+            return ObjectCloneSnippets.genericCloneMethod;
+        } else {
+            return ObjectCloneSnippets.instanceCloneMethod;
+        }
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        if (!GraalOptions.IntrinsifyObjectClone) {
+            super.lower(tool);
+            return;
+        }
+        ResolvedJavaMethod snippetMethod = tool.getRuntime().lookupJavaMethod(selectSnippetMethod(tool));
+        if (Debug.isLogEnabled()) {
+            Debug.log("%s > Intrinsify (%s)", Debug.currentScope(), snippetMethod.getSignature().getParameterType(0, snippetMethod.getDeclaringClass()).getComponentType());
+        }
+
+        StructuredGraph snippetGraph = (StructuredGraph) snippetMethod.getCompilerStorage().get(Graph.class);
+        assert snippetGraph != null : "ObjectCloneSnippets should be installed";
+        InvokeNode invoke = replaceWithInvoke();
+        InliningUtil.inline(invoke, snippetGraph, false);
+    }
+
+    private static boolean isCloneableType(ResolvedJavaType type, MetaAccessProvider metaAccess) {
+        return metaAccess.lookupJavaType(Cloneable.class).isAssignableFrom(type);
+    }
+
+    private static ResolvedJavaType getConcreteType(ObjectStamp stamp, Assumptions assumptions) {
+        if (stamp.isExactType()) {
+            return stamp.type();
+        } else {
+            ResolvedJavaType type = stamp.type().findUniqueConcreteSubtype();
+            if (type != null) {
+                assumptions.recordConcreteSubtype(stamp.type(), type);
+            }
+            return type;
+        }
+    }
+
+    @Override
+    public void virtualize(VirtualizerTool tool) {
+        State originalState = tool.getObjectState(getObject());
+        if (originalState != null && originalState.getState() == EscapeState.Virtual) {
+            VirtualObjectNode originalVirtual = originalState.getVirtualObject();
+            if (isCloneableType(originalVirtual.type(), tool.getMetaAccessProvider())) {
+                ValueNode[] newEntryState = new ValueNode[originalVirtual.entryCount()];
+                for (int i = 0; i < newEntryState.length; i++) {
+                    newEntryState[i] = originalState.getEntry(i);
+                }
+                VirtualObjectNode newVirtual = (VirtualObjectNode) originalVirtual.copyWithInputs();
+                tool.createVirtualObject(newVirtual, newEntryState, 0);
+                tool.replaceWithVirtual(newVirtual);
+            }
+        } else {
+            ValueNode obj;
+            if (originalState != null) {
+                obj = originalState.getMaterializedValue();
+            } else {
+                obj = tool.getReplacedValue(getObject());
+            }
+            ResolvedJavaType type = getConcreteType(obj.objectStamp(), tool.getAssumptions());
+            if (isCloneableType(type, tool.getMetaAccessProvider())) {
+                if (!type.isArray()) {
+                    ResolvedJavaField[] fields = type.getInstanceFields(true);
+                    ValueNode[] state = new ValueNode[fields.length];
+                    final LoadFieldNode[] loads = new LoadFieldNode[fields.length];
+                    for (int i = 0; i < fields.length; i++) {
+                        state[i] = loads[i] = graph().add(new LoadFieldNode(obj, fields[i]));
+                    }
+
+                    VirtualObjectNode newVirtual = new VirtualInstanceNode(type, fields);
+                    final StructuredGraph structuredGraph = (StructuredGraph) graph();
+                    tool.customAction(new Runnable() {
+
+                        public void run() {
+                            for (LoadFieldNode load : loads) {
+                                structuredGraph.addBeforeFixed(ObjectCloneNode.this, load);
+                            }
+                        }
+                    });
+                    tool.createVirtualObject(newVirtual, state, 0);
+                    tool.replaceWithVirtual(newVirtual);
+                }
+            }
+        }
+    }
+
+    @Override
+    public ValueNode length() {
+        if (getObject() instanceof ArrayLengthProvider) {
+            return ((ArrayLengthProvider) getObject()).length();
+        } else {
+            return null;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ObjectCloneSnippets.java	Fri Feb 08 11:14:15 2013 +0100
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2011, 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.hotspot.snippets;
+
+import static com.oracle.graal.hotspot.snippets.HotSpotSnippetUtils.*;
+import static com.oracle.graal.snippets.nodes.BranchProbabilityNode.*;
+
+import java.lang.reflect.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.snippets.*;
+import com.oracle.graal.word.*;
+
+public class ObjectCloneSnippets implements SnippetsInterface {
+
+    public static final Method instanceCloneMethod = getCloneMethod("instanceClone");
+    public static final Method arrayCloneMethod = getCloneMethod("arrayClone");
+    public static final Method genericCloneMethod = getCloneMethod("genericClone");
+
+    private static Method getCloneMethod(String name) {
+        try {
+            return ObjectCloneSnippets.class.getDeclaredMethod(name, Object.class);
+        } catch (SecurityException | NoSuchMethodException e) {
+            throw new GraalInternalError(e);
+        }
+    }
+
+    private static Object instanceClone(Object src, Word hub, int layoutHelper) {
+        int instanceSize = layoutHelper;
+        Pointer memory = NewObjectSnippets.allocate(instanceSize);
+        Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset());
+        Object result = NewObjectSnippets.initializeObject((Word) memory, hub, prototypeMarkWord, instanceSize, false, false);
+
+        memory = Word.fromObject(result);
+        for (int offset = 2 * wordSize(); offset < instanceSize; offset += wordSize()) {
+            memory.writeWord(offset, Word.fromObject(src).readWord(offset));
+        }
+
+        return result;
+    }
+
+    private static Object arrayClone(Object src, Word hub, int layoutHelper) {
+        int arrayLength = ArrayLengthNode.arrayLength(src);
+        int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift()) & layoutHelperLog2ElementSizeMask();
+        int headerSize = (layoutHelper >> layoutHelperHeaderSizeShift()) & layoutHelperHeaderSizeMask();
+        int sizeInBytes = NewObjectSnippets.computeArrayAllocationSize(arrayLength, wordSize(), headerSize, log2ElementSize);
+
+        Pointer memory = NewObjectSnippets.allocate(sizeInBytes);
+        Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset());
+        Object result = NewObjectSnippets.initializeArray((Word) memory, hub, arrayLength, sizeInBytes, prototypeMarkWord, headerSize, false, false);
+
+        memory = Word.fromObject(result);
+        for (int offset = headerSize; offset < sizeInBytes; offset += wordSize()) {
+            memory.writeWord(offset, Word.fromObject(src).readWord(offset));
+        }
+        return result;
+    }
+
+    private static Word getAndCheckHub(Object src) {
+        Word hub = loadHub(src);
+        if (!(src instanceof Cloneable)) {
+            probability(DEOPT_PATH_PROBABILITY);
+            DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
+        }
+        return hub;
+    }
+
+    @Snippet
+    public static Object instanceClone(Object src) {
+        instanceCloneCounter.inc();
+        Word hub = getAndCheckHub(src);
+        return instanceClone(src, hub, hub.readInt(layoutHelperOffset()));
+    }
+
+    @Snippet
+    public static Object arrayClone(Object src) {
+        arrayCloneCounter.inc();
+        Word hub = getAndCheckHub(src);
+        int layoutHelper = hub.readInt(layoutHelperOffset());
+        return arrayClone(src, hub, layoutHelper);
+    }
+
+    @Snippet
+    public static Object genericClone(Object src) {
+        genericCloneCounter.inc();
+        Word hub = getAndCheckHub(src);
+        int layoutHelper = hub.readInt(layoutHelperOffset());
+        if (layoutHelper < 0) {
+            probability(LIKELY_PROBABILITY);
+            genericArrayCloneCounter.inc();
+            return arrayClone(src, hub, layoutHelper);
+        } else {
+            genericInstanceCloneCounter.inc();
+            return instanceClone(src, hub, layoutHelper);
+        }
+    }
+
+    private static final SnippetCounter.Group cloneCounters = GraalOptions.SnippetCounters ? new SnippetCounter.Group("Object.clone") : null;
+    private static final SnippetCounter instanceCloneCounter = new SnippetCounter(cloneCounters, "instanceClone", "clone snippet for instances");
+    private static final SnippetCounter arrayCloneCounter = new SnippetCounter(cloneCounters, "arrayClone", "clone snippet for arrays");
+    private static final SnippetCounter genericCloneCounter = new SnippetCounter(cloneCounters, "genericClone", "clone snippet for arrays and instances");
+
+    private static final SnippetCounter.Group genericCloneCounters = GraalOptions.SnippetCounters ? new SnippetCounter.Group("Object.clone generic snippet") : null;
+    private static final SnippetCounter genericInstanceCloneCounter = new SnippetCounter(genericCloneCounters, "genericInstanceClone", "generic clone implementation took instance path");
+    private static final SnippetCounter genericArrayCloneCounter = new SnippetCounter(genericCloneCounters, "genericArrayClone", "generic clone implementation took array path");
+
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ObjectSubstitutions.java	Fri Feb 08 10:41:09 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ObjectSubstitutions.java	Fri Feb 08 11:14:15 2013 +0100
@@ -26,7 +26,7 @@
 import static com.oracle.graal.nodes.extended.UnsafeCastNode.*;
 
 import com.oracle.graal.snippets.*;
-import com.oracle.graal.snippets.ClassSubstitution.MethodSubstitution;
+import com.oracle.graal.snippets.ClassSubstitution.*;
 import com.oracle.graal.word.*;
 
 /**
@@ -45,4 +45,7 @@
     public static int hashCode(final Object thisObj) {
         return computeHashCode(thisObj);
     }
+
+    @MacroSubstitution(macro = ObjectCloneNode.class, isStatic = false)
+    public static native Object clone(Object obj);
 }
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java	Fri Feb 08 10:41:09 2013 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java	Fri Feb 08 11:14:15 2013 +0100
@@ -197,6 +197,7 @@
     public static boolean OptDevirtualizeInvokesOptimistically = true;
 
     // Intrinsification settings
+    public static boolean IntrinsifyObjectClone              = true;
     public static boolean IntrinsifyArrayCopy                = true;
     public static boolean IntrinsifyObjectMethods            = true;
     public static boolean IntrinsifySystemMethods            = true;