changeset 7766:e393b8156c42

Merge
author Lukas Stadler <lukas.stadler@jku.at>
date Mon, 11 Feb 2013 10:46:48 +0100
parents f20c2b1f5289 (diff) 52fd6491fca8 (current diff)
children 4a6646d8eb87
files graal/com.oracle.graal.asm.amd64.test/src/com/oracle/graal/asm/amd64/test/AMD64AssemblerTest.java
diffstat 26 files changed, 432 insertions(+), 57 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Fri Feb 08 18:05:40 2013 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Mon Feb 11 10:46:48 2013 +0100
@@ -74,7 +74,7 @@
 
     /**
      * Denotes that a parameter of an {@linkplain NodeIntrinsic intrinsic} method must be a compile
-     * time constant at all call sites to the intrinic method.
+     * time constant at all call sites to the intrinsic method.
      */
     @Retention(RetentionPolicy.RUNTIME)
     @Target(ElementType.PARAMETER)
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Fri Feb 08 18:05:40 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Mon Feb 11 10:46:48 2013 +0100
@@ -287,6 +287,7 @@
     public int layoutHelperLog2ElementSizeMask;
     public int layoutHelperElementTypeShift;
     public int layoutHelperElementTypeMask;
+    public int layoutHelperElementTypePrimitiveInPlace;
     public int layoutHelperHeaderSizeShift;
     public int layoutHelperHeaderSizeMask;
     public int layoutHelperOffset;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Fri Feb 08 18:05:40 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Mon Feb 11 10:46:48 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);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ArrayCopySnippets.java	Fri Feb 08 18:05:40 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ArrayCopySnippets.java	Mon Feb 11 10:46:48 2013 +0100
@@ -256,7 +256,7 @@
             long end = (dstAddr + header + ((long) destPos + length - 1) * scale) >>> cardShift;
             long count = end - start + 1;
             while (count-- > 0) {
-                DirectStoreNode.store((start + cardStart) + count, false);
+                DirectStoreNode.store((start + cardStart) + count, false, Kind.Boolean);
             }
         }
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/HotSpotSnippetUtils.java	Fri Feb 08 18:05:40 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/HotSpotSnippetUtils.java	Mon Feb 11 10:46:48 2013 +0100
@@ -442,6 +442,12 @@
         return config().layoutHelperElementTypeMask;
     }
 
+    @Fold
+    public static int layoutHelperElementTypePrimitiveInPlace() {
+        System.out.println(String.format("%x", config().layoutHelperElementTypePrimitiveInPlace));
+        return config().layoutHelperElementTypePrimitiveInPlace;
+    }
+
     static {
         assert arrayIndexScale(Kind.Byte) == 1;
         assert arrayIndexScale(Kind.Boolean) == 1;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ObjectCloneNode.java	Mon Feb 11 10:46:48 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 = originalVirtual.duplicate();
+                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	Mon Feb 11 10:46:48 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 18:05:40 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ObjectSubstitutions.java	Mon Feb 11 10:46:48 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.hotspot/src/com/oracle/graal/hotspot/snippets/SystemSubstitutions.java	Fri Feb 08 18:05:40 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/SystemSubstitutions.java	Mon Feb 11 10:46:48 2013 +0100
@@ -42,7 +42,7 @@
     public static final Descriptor JAVA_TIME_MILLIS = new Descriptor("javaTimeMillis", false, long.class);
     public static final Descriptor JAVA_TIME_NANOS = new Descriptor("javaTimeNanos", false, long.class);
 
-    @MacroSubstitution(macro = ArrayCopyNode.class, isStatic = true)
+    @MacroSubstitution(macro = ArrayCopyNode.class)
     public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);
 
     @MethodSubstitution
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Fri Feb 08 18:05:40 2013 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Mon Feb 11 10:46:48 2013 +0100
@@ -642,14 +642,14 @@
     private JavaMethod lookupMethod(int cpi, int opcode) {
         eagerResolvingForSnippets(cpi, opcode);
         JavaMethod result = constantPool.lookupMethod(cpi, opcode);
-        assert !graphBuilderConfig.eagerResolvingForSnippets() || ((result instanceof ResolvedJavaMethod) && ((ResolvedJavaMethod) result).getDeclaringClass().isInitialized());
+        assert !graphBuilderConfig.eagerResolvingForSnippets() || ((result instanceof ResolvedJavaMethod) && ((ResolvedJavaMethod) result).getDeclaringClass().isInitialized()) : result;
         return result;
     }
 
     private JavaField lookupField(int cpi, int opcode) {
         eagerResolvingForSnippets(cpi, opcode);
         JavaField result = constantPool.lookupField(cpi, opcode);
-        assert !graphBuilderConfig.eagerResolvingForSnippets() || (result instanceof ResolvedJavaField && ((ResolvedJavaField) result).getDeclaringClass().isInitialized());
+        assert !graphBuilderConfig.eagerResolvingForSnippets() || (result instanceof ResolvedJavaField && ((ResolvedJavaField) result).getDeclaringClass().isInitialized()) : result;
         return result;
     }
 
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64TestOp.java	Fri Feb 08 18:05:40 2013 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64TestOp.java	Mon Feb 11 10:46:48 2013 +0100
@@ -30,7 +30,6 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.lir.asm.*;
 
-//@formatter:off
 public class AMD64TestOp extends AMD64LIRInstruction {
 
     @Use({REG}) protected Value x;
@@ -55,21 +54,36 @@
     public static void emit(TargetMethodAssembler tasm, AMD64MacroAssembler masm, Value x, Value y) {
         if (isRegister(y)) {
             switch (x.getKind()) {
-                case Int: masm.testl(asIntReg(x), asIntReg(y)); break;
-                case Long: masm.testq(asLongReg(x), asLongReg(y)); break;
-                default: throw GraalInternalError.shouldNotReachHere();
+                case Int:
+                    masm.testl(asIntReg(x), asIntReg(y));
+                    break;
+                case Long:
+                    masm.testq(asLongReg(x), asLongReg(y));
+                    break;
+                default:
+                    throw GraalInternalError.shouldNotReachHere();
             }
         } else if (isConstant(y)) {
             switch (x.getKind()) {
-                case Int: masm.testl(asIntReg(x), tasm.asIntConst(y)); break;
-                case Long: masm.testq(asLongReg(x), tasm.asIntConst(y)); break;
-                default: throw GraalInternalError.shouldNotReachHere();
+                case Int:
+                    masm.testl(asIntReg(x), tasm.asIntConst(y));
+                    break;
+                case Long:
+                    masm.testq(asLongReg(x), tasm.asIntConst(y));
+                    break;
+                default:
+                    throw GraalInternalError.shouldNotReachHere();
             }
         } else {
             switch (x.getKind()) {
-                case Int: masm.testl(asIntReg(x), tasm.asIntAddr(y)); break;
-                case Long: masm.testq(asLongReg(x), tasm.asLongAddr(y)); break;
-                default: throw GraalInternalError.shouldNotReachHere();
+                case Int:
+                    masm.testl(asIntReg(x), tasm.asIntAddr(y));
+                    break;
+                case Long:
+                    masm.testq(asLongReg(x), tasm.asLongAddr(y));
+                    break;
+                default:
+                    throw GraalInternalError.shouldNotReachHere();
             }
         }
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerTestNode.java	Fri Feb 08 18:05:40 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerTestNode.java	Mon Feb 11 10:46:48 2013 +0100
@@ -26,6 +26,11 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
+/**
+ * This node will perform a "test" operation on its arguments. Its result is equivalent to the
+ * expression "(x &amp; y) == 0", meaning that it will return true if (and only if) no bit is set in
+ * both x and y.
+ */
 public class IntegerTestNode extends BooleanNode implements Canonicalizable, LIRLowerable {
 
     @Input private ValueNode x;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ArrayLengthNode.java	Fri Feb 08 18:05:40 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ArrayLengthNode.java	Mon Feb 11 10:46:48 2013 +0100
@@ -47,8 +47,9 @@
     public ValueNode canonical(CanonicalizerTool tool) {
         if (array() instanceof ArrayLengthProvider) {
             ValueNode length = ((ArrayLengthProvider) array()).length();
-            assert length != null;
-            return length;
+            if (length != null) {
+                return length;
+            }
         }
         MetaAccessProvider runtime = tool.runtime();
         if (runtime != null && array().isConstant() && !array().isNullConstant()) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/ArrayLengthProvider.java	Fri Feb 08 18:05:40 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/ArrayLengthProvider.java	Mon Feb 11 10:46:48 2013 +0100
@@ -26,5 +26,8 @@
 
 public interface ArrayLengthProvider {
 
+    /**
+     * @return the length of the array described by this node, or null if it is not available
+     */
     ValueNode length();
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizerTool.java	Fri Feb 08 18:05:40 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizerTool.java	Mon Feb 11 10:46:48 2013 +0100
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.nodes.spi;
 
+import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
@@ -43,6 +44,12 @@
     MetaAccessProvider getMetaAccessProvider();
 
     /**
+     * @return the {@link Assumptions} associated with the current compilation, which can be used to
+     *         make type assumptions during virtualization.
+     */
+    Assumptions getAssumptions();
+
+    /**
      * This method should be used to query the maximum size of virtualized objects before attempting
      * virtualization.
      * 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/BoxedVirtualObjectNode.java	Fri Feb 08 18:05:40 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/BoxedVirtualObjectNode.java	Mon Feb 11 10:46:48 2013 +0100
@@ -70,4 +70,9 @@
     public Kind entryKind(int index) {
         return kind;
     }
+
+    @Override
+    public BoxedVirtualObjectNode duplicate() {
+        return new BoxedVirtualObjectNode(type, kind, unboxedValue);
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualArrayNode.java	Fri Feb 08 18:05:40 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualArrayNode.java	Mon Feb 11 10:46:48 2013 +0100
@@ -132,4 +132,9 @@
         assert index >= 0 && index < length;
         return componentType.getKind();
     }
+
+    @Override
+    public VirtualArrayNode duplicate() {
+        return new VirtualArrayNode(componentType, length);
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualInstanceNode.java	Fri Feb 08 18:05:40 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualInstanceNode.java	Mon Feb 11 10:46:48 2013 +0100
@@ -32,16 +32,23 @@
 
     private final ResolvedJavaType type;
     private final ResolvedJavaField[] fields;
-    private final HashMap<ResolvedJavaField, Integer> fieldMap = new HashMap<>();
+    private final HashMap<ResolvedJavaField, Integer> fieldMap;
 
     public VirtualInstanceNode(ResolvedJavaType type, ResolvedJavaField[] fields) {
         this.type = type;
         this.fields = fields;
+        fieldMap = new HashMap<>();
         for (int i = 0; i < fields.length; i++) {
             fieldMap.put(fields[i], i);
         }
     }
 
+    private VirtualInstanceNode(ResolvedJavaType type, ResolvedJavaField[] fields, HashMap<ResolvedJavaField, Integer> fieldMap) {
+        this.type = type;
+        this.fields = fields;
+        this.fieldMap = fieldMap;
+    }
+
     @Override
     public ResolvedJavaType type() {
         return type;
@@ -85,4 +92,9 @@
         assert index >= 0 && index < fields.length;
         return fields[index].getKind();
     }
+
+    @Override
+    public VirtualInstanceNode duplicate() {
+        return new VirtualInstanceNode(type, fields, fieldMap);
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java	Fri Feb 08 18:05:40 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java	Mon Feb 11 10:46:48 2013 +0100
@@ -53,4 +53,6 @@
     public abstract int entryIndexForOffset(long constantOffset);
 
     public abstract Kind entryKind(int index);
+
+    public abstract VirtualObjectNode duplicate();
 }
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java	Fri Feb 08 18:05:40 2013 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java	Mon Feb 11 10:46:48 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;
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/UnsafeSubstitutions.java	Fri Feb 08 18:05:40 2013 +0100
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/UnsafeSubstitutions.java	Mon Feb 11 10:46:48 2013 +0100
@@ -313,37 +313,37 @@
 
     @MethodSubstitution(isStatic = false)
     public static void putByte(@SuppressWarnings("unused") final Object thisObj, long address, byte value) {
-        DirectStoreNode.store(address, value);
+        DirectStoreNode.store(address, value, Kind.Byte);
     }
 
     @MethodSubstitution(isStatic = false)
     public static void putShort(@SuppressWarnings("unused") final Object thisObj, long address, short value) {
-        DirectStoreNode.store(address, value);
+        DirectStoreNode.store(address, value, Kind.Short);
     }
 
     @MethodSubstitution(isStatic = false)
     public static void putChar(@SuppressWarnings("unused") final Object thisObj, long address, char value) {
-        DirectStoreNode.store(address, value);
+        DirectStoreNode.store(address, value, Kind.Char);
     }
 
     @MethodSubstitution(isStatic = false)
     public static void putInt(@SuppressWarnings("unused") final Object thisObj, long address, int value) {
-        DirectStoreNode.store(address, value);
+        DirectStoreNode.store(address, value, Kind.Int);
     }
 
     @MethodSubstitution(isStatic = false)
     public static void putLong(@SuppressWarnings("unused") final Object thisObj, long address, long value) {
-        DirectStoreNode.store(address, value);
+        DirectStoreNode.store(address, value, Kind.Long);
     }
 
     @MethodSubstitution(isStatic = false)
     public static void putFloat(@SuppressWarnings("unused") final Object thisObj, long address, float value) {
-        DirectStoreNode.store(address, value);
+        DirectStoreNode.store(address, value, Kind.Float);
     }
 
     @MethodSubstitution(isStatic = false)
     public static void putDouble(@SuppressWarnings("unused") final Object thisObj, long address, double value) {
-        DirectStoreNode.store(address, value);
+        DirectStoreNode.store(address, value, Kind.Double);
     }
 
     @MethodSubstitution(isStatic = false)
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/DirectStoreNode.java	Fri Feb 08 18:05:40 2013 +0100
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/DirectStoreNode.java	Mon Feb 11 10:46:48 2013 +0100
@@ -37,40 +37,48 @@
 
     @Input private ValueNode address;
     @Input private ValueNode value;
+    private final Kind kind;
 
-    public DirectStoreNode(ValueNode address, ValueNode value) {
+    public DirectStoreNode(ValueNode address, ValueNode value, Kind kind) {
         super(StampFactory.forVoid());
         this.address = address;
         this.value = value;
+        this.kind = kind;
     }
 
-    @NodeIntrinsic
-    public static native void store(long address, boolean value);
-
-    @NodeIntrinsic
-    public static native void store(long address, byte value);
-
-    @NodeIntrinsic
-    public static native void store(long address, short value);
-
-    @NodeIntrinsic
-    public static native void store(long address, char value);
-
-    @NodeIntrinsic
-    public static native void store(long address, int value);
-
-    @NodeIntrinsic
-    public static native void store(long address, long value);
-
-    @NodeIntrinsic
-    public static native void store(long address, float value);
-
-    @NodeIntrinsic
-    public static native void store(long address, double value);
-
     @Override
     public void generate(LIRGeneratorTool gen) {
         Value v = gen.operand(value);
-        gen.emitStore(new Address(v.getKind(), gen.operand(address)), v, false);
+        gen.emitStore(new Address(kind, gen.operand(address)), v, false);
     }
+
+    /*
+     * The kind of the store is provided explicitly in these intrinsics because it is not always
+     * possible to determine the kind from the given value during compilation (because stack kinds
+     * are used).
+     */
+
+    @NodeIntrinsic
+    public static native void store(long address, boolean value, @ConstantNodeParameter Kind kind);
+
+    @NodeIntrinsic
+    public static native void store(long address, byte value, @ConstantNodeParameter Kind kind);
+
+    @NodeIntrinsic
+    public static native void store(long address, short value, @ConstantNodeParameter Kind kind);
+
+    @NodeIntrinsic
+    public static native void store(long address, char value, @ConstantNodeParameter Kind kind);
+
+    @NodeIntrinsic
+    public static native void store(long address, int value, @ConstantNodeParameter Kind kind);
+
+    @NodeIntrinsic
+    public static native void store(long address, long value, @ConstantNodeParameter Kind kind);
+
+    @NodeIntrinsic
+    public static native void store(long address, float value, @ConstantNodeParameter Kind kind);
+
+    @NodeIntrinsic
+    public static native void store(long address, double value, @ConstantNodeParameter Kind kind);
 }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeAnalysisPhase.java	Fri Feb 08 18:05:40 2013 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeAnalysisPhase.java	Mon Feb 11 10:46:48 2013 +0100
@@ -92,7 +92,7 @@
                 public Boolean call() {
                     SchedulePhase schedule = new SchedulePhase();
                     schedule.apply(graph, false);
-                    PartialEscapeClosure closure = new PartialEscapeClosure(graph.createNodeBitMap(), schedule, runtime);
+                    PartialEscapeClosure closure = new PartialEscapeClosure(graph.createNodeBitMap(), schedule, runtime, assumptions);
                     ReentrantBlockIterator.apply(closure, schedule.getCFG().getStartBlock(), new BlockState(), null);
 
                     if (closure.getNewVirtualObjectCount() == 0) {
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Fri Feb 08 18:05:40 2013 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Mon Feb 11 10:46:48 2013 +0100
@@ -26,6 +26,7 @@
 
 import java.util.*;
 
+import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
@@ -59,10 +60,10 @@
 
     private final VirtualizerToolImpl tool;
 
-    public PartialEscapeClosure(NodeBitMap usages, SchedulePhase schedule, MetaAccessProvider metaAccess) {
+    public PartialEscapeClosure(NodeBitMap usages, SchedulePhase schedule, MetaAccessProvider metaAccess, Assumptions assumptions) {
         this.usages = usages;
         this.schedule = schedule;
-        tool = new VirtualizerToolImpl(effects, usages, metaAccess);
+        tool = new VirtualizerToolImpl(effects, usages, metaAccess, assumptions);
     }
 
     public GraphEffectList getEffects() {
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java	Fri Feb 08 18:05:40 2013 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java	Mon Feb 11 10:46:48 2013 +0100
@@ -24,6 +24,7 @@
 
 import static com.oracle.graal.virtual.phases.ea.PartialEscapeAnalysisPhase.*;
 
+import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
@@ -38,11 +39,13 @@
     private final GraphEffectList effects;
     private final NodeBitMap usages;
     private final MetaAccessProvider metaAccess;
+    private final Assumptions assumptions;
 
-    VirtualizerToolImpl(GraphEffectList effects, NodeBitMap usages, MetaAccessProvider metaAccess) {
+    VirtualizerToolImpl(GraphEffectList effects, NodeBitMap usages, MetaAccessProvider metaAccess, Assumptions assumptions) {
         this.effects = effects;
         this.usages = usages;
         this.metaAccess = metaAccess;
+        this.assumptions = assumptions;
     }
 
     private boolean deleted;
@@ -56,6 +59,11 @@
         return metaAccess;
     }
 
+    @Override
+    public Assumptions getAssumptions() {
+        return assumptions;
+    }
+
     public void reset(BlockState newState, ValueNode newCurrent) {
         deleted = false;
         customAction = false;
--- a/src/share/vm/graal/graalCompilerToVM.cpp	Fri Feb 08 18:05:40 2013 +0100
+++ b/src/share/vm/graal/graalCompilerToVM.cpp	Mon Feb 11 10:46:48 2013 +0100
@@ -701,6 +701,8 @@
   set_int("layoutHelperLog2ElementSizeMask", Klass::_lh_log2_element_size_mask);
   set_int("layoutHelperElementTypeShift", Klass::_lh_element_type_shift);
   set_int("layoutHelperElementTypeMask", Klass::_lh_element_type_mask);
+  // this filters out the bit that differentiates a type array from an object array
+  set_int("layoutHelperElementTypePrimitiveInPlace", (Klass::_lh_array_tag_type_value & ~Klass::_lh_array_tag_obj_value) << Klass::_lh_array_tag_shift);
   set_int("layoutHelperHeaderSizeShift", Klass::_lh_header_size_shift);
   set_int("layoutHelperHeaderSizeMask", Klass::_lh_header_size_mask);
   set_int("layoutHelperOffset", in_bytes(Klass::layout_helper_offset()));