changeset 5563:6a2671066204

added NewInstanceSnippets for lowering NewInstanceNodes (currently disabled by default) added Word type and WordTypeRewriterPhase to support programming against machine word values in snippets without duplicating the code for 32 and 64 bit platforms added GraphUtil.approxSourceLocation() utility method for getting an approximate source code location for a node
author Doug Simon <doug.simon@oracle.com>
date Mon, 11 Jun 2012 15:39:57 +0200
parents 4ffc061dc71a
children 102f87543d5e
files graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/SnippetIntrinsificationPhase.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotDebugConfig.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewInstanceStubCall.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/RegisterNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/NewInstanceSnippets.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/target/AMD64NewInstanceStubCallOp.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConditionalNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Negatable.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Snippets.java graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Word.java graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/WordTypeRewriterPhase.java
diffstat 20 files changed, 771 insertions(+), 24 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java	Mon Jun 11 15:35:23 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java	Mon Jun 11 15:39:57 2012 +0200
@@ -257,11 +257,11 @@
     public static int InstanceOfMaxHints = 1;
 
     /**
-     * Use HIR lowering instead of LIR lowering for checkcast instructions.
-     * Only checkcasts in methods whose fully qualified name contains this option will be HIR lowered.
-     * TODO (dnsimon) remove once HIR checkcast lowering works reliably
+     * Use HIR lowering instead of LIR lowering for certain instructions.
+     * Only instructions in methods whose fully qualified name contains this option will be HIR lowered.
      */
     public static String HIRLowerCheckcast = "";
+    public static String HIRLowerNewInstance = null;
 
     /**
      * The profiling info cache directory.
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/SnippetIntrinsificationPhase.java	Mon Jun 11 15:35:23 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/SnippetIntrinsificationPhase.java	Mon Jun 11 15:39:57 2012 +0200
@@ -233,6 +233,11 @@
         }
     }
 
+    private static String sourceLocation(Node n) {
+        String loc = GraphUtil.approxSourceLocation(n);
+        return loc == null ? "<unknown>" : loc;
+    }
+
     public void cleanUpReturnCheckCast(Node newInstance) {
         if (newInstance instanceof ValueNode && ((ValueNode) newInstance).kind() != Kind.Object) {
             StructuredGraph graph = (StructuredGraph) newInstance.graph();
@@ -246,7 +251,9 @@
                         graph.removeFixed(valueAnchorNode);
                     } else if (checkCastUsage instanceof MethodCallTargetNode) {
                         MethodCallTargetNode checkCastCallTarget = (MethodCallTargetNode) checkCastUsage;
-                        assert pool.isUnboxingMethod(checkCastCallTarget.targetMethod());
+                        assert pool.isUnboxingMethod(checkCastCallTarget.targetMethod()) :
+                            "checkcast at " + sourceLocation(checkCastNode) + " not used by an unboxing method but by a call at " +
+                            sourceLocation(checkCastCallTarget.usages().first()) + " to " + checkCastCallTarget.targetMethod();
                         Invoke invokeNode = checkCastCallTarget.invoke();
                         invokeNode.node().replaceAtUsages(newInstance);
                         if (invokeNode instanceof InvokeWithExceptionNode) {
@@ -262,7 +269,7 @@
                     } else if (checkCastUsage instanceof FrameState) {
                         checkCastUsage.replaceFirstInput(checkCastNode, null);
                     } else {
-                        assert false : "unexpected checkcast usage: " + checkCastUsage;
+                        assert false : sourceLocation(checkCastUsage) + " has unexpected usage " + checkCastUsage + " of checkcast at " + sourceLocation(checkCastNode);
                     }
                 }
                 FixedNode next = checkCastNode.next();
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotDebugConfig.java	Mon Jun 11 15:35:23 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotDebugConfig.java	Mon Jun 11 15:39:57 2012 +0200
@@ -30,6 +30,7 @@
 import com.oracle.graal.compiler.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.printer.*;
 import com.oracle.max.criutils.*;
 
@@ -150,13 +151,22 @@
         Debug.setConfig(Debug.fixedConfig(true, true, false, false, dumpHandlers, output));
         Debug.log(String.format("Exception occurred in scope: %s", Debug.currentScope()));
         for (Object o : Debug.context()) {
-            Debug.log("Context obj %s", o);
             if (o instanceof Graph) {
+                Debug.log("Context obj %s", o);
                 if (GraalOptions.DumpOnError) {
                     Debug.dump(o, "Exception graph");
                 } else {
                     Debug.log("Use -G:+DumpOnError to enable dumping of graphs on this error");
                 }
+            } else if (o instanceof Node) {
+                String location = GraphUtil.approxSourceLocation((Node) o);
+                if (location != null) {
+                    Debug.log("Context obj %s (approx. location: %s)", o, location);
+                } else {
+                    Debug.log("Context obj %s", o);
+                }
+            } else {
+                Debug.log("Context obj %s", o);
             }
         }
         return null;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Mon Jun 11 15:35:23 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Mon Jun 11 15:39:57 2012 +0200
@@ -56,7 +56,8 @@
     final HotSpotRegisterConfig regConfig;
     private final HotSpotRegisterConfig globalStubRegConfig;
     private final HotSpotGraalRuntime compiler;
-    private CheckCastSnippets.Templates checkcasts;
+    private CheckCastSnippets.Templates checkcastSnippets;
+    private NewInstanceSnippets.Templates newInstanceSnippets;
 
     public HotSpotRuntime(HotSpotVMConfig config, HotSpotGraalRuntime compiler) {
         this.config = config;
@@ -72,7 +73,9 @@
         Snippets.install(this, compiler.getTarget(), new UnsafeSnippets());
         Snippets.install(this, compiler.getTarget(), new ArrayCopySnippets());
         Snippets.install(this, compiler.getTarget(), new CheckCastSnippets());
-        checkcasts = new CheckCastSnippets.Templates(this);
+        Snippets.install(this, compiler.getTarget(), new NewInstanceSnippets());
+        checkcastSnippets = new CheckCastSnippets.Templates(this);
+        newInstanceSnippets = new NewInstanceSnippets.Templates(this);
     }
 
 
@@ -336,7 +339,9 @@
             assert load.kind() != Kind.Illegal;
             IndexedLocationNode location = IndexedLocationNode.create(LocationNode.ANY_LOCATION, load.loadKind(), load.displacement(), load.offset(), graph, false);
             ReadNode memoryRead = graph.add(new ReadNode(load.object(), location, load.stamp()));
-            memoryRead.dependencies().add(tool.createNullCheckGuard(load.object(), StructuredGraph.INVALID_GRAPH_ID));
+            if (load.object().kind().isObject()) {
+                memoryRead.dependencies().add(tool.createNullCheckGuard(load.object(), StructuredGraph.INVALID_GRAPH_ID));
+            }
             graph.replaceFixedWithFixed(load, memoryRead);
         } else if (n instanceof UnsafeStoreNode) {
             UnsafeStoreNode store = (UnsafeStoreNode) n;
@@ -355,16 +360,19 @@
             memoryRead.dependencies().add(tool.createNullCheckGuard(objectClassNode.object(), StructuredGraph.INVALID_GRAPH_ID));
             graph.replaceFixed(objectClassNode, memoryRead);
         } else if (n instanceof CheckCastNode) {
-            if (shouldLowerCheckcast(graph)) {
-                checkcasts.lower((CheckCastNode) n, tool);
+            if (shouldLower(graph, GraalOptions.HIRLowerCheckcast)) {
+                checkcastSnippets.lower((CheckCastNode) n, tool);
+            }
+        } else if (n instanceof NewInstanceNode) {
+            if (shouldLower(graph, GraalOptions.HIRLowerNewInstance)) {
+                newInstanceSnippets.lower((NewInstanceNode) n, tool);
             }
         } else {
             assert false : "Node implementing Lowerable not handled: " + n;
         }
     }
 
-    private static boolean shouldLowerCheckcast(StructuredGraph graph) {
-        String option = GraalOptions.HIRLowerCheckcast;
+    private static boolean shouldLower(StructuredGraph graph, String option) {
         if (option != null) {
             if (option.length() == 0) {
                 return true;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewInstanceStubCall.java	Mon Jun 11 15:39:57 2012 +0200
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2012, 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.nodes;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.compiler.target.*;
+import com.oracle.graal.hotspot.target.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.type.*;
+import com.oracle.max.asm.target.amd64.*;
+
+/**
+ * Node implementing a call to HotSpot's {@code new_instance} stub.
+ *
+ * @see AMD64NewInstanceStubCallOp
+ */
+public class NewInstanceStubCall extends FixedWithNextNode implements LIRGenLowerable {
+
+    @Input private final ValueNode hub;
+
+    public NewInstanceStubCall(ValueNode hub) {
+        super(StampFactory.objectNonNull());
+        this.hub = hub;
+    }
+
+    @Override
+    public void generate(LIRGenerator gen) {
+        Variable result = gen.newVariable(Kind.Object);
+        gen.emitMove(gen.operand(hub), AMD64.rdx.asValue());
+        AMD64NewInstanceStubCallOp op = new AMD64NewInstanceStubCallOp(result, AMD64.rdx.asValue());
+        gen.append(op);
+        gen.setResult(this, result);
+    }
+
+    @SuppressWarnings("unused")
+    @NodeIntrinsic
+    public static Object call(Object hub) {
+        throw new UnsupportedOperationException();
+    }
+
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/RegisterNode.java	Mon Jun 11 15:39:57 2012 +0200
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2012, 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.nodes;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+
+/**
+ * Access the value of a specific register.
+ */
+public final class RegisterNode extends FloatingNode implements LIRLowerable {
+
+    private final Register register;
+
+    public RegisterNode(Register register, Kind kind) {
+        super(StampFactory.forKind(kind));
+        this.register = register;
+    }
+
+    @Override
+    public void generate(LIRGeneratorTool generator) {
+        Value result = generator.newVariable(kind());
+        generator.emitMove(register.asValue(kind()), result);
+        generator.setResult(this, result);
+    }
+
+    @Override
+    public String toString(Verbosity verbosity) {
+        if (verbosity == Verbosity.Name) {
+            return super.toString(Verbosity.Name) + "%" + register;
+        } else {
+            return super.toString(verbosity);
+        }
+    }
+
+    @Override
+    public Map<Object, Object> getDebugProperties() {
+        Map<Object, Object> properties = super.getDebugProperties();
+        properties.put("register", register.toString());
+        return properties;
+    }
+
+    @SuppressWarnings("unused")
+    @NodeIntrinsic
+    public static <T> T register(@ConstantNodeParameter Register register, @ConstantNodeParameter Kind kind) {
+        throw new UnsupportedOperationException();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/NewInstanceSnippets.java	Mon Jun 11 15:39:57 2012 +0200
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2012, 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.nodes.RegisterNode.*;
+import static com.oracle.graal.hotspot.snippets.DirectObjectStoreNode.*;
+import static com.oracle.graal.nodes.calc.Condition.*;
+import static com.oracle.graal.nodes.extended.UnsafeCastNode.*;
+import static com.oracle.graal.nodes.extended.UnsafeLoadNode.*;
+import static com.oracle.graal.snippets.SnippetTemplate.Arguments.*;
+import static com.oracle.graal.snippets.nodes.ExplodeLoopNode.*;
+import static com.oracle.max.asm.target.amd64.AMD64.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.phases.*;
+import com.oracle.graal.cri.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.Node.Fold;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.snippets.*;
+import com.oracle.graal.snippets.Snippet.ConstantParameter;
+import com.oracle.graal.snippets.Snippet.Parameter;
+import com.oracle.graal.snippets.SnippetTemplate.Arguments;
+import com.oracle.graal.snippets.SnippetTemplate.Cache;
+import com.oracle.graal.snippets.SnippetTemplate.Key;
+
+/**
+ * Snippets used for implementing NEW.
+ */
+public class NewInstanceSnippets implements SnippetsInterface {
+
+    /**
+     * Type test used when the type being tested against is a final type.
+     */
+    @Snippet
+    public static Object newInstance(@Parameter("hub") Object hub, @ConstantParameter("size") int size, @ConstantParameter("checkInit") boolean checkInit) {
+        if (checkInit) {
+            int klassState = load(hub, 0, klassStateOffset(), Kind.Int);
+            if (klassState != klassStateFullyInitialized()) {
+                Object instance = NewInstanceStubCall.call(hub);
+                return formatInstance(hub, size, instance);
+            }
+        }
+
+        Word thread = asWord(register(r15, wordKind()));
+        Word top = loadWord(thread, threadTlabTopOffset());
+        Word end = loadWord(thread, threadTlabEndOffset());
+        Word newTop = top.plus(size);
+        Object instance;
+        if (newTop.cmp(BE, end)) {
+            instance = cast(top, Object.class);
+            store(thread, 0, threadTlabTopOffset(), newTop);
+        } else {
+            instance = NewInstanceStubCall.call(hub);
+        }
+
+        return formatInstance(hub, size, instance);
+    }
+
+    private static Word asWord(Object object) {
+        return cast(object, Word.class);
+    }
+
+    private static Word loadWord(Object object, int offset) {
+        return cast(load(object, 0, offset, wordKind()), Word.class);
+    }
+
+    /**
+     * Formats the header of a created instance and zeroes out its body.
+     */
+    private static Object formatInstance(Object hub, int size, Object instance) {
+        Word headerPrototype = cast(load(hub, 0, instanceHeaderPrototypeOffset(), wordKind()), Word.class);
+        store(instance, 0, 0, headerPrototype);
+        store(instance, 0, hubOffset(), hub);
+        explodeLoop();
+        for (int offset = 2 * wordSize(); offset < size; offset += wordSize()) {
+            store(instance, 0, offset, 0);
+        }
+        return instance;
+    }
+
+    @Fold
+    private static int klassStateOffset() {
+        return HotSpotGraalRuntime.getInstance().getConfig().klassStateOffset;
+    }
+
+    @Fold
+    private static int klassStateFullyInitialized() {
+        return HotSpotGraalRuntime.getInstance().getConfig().klassStateFullyInitialized;
+    }
+
+    @Fold
+    private static int threadTlabTopOffset() {
+        return HotSpotGraalRuntime.getInstance().getConfig().threadTlabTopOffset;
+    }
+
+    @Fold
+    private static int threadTlabEndOffset() {
+        return HotSpotGraalRuntime.getInstance().getConfig().threadTlabEndOffset;
+    }
+
+    @Fold
+    private static Kind wordKind() {
+        return HotSpotGraalRuntime.getInstance().getTarget().wordKind;
+    }
+
+    @Fold
+    private static int wordSize() {
+        return HotSpotGraalRuntime.getInstance().getTarget().wordSize;
+    }
+
+    @Fold
+    private static int instanceHeaderPrototypeOffset() {
+        return HotSpotGraalRuntime.getInstance().getConfig().instanceHeaderPrototypeOffset;
+    }
+
+    @Fold
+    private static int hubOffset() {
+        return HotSpotGraalRuntime.getInstance().getConfig().hubOffset;
+    }
+
+    public static class Templates {
+
+        private final Cache cache;
+        private final ResolvedJavaMethod newInstance;
+        private final CodeCacheProvider runtime;
+
+        public Templates(CodeCacheProvider runtime) {
+            this.runtime = runtime;
+            this.cache = new Cache(runtime);
+            try {
+                newInstance = runtime.getResolvedJavaMethod(NewInstanceSnippets.class.getDeclaredMethod("newInstance", Object.class, int.class, boolean.class));
+            } catch (NoSuchMethodException e) {
+                throw new GraalInternalError(e);
+            }
+        }
+
+        /**
+         * Lowers a {@link NewInstanceNode}.
+         */
+        @SuppressWarnings("unused")
+        public void lower(NewInstanceNode newInstanceNode, CiLoweringTool tool) {
+            StructuredGraph graph = (StructuredGraph) newInstanceNode.graph();
+            HotSpotResolvedJavaType type = (HotSpotResolvedJavaType) newInstanceNode.instanceClass();
+            HotSpotKlassOop hub = type.klassOop();
+            int instanceSize = type.instanceSize();
+            Key key = new Key(newInstance).add("size", instanceSize).add("checkInit", !type.isInitialized());
+            Arguments arguments = arguments("hub", hub);
+            SnippetTemplate template = cache.get(key);
+            Debug.log("Lowering newInstance in %s: node=%s, template=%s, arguments=%s", graph, newInstanceNode, template, arguments);
+            template.instantiate(runtime, newInstanceNode, newInstanceNode, arguments);
+            new DeadCodeEliminationPhase().apply(graph);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/target/AMD64NewInstanceStubCallOp.java	Mon Jun 11 15:39:57 2012 +0200
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2012, 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.target;
+
+import static com.oracle.graal.api.code.ValueUtil.*;
+
+import java.util.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.lir.amd64.*;
+import com.oracle.graal.lir.asm.*;
+import com.oracle.max.asm.target.amd64.*;
+
+/**
+ * LIR instruction for calling HotSpot's {@code new_instance} stub. This stub is declared in c1_Runtime1.hpp
+ * and implemented in Runtime1::generate_code_for() which is located in c1_Runtime1_x86.cpp.
+ */
+public class AMD64NewInstanceStubCallOp extends AMD64LIRInstruction {
+    public AMD64NewInstanceStubCallOp(Value result, Value hub) {
+        super("NEW_INSTANCE", new Value[] {result}, null, new Value[] {hub}, NO_OPERANDS, NO_OPERANDS);
+    }
+
+    @Override
+    public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
+        Value result = output(0);
+        Value hub = input(0);
+
+        // rdx: (in) hub
+        // rax: (out) result
+        assert asRegister(hub) == AMD64.rdx;
+        AMD64Call.directCall(tasm, masm, HotSpotGraalRuntime.getInstance().getConfig().newInstanceStub, null);
+        if (asRegister(result) != AMD64.rax) {
+            masm.movq(asRegister(result), AMD64.rax);
+        }
+    }
+
+    @Override
+    protected EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
+        if (mode == OperandMode.Input) {
+            return EnumSet.of(OperandFlag.Register);
+        } else if (mode == OperandMode.Output) {
+            return EnumSet.of(OperandFlag.Register);
+        }
+        throw GraalInternalError.shouldNotReachHere();
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java	Mon Jun 11 15:35:23 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java	Mon Jun 11 15:39:57 2012 +0200
@@ -98,7 +98,8 @@
     }
 
     @Override
-    public void negate() {
+    public Negatable negate() {
         negated = !negated;
+        return this;
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardNode.java	Mon Jun 11 15:35:23 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardNode.java	Mon Jun 11 15:39:57 2012 +0200
@@ -134,7 +134,8 @@
     }
 
     @Override
-    public void negate() {
+    public Negatable negate() {
         negated = !negated;
+        return this;
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Mon Jun 11 15:35:23 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Mon Jun 11 15:39:57 2012 +0200
@@ -188,7 +188,7 @@
     }
 
     @Override
-    public void negate() {
+    public Negatable negate() {
         BeginNode trueSucc = trueSuccessor();
         BeginNode falseSucc = falseSuccessor();
         setTrueSuccessor(null);
@@ -198,5 +198,6 @@
         double prop = branchProbability[TRUE_EDGE];
         branchProbability[TRUE_EDGE] = branchProbability[FALSE_EDGE];
         branchProbability[FALSE_EDGE] = prop;
+        return this;
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNode.java	Mon Jun 11 15:35:23 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNode.java	Mon Jun 11 15:39:57 2012 +0200
@@ -28,6 +28,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.type.GenericStamp.*;
+import com.oracle.graal.nodes.util.*;
 
 /**
  * This class represents a value within the graph, including local variables, phis, and
@@ -108,15 +109,24 @@
         return null;
     }
 
+    public <T extends Stamp> boolean verifyStamp(Class<T> stampClass) {
+        assert stampClass.isInstance(stamp) : this + " (" + GraphUtil.approxSourceLocation(this) + ") has unexpected stamp type: expected " + stampClass.getName() +
+            ", got " + stamp.getClass().getName();
+        return true;
+    }
+
     public final ObjectStamp objectStamp() {
+        assert verifyStamp(ObjectStamp.class);
         return (ObjectStamp) stamp;
     }
 
     public final IntegerStamp integerStamp() {
+        assert verifyStamp(IntegerStamp.class);
         return (IntegerStamp) stamp;
     }
 
     public final FloatStamp floatStamp() {
+        assert verifyStamp(FloatStamp.class);
         return (FloatStamp) stamp;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConditionalNode.java	Mon Jun 11 15:35:23 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConditionalNode.java	Mon Jun 11 15:39:57 2012 +0200
@@ -74,7 +74,9 @@
     }
 
     @Override
-    public void negate() {
-        ((StructuredGraph) graph()).replaceFloating(this, graph().unique(new ConditionalNode(condition, falseValue(), trueValue())));
+    public Negatable negate() {
+        ConditionalNode replacement = graph().unique(new ConditionalNode(condition, falseValue(), trueValue()));
+        ((StructuredGraph) graph()).replaceFloating(this, replacement);
+        return replacement;
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java	Mon Jun 11 15:35:23 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java	Mon Jun 11 15:39:57 2012 +0200
@@ -32,7 +32,7 @@
 /**
  * The {@code UnsafeCastNode} produces the same value as its input, but with a different type.
  */
-public final class UnsafeCastNode extends FloatingNode implements Canonicalizable, Lowerable {
+public final class UnsafeCastNode extends FloatingNode implements Canonicalizable, Lowerable, LIRLowerable {
 
     @Input private ValueNode object;
     private ResolvedJavaType toType;
@@ -49,15 +49,20 @@
 
     @Override
     public ValueNode canonical(CanonicalizerTool tool) {
-        if (object != null && object.objectStamp().type() != null && object.objectStamp().type().isSubtypeOf(toType)) {
+        if (object != null && object.kind().isObject() && object.objectStamp().type() != null && object.objectStamp().type().isSubtypeOf(toType)) {
             return object;
         }
         return this;
     }
 
+
     @Override
     public void lower(CiLoweringTool tool) {
-        ((StructuredGraph) graph()).replaceFloating(this, object);
+        if (object.kind() == kind()) {
+            ((StructuredGraph) graph()).replaceFloating(this, object);
+        } else {
+            // Cannot remove an unsafe cast between two different kinds
+        }
     }
 
     @SuppressWarnings("unused")
@@ -65,4 +70,11 @@
     public static <T> T cast(Object object, @ConstantNodeParameter Class<?> toType) {
         throw new UnsupportedOperationException("This method may only be compiled with the Graal compiler");
     }
+
+    @Override
+    public void generate(LIRGeneratorTool generator) {
+        Value result = generator.newVariable(kind());
+        generator.emitMove(generator.operand(object), result);
+        generator.setResult(this, result);
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java	Mon Jun 11 15:35:23 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java	Mon Jun 11 15:39:57 2012 +0200
@@ -25,6 +25,7 @@
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.cri.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
@@ -34,7 +35,7 @@
 /**
  * The {@code NewInstanceNode} represents the allocation of an instance class object.
  */
-public final class NewInstanceNode extends FixedWithNextNode implements EscapeAnalyzable, LIRLowerable, Node.IterableNodeType {
+public final class NewInstanceNode extends FixedWithNextNode implements EscapeAnalyzable, Lowerable, LIRLowerable, Node.IterableNodeType {
 
     private final ResolvedJavaType instanceClass;
 
@@ -56,6 +57,11 @@
     }
 
     @Override
+    public void lower(CiLoweringTool tool) {
+        tool.getRuntime().lower(this, tool);
+    }
+
+    @Override
     public void generate(LIRGeneratorTool gen) {
         gen.visitNewInstance(this);
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Negatable.java	Mon Jun 11 15:35:23 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Negatable.java	Mon Jun 11 15:39:57 2012 +0200
@@ -36,5 +36,5 @@
      * Tells this node that a condition it depends has been negated, and that it thus needs to invert its own effect.
      * For example, an {@link IfNode} would switch its true and false successors.
      */
-    void negate();
+    Negatable negate();
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java	Mon Jun 11 15:35:23 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java	Mon Jun 11 15:39:57 2012 +0200
@@ -26,12 +26,14 @@
 
 import java.util.*;
 
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.iterators.*;
 import com.oracle.graal.graph.iterators.NodePredicates.PositiveTypePredicate;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.PhiNode.PhiType;
 import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.virtual.*;
 
 public class GraphUtil {
@@ -180,6 +182,36 @@
         }
     }
 
+    /**
+     * Gets an approximate source code location for a node if possible.
+     *
+     * @return a file name and source line number in stack trace format (e.g. "String.java:32")
+     *          if an approximate source location is found, null otherwise
+     */
+    public static String approxSourceLocation(Node node) {
+        Node n = node;
+        while (n != null) {
+            if (n instanceof MethodCallTargetNode) {
+                n = ((MethodCallTargetNode) n).invoke().node();
+            }
+
+            if (n instanceof StateSplit) {
+                FrameState stateAfter = ((StateSplit) n).stateAfter();
+                if (stateAfter != null) {
+                    ResolvedJavaMethod method = stateAfter.method();
+                    if (method != null) {
+                        StackTraceElement stackTraceElement = method.toStackTraceElement(stateAfter.bci);
+                        if (stackTraceElement.getFileName() != null && stackTraceElement.getLineNumber() >= 0) {
+                            return stackTraceElement.getFileName() + ":" + stackTraceElement.getLineNumber();
+                        }
+                    }
+                }
+            }
+            n = n.predecessor();
+        }
+        return null;
+    }
+
     public static ValueNode unProxify(ValueNode proxy) {
         ValueNode v = proxy;
         while (v instanceof ValueProxyNode) {
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Snippets.java	Mon Jun 11 15:35:23 2012 +0200
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Snippets.java	Mon Jun 11 15:39:57 2012 +0200
@@ -113,7 +113,9 @@
                             targetGraph = buildSnippetGraph(targetMethod, runtime, target, pool);
                         }
                         InliningUtil.inline(invoke, targetGraph, true);
+                        Debug.dump(graph, "after inlining %s", targetMethod);
                         if (GraalOptions.OptCanonicalizer) {
+                            new WordTypeRewriterPhase(target).apply(graph);
                             new CanonicalizerPhase(target, runtime, null).apply(graph);
                         }
                     }
@@ -121,7 +123,8 @@
 
                 new SnippetIntrinsificationPhase(runtime, pool).apply(graph);
 
-                Debug.dump(graph, "%s: %s", snippetRiMethod.name(), GraphBuilderPhase.class.getSimpleName());
+                new WordTypeRewriterPhase(target).apply(graph);
+
                 new DeadCodeEliminationPhase().apply(graph);
                 if (GraalOptions.OptCanonicalizer) {
                     new CanonicalizerPhase(target, runtime, null).apply(graph);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Word.java	Mon Jun 11 15:39:57 2012 +0200
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2012, 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.snippets;
+
+import static com.oracle.graal.snippets.Word.Opcode.*;
+
+import java.lang.annotation.*;
+
+import com.oracle.graal.nodes.calc.*;
+
+/**
+ * Special type for use in snippets to represent machine word sized data.
+ */
+public final class Word {
+
+    /**
+     * Links a method to a canonical operation represented by an {@link Opcode} value.
+     */
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.METHOD)
+    public @interface Operation {
+        Opcode value();
+    }
+
+    /**
+     * The canonical {@link Operation} represented by a method in the {@link Word} class.
+     */
+    public enum Opcode {
+        PLUS,
+        MINUS,
+        COMPARE;
+    }
+
+    private Word() {
+    }
+
+    @Operation(COMPARE)
+    public native boolean cmp(Condition condition, Word other);
+
+    @Operation(PLUS)
+    public native Word plus(int addend);
+
+    @Operation(PLUS)
+    public native Word plus(long addend);
+
+    @Operation(PLUS)
+    public native Word plus(Word addend);
+
+    @Operation(MINUS)
+    public native Word minus(int addend);
+
+    @Operation(MINUS)
+    public native Word minus(long addend);
+
+    @Operation(MINUS)
+    public native Word minus(Word addend);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/WordTypeRewriterPhase.java	Mon Jun 11 15:39:57 2012 +0200
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2012, 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.snippets;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.phases.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.PhiNode.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.calc.ConvertNode.Op;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.snippets.Word.Opcode;
+import com.oracle.graal.snippets.Word.Operation;
+
+/**
+ * Transforms all uses of the {@link Word} class into unsigned
+ * operations on {@code int} or {@code long} values, depending
+ * on the word kind of the underlying platform.
+ */
+public class WordTypeRewriterPhase extends Phase {
+
+    private final Kind wordKind;
+
+    public WordTypeRewriterPhase(TargetDescription target) {
+        this.wordKind = target.wordKind;
+    }
+
+    @Override
+    protected void run(StructuredGraph graph) {
+        for (Node n : graph.getNodes()) {
+            if (n instanceof ValueNode) {
+                ValueNode valueNode = (ValueNode) n;
+                if (isWord(valueNode)) {
+                    changeToWord(valueNode);
+                }
+            }
+        }
+
+        // Remove all checkcasts to Word
+        for (CheckCastNode checkCastNode : graph.getNodes(CheckCastNode.class).snapshot()) {
+            if (!checkCastNode.object().stamp().kind().isObject()) {
+                checkCastNode.replaceAtUsages(checkCastNode.object());
+                graph.removeFixed(checkCastNode);
+            }
+        }
+
+        // Remove unnecessary/redundant unsafe casts
+        for (UnsafeCastNode unsafeCastNode : graph.getNodes().filter(UnsafeCastNode.class).snapshot()) {
+            if (!unsafeCastNode.isDeleted() && unsafeCastNode.object().stamp() == unsafeCastNode.stamp()) {
+                graph.replaceFloating(unsafeCastNode, unsafeCastNode.object());
+            }
+        }
+
+        for (MethodCallTargetNode callTargetNode : graph.getNodes(MethodCallTargetNode.class).snapshot()) {
+            ResolvedJavaMethod targetMethod = callTargetNode.targetMethod();
+            Operation operation = targetMethod.getAnnotation(Word.Operation.class);
+            if (operation != null) {
+                NodeInputList<ValueNode> arguments = callTargetNode.arguments();
+                Invoke invoke = (Invoke) callTargetNode.usages().first();
+                assert invoke != null;
+
+                Opcode opcode = operation.value();
+                switch (opcode) {
+                    case COMPARE: {
+                        assert arguments.size() == 3;
+                        assert arguments.get(1) instanceof ConstantNode;
+                        Condition condition = (Condition) arguments.get(1).asConstant().asObject();
+                        invoke.intrinsify(compare(condition, graph, arguments.first(), arguments.last()));
+                        break;
+                    }
+
+                    case PLUS: {
+                        ValueNode addend = asWordKind(graph, arguments.last());
+                        IntegerAddNode op = graph.unique(new IntegerAddNode(wordKind, arguments.first(), addend));
+                        invoke.intrinsify(op);
+                        break;
+                    }
+                    default: {
+                        throw new GraalInternalError("Unknown opcode: %s", opcode);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Creates comparison node for a given condition and two input values.
+     */
+    private ValueNode compare(Condition condition, StructuredGraph graph, ValueNode left, ValueNode right) {
+        assert condition.isUnsigned();
+        assert left.kind() == wordKind;
+        assert right.kind() == wordKind;
+
+        // mirroring gets the condition into canonical form
+        boolean mirror = condition.canonicalMirror();
+
+        ValueNode a = mirror ? right : left;
+        ValueNode b = mirror ? left : right;
+
+        MaterializeNode materialize;
+        if (condition == Condition.EQ || condition == Condition.NE) {
+            materialize = MaterializeNode.create(graph.unique(new IntegerEqualsNode(a, b)), graph);
+        } else {
+            materialize = MaterializeNode.create(graph.unique(new IntegerBelowThanNode(a, b)), graph);
+        }
+
+        ValueNode op;
+        if (condition.canonicalNegate()) {
+            op = (ValueNode) materialize.negate();
+        } else {
+            op = materialize;
+        }
+        return op;
+    }
+
+    /**
+     * Adds a node if necessary to convert a given value into the word kind.
+     *
+     * @return the node for {@code value} producing a value of word kind
+     */
+    private ValueNode asWordKind(StructuredGraph graph, ValueNode value) {
+        if (value.kind() != wordKind) {
+            Op op;
+            if (wordKind.isLong()) {
+                assert value.kind().isInt();
+                op = Op.I2L;
+            } else {
+                assert wordKind.isInt();
+                assert value.kind().isLong();
+                op = Op.L2I;
+            }
+            return graph.unique(new ConvertNode(op, value));
+        }
+        return value;
+    }
+
+    public boolean isWord(ValueNode node) {
+        return isWord(node.stamp().declaredType());
+    }
+
+    public boolean isWord(ResolvedJavaType type) {
+        if (type != null && type.toJava() == Word.class) {
+            return true;
+        }
+        return false;
+    }
+
+    private void changeToWord(ValueNode valueNode) {
+        assert !(valueNode instanceof ConstantNode);
+        valueNode.setStamp(StampFactory.forKind(wordKind));
+
+        // Propagate word kind.
+        for (Node n : valueNode.usages()) {
+            if (n instanceof PhiNode) {
+                changeToWord((ValueNode) n);
+                PhiNode phi = (PhiNode) n;
+                assert phi.type() == PhiType.Value;
+//                    for (ValueNode v : phi.values()) {
+//                        assertTrue(v.kind() == phi.kind(), "all phi values must have same kind");
+//                    }
+
+            } else if (n instanceof ReturnNode) {
+                changeToWord((ValueNode) n);
+            }
+        }
+    }
+}