changeset 11698:4eec2ac671c2

Refactor the WordTypeVerificationPhase to use fewer graph iterations, and invoke it a fewer places
author Christian Wimmer <christian.wimmer@oracle.com>
date Tue, 17 Sep 2013 18:36:54 -0700
parents 56e59e384dc1
children 03fe11f5f186
files graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CStringNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentJavaThreadNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentLockNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DimensionsNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorCounterNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ForeignCallStub.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampFactory.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeVerificationPhase.java
diffstat 14 files changed, 345 insertions(+), 341 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Wed Sep 18 02:41:52 2013 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Tue Sep 17 18:36:54 2013 -0700
@@ -104,6 +104,9 @@
         /**
          * Determines if the stamp of the instantiated intrinsic node has its stamp set from the
          * return type of the annotated method.
+         * <p>
+         * When it is set to true, the stamp that is passed in to the constructor of ValueNode is
+         * ignored and can therefore safely be {@code null}.
          */
         boolean setStampFromReturnType() default false;
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java	Wed Sep 18 02:41:52 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java	Tue Sep 17 18:36:54 2013 -0700
@@ -29,7 +29,6 @@
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.word.*;
 
 /**
@@ -42,8 +41,8 @@
 
     private int lockDepth;
 
-    public BeginLockScopeNode(int lockDepth) {
-        super(StampFactory.forWord());
+    private BeginLockScopeNode(int lockDepth) {
+        super(null);
         this.lockDepth = lockDepth;
     }
 
@@ -66,6 +65,6 @@
         gen.setResult(this, result);
     }
 
-    @NodeIntrinsic
+    @NodeIntrinsic(setStampFromReturnType = true)
     public static native Word beginLockScope(@ConstantNodeParameter int lockDepth);
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CStringNode.java	Wed Sep 18 02:41:52 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CStringNode.java	Tue Sep 17 18:36:54 2013 -0700
@@ -27,7 +27,6 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.word.*;
 
 /**
@@ -38,8 +37,8 @@
 
     private final String string;
 
-    public CStringNode(String string) {
-        super(StampFactory.forWord());
+    private CStringNode(String string) {
+        super(null);
         this.string = string;
     }
 
@@ -55,6 +54,6 @@
         graph().replaceFloating(this, replacement);
     }
 
-    @NodeIntrinsic
+    @NodeIntrinsic(setStampFromReturnType = true)
     public static native Word cstring(@ConstantNodeParameter String string);
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentJavaThreadNode.java	Wed Sep 18 02:41:52 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentJavaThreadNode.java	Tue Sep 17 18:36:54 2013 -0700
@@ -28,16 +28,15 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.word.*;
 
 /**
  * Gets the address of the C++ JavaThread object for the current thread.
  */
-public class CurrentJavaThreadNode extends FloatingNode implements LIRLowerable {
+public final class CurrentJavaThreadNode extends FloatingNode implements LIRLowerable {
 
-    public CurrentJavaThreadNode() {
-        super(StampFactory.forWord());
+    private CurrentJavaThreadNode() {
+        super(null);
     }
 
     @Override
@@ -54,7 +53,7 @@
         }
     }
 
-    @NodeIntrinsic
+    @NodeIntrinsic(setStampFromReturnType = true)
     public static Word get() {
         return Word.unsigned(unsafeReadWord(Thread.currentThread(), eetopOffset()));
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentLockNode.java	Wed Sep 18 02:41:52 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentLockNode.java	Tue Sep 17 18:36:54 2013 -0700
@@ -28,7 +28,6 @@
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.word.*;
 
 /**
@@ -38,8 +37,8 @@
 
     private int lockDepth;
 
-    public CurrentLockNode(int lockDepth) {
-        super(StampFactory.forWord());
+    private CurrentLockNode(int lockDepth) {
+        super(null);
         this.lockDepth = lockDepth;
     }
 
@@ -53,6 +52,6 @@
         gen.setResult(this, result);
     }
 
-    @NodeIntrinsic
+    @NodeIntrinsic(setStampFromReturnType = true)
     public static native Word currentLock(@ConstantNodeParameter int lockDepth);
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DimensionsNode.java	Wed Sep 18 02:41:52 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DimensionsNode.java	Tue Sep 17 18:36:54 2013 -0700
@@ -27,7 +27,6 @@
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.word.*;
 
 /**
@@ -38,8 +37,8 @@
 
     private final int rank;
 
-    public DimensionsNode(int rank) {
-        super(StampFactory.forWord());
+    private DimensionsNode(int rank) {
+        super(null);
         this.rank = rank;
     }
 
@@ -51,6 +50,6 @@
         gen.setResult(this, result);
     }
 
-    @NodeIntrinsic
+    @NodeIntrinsic(setStampFromReturnType = true)
     public static native Word allocaDimsArray(@ConstantNodeParameter int rank);
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorCounterNode.java	Wed Sep 18 02:41:52 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorCounterNode.java	Tue Sep 17 18:36:54 2013 -0700
@@ -27,7 +27,6 @@
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.word.*;
 
 /**
@@ -35,8 +34,8 @@
  */
 public final class MonitorCounterNode extends FloatingNode implements LIRGenLowerable {
 
-    public MonitorCounterNode() {
-        super(StampFactory.forWord());
+    private MonitorCounterNode() {
+        super(null);
     }
 
     @Override
@@ -47,6 +46,6 @@
         gen.setResult(this, result);
     }
 
-    @NodeIntrinsic
+    @NodeIntrinsic(setStampFromReturnType = true)
     public static native Word counter();
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ForeignCallStub.java	Wed Sep 18 02:41:52 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ForeignCallStub.java	Tue Sep 17 18:36:54 2013 -0700
@@ -237,9 +237,14 @@
             Debug.dump(builder.graph, "Initial stub graph");
         }
 
+        /* Rewrite all word types that can come in from the method argument types. */
+        new WordTypeRewriterPhase(runtime, wordKind()).apply(builder.graph);
+        /* Inline all method calls that are create above. */
         for (InvokeNode invoke : builder.graph.getNodes().filter(InvokeNode.class).snapshot()) {
             inline(invoke);
         }
+        /* Clean up all code that is now dead after inlining. */
+        new DeadCodeEliminationPhase().apply(builder.graph);
         assert builder.graph.getNodes().filter(InvokeNode.class).isEmpty();
 
         if (Debug.isDumpEnabled()) {
@@ -294,13 +299,9 @@
     }
 
     private void inline(InvokeNode invoke) {
-        StructuredGraph graph = invoke.graph();
         ResolvedJavaMethod method = ((MethodCallTargetNode) invoke.callTarget()).targetMethod();
         ReplacementsImpl repl = new ReplacementsImpl(runtime, new Assumptions(false), runtime.getTarget());
         StructuredGraph calleeGraph = repl.makeGraph(method, null, null);
         InliningUtil.inline(invoke, calleeGraph, false);
-        new NodeIntrinsificationPhase(runtime).apply(graph);
-        new WordTypeRewriterPhase(runtime, wordKind()).apply(graph);
-        new DeadCodeEliminationPhase().apply(graph);
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampFactory.java	Wed Sep 18 02:41:52 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampFactory.java	Tue Sep 17 18:36:54 2013 -0700
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.nodes.type;
 
-import com.oracle.graal.api.code.*;
-
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.type.GenericStamp.GenericStampType;
@@ -43,7 +41,6 @@
     private static final Stamp conditionStamp = new GenericStamp(GenericStampType.Condition);
     private static final Stamp voidStamp = new GenericStamp(GenericStampType.Void);
     private static final Stamp nodeIntrinsicStamp = new ObjectStamp(null, false, false, false);
-    private static final Stamp wordStamp = new ObjectStamp(null, false, false, false);
     private static final Stamp positiveInt = forInteger(Kind.Int, 0, Integer.MAX_VALUE, 0, Integer.MAX_VALUE);
 
     private static void setCache(Kind kind, Stamp stamp) {
@@ -85,14 +82,6 @@
         return nodeIntrinsicStamp;
     }
 
-    /**
-     * A stamp used only in the graph of intrinsics, e.g., snippets. It is then replaced by the
-     * actual primitive type stamp for the target-specific {@link TargetDescription#wordKind}.
-     */
-    public static Stamp forWord() {
-        return wordStamp;
-    }
-
     public static Stamp intValue() {
         return forKind(Kind.Int);
     }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java	Wed Sep 18 02:41:52 2013 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java	Tue Sep 17 18:36:54 2013 -0700
@@ -76,7 +76,6 @@
             assert Modifier.isStatic(target.getModifiers()) : "node intrinsic must be static: " + target;
 
             ResolvedJavaType[] parameterTypes = MetaUtil.resolveJavaTypes(MetaUtil.signatureToTypes(target), declaringClass);
-            ResolvedJavaType returnType = target.getSignature().getReturnType(declaringClass).resolve(declaringClass);
 
             // Prepare the arguments for the reflective constructor call on the node class.
             Constant[] nodeConstructorArguments = prepareArguments(methodCallTargetNode, parameterTypes, target, false);
@@ -86,7 +85,7 @@
 
             // Create the new node instance.
             ResolvedJavaType c = getNodeClass(target, intrinsic);
-            Node newInstance = createNodeInstance(c, parameterTypes, returnType, intrinsic.setStampFromReturnType(), nodeConstructorArguments);
+            Node newInstance = createNodeInstance(c, parameterTypes, methodCallTargetNode.invoke().asNode().stamp(), intrinsic.setStampFromReturnType(), nodeConstructorArguments);
 
             // Replace the invoke with the new node.
             newInstance = methodCallTargetNode.graph().addOrUnique(newInstance);
@@ -194,7 +193,7 @@
         return result;
     }
 
-    private Node createNodeInstance(ResolvedJavaType nodeClass, ResolvedJavaType[] parameterTypes, ResolvedJavaType returnType, boolean setStampFromReturnType, Constant[] nodeConstructorArguments) {
+    private Node createNodeInstance(ResolvedJavaType nodeClass, ResolvedJavaType[] parameterTypes, Stamp invokeStamp, boolean setStampFromReturnType, Constant[] nodeConstructorArguments) {
         ResolvedJavaMethod constructor = null;
         Constant[] arguments = null;
 
@@ -218,11 +217,7 @@
             ValueNode intrinsicNode = (ValueNode) constructor.newInstance(arguments).asObject();
 
             if (setStampFromReturnType) {
-                if (returnType.getKind() == Kind.Object) {
-                    intrinsicNode.setStamp(StampFactory.declared(returnType));
-                } else {
-                    intrinsicNode.setStamp(StampFactory.forKind(returnType.getKind()));
-                }
+                intrinsicNode.setStamp(invokeStamp);
             }
             return intrinsicNode;
         } catch (Exception e) {
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Wed Sep 18 02:41:52 2013 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Tue Sep 17 18:36:54 2013 -0700
@@ -161,7 +161,7 @@
 
     /**
      * Registers a method substitution.
-     *
+     * 
      * @param originalMember a method or constructor being substituted
      * @param substituteMethod the substitute method
      * @return the original method
@@ -182,7 +182,7 @@
 
     /**
      * Registers a macro substitution.
-     *
+     * 
      * @param originalMethod a method or constructor being substituted
      * @param macro the substitute macro node class
      * @return the original method
@@ -216,7 +216,7 @@
 
     /**
      * Creates a preprocessed graph for a snippet or method substitution.
-     *
+     * 
      * @param method the snippet or method substitution for which a graph will be created
      * @param original the original method if {@code method} is a {@linkplain MethodSubstitution
      *            substitution} otherwise null
@@ -325,13 +325,11 @@
 
                 @Override
                 public void run() {
-                    GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault();
-                    GraphBuilderPhase graphBuilder = new GraphBuilderPhase(runtime, config, OptimisticOptimizations.NONE);
-                    graphBuilder.apply(graph);
+                    new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getSnippetDefault(), OptimisticOptimizations.NONE).apply(graph);
+                    new WordTypeVerificationPhase(runtime, target.wordKind).apply(graph);
+                    new WordTypeRewriterPhase(runtime, target.wordKind).apply(graph);
 
-                    new WordTypeVerificationPhase(runtime, target.wordKind).apply(graph);
                     if (OptCanonicalizer.getValue()) {
-                        new WordTypeRewriterPhase(runtime, target.wordKind).apply(graph);
                         new CanonicalizerPhase(true).apply(graph, new PhaseContext(runtime, assumptions, ReplacementsImpl.this));
                     }
                 }
@@ -345,14 +343,13 @@
 
         /**
          * Called after a graph is inlined.
-         *
+         * 
          * @param caller the graph into which {@code callee} was inlined
          * @param callee the graph that was inlined into {@code caller}
          * @param beforeInlineData value returned by {@link #beforeInline}.
          */
         protected void afterInline(StructuredGraph caller, StructuredGraph callee, Object beforeInlineData) {
             if (OptCanonicalizer.getValue()) {
-                new WordTypeRewriterPhase(runtime, target.wordKind).apply(caller);
                 new CanonicalizerPhase(true).apply(caller, new PhaseContext(runtime, assumptions, ReplacementsImpl.this));
             }
         }
@@ -362,9 +359,6 @@
          */
         protected void afterInlining(StructuredGraph graph) {
             new NodeIntrinsificationPhase(runtime).apply(graph);
-
-            new WordTypeRewriterPhase(runtime, target.wordKind).apply(graph);
-
             new DeadCodeEliminationPhase().apply(graph);
             if (OptCanonicalizer.getValue()) {
                 new CanonicalizerPhase(true).apply(graph, new PhaseContext(runtime, assumptions, ReplacementsImpl.this));
@@ -383,6 +377,9 @@
                         if (callee == method) {
                             final StructuredGraph originalGraph = new StructuredGraph(original);
                             new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getSnippetDefault(), OptimisticOptimizations.NONE).apply(originalGraph);
+                            new WordTypeVerificationPhase(runtime, target.wordKind).apply(graph);
+                            new WordTypeRewriterPhase(runtime, target.wordKind).apply(graph);
+
                             InliningUtil.inline(callTarget.invoke(), originalGraph, true);
 
                             Debug.dump(graph, "after inlining %s", callee);
@@ -434,7 +431,7 @@
 
     /**
      * Resolves a name to a class.
-     *
+     * 
      * @param className the name of the class to resolve
      * @param optional if true, resolution failure returns null
      * @return the resolved class or null if resolution fails and {@code optional} is true
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Wed Sep 18 02:41:52 2013 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Tue Sep 17 18:36:54 2013 -0700
@@ -46,7 +46,6 @@
 import com.oracle.graal.replacements.Snippet.VarargsParameter;
 import com.oracle.graal.replacements.nodes.*;
 import com.oracle.graal.word.*;
-import com.oracle.graal.word.phases.*;
 
 /**
  * A snippet template is a graph created by parsing a snippet method and then specialized by binding
@@ -352,7 +351,7 @@
 
                         @Override
                         public SnippetTemplate call() throws Exception {
-                            return new SnippetTemplate(runtime, replacements, target, args);
+                            return new SnippetTemplate(runtime, replacements, args);
                         }
                     });
                     templates.put(args.cacheKey, template);
@@ -383,7 +382,7 @@
     /**
      * Creates a snippet template.
      */
-    protected SnippetTemplate(MetaAccessProvider runtime, Replacements replacements, TargetDescription target, Arguments args) {
+    protected SnippetTemplate(MetaAccessProvider runtime, Replacements replacements, Arguments args) {
         StructuredGraph snippetGraph = replacements.getSnippet(args.info.method);
 
         ResolvedJavaMethod method = snippetGraph.method();
@@ -426,8 +425,6 @@
         if (!nodeReplacements.isEmpty()) {
             // Do deferred intrinsification of node intrinsics
             new NodeIntrinsificationPhase(runtime).apply(snippetCopy);
-            new WordTypeRewriterPhase(runtime, target.wordKind).apply(snippetCopy);
-
             new CanonicalizerPhase(true).apply(snippetCopy, context);
         }
         NodeIntrinsificationVerificationPhase.verify(snippetCopy);
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java	Wed Sep 18 02:41:52 2013 +0200
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java	Tue Sep 17 18:36:54 2013 -0700
@@ -47,10 +47,10 @@
  */
 public class WordTypeRewriterPhase extends Phase {
 
-    private final MetaAccessProvider metaAccess;
-    private final ResolvedJavaType wordBaseType;
-    private final ResolvedJavaType wordImplType;
-    private final Kind wordKind;
+    protected final MetaAccessProvider metaAccess;
+    protected final ResolvedJavaType wordBaseType;
+    protected final ResolvedJavaType wordImplType;
+    protected final Kind wordKind;
 
     public WordTypeRewriterPhase(MetaAccessProvider metaAccess, Kind wordKind) {
         this.metaAccess = metaAccess;
@@ -59,198 +59,250 @@
         this.wordImplType = metaAccess.lookupJavaType(Word.class);
     }
 
-    public ResolvedJavaType getWordBaseType() {
-        return wordBaseType;
-    }
-
-    public ResolvedJavaType getWordImplType() {
-        return wordImplType;
-    }
-
     @Override
     protected void run(StructuredGraph graph) {
-        for (Node n : GraphOrder.forwardGraph(graph)) {
-            if (n instanceof ValueNode && !(n instanceof PhiNode && ((PhiNode) n).isLoopPhi())) {
-                ValueNode valueNode = (ValueNode) n;
-                if (isWord(valueNode)) {
-                    changeToWord(valueNode);
-                }
-            }
-        }
-        for (PhiNode phi : graph.getNodes(PhiNode.class)) {
-            if (phi.isLoopPhi() && isWord(phi)) {
-                changeToWord(phi);
-            }
-        }
-
-        // Remove casts between different word types (which by now no longer have kind Object)
-        for (CheckCastNode checkCastNode : graph.getNodes().filter(CheckCastNode.class).snapshot()) {
-            if (!checkCastNode.isDeleted() && checkCastNode.kind() == wordKind) {
-                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());
-            }
-        }
-
-        // Fold constant field reads (e.g. enum constants)
-        for (LoadFieldNode load : graph.getNodes(LoadFieldNode.class).snapshot()) {
-            ConstantNode constant = load.asConstant(metaAccess);
-            if (constant != null) {
-                graph.replaceFixedWithFloating(load, constant);
-            }
-        }
+        inferStamps(graph);
 
-        // Replace ObjectEqualsNodes with IntegerEqualsNodes where the values being compared are
-        // words
-        for (ObjectEqualsNode objectEqualsNode : graph.getNodes().filter(ObjectEqualsNode.class).snapshot()) {
-            ValueNode x = objectEqualsNode.x();
-            ValueNode y = objectEqualsNode.y();
-            if (x.kind() == wordKind || y.kind() == wordKind) {
-                assert x.kind() == wordKind;
-                assert y.kind() == wordKind;
-
-                // TODO Remove the whole iteration of ObjectEqualsNodes when we are sure that there
-                // is no more code where this triggers.
-                throw GraalInternalError.shouldNotReachHere("Comparison of words with == and != is no longer supported");
-            }
-        }
-
-        for (AccessIndexedNode node : graph.getNodes().filter(AccessIndexedNode.class).snapshot()) {
-            ValueNode array = node.array();
-            ResolvedJavaType arrayType = ObjectStamp.typeOrNull(array);
-            if (arrayType == null) {
-                // There are cases where the array does not have a known type yet. Assume it is not
-                // a word type.
-                continue;
-            }
-            assert arrayType.isArray();
-            if (isWord(arrayType.getComponentType())) {
-                /*
-                 * The elementKind of the node is a final field, and other information such as the
-                 * stamp depends on elementKind. Therefore, just create a new node and replace the
-                 * old one.
-                 */
-                if (node instanceof LoadIndexedNode) {
-                    graph.replaceFixedWithFixed(node, graph.add(new LoadIndexedNode(node.array(), node.index(), wordKind)));
-                } else if (node instanceof StoreIndexedNode) {
-                    graph.replaceFixedWithFixed(node, graph.add(new StoreIndexedNode(node.array(), node.index(), wordKind, ((StoreIndexedNode) node).value())));
-                } else {
-                    throw GraalInternalError.shouldNotReachHere();
-                }
+        for (Node n : graph.getNodes()) {
+            if (n instanceof ValueNode) {
+                changeToWord(graph, (ValueNode) n);
             }
         }
 
-        for (MethodCallTargetNode callTargetNode : graph.getNodes(MethodCallTargetNode.class).snapshot()) {
-            ResolvedJavaMethod targetMethod = callTargetNode.targetMethod();
-            if (!callTargetNode.isStatic() && (callTargetNode.receiver().kind() == wordKind || isWord(callTargetNode.receiver()))) {
-                targetMethod = getWordImplType().resolveMethod(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 : callTargetNode.targetMethod();
-
-                switch (operation.opcode()) {
-                    case NODE_CLASS:
-                        assert arguments.size() == 2;
-                        ValueNode left = arguments.get(0);
-                        ValueNode right = operation.rightOperandIsInt() ? toUnsigned(graph, arguments.get(1), Kind.Int) : fromSigned(graph, arguments.get(1));
-                        replace(invoke, nodeClassOp(graph, operation.node(), left, right, invoke));
-                        break;
-
-                    case COMPARISON:
-                        assert arguments.size() == 2;
-                        replace(invoke, comparisonOp(graph, operation.condition(), arguments.get(0), fromSigned(graph, arguments.get(1))));
-                        break;
+        for (Node node : graph.getNodes()) {
+            rewriteNode(graph, node);
+        }
+    }
 
-                    case NOT:
-                        assert arguments.size() == 1;
-                        replace(invoke, graph.unique(new XorNode(wordKind, arguments.get(0), ConstantNode.forIntegerKind(wordKind, -1, graph))));
-                        break;
-
-                    case READ: {
-                        assert arguments.size() == 2 || arguments.size() == 3;
-                        Kind readKind = asKind(callTargetNode.returnType());
-                        LocationNode location;
-                        if (arguments.size() == 2) {
-                            location = makeLocation(graph, arguments.get(1), readKind, ANY_LOCATION);
-                        } else {
-                            location = makeLocation(graph, arguments.get(1), readKind, arguments.get(2));
-                        }
-                        replace(invoke, readOp(graph, arguments.get(0), invoke, location, BarrierType.NONE, false));
-                        break;
-                    }
-                    case READ_HEAP: {
-                        assert arguments.size() == 4;
-                        Kind readKind = asKind(callTargetNode.returnType());
-                        LocationNode location = makeLocation(graph, arguments.get(1), readKind, ANY_LOCATION);
-                        BarrierType barrierType = (BarrierType) arguments.get(2).asConstant().asObject();
-                        replace(invoke, readOp(graph, arguments.get(0), invoke, location, barrierType, arguments.get(3).asConstant().asInt() == 0 ? false : true));
-                        break;
+    /**
+     * Infer the stamps for all Object nodes in the graph, to make the stamps as precise as
+     * possible. For example, this propagates the word-type through phi functions. To handle phi
+     * functions at loop headers, the stamp inference is called until a fix point is reached.
+     * <p>
+     * Note that we cannot rely on the normal canonicalizer to propagate stamps: The word type
+     * rewriting must run before the first run of the canonicalizer because many nodes are not
+     * prepared to see the word type during canonicalization.
+     */
+    protected void inferStamps(StructuredGraph graph) {
+        boolean stampChanged;
+        do {
+            stampChanged = false;
+            for (Node n : GraphOrder.forwardGraph(graph)) {
+                if (n instanceof ValueNode) {
+                    ValueNode node = (ValueNode) n;
+                    if (node.kind() == Kind.Object) {
+                        stampChanged |= node.inferStamp();
                     }
-                    case WRITE:
-                    case INITIALIZE: {
-                        assert arguments.size() == 3 || arguments.size() == 4;
-                        Kind writeKind = asKind(targetMethod.getSignature().getParameterType(1, targetMethod.getDeclaringClass()));
-                        LocationNode location;
-                        if (arguments.size() == 3) {
-                            location = makeLocation(graph, arguments.get(1), writeKind, LocationIdentity.ANY_LOCATION);
-                        } else {
-                            location = makeLocation(graph, arguments.get(1), writeKind, arguments.get(3));
-                        }
-                        replace(invoke, writeOp(graph, arguments.get(0), arguments.get(2), invoke, location, operation.opcode()));
-                        break;
-                    }
-                    case ZERO:
-                        assert arguments.size() == 0;
-                        replace(invoke, ConstantNode.forIntegerKind(wordKind, 0L, graph));
-                        break;
-
-                    case FROM_UNSIGNED:
-                        assert arguments.size() == 1;
-                        replace(invoke, fromUnsigned(graph, arguments.get(0)));
-                        break;
+                }
+            }
+        } while (stampChanged);
+    }
 
-                    case FROM_SIGNED:
-                        assert arguments.size() == 1;
-                        replace(invoke, fromSigned(graph, arguments.get(0)));
-                        break;
-
-                    case TO_RAW_VALUE:
-                        assert arguments.size() == 1;
-                        replace(invoke, toUnsigned(graph, arguments.get(0), Kind.Long));
-                        break;
+    /**
+     * Change the stamp for word nodes from the object stamp ({@link WordBase} or anything extending
+     * or implementing that interface) to the primitive word stamp.
+     */
+    protected void changeToWord(StructuredGraph graph, ValueNode node) {
+        if (isWord(node)) {
+            if (node.isConstant()) {
+                ConstantNode oldConstant = (ConstantNode) node;
+                assert oldConstant.value.getKind() == Kind.Object;
+                WordBase value = (WordBase) oldConstant.value.asObject();
+                ConstantNode newConstant = ConstantNode.forIntegerKind(wordKind, value.rawValue(), node.graph());
+                graph.replaceFloating(oldConstant, newConstant);
 
-                    case FROM_OBJECT:
-                        assert arguments.size() == 1;
-                        replace(invoke, graph.unique(new UnsafeCastNode(arguments.get(0), StampFactory.forKind(wordKind))));
-                        break;
-
-                    case FROM_ARRAY:
-                        assert arguments.size() == 2;
-                        replace(invoke, graph.unique(new ComputeAddressNode(arguments.get(0), arguments.get(1), StampFactory.forKind(wordKind))));
-                        break;
-
-                    case TO_OBJECT:
-                        assert arguments.size() == 1;
-                        replace(invoke, graph.unique(new UnsafeCastNode(arguments.get(0), invoke.asNode().stamp())));
-                        break;
-
-                    default:
-                        throw new GraalInternalError("Unknown opcode: %s", operation.opcode());
-                }
+            } else {
+                node.setStamp(StampFactory.forKind(wordKind));
             }
         }
     }
 
-    private ValueNode fromUnsigned(StructuredGraph graph, ValueNode value) {
+    /**
+     * Clean up nodes that are no longer necessary or valid after the stamp change, and perform
+     * intrinsification of all methods called on word types.
+     */
+    protected void rewriteNode(StructuredGraph graph, Node node) {
+        if (node instanceof CheckCastNode) {
+            rewriteCheckCast(graph, (CheckCastNode) node);
+        } else if (node instanceof UnsafeCastNode) {
+            rewriteUnsafeCast(graph, (UnsafeCastNode) node);
+        } else if (node instanceof LoadFieldNode) {
+            rewriteLoadField(graph, (LoadFieldNode) node);
+        } else if (node instanceof AccessIndexedNode) {
+            rewriteAccessIndexed(graph, (AccessIndexedNode) node);
+        } else if (node instanceof MethodCallTargetNode) {
+            rewriteInvoke(graph, (MethodCallTargetNode) node);
+        }
+    }
+
+    /**
+     * Remove casts between word types (which by now no longer have kind Object).
+     */
+    protected void rewriteCheckCast(StructuredGraph graph, CheckCastNode node) {
+        if (node.kind() == wordKind) {
+            node.replaceAtUsages(node.object());
+            graph.removeFixed(node);
+        }
+    }
+
+    /**
+     * Remove unnecessary/redundant unsafe casts.
+     */
+    protected void rewriteUnsafeCast(StructuredGraph graph, UnsafeCastNode node) {
+        if (node.object().stamp() == node.stamp()) {
+            node.replaceAtUsages(node.object());
+            graph.removeFloating(node);
+        }
+    }
+
+    /**
+     * Fold constant field reads, e.g. enum constants.
+     */
+    protected void rewriteLoadField(StructuredGraph graph, LoadFieldNode node) {
+        ConstantNode constant = node.asConstant(metaAccess);
+        if (constant != null) {
+            node.replaceAtUsages(constant);
+            graph.removeFixed(node);
+        }
+    }
+
+    /**
+     * Change loads and stores of word-arrays. Since the element kind is managed by the node on its
+     * own and not in the stamp, {@link #changeToWord} does not perform all necessary changes.
+     */
+    protected void rewriteAccessIndexed(StructuredGraph graph, AccessIndexedNode node) {
+        ResolvedJavaType arrayType = ObjectStamp.typeOrNull(node.array());
+        /*
+         * There are cases where the array does not have a known type yet, i.e., the type is null.
+         * In that case we assume it is not a word type.
+         */
+        if (arrayType != null && isWord(arrayType.getComponentType()) && node.elementKind() != wordKind) {
+            /*
+             * The elementKind of the node is a final field, and other information such as the stamp
+             * depends on elementKind. Therefore, just create a new node and replace the old one.
+             */
+            if (node instanceof LoadIndexedNode) {
+                graph.replaceFixedWithFixed(node, graph.add(new LoadIndexedNode(node.array(), node.index(), wordKind)));
+            } else if (node instanceof StoreIndexedNode) {
+                graph.replaceFixedWithFixed(node, graph.add(new StoreIndexedNode(node.array(), node.index(), wordKind, ((StoreIndexedNode) node).value())));
+            } else {
+                throw GraalInternalError.shouldNotReachHere();
+            }
+        }
+    }
+
+    /**
+     * Intrinsification of methods defined on the {@link Word} class that are annotated with
+     * {@link Operation}.
+     */
+    protected void rewriteInvoke(StructuredGraph graph, MethodCallTargetNode callTargetNode) {
+        ResolvedJavaMethod targetMethod = callTargetNode.targetMethod();
+        if (!callTargetNode.isStatic() && (callTargetNode.receiver().kind() == wordKind || isWord(callTargetNode.receiver()))) {
+            targetMethod = wordImplType.resolveMethod(targetMethod);
+        }
+        Operation operation = targetMethod.getAnnotation(Word.Operation.class);
+        if (operation != null) {
+            NodeInputList<ValueNode> arguments = callTargetNode.arguments();
+            Invoke invoke = callTargetNode.invoke();
+
+            switch (operation.opcode()) {
+                case NODE_CLASS:
+                    assert arguments.size() == 2;
+                    ValueNode left = arguments.get(0);
+                    ValueNode right = operation.rightOperandIsInt() ? toUnsigned(graph, arguments.get(1), Kind.Int) : fromSigned(graph, arguments.get(1));
+
+                    ValueNode replacement = graph.addOrUnique(createBinaryNodeInstance(operation.node(), wordKind, left, right));
+                    if (replacement instanceof FixedWithNextNode) {
+                        graph.addBeforeFixed(invoke.asNode(), (FixedWithNextNode) replacement);
+                    }
+                    replace(invoke, replacement);
+                    break;
+
+                case COMPARISON:
+                    assert arguments.size() == 2;
+                    replace(invoke, comparisonOp(graph, operation.condition(), arguments.get(0), fromSigned(graph, arguments.get(1))));
+                    break;
+
+                case NOT:
+                    assert arguments.size() == 1;
+                    replace(invoke, graph.unique(new XorNode(wordKind, arguments.get(0), ConstantNode.forIntegerKind(wordKind, -1, graph))));
+                    break;
+
+                case READ: {
+                    assert arguments.size() == 2 || arguments.size() == 3;
+                    Kind readKind = asKind(callTargetNode.returnType());
+                    LocationNode location;
+                    if (arguments.size() == 2) {
+                        location = makeLocation(graph, arguments.get(1), readKind, ANY_LOCATION);
+                    } else {
+                        location = makeLocation(graph, arguments.get(1), readKind, arguments.get(2));
+                    }
+                    replace(invoke, readOp(graph, arguments.get(0), invoke, location, BarrierType.NONE, false));
+                    break;
+                }
+                case READ_HEAP: {
+                    assert arguments.size() == 4;
+                    Kind readKind = asKind(callTargetNode.returnType());
+                    LocationNode location = makeLocation(graph, arguments.get(1), readKind, ANY_LOCATION);
+                    BarrierType barrierType = (BarrierType) arguments.get(2).asConstant().asObject();
+                    replace(invoke, readOp(graph, arguments.get(0), invoke, location, barrierType, arguments.get(3).asConstant().asInt() == 0 ? false : true));
+                    break;
+                }
+                case WRITE:
+                case INITIALIZE: {
+                    assert arguments.size() == 3 || arguments.size() == 4;
+                    Kind writeKind = asKind(targetMethod.getSignature().getParameterType(1, targetMethod.getDeclaringClass()));
+                    LocationNode location;
+                    if (arguments.size() == 3) {
+                        location = makeLocation(graph, arguments.get(1), writeKind, LocationIdentity.ANY_LOCATION);
+                    } else {
+                        location = makeLocation(graph, arguments.get(1), writeKind, arguments.get(3));
+                    }
+                    replace(invoke, writeOp(graph, arguments.get(0), arguments.get(2), invoke, location, operation.opcode()));
+                    break;
+                }
+                case ZERO:
+                    assert arguments.size() == 0;
+                    replace(invoke, ConstantNode.forIntegerKind(wordKind, 0L, graph));
+                    break;
+
+                case FROM_UNSIGNED:
+                    assert arguments.size() == 1;
+                    replace(invoke, fromUnsigned(graph, arguments.get(0)));
+                    break;
+
+                case FROM_SIGNED:
+                    assert arguments.size() == 1;
+                    replace(invoke, fromSigned(graph, arguments.get(0)));
+                    break;
+
+                case TO_RAW_VALUE:
+                    assert arguments.size() == 1;
+                    replace(invoke, toUnsigned(graph, arguments.get(0), Kind.Long));
+                    break;
+
+                case FROM_OBJECT:
+                    assert arguments.size() == 1;
+                    replace(invoke, graph.unique(new UnsafeCastNode(arguments.get(0), StampFactory.forKind(wordKind))));
+                    break;
+
+                case FROM_ARRAY:
+                    assert arguments.size() == 2;
+                    replace(invoke, graph.unique(new ComputeAddressNode(arguments.get(0), arguments.get(1), StampFactory.forKind(wordKind))));
+                    break;
+
+                case TO_OBJECT:
+                    assert arguments.size() == 1;
+                    replace(invoke, graph.unique(new UnsafeCastNode(arguments.get(0), invoke.asNode().stamp())));
+                    break;
+
+                default:
+                    throw new GraalInternalError("Unknown opcode: %s", operation.opcode());
+            }
+        }
+    }
+
+    protected ValueNode fromUnsigned(StructuredGraph graph, ValueNode value) {
         return convert(graph, value, wordKind, ConvertNode.Op.L2I, ConvertNode.Op.UNSIGNED_I2L);
     }
 
@@ -258,7 +310,7 @@
         return convert(graph, value, wordKind, ConvertNode.Op.L2I, ConvertNode.Op.I2L);
     }
 
-    private static ValueNode toUnsigned(StructuredGraph graph, ValueNode value, Kind toKind) {
+    protected ValueNode toUnsigned(StructuredGraph graph, ValueNode value, Kind toKind) {
         return convert(graph, value, toKind, ConvertNode.Op.L2I, ConvertNode.Op.UNSIGNED_I2L);
     }
 
@@ -279,14 +331,15 @@
         }
     }
 
-    private ValueNode nodeClassOp(StructuredGraph graph, Class<? extends ValueNode> nodeClass, ValueNode left, ValueNode right, Invoke invoke) {
+    /**
+     * Create an instance of a binary node which is used to lower Word operations. This method is
+     * called for all Word operations which are annotated with @Operation(node = ...) and
+     * encapsulates the reflective allocation of the node.
+     */
+    private static ValueNode createBinaryNodeInstance(Class<? extends ValueNode> nodeClass, Kind kind, ValueNode left, ValueNode right) {
         try {
             Constructor<? extends ValueNode> constructor = nodeClass.getConstructor(Kind.class, ValueNode.class, ValueNode.class);
-            ValueNode result = graph.addOrUnique(constructor.newInstance(wordKind, left, right));
-            if (result instanceof FixedWithNextNode) {
-                graph.addBeforeFixed(invoke.asNode(), (FixedWithNextNode) result);
-            }
-            return result;
+            return constructor.newInstance(kind, left, right);
         } catch (Throwable ex) {
             throw new GraalInternalError(ex).addContext(nodeClass.getName());
         }
@@ -329,20 +382,22 @@
         return SnippetLocationNode.create(locationIdentity, ConstantNode.forObject(readKind, metaAccess, graph), ConstantNode.forLong(0, graph), offset, ConstantNode.forInt(1, graph), graph);
     }
 
-    private static LocationNode makeLocation(StructuredGraph graph, ValueNode offset, Kind readKind, LocationIdentity locationIdentity) {
+    protected LocationNode makeLocation(StructuredGraph graph, ValueNode offset, Kind readKind, LocationIdentity locationIdentity) {
         return IndexedLocationNode.create(locationIdentity, readKind, 0, offset, graph, 1);
     }
 
-    private static ValueNode readOp(StructuredGraph graph, ValueNode base, Invoke invoke, LocationNode location, BarrierType barrierType, boolean compressible) {
+    protected ValueNode readOp(StructuredGraph graph, ValueNode base, Invoke invoke, LocationNode location, BarrierType barrierType, boolean compressible) {
         ReadNode read = graph.add(new ReadNode(base, location, invoke.asNode().stamp(), barrierType, compressible));
         graph.addBeforeFixed(invoke.asNode(), read);
-        // The read must not float outside its block otherwise it may float above an explicit zero
-        // check on its base address
+        /*
+         * The read must not float outside its block otherwise it may float above an explicit zero
+         * check on its base address.
+         */
         read.setGuard(AbstractBeginNode.prevBegin(invoke.asNode()));
         return read;
     }
 
-    private static ValueNode writeOp(StructuredGraph graph, ValueNode base, ValueNode value, Invoke invoke, LocationNode location, Opcode op) {
+    protected ValueNode writeOp(StructuredGraph graph, ValueNode base, ValueNode value, Invoke invoke, LocationNode location, Opcode op) {
         assert op == Opcode.WRITE || op == Opcode.INITIALIZE;
         WriteNode write = graph.add(new WriteNode(base, value, location, BarrierType.NONE, false, op == Opcode.INITIALIZE));
         write.setStateAfter(invoke.stateAfter());
@@ -350,7 +405,7 @@
         return write;
     }
 
-    private static void replace(Invoke invoke, ValueNode value) {
+    protected void replace(Invoke invoke, ValueNode value) {
         FixedNode next = invoke.next();
         invoke.setNext(null);
         invoke.asNode().replaceAtPredecessor(next);
@@ -358,52 +413,19 @@
         GraphUtil.killCFG(invoke.asNode());
     }
 
-    public boolean isWord(ValueNode node) {
-        /*
-         * If we already know that we have a word type, we do not need to infer the stamp. This
-         * avoids exceptions in inferStamp when the inputs have already been rewritten to word,
-         * i.e., when the expected input is no longer an object.
-         */
-        if (isWord0(node)) {
-            return true;
-        }
-        node.inferStamp();
-        return isWord0(node);
-    }
-
-    private boolean isWord0(ValueNode node) {
-        if (node.stamp() == StampFactory.forWord()) {
-            return true;
-        }
-        if (node.stamp() instanceof ObjectStamp) {
-            return isWord(((ObjectStamp) node.stamp()).type());
-        }
-        return false;
+    protected boolean isWord(ValueNode node) {
+        return isWord(ObjectStamp.typeOrNull(node));
     }
 
-    public boolean isWord(ResolvedJavaType type) {
-        if (type != null && wordBaseType.isAssignableFrom(type)) {
-            return true;
-        }
-        return false;
+    protected boolean isWord(ResolvedJavaType type) {
+        return type != null && wordBaseType.isAssignableFrom(type);
     }
 
-    public Kind asKind(JavaType type) {
-        if (type instanceof ResolvedJavaType) {
-            return isWord((ResolvedJavaType) type) ? wordKind : type.getKind();
+    protected Kind asKind(JavaType type) {
+        if (type instanceof ResolvedJavaType && isWord((ResolvedJavaType) type)) {
+            return wordKind;
         } else {
-            return Kind.Object;
-        }
-    }
-
-    private void changeToWord(ValueNode valueNode) {
-        if (valueNode.isConstant() && valueNode.asConstant().getKind() == Kind.Object) {
-            WordBase value = (WordBase) valueNode.asConstant().asObject();
-            ConstantNode newConstant = ConstantNode.forIntegerKind(wordKind, value.rawValue(), valueNode.graph());
-            valueNode.graph().replaceFloating((ConstantNode) valueNode, newConstant);
-        } else {
-            assert !(valueNode instanceof ConstantNode) : "boxed Word constants should not appear in a snippet graph: " + valueNode + ", stamp: " + valueNode.stamp();
-            valueNode.setStamp(StampFactory.forKind(wordKind));
+            return type.getKind();
         }
     }
 }
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeVerificationPhase.java	Wed Sep 18 02:41:52 2013 +0200
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeVerificationPhase.java	Tue Sep 17 18:36:54 2013 -0700
@@ -36,8 +36,8 @@
 import com.oracle.graal.word.Word.Operation;
 
 /**
- * Verifies invariants that must hold for snippet code above and beyond normal bytecode
- * verification.
+ * Verifies invariants that must hold for code that uses the {@link WordBase word type} above and
+ * beyond normal bytecode verification.
  */
 public class WordTypeVerificationPhase extends Phase {
 
@@ -49,6 +49,17 @@
 
     @Override
     protected void run(StructuredGraph graph) {
+        assert verify(graph);
+    }
+
+    protected boolean verify(StructuredGraph inputGraph) {
+        /*
+         * This is a verification phase, so we do not want to have side effects. Since inferStamps()
+         * modifies the stamp of nodes, we copy the graph before running the verification.
+         */
+        StructuredGraph graph = inputGraph.copy();
+        wordAccess.inferStamps(graph);
+
         for (ValueNode node : graph.getNodes().filter(ValueNode.class)) {
             for (Node usage : node.usages()) {
                 if (usage instanceof AccessMonitorNode) {
@@ -70,32 +81,7 @@
                     verify(!isWord(node) || ((StoreIndexedNode) usage).value() != node, node, usage, "cannot store word value to array");
                 } else if (usage instanceof MethodCallTargetNode) {
                     MethodCallTargetNode callTarget = (MethodCallTargetNode) usage;
-                    ResolvedJavaMethod method = callTarget.targetMethod();
-                    if (method.getAnnotation(NodeIntrinsic.class) == null) {
-                        Invoke invoke = (Invoke) callTarget.usages().first();
-                        NodeInputList<ValueNode> arguments = callTarget.arguments();
-                        boolean isStatic = Modifier.isStatic(method.getModifiers());
-                        int argc = 0;
-                        if (!isStatic) {
-                            ValueNode receiver = arguments.get(argc);
-                            if (receiver == node && isWord(node)) {
-                                ResolvedJavaMethod resolvedMethod = wordAccess.getWordImplType().resolveMethod(method);
-                                verify(resolvedMethod != null, node, invoke.asNode(), "cannot resolve method on Word class: " + MetaUtil.format("%H.%n(%P) %r", method));
-                                Operation operation = resolvedMethod.getAnnotation(Word.Operation.class);
-                                verify(operation != null, node, invoke.asNode(), "cannot dispatch on word value to non @Operation annotated method " + resolvedMethod);
-                            }
-                            argc++;
-                        }
-                        Signature signature = method.getSignature();
-                        for (int i = 0; i < signature.getParameterCount(false); i++) {
-                            ValueNode argument = arguments.get(argc);
-                            if (argument == node) {
-                                ResolvedJavaType type = (ResolvedJavaType) signature.getParameterType(i, method.getDeclaringClass());
-                                verify(isWord(type) == isWord(argument), node, invoke.asNode(), "cannot pass word value to non-word parameter " + i + " or vice-versa");
-                            }
-                            argc++;
-                        }
-                    }
+                    verifyInvoke(node, callTarget);
                 } else if (usage instanceof ObjectEqualsNode) {
                     verify(!isWord(node) || ((ObjectEqualsNode) usage).x() != node, node, usage, "cannot use word type in comparison");
                     verify(!isWord(node) || ((ObjectEqualsNode) usage).y() != node, node, usage, "cannot use word type in comparison");
@@ -111,19 +97,39 @@
                 }
             }
         }
+        return true;
+    }
+
+    protected void verifyInvoke(ValueNode node, MethodCallTargetNode callTarget) {
+        ResolvedJavaMethod method = callTarget.targetMethod();
+        if (method.getAnnotation(NodeIntrinsic.class) == null) {
+            Invoke invoke = (Invoke) callTarget.usages().first();
+            NodeInputList<ValueNode> arguments = callTarget.arguments();
+            boolean isStatic = Modifier.isStatic(method.getModifiers());
+            int argc = 0;
+            if (!isStatic) {
+                ValueNode receiver = arguments.get(argc);
+                if (receiver == node && isWord(node)) {
+                    ResolvedJavaMethod resolvedMethod = wordAccess.wordImplType.resolveMethod(method);
+                    verify(resolvedMethod != null, node, invoke.asNode(), "cannot resolve method on Word class: " + MetaUtil.format("%H.%n(%P) %r", method));
+                    Operation operation = resolvedMethod.getAnnotation(Word.Operation.class);
+                    verify(operation != null, node, invoke.asNode(), "cannot dispatch on word value to non @Operation annotated method " + resolvedMethod);
+                }
+                argc++;
+            }
+            Signature signature = method.getSignature();
+            for (int i = 0; i < signature.getParameterCount(false); i++) {
+                ValueNode argument = arguments.get(argc);
+                if (argument == node) {
+                    ResolvedJavaType type = (ResolvedJavaType) signature.getParameterType(i, method.getDeclaringClass());
+                    verify(isWord(type) == isWord(argument), node, invoke.asNode(), "cannot pass word value to non-word parameter " + i + " or vice-versa");
+                }
+                argc++;
+            }
+        }
     }
 
     private boolean isWord(ValueNode node) {
-        if (node instanceof ProxyNode) {
-            /*
-             * The proxy node will eventually get the same stamp as the value it is proxying.
-             * However, since we cannot guarantee the order in which isWord is called during the
-             * verification phase, the stamp assignment for the value might not have happened yet.
-             * Therefore, we check the proxied value directly instead of the proxy.
-             */
-            return isWord(((ProxyNode) node).value());
-        }
-
         return wordAccess.isWord(node);
     }