changeset 11876:acfff1de2aa7

Merge
author Lukas Stadler <lukas.stadler@jku.at>
date Wed, 02 Oct 2013 17:34:27 +0200
parents 35bdfb9ac12f (diff) 18824519c172 (current diff)
children ef895852aeb4
files
diffstat 14 files changed, 250 insertions(+), 156 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Wed Oct 02 15:37:06 2013 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Wed Oct 02 17:34:27 2013 +0200
@@ -86,7 +86,7 @@
          */
         @Option(help = "Pattern for method(s) to which intrinsification will not be applied. " +
                        "See MethodFilter class for pattern syntax.")
-        public static final OptionValue<String> IntrinsificationsDisabled = new OptionValue<>("Object.clone");
+        public static final OptionValue<String> IntrinsificationsDisabled = new OptionValue<>(null);
         // @formatter:on
 
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/BenchmarkCounters.java	Wed Oct 02 15:37:06 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/BenchmarkCounters.java	Wed Oct 02 17:34:27 2013 +0200
@@ -44,6 +44,19 @@
 import com.oracle.graal.options.*;
 import com.oracle.graal.replacements.nodes.*;
 
+/**
+ * This class contains infrastructure to maintain counters based on {@link DynamicCounterNode}s. The
+ * infrastructure is enabled by specifying either the GenericDynamicCounters or
+ * BenchmarkDynamicCounters option.<br/>
+ * 
+ * The counters are kept in a special area in the native JavaThread object, and the number of
+ * counters is configured in {@code thread.hpp (GRAAL_COUNTERS_SIZE)}. This file also contains an
+ * option to exclude compiler threads ({@code GRAAL_COUNTERS_EXCLUDE_COMPILER_THREADS}, which
+ * defaults to true).
+ * 
+ * The subsystems that use the logging need to have their own options to turn on the counters, and
+ * insert DynamicCounterNodes when they're enabled.
+ */
 public class BenchmarkCounters {
 
     static class Options {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java	Wed Oct 02 15:37:06 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java	Wed Oct 02 17:34:27 2013 +0200
@@ -40,14 +40,17 @@
 import com.oracle.graal.graph.iterators.*;
 import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.debug.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.options.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.replacements.*;
 import com.oracle.graal.replacements.Snippet.ConstantParameter;
+import com.oracle.graal.replacements.Snippet.Fold;
 import com.oracle.graal.replacements.SnippetTemplate.AbstractTemplates;
 import com.oracle.graal.replacements.SnippetTemplate.Arguments;
 import com.oracle.graal.replacements.SnippetTemplate.SnippetInfo;
@@ -63,6 +66,22 @@
  */
 public class MonitorSnippets implements Snippets {
 
+    public static class Options {
+
+        //@formatter:off
+        @Option(help = "")
+        private static final OptionValue<Boolean> ProfileMonitors = new OptionValue<>(false);
+        //@formatter:on
+    }
+
+    private static final boolean PROFILE_CONTEXT = false;
+
+    @Fold
+    @SuppressWarnings("unused")
+    private static boolean doProfile(String path) {
+        return Options.ProfileMonitors.getValue();
+    }
+
     /**
      * Monitor operations on objects whose type contains this substring will be traced.
      */
@@ -118,7 +137,7 @@
                 trace(trace, "              tmp: 0x%016lx\n", tmp);
                 if (probability(FREQUENT_PROBABILITY, tmp.equal(0))) {
                     // Object is already biased to current thread -> done
-                    traceObject(trace, "+lock{bias:existing}", object);
+                    traceObject(trace, "+lock{bias:existing}", object, true);
                     return;
                 }
 
@@ -154,13 +173,13 @@
                         trace(trace, "       biasedMark: 0x%016lx\n", biasedMark);
                         if (probability(VERY_FAST_PATH_PROBABILITY, compareAndSwap(object, markOffset(), unbiasedMark, biasedMark, MARK_WORD_LOCATION).equal(unbiasedMark))) {
                             // Object is now biased to current thread -> done
-                            traceObject(trace, "+lock{bias:acquired}", object);
+                            traceObject(trace, "+lock{bias:acquired}", object, true);
                             return;
                         }
                         // If the biasing toward our thread failed, this means that another thread
                         // owns the bias and we need to revoke that bias. The revocation will occur
                         // in the interpreter runtime.
-                        traceObject(trace, "+lock{stub:revoke}", object);
+                        traceObject(trace, "+lock{stub:revoke}", object, true);
                         monitorenterStub(MONITORENTER, object, lock);
                         return;
                     } else {
@@ -174,13 +193,13 @@
                         trace(trace, "       biasedMark: 0x%016lx\n", biasedMark);
                         if (probability(VERY_FAST_PATH_PROBABILITY, compareAndSwap(object, markOffset(), mark, biasedMark, MARK_WORD_LOCATION).equal(mark))) {
                             // Object is now biased to current thread -> done
-                            traceObject(trace, "+lock{bias:transfer}", object);
+                            traceObject(trace, "+lock{bias:transfer}", object, true);
                             return;
                         }
                         // If the biasing toward our thread failed, then another thread
                         // succeeded in biasing it toward itself and we need to revoke that
                         // bias. The revocation will occur in the runtime in the slow case.
-                        traceObject(trace, "+lock{stub:epoch-expired}", object);
+                        traceObject(trace, "+lock{stub:epoch-expired}", object, true);
                         monitorenterStub(MONITORENTER, object, lock);
                         return;
                     }
@@ -237,16 +256,16 @@
             final Word stackPointer = stackPointer();
             if (probability(VERY_SLOW_PATH_PROBABILITY, currentMark.subtract(stackPointer).and(alignedMask.subtract(pageSize())).notEqual(0))) {
                 // Most likely not a recursive lock, go into a slow runtime call
-                traceObject(trace, "+lock{stub:failed-cas}", object);
+                traceObject(trace, "+lock{stub:failed-cas}", object, true);
                 monitorenterStub(MONITORENTER, object, lock);
                 return;
             } else {
                 // Recursively locked => write 0 to the lock slot
                 lock.writeWord(lockDisplacedMarkOffset(), Word.zero(), DISPLACED_MARK_WORD_LOCATION);
-                traceObject(trace, "+lock{recursive}", object);
+                traceObject(trace, "+lock{recursive}", object, true);
             }
         } else {
-            traceObject(trace, "+lock{cas}", object);
+            traceObject(trace, "+lock{cas}", object, true);
         }
     }
 
@@ -263,7 +282,7 @@
         // BeginLockScope nodes do not read from object so a use of object
         // cannot float about the null check above
         final Word lock = beginLockScope(lockDepth);
-        traceObject(trace, "+lock{stub}", object);
+        traceObject(trace, "+lock{stub}", object, true);
         monitorenterStub(MONITORENTER, object, lock);
     }
 
@@ -282,7 +301,7 @@
             if (probability(FREQUENT_PROBABILITY, mark.and(biasedLockMaskInPlace()).equal(Word.unsigned(biasedLockPattern())))) {
                 endLockScope();
                 decCounter();
-                traceObject(trace, "-lock{bias}", object);
+                traceObject(trace, "-lock{bias}", object, false);
                 return;
             }
         }
@@ -295,7 +314,7 @@
 
         if (displacedMark.equal(0)) {
             // Recursive locking => done
-            traceObject(trace, "-lock{recursive}", object);
+            traceObject(trace, "-lock{recursive}", object, false);
         } else {
             verifyOop(object);
             // Test if object's mark word is pointing to the displaced mark word, and if so, restore
@@ -304,10 +323,10 @@
             if (probability(VERY_SLOW_PATH_PROBABILITY, DirectCompareAndSwapNode.compareAndSwap(object, markOffset(), lock, displacedMark, MARK_WORD_LOCATION).notEqual(lock))) {
                 // The object's mark word was not pointing to the displaced header,
                 // we do unlocking via runtime call.
-                traceObject(trace, "-lock{stub}", object);
+                traceObject(trace, "-lock{stub}", object, false);
                 MonitorExitStubCall.call(object, lockDepth);
             } else {
-                traceObject(trace, "-lock{cas}", object);
+                traceObject(trace, "-lock{cas}", object, false);
             }
         }
         endLockScope();
@@ -320,13 +339,16 @@
     @Snippet
     public static void monitorexitStub(Object object, @ConstantParameter int lockDepth, @ConstantParameter boolean trace) {
         verifyOop(object);
-        traceObject(trace, "-lock{stub}", object);
+        traceObject(trace, "-lock{stub}", object, false);
         MonitorExitStubCall.call(object, lockDepth);
         endLockScope();
         decCounter();
     }
 
-    private static void traceObject(boolean enabled, String action, Object object) {
+    private static void traceObject(boolean enabled, String action, Object object, boolean enter) {
+        if (doProfile(action)) {
+            DynamicCounterNode.counter(action, enter ? "~monitorenter" : "~monitorexit", 1, PROFILE_CONTEXT);
+        }
         if (enabled) {
             Log.print(action);
             Log.print(' ');
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java	Wed Oct 02 15:37:06 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java	Wed Oct 02 17:34:27 2013 +0200
@@ -34,17 +34,21 @@
 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.graph.Node.ConstantNodeParameter;
 import com.oracle.graal.graph.Node.NodeIntrinsic;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.debug.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.options.*;
 import com.oracle.graal.replacements.*;
 import com.oracle.graal.replacements.Snippet.ConstantParameter;
+import com.oracle.graal.replacements.Snippet.Fold;
 import com.oracle.graal.replacements.Snippet.VarargsParameter;
 import com.oracle.graal.replacements.SnippetTemplate.AbstractTemplates;
 import com.oracle.graal.replacements.SnippetTemplate.Arguments;
@@ -59,6 +63,20 @@
 
     public static final LocationIdentity INIT_LOCATION = new NamedLocationIdentity("Initialization");
 
+    public static class Options {
+
+        //@formatter:off
+        @Option(help = "")
+        private static final OptionValue<Boolean> ProfileAllocations = new OptionValue<>(false);
+        //@formatter:on
+    }
+
+    static enum ProfileMode {
+        AllocatingMethods, InstanceOrArray, AllocatedTypes, AllocatedTypesInMethods, Total
+    }
+
+    public static final ProfileMode PROFILE_MODE = ProfileMode.Total;
+
     @Snippet
     public static Word allocate(int size) {
         Word thread = thread();
@@ -76,8 +94,41 @@
         return Word.zero();
     }
 
+    @Fold
+    private static String createName(String path, String typeContext) {
+        switch (PROFILE_MODE) {
+            case AllocatingMethods:
+                return "";
+            case InstanceOrArray:
+                return path;
+            case AllocatedTypes:
+            case AllocatedTypesInMethods:
+                return typeContext;
+            case Total:
+                return "bytes";
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
+    }
+
+    @Fold
+    @SuppressWarnings("unused")
+    private static boolean doProfile(String path, String typeContext) {
+        return Options.ProfileAllocations.getValue();
+    }
+
+    private static void profileAllocation(String path, long size, String typeContext) {
+        if (doProfile(path, typeContext)) {
+            String name = createName(path, typeContext);
+
+            boolean context = PROFILE_MODE == ProfileMode.AllocatingMethods || PROFILE_MODE == ProfileMode.AllocatedTypesInMethods;
+            DynamicCounterNode.counter(name, "~bytes", size, context);
+            DynamicCounterNode.counter(name, "~sites", 1, context);
+        }
+    }
+
     @Snippet
-    public static Object allocateInstance(@ConstantParameter int size, Word hub, Word prototypeMarkWord, @ConstantParameter boolean fillContents) {
+    public static Object allocateInstance(@ConstantParameter int size, Word hub, Word prototypeMarkWord, @ConstantParameter boolean fillContents, @ConstantParameter String typeContext) {
         Object result;
         Word thread = thread();
         Word top = readTlabTop(thread);
@@ -90,6 +141,7 @@
             new_stub.inc();
             result = NewInstanceStubCall.call(hub);
         }
+        profileAllocation("instance", size, typeContext);
         return piCast(verifyOop(result), StampFactory.forNodeIntrinsic());
     }
 
@@ -99,15 +151,16 @@
     public static final int MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH = 0x00FFFFFF;
 
     @Snippet
-    public static Object allocateArray(Word hub, int length, Word prototypeMarkWord, @ConstantParameter int headerSize, @ConstantParameter int log2ElementSize, @ConstantParameter boolean fillContents) {
+    public static Object allocateArray(Word hub, int length, Word prototypeMarkWord, @ConstantParameter int headerSize, @ConstantParameter int log2ElementSize,
+                    @ConstantParameter boolean fillContents, @ConstantParameter String typeContext) {
         if (!belowThan(length, MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH)) {
             // This handles both negative array sizes and very large array sizes
             DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
         }
-        return allocateArrayImpl(hub, length, prototypeMarkWord, headerSize, log2ElementSize, fillContents);
+        return allocateArrayImpl(hub, length, prototypeMarkWord, headerSize, log2ElementSize, fillContents, typeContext);
     }
 
-    private static Object allocateArrayImpl(Word hub, int length, Word prototypeMarkWord, int headerSize, int log2ElementSize, boolean fillContents) {
+    private static Object allocateArrayImpl(Word hub, int length, Word prototypeMarkWord, int headerSize, int log2ElementSize, boolean fillContents, String typeContext) {
         Object result;
         int alignment = wordSize();
         int allocationSize = computeArrayAllocationSize(length, alignment, headerSize, log2ElementSize);
@@ -123,6 +176,7 @@
             newarray_stub.inc();
             result = NewArrayStubCall.call(hub, length);
         }
+        profileAllocation("array", allocationSize, typeContext);
         return piArrayCast(verifyOop(result), length, StampFactory.forNodeIntrinsic());
     }
 
@@ -156,7 +210,7 @@
         int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift()) & layoutHelperLog2ElementSizeMask();
         Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION);
 
-        return allocateArrayImpl(hub, length, prototypeMarkWord, headerSize, log2ElementSize, fillContents);
+        return allocateArrayImpl(hub, length, prototypeMarkWord, headerSize, log2ElementSize, fillContents, "dynamic type");
     }
 
     /**
@@ -261,6 +315,7 @@
             args.add("hub", hub);
             args.add("prototypeMarkWord", type.prototypeMarkWord());
             args.addConst("fillContents", newInstanceNode.fillContents());
+            args.addConst("typeContext", MetaUtil.toJavaName(type, false));
 
             SnippetTemplate template = template(args);
             Debug.log("Lowering allocateInstance in %s: node=%s, template=%s, arguments=%s", graph, newInstanceNode, template, args);
@@ -286,6 +341,7 @@
             args.addConst("headerSize", headerSize);
             args.addConst("log2ElementSize", log2ElementSize);
             args.addConst("fillContents", newArrayNode.fillContents());
+            args.addConst("typeContext", MetaUtil.toJavaName(arrayType, false));
 
             SnippetTemplate template = template(args);
             Debug.log("Lowering allocateArray in %s: node=%s, template=%s, arguments=%s", graph, newArrayNode, template, args);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneNode.java	Wed Oct 02 15:37:06 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneNode.java	Wed Oct 02 17:34:27 2013 +0200
@@ -59,49 +59,72 @@
         }
 
         ResolvedJavaType type = ObjectStamp.typeOrNull(getObject());
-        Method method;
-        /*
-         * The first condition tests if the parameter is an array, the second condition tests if the
-         * parameter can be an array. Otherwise, the parameter is known to be a non-array object.
-         */
-        if (type.isArray()) {
-            method = ObjectCloneSnippets.arrayCloneMethod;
-        } else if (type == null || type.isAssignableFrom(tool.getRuntime().lookupJavaType(Object[].class))) {
-            method = ObjectCloneSnippets.genericCloneMethod;
-        } else {
-            method = ObjectCloneSnippets.instanceCloneMethod;
+        if (type != null) {
+            if (type.isArray()) {
+                Method method = ObjectCloneSnippets.arrayCloneMethods.get(type.getComponentType().getKind());
+                if (method != null) {
+                    final ResolvedJavaMethod snippetMethod = tool.getRuntime().lookupJavaMethod(method);
+                    final Replacements replacements = tool.getReplacements();
+                    StructuredGraph snippetGraph = Debug.scope("ArrayCopySnippet", snippetMethod, new Callable<StructuredGraph>() {
+
+                        @Override
+                        public StructuredGraph call() throws Exception {
+                            return replacements.getSnippet(snippetMethod);
+                        }
+                    });
+
+                    assert snippetGraph != null : "ObjectCloneSnippets should be installed";
+                    return lowerReplacement(snippetGraph.copy(), tool);
+                }
+            } else {
+                type = getConcreteType(getObject().stamp(), tool.assumptions(), tool.getRuntime());
+                if (type != null) {
+                    StructuredGraph newGraph = new StructuredGraph();
+                    LocalNode local = newGraph.add(new LocalNode(0, getObject().stamp()));
+                    NewInstanceNode newInstance = newGraph.add(new NewInstanceNode(type, true));
+                    newGraph.addAfterFixed(newGraph.start(), newInstance);
+                    ReturnNode returnNode = newGraph.add(new ReturnNode(newInstance));
+                    newGraph.addAfterFixed(newInstance, returnNode);
+
+                    for (ResolvedJavaField field : type.getInstanceFields(true)) {
+                        LoadFieldNode load = newGraph.add(new LoadFieldNode(local, field));
+                        newGraph.addBeforeFixed(returnNode, load);
+                        newGraph.addBeforeFixed(returnNode, newGraph.add(new StoreFieldNode(newInstance, field, load)));
+                    }
+                    return lowerReplacement(newGraph, tool);
+                }
+            }
         }
-        final ResolvedJavaMethod snippetMethod = tool.getRuntime().lookupJavaMethod(method);
-        final Replacements replacements = tool.getReplacements();
-        StructuredGraph snippetGraph = Debug.scope("ArrayCopySnippet", snippetMethod, new Callable<StructuredGraph>() {
-
-            @Override
-            public StructuredGraph call() throws Exception {
-                return replacements.getSnippet(snippetMethod);
-            }
-        });
-
-        assert snippetGraph != null : "ObjectCloneSnippets should be installed";
-        return lowerReplacement(snippetGraph.copy(), tool);
+        return null;
     }
 
     private static boolean isCloneableType(ResolvedJavaType type, MetaAccessProvider metaAccess) {
-        return type != null && metaAccess.lookupJavaType(Cloneable.class).isAssignableFrom(type);
+        return metaAccess.lookupJavaType(Cloneable.class).isAssignableFrom(type);
     }
 
-    private static ResolvedJavaType getConcreteType(Stamp stamp, Assumptions assumptions) {
+    /*
+     * 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.
+     */
+    private static ResolvedJavaType getConcreteType(Stamp stamp, Assumptions assumptions, MetaAccessProvider metaAccess) {
         if (!(stamp instanceof ObjectStamp)) {
             return null;
         }
         ObjectStamp objectStamp = (ObjectStamp) stamp;
-        if (objectStamp.isExactType() || objectStamp.type() == null) {
-            return objectStamp.type();
+        if (objectStamp.type() == null) {
+            return null;
+        } else if (objectStamp.isExactType()) {
+            return isCloneableType(objectStamp.type(), metaAccess) ? objectStamp.type() : null;
         } else {
             ResolvedJavaType type = objectStamp.type().findUniqueConcreteSubtype();
-            if (type != null) {
+            if (type != null && isCloneableType(type, metaAccess)) {
                 assumptions.recordConcreteSubtype(objectStamp.type(), type);
+                return type;
+            } else {
+                return null;
             }
-            return type;
         }
     }
 
@@ -126,21 +149,19 @@
             } else {
                 obj = tool.getReplacedValue(getObject());
             }
-            ResolvedJavaType type = getConcreteType(obj.stamp(), tool.getAssumptions());
-            if (isCloneableType(type, tool.getMetaAccessProvider())) {
-                if (!type.isArray()) {
-                    VirtualInstanceNode newVirtual = new VirtualInstanceNode(type, true);
-                    ResolvedJavaField[] fields = newVirtual.getFields();
+            ResolvedJavaType type = getConcreteType(obj.stamp(), tool.getAssumptions(), tool.getMetaAccessProvider());
+            if (type != null && !type.isArray()) {
+                VirtualInstanceNode newVirtual = new VirtualInstanceNode(type, true);
+                ResolvedJavaField[] fields = newVirtual.getFields();
 
-                    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] = new LoadFieldNode(obj, fields[i]);
-                        tool.addNode(loads[i]);
-                    }
-                    tool.createVirtualObject(newVirtual, state, null);
-                    tool.replaceWithVirtual(newVirtual);
+                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] = new LoadFieldNode(obj, fields[i]);
+                    tool.addNode(loads[i]);
                 }
+                tool.createVirtualObject(newVirtual, state, null);
+                tool.replaceWithVirtual(newVirtual);
             }
         }
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneSnippets.java	Wed Oct 02 15:37:06 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneSnippets.java	Wed Oct 02 17:34:27 2013 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -22,113 +22,77 @@
  */
 package com.oracle.graal.hotspot.replacements;
 
-import static com.oracle.graal.api.meta.LocationIdentity.*;
-import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
-import static com.oracle.graal.nodes.extended.BranchProbabilityNode.*;
-import static com.oracle.graal.phases.GraalOptions.*;
-
 import java.lang.reflect.*;
+import java.util.*;
 
 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.replacements.*;
-import com.oracle.graal.word.*;
 
 public class ObjectCloneSnippets implements Snippets {
 
-    public static final Method instanceCloneMethod = getCloneMethod("instanceClone");
-    public static final Method arrayCloneMethod = getCloneMethod("arrayClone");
-    public static final Method genericCloneMethod = getCloneMethod("genericClone");
+    public static final EnumMap<Kind, Method> arrayCloneMethods = new EnumMap<>(Kind.class);
 
-    private static Method getCloneMethod(String name) {
+    static {
+        arrayCloneMethods.put(Kind.Byte, getCloneMethod("byteArrayClone", byte[].class));
+        arrayCloneMethods.put(Kind.Char, getCloneMethod("charArrayClone", char[].class));
+        arrayCloneMethods.put(Kind.Int, getCloneMethod("intArrayClone", int[].class));
+        arrayCloneMethods.put(Kind.Long, getCloneMethod("longArrayClone", long[].class));
+        arrayCloneMethods.put(Kind.Object, getCloneMethod("objectArrayClone", Object[].class));
+    }
+
+    private static Method getCloneMethod(String name, Class<?> param) {
         try {
-            return ObjectCloneSnippets.class.getDeclaredMethod(name, Object.class);
+            return ObjectCloneSnippets.class.getDeclaredMethod(name, param);
         } catch (SecurityException | NoSuchMethodException e) {
             throw new GraalInternalError(e);
         }
     }
 
-    private static Object instanceClone(Object src, Word hub, int layoutHelper) {
-        int instanceSize = layoutHelper;
-        Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION);
-        Object result = NewObjectSnippets.allocateInstance(instanceSize, hub, prototypeMarkWord, false);
-
-        for (int offset = instanceHeaderSize(); offset < instanceSize; offset += wordSize()) {
-            /*
-             * TODO atomicity problem on 32-bit architectures: The JVM spec requires double values
-             * to be copied atomically, but here they are copied as two 4-byte word values.
-             */
-            ObjectAccess.writeWord(result, offset, ObjectAccess.readWord(src, offset, ANY_LOCATION), ANY_LOCATION);
+    @Snippet(removeAllFrameStates = true)
+    public static byte[] byteArrayClone(byte[] src) {
+        byte[] result = new byte[src.length];
+        for (int i = 0; i < result.length; i++) {
+            result[i] = src[i];
         }
-
         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);
-
-        Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION);
-        Object result = NewObjectSnippets.allocateArray(hub, arrayLength, prototypeMarkWord, headerSize, log2ElementSize, false);
-
-        for (int offset = headerSize; offset < sizeInBytes; offset += wordSize()) {
-            /*
-             * TODO atomicity problem on 32-bit architectures: The JVM spec requires double values
-             * to be copied atomically, but here they are copied as two 4-byte word values.
-             */
-            ObjectAccess.writeWord(result, offset, ObjectAccess.readWord(src, offset, ANY_LOCATION), ANY_LOCATION);
+    @Snippet(removeAllFrameStates = true)
+    public static char[] charArrayClone(char[] src) {
+        char[] result = new char[src.length];
+        for (int i = 0; i < result.length; i++) {
+            result[i] = src[i];
         }
         return result;
     }
 
-    private static Word getAndCheckHub(Object src) {
-        Word hub = loadHub(src);
-        if (!(src instanceof Cloneable)) {
-            DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
+    @Snippet(removeAllFrameStates = true)
+    public static int[] intArrayClone(int[] src) {
+        int[] result = new int[src.length];
+        for (int i = 0; i < result.length; i++) {
+            result[i] = src[i];
         }
-        return hub;
-    }
-
-    @Snippet
-    public static Object instanceClone(Object src) {
-        instanceCloneCounter.inc();
-        Word hub = getAndCheckHub(src);
-        return instanceClone(src, hub, hub.readInt(layoutHelperOffset(), FINAL_LOCATION));
-    }
-
-    @Snippet
-    public static Object arrayClone(Object src) {
-        arrayCloneCounter.inc();
-        Word hub = getAndCheckHub(src);
-        int layoutHelper = hub.readInt(layoutHelperOffset(), FINAL_LOCATION);
-        return arrayClone(src, hub, layoutHelper);
+        return result;
     }
 
-    @Snippet
-    public static Object genericClone(Object src) {
-        genericCloneCounter.inc();
-        Word hub = getAndCheckHub(src);
-        int layoutHelper = hub.readInt(layoutHelperOffset(), FINAL_LOCATION);
-        if (probability(LIKELY_PROBABILITY, layoutHelper < 0)) {
-            genericArrayCloneCounter.inc();
-            return arrayClone(src, hub, layoutHelper);
-        } else {
-            genericInstanceCloneCounter.inc();
-            return instanceClone(src, hub, layoutHelper);
+    @Snippet(removeAllFrameStates = true)
+    public static long[] longArrayClone(long[] src) {
+        long[] result = new long[src.length];
+        for (int i = 0; i < result.length; i++) {
+            result[i] = src[i];
         }
+        return result;
     }
 
-    private static final SnippetCounter.Group cloneCounters = SnippetCounters.getValue() ? 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 = SnippetCounters.getValue() ? 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");
-
+    @Snippet(removeAllFrameStates = true)
+    public static Object[] objectArrayClone(Object[] src) {
+        Object[] result = (Object[]) DynamicNewArrayNode.newArray(GuardingPiNode.guardingNonNull(src.getClass().getComponentType()), src.length);
+        for (int i = 0; i < result.length; i++) {
+            result[i] = src[i];
+        }
+        return result;
+    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ForeignCallStub.java	Wed Oct 02 15:37:06 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ForeignCallStub.java	Wed Oct 02 17:34:27 2013 +0200
@@ -305,7 +305,7 @@
     private void inline(InvokeNode invoke) {
         ResolvedJavaMethod method = ((MethodCallTargetNode) invoke.callTarget()).targetMethod();
         ReplacementsImpl repl = new ReplacementsImpl(runtime, new Assumptions(false), runtime.getTarget());
-        StructuredGraph calleeGraph = repl.makeGraph(method, null, null);
+        StructuredGraph calleeGraph = repl.makeGraph(method, null, null, false);
         InliningUtil.inline(invoke, calleeGraph, false);
     }
 }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java	Wed Oct 02 15:37:06 2013 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java	Wed Oct 02 17:34:27 2013 +0200
@@ -36,6 +36,7 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.util.*;
+import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.graph.*;
 import com.oracle.graal.phases.tiers.*;
@@ -172,6 +173,9 @@
         int fixedCount = 0;
         while (fixed instanceof FixedWithNextNode) {
             fixed = ((FixedWithNextNode) fixed).next();
+            if (fixed instanceof CommitAllocationNode) {
+                return false;
+            }
             fixedCount++;
         }
         if (fixedCount > 1) {
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java	Wed Oct 02 15:37:06 2013 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java	Wed Oct 02 17:34:27 2013 +0200
@@ -70,8 +70,6 @@
     @Option(help = "")
     public static final OptionValue<Boolean> PartialEscapeAnalysis = new OptionValue<>(true);
     @Option(help = "")
-    public static final OptionValue<Boolean> EscapeAnalysisHistogram = new OptionValue<>(false);
-    @Option(help = "")
     public static final OptionValue<Integer> EscapeAnalysisIterations = new OptionValue<>(2);
     @Option(help = "")
     public static final OptionValue<String> EscapeAnalyzeOnly = new OptionValue<>(null);
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java	Wed Oct 02 15:37:06 2013 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java	Wed Oct 02 17:34:27 2013 +0200
@@ -57,7 +57,7 @@
     @Override
     protected StructuredGraph parse(Method m) {
         ResolvedJavaMethod resolvedMethod = runtime.lookupJavaMethod(m);
-        return installer.makeGraph(resolvedMethod, null, inliningPolicy.get());
+        return installer.makeGraph(resolvedMethod, null, inliningPolicy.get(), false);
     }
 
     @Test
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java	Wed Oct 02 15:37:06 2013 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java	Wed Oct 02 17:34:27 2013 +0200
@@ -61,7 +61,7 @@
     @Override
     protected StructuredGraph parse(Method m) {
         ResolvedJavaMethod resolvedMethod = runtime.lookupJavaMethod(m);
-        return installer.makeGraph(resolvedMethod, null, inliningPolicy.get());
+        return installer.makeGraph(resolvedMethod, null, inliningPolicy.get(), false);
     }
 
     @Test
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/WordTest.java	Wed Oct 02 15:37:06 2013 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/WordTest.java	Wed Oct 02 17:34:27 2013 +0200
@@ -51,7 +51,7 @@
     @Override
     protected StructuredGraph parse(Method m) {
         ResolvedJavaMethod resolvedMethod = runtime.lookupJavaMethod(m);
-        return installer.makeGraph(resolvedMethod, null, inliningPolicy.get());
+        return installer.makeGraph(resolvedMethod, null, inliningPolicy.get(), false);
     }
 
     @LongTest
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Wed Oct 02 15:37:06 2013 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Wed Oct 02 17:34:27 2013 +0200
@@ -84,7 +84,7 @@
 
         StructuredGraph graph = graphs.get(method);
         if (graph == null) {
-            graphs.putIfAbsent(method, makeGraph(method, null, inliningPolicy(method)));
+            graphs.putIfAbsent(method, makeGraph(method, null, inliningPolicy(method), method.getAnnotation(Snippet.class).removeAllFrameStates()));
             graph = graphs.get(method);
         }
         return graph;
@@ -97,7 +97,7 @@
         }
         StructuredGraph graph = graphs.get(substitute);
         if (graph == null) {
-            graphs.putIfAbsent(substitute, makeGraph(substitute, original, inliningPolicy(substitute)));
+            graphs.putIfAbsent(substitute, makeGraph(substitute, original, inliningPolicy(substitute), false));
             graph = graphs.get(substitute);
         }
         return graph;
@@ -221,9 +221,10 @@
      * @param original the original method if {@code method} is a {@linkplain MethodSubstitution
      *            substitution} otherwise null
      * @param policy the inlining policy to use during preprocessing
+     * @param removeAllFrameStates removes all frame states from side effecting instructions
      */
-    public StructuredGraph makeGraph(ResolvedJavaMethod method, ResolvedJavaMethod original, SnippetInliningPolicy policy) {
-        return createGraphMaker(method, original).makeGraph(policy);
+    public StructuredGraph makeGraph(ResolvedJavaMethod method, ResolvedJavaMethod original, SnippetInliningPolicy policy, boolean removeAllFrameStates) {
+        return createGraphMaker(method, original).makeGraph(policy, removeAllFrameStates);
     }
 
     /**
@@ -261,7 +262,7 @@
             this.original = original;
         }
 
-        public StructuredGraph makeGraph(final SnippetInliningPolicy policy) {
+        public StructuredGraph makeGraph(final SnippetInliningPolicy policy, final boolean removeAllFrameStates) {
             return Debug.scope("BuildSnippetGraph", new Object[]{method}, new Callable<StructuredGraph>() {
 
                 @Override
@@ -271,7 +272,7 @@
                     // Cannot have a finalized version of a graph in the cache
                     graph = graph.copy();
 
-                    finalizeGraph(graph);
+                    finalizeGraph(graph, removeAllFrameStates);
 
                     Debug.dump(graph, "%s: Final", method.getName());
 
@@ -283,7 +284,7 @@
         /**
          * Does final processing of a snippet graph.
          */
-        protected void finalizeGraph(StructuredGraph graph) {
+        protected void finalizeGraph(StructuredGraph graph, boolean removeAllFrameStates) {
             new NodeIntrinsificationPhase(runtime).apply(graph);
             if (!SnippetTemplate.hasConstantParameter(method)) {
                 NodeIntrinsificationVerificationPhase.verify(graph);
@@ -291,7 +292,15 @@
             new ConvertDeoptimizeToGuardPhase().apply(graph);
 
             if (original == null) {
-                new SnippetFrameStateCleanupPhase().apply(graph);
+                if (removeAllFrameStates) {
+                    for (Node node : graph.getNodes()) {
+                        if (node instanceof StateSplit) {
+                            ((StateSplit) node).setStateAfter(null);
+                        }
+                    }
+                } else {
+                    new SnippetFrameStateCleanupPhase().apply(graph);
+                }
             }
             new DeadCodeEliminationPhase().apply(graph);
         }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/Snippet.java	Wed Oct 02 15:37:06 2013 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/Snippet.java	Wed Oct 02 17:34:27 2013 +0200
@@ -45,6 +45,13 @@
     Class<? extends SnippetInliningPolicy> inlining() default SnippetInliningPolicy.class;
 
     /**
+     * Specifies whether all FrameStates within this snippet should always be removed. If this is
+     * false, FrameStates are only removed if there are no side-effecting instructions in the
+     * snippet.
+     */
+    boolean removeAllFrameStates() default false;
+
+    /**
      * Guides inlining decisions used when installing a snippet.
      */
     public interface SnippetInliningPolicy {