changeset 16084:b37dbfdfbbfb

assertion mechanism for snippets and stubs
author Lukas Stadler <lukas.stadler@oracle.com>
date Tue, 10 Jun 2014 12:11:48 +0200
parents 640a875667fe
children 0cdce0e2d122 0bd92901891c
files graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/replacements/HSAILNewObjectSnippets.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AssertionSnippets.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsUtil.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/AssertionNode.java
diffstat 8 files changed, 258 insertions(+), 12 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/replacements/HSAILNewObjectSnippets.java	Wed Jun 11 11:17:30 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/replacements/HSAILNewObjectSnippets.java	Tue Jun 10 12:11:48 2014 +0200
@@ -161,7 +161,7 @@
 
     protected static Object addressToFormattedObject(Word addr, @ConstantParameter int size, Word hub, Word prototypeMarkWord, @ConstantParameter boolean fillContents,
                     @ConstantParameter String typeContext) {
-        Object result = formatObject(hub, size, addr, prototypeMarkWord, fillContents, true, false, true);
+        Object result = formatObject(hub, size, addr, prototypeMarkWord, fillContents, true, true);
         profileAllocation("instance", size, typeContext);
         return piCast(verifyOop(result), StampFactory.forNodeIntrinsic());
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java	Wed Jun 11 11:17:30 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java	Tue Jun 10 12:11:48 2014 +0200
@@ -49,6 +49,7 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.replacements.*;
+import com.oracle.graal.replacements.nodes.*;
 
 /**
  * HotSpot implementation of {@link LoweringProvider}.
@@ -66,6 +67,7 @@
     protected WriteBarrierSnippets.Templates writeBarrierSnippets;
     protected LoadExceptionObjectSnippets.Templates exceptionObjectSnippets;
     protected UnsafeLoadSnippets.Templates unsafeLoadSnippets;
+    protected AssertionSnippets.Templates assertionSnippets;
 
     public DefaultHotSpotLoweringProvider(HotSpotGraalRuntime runtime, MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls, HotSpotRegistersProvider registers, TargetDescription target) {
         super(metaAccess, target);
@@ -85,6 +87,7 @@
         writeBarrierSnippets = new WriteBarrierSnippets.Templates(providers, target, config.useCompressedOops ? config.getOopEncoding() : null);
         exceptionObjectSnippets = new LoadExceptionObjectSnippets.Templates(providers, target);
         unsafeLoadSnippets = new UnsafeLoadSnippets.Templates(providers, target);
+        assertionSnippets = new AssertionSnippets.Templates(providers, target);
         providers.getReplacements().registerSnippetTemplateCache(new UnsafeArrayCopySnippets.Templates(providers, target));
     }
 
@@ -158,6 +161,8 @@
             }
         } else if (n instanceof LoadExceptionObjectNode) {
             exceptionObjectSnippets.lower((LoadExceptionObjectNode) n, registers, tool);
+        } else if (n instanceof AssertionNode) {
+            assertionSnippets.lower((AssertionNode) n, tool);
         } else if (n instanceof IntegerDivNode || n instanceof IntegerRemNode || n instanceof UnsignedDivNode || n instanceof UnsignedRemNode) {
             // Nothing to do for division nodes. The HotSpot signal handler catches divisions by
             // zero and the MIN_VALUE / -1 cases.
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java	Wed Jun 11 11:17:30 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java	Tue Jun 10 12:11:48 2014 +0200
@@ -28,6 +28,7 @@
 import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.RegisterEffect.*;
 import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.Transition.*;
 import static com.oracle.graal.hotspot.meta.DefaultHotSpotLoweringProvider.RuntimeCalls.*;
+import static com.oracle.graal.hotspot.replacements.AssertionSnippets.*;
 import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
 import static com.oracle.graal.hotspot.replacements.MonitorSnippets.*;
 import static com.oracle.graal.hotspot.replacements.NewObjectSnippets.*;
@@ -136,6 +137,7 @@
         registerForeignCall(UNPACK_FRAMES, c.deoptimizationUnpackFrames, NativeCall, DESTROYS_REGISTERS, LEAF, NOT_REEXECUTABLE, ANY_LOCATION);
 
         registerForeignCall(VM_MESSAGE_C, c.vmMessageAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, NO_LOCATIONS);
+        registerForeignCall(ASSERTION_VM_MESSAGE_C, c.vmMessageAddress, NativeCall, PRESERVES_REGISTERS, LEAF, REEXECUTABLE, NO_LOCATIONS);
 
         link(new NewInstanceStub(providers, target, registerStubCall(NEW_INSTANCE, REEXECUTABLE, NOT_LEAF, ANY_LOCATION)));
         link(new NewArrayStub(providers, target, registerStubCall(NEW_ARRAY, REEXECUTABLE, NOT_LEAF, INIT_LOCATION)));
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AssertionSnippets.java	Tue Jun 10 12:11:48 2014 +0200
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2014, 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.replacements;
+
+import static com.oracle.graal.hotspot.nodes.CStringNode.*;
+import static com.oracle.graal.replacements.SnippetTemplate.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.Node.ConstantNodeParameter;
+import com.oracle.graal.graph.Node.NodeIntrinsic;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.replacements.*;
+import com.oracle.graal.replacements.Snippet.ConstantParameter;
+import com.oracle.graal.replacements.SnippetTemplate.AbstractTemplates;
+import com.oracle.graal.replacements.SnippetTemplate.Arguments;
+import com.oracle.graal.replacements.SnippetTemplate.SnippetInfo;
+import com.oracle.graal.replacements.nodes.*;
+import com.oracle.graal.word.*;
+
+public class AssertionSnippets implements Snippets {
+
+    /**
+     * This call can only be used with true for the "vmError" parameter, so that it can be
+     * configured to be a leaf method.
+     */
+    public static final ForeignCallDescriptor ASSERTION_VM_MESSAGE_C = new ForeignCallDescriptor("assertionVmMessageC", void.class, boolean.class, Word.class, long.class, long.class, long.class);
+
+    @Snippet
+    public static void assertion(boolean value, @ConstantParameter String message) {
+        if (!value) {
+            vmMessageC(ASSERTION_VM_MESSAGE_C, true, cstring(message), 0L, 0L, 0L);
+        }
+    }
+
+    @Snippet
+    public static void stubAssertion(boolean value, @ConstantParameter String message) {
+        if (!value) {
+            vmMessageC(ASSERTION_VM_MESSAGE_C, true, cstring(message), 0L, 0L, 0L);
+        }
+    }
+
+    @NodeIntrinsic(ForeignCallNode.class)
+    private static native void vmMessageC(@ConstantNodeParameter ForeignCallDescriptor stubPrintfC, boolean vmError, Word format, long v1, long v2, long v3);
+
+    @NodeIntrinsic(StubForeignCallNode.class)
+    private static native void stubVmMessageC(@ConstantNodeParameter ForeignCallDescriptor stubPrintfC, boolean vmError, Word format, long v1, long v2, long v3);
+
+    public static class Templates extends AbstractTemplates {
+
+        private final SnippetInfo assertion = snippet(AssertionSnippets.class, "assertion");
+        private final SnippetInfo stubAssertion = snippet(AssertionSnippets.class, "stubAssertion");
+
+        public Templates(HotSpotProviders providers, TargetDescription target) {
+            super(providers, providers.getSnippetReflection(), target);
+        }
+
+        public void lower(AssertionNode assertionNode, LoweringTool tool) {
+            StructuredGraph graph = assertionNode.graph();
+            Arguments args = new Arguments(graph.start() instanceof StubStartNode ? stubAssertion : assertion, graph.getGuardsStage(), tool.getLoweringStage());
+            args.add("value", assertionNode.value());
+            args.addConst("message", "failed runtime assertion in snippet/stub: " + assertionNode.message() + " (" + graph.method() + ")");
+
+            template(args).instantiate(providers.getMetaAccess(), assertionNode, DEFAULT_REPLACER, args);
+        }
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java	Wed Jun 11 11:17:30 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java	Tue Jun 10 12:11:48 2014 +0200
@@ -35,6 +35,7 @@
 import com.oracle.graal.graph.Node.NodeIntrinsic;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.replacements.*;
 import com.oracle.graal.replacements.Snippet.Fold;
 import com.oracle.graal.replacements.nodes.*;
 import com.oracle.graal.word.*;
@@ -539,7 +540,7 @@
     private static native Object verifyOopStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Object object);
 
     public static Word loadWordFromObject(Object object, int offset) {
-        assert offset != hubOffset() : "Use loadHubIntrinsic instead";
+        ReplacementsUtil.staticAssert(offset != hubOffset(), "Use loadHubIntrinsic instead of loadWordFromObject");
         return loadWordFromObjectIntrinsic(object, offset, getWordKind(), LocationIdentity.ANY_LOCATION);
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java	Wed Jun 11 11:17:30 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java	Tue Jun 10 12:11:48 2014 +0200
@@ -141,7 +141,7 @@
         if (useTLAB() && probability(FAST_PATH_PROBABILITY, newTop.belowOrEqual(end))) {
             writeTlabTop(thread, newTop);
             emitPrefetchAllocate(newTop, false);
-            result = formatObject(hub, size, top, prototypeMarkWord, fillContents, constantSize, false, true);
+            result = formatObject(hub, size, top, prototypeMarkWord, fillContents, constantSize, true);
         } else {
             new_stub.inc();
             result = NewInstanceStubCall.call(hub);
@@ -290,16 +290,16 @@
      * @param startOffset offset to begin zeroing. May not be word aligned.
      * @param manualUnroll maximally unroll zeroing
      */
-    private static void zeroMemory(int size, Word memory, boolean constantSize, int startOffset, boolean manualUnroll, boolean noAsserts, boolean useSnippetCounters) {
-        assert noAsserts || size % 8 == 0 : "unaligned object size";
+    private static void zeroMemory(int size, Word memory, boolean constantSize, int startOffset, boolean manualUnroll, boolean useSnippetCounters) {
+        ReplacementsUtil.runtimeAssert((size & 0x7) == 0, "unaligned object size");
         int offset = startOffset;
-        if (offset % 8 != 0) {
+        if ((offset & 0x7) != 0) {
             memory.writeInt(offset, 0, INIT_LOCATION);
             offset += 4;
         }
-        assert noAsserts || offset % 8 == 0 : "unaligned";
+        ReplacementsUtil.runtimeAssert((offset & 0x7) == 0, "unaligned offset");
         if (manualUnroll && ((size - offset) / 8) <= MAX_UNROLLED_OBJECT_ZEROING_STORES) {
-            assert noAsserts || !constantSize : "size shouldn't be constant at instantiation time";
+            ReplacementsUtil.staticAssert(!constantSize, "size shouldn't be constant at instantiation time");
             // This case handles arrays of constant length. Instead of having a snippet variant for
             // each length, generate a chain of stores of maximum length. Once it's inlined the
             // break statement will trim excess stores.
@@ -337,17 +337,17 @@
      * since they can't be compiled in stubs.
      */
     public static Object formatObjectForStub(Word hub, int size, Word memory, Word compileTimePrototypeMarkWord) {
-        return formatObject(hub, size, memory, compileTimePrototypeMarkWord, true, false, true, false);
+        return formatObject(hub, size, memory, compileTimePrototypeMarkWord, true, false, false);
     }
 
     /**
      * Formats some allocated memory with an object header and zeroes out the rest.
      */
-    protected static Object formatObject(Word hub, int size, Word memory, Word compileTimePrototypeMarkWord, boolean fillContents, boolean constantSize, boolean noAsserts, boolean useSnippetCounters) {
+    protected static Object formatObject(Word hub, int size, Word memory, Word compileTimePrototypeMarkWord, boolean fillContents, boolean constantSize, boolean useSnippetCounters) {
         Word prototypeMarkWord = useBiasedLocking() ? hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION) : compileTimePrototypeMarkWord;
         initializeObjectHeader(memory, prototypeMarkWord, hub);
         if (fillContents) {
-            zeroMemory(size, memory, constantSize, instanceHeaderSize(), false, noAsserts, useSnippetCounters);
+            zeroMemory(size, memory, constantSize, instanceHeaderSize(), false, useSnippetCounters);
         }
         return memory.toObject();
     }
@@ -364,7 +364,7 @@
          */
         initializeObjectHeader(memory, prototypeMarkWord, hub);
         if (fillContents) {
-            zeroMemory(allocationSize, memory, false, headerSize, maybeUnroll, true, useSnippetCounters);
+            zeroMemory(allocationSize, memory, false, headerSize, maybeUnroll, useSnippetCounters);
         }
         return memory.toObject();
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsUtil.java	Tue Jun 10 12:11:48 2014 +0200
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2014, 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.replacements;
+
+import com.oracle.graal.replacements.nodes.*;
+
+public class ReplacementsUtil {
+    private ReplacementsUtil() {
+        // empty
+    }
+
+    private static final boolean REPLACEMENTS_ASSERTIONS_ENABLED;
+
+    static {
+        boolean assertionsEnabled = false;
+        assert (assertionsEnabled = true) != false;
+        REPLACEMENTS_ASSERTIONS_ENABLED = assertionsEnabled;
+    }
+
+    /**
+     * Asserts that condition evaluates to true by the time compilation is finished. This is
+     * intended to be used within snippets or stubs, and will lead to a compile error if the
+     * assertion fails.
+     */
+    public static void staticAssert(boolean condition, String message) {
+        if (REPLACEMENTS_ASSERTIONS_ENABLED) {
+            AssertionNode.assertion(true, condition, message);
+        }
+    }
+
+    /**
+     * Asserts that condition evaluates to true at runtime. This is intended to be used within
+     * snippets or stubs, and will lead to a VM error if it fails.
+     */
+    public static void runtimeAssert(boolean condition, String message) {
+        if (REPLACEMENTS_ASSERTIONS_ENABLED) {
+            AssertionNode.assertion(false, condition, message);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/AssertionNode.java	Tue Jun 10 12:11:48 2014 +0200
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2014, 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.replacements.nodes;
+
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+
+/**
+ * Assertion nodes will go away as soon as the value evaluates to true. Compile-time assertions will
+ * fail if this has not happened by the time the node is lowered to LIR, while runtime assertions
+ * may need to insert a check.
+ */
+public class AssertionNode extends FixedWithNextNode implements Lowerable, Canonicalizable, LIRLowerable {
+
+    @Input private ValueNode value;
+
+    private final boolean compileTimeAssertion;
+    private final String message;
+
+    public AssertionNode(boolean compileTimeAssertion, ValueNode value, String message) {
+        super(StampFactory.forVoid());
+        this.value = value;
+        this.compileTimeAssertion = compileTimeAssertion;
+        this.message = message;
+    }
+
+    public ValueNode value() {
+        return value;
+    }
+
+    public String message() {
+        return message;
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        if (value.isConstant() && value.asConstant().asInt() != 0) {
+            return null;
+        }
+        return this;
+    }
+
+    public void lower(LoweringTool tool) {
+        if (!compileTimeAssertion) {
+            tool.getLowerer().lower(this, tool);
+        }
+    }
+
+    public void generate(NodeLIRBuilderTool generator) {
+        assert compileTimeAssertion;
+        if (value.isConstant() && value.asConstant().asInt() == 0) {
+            throw new GraalInternalError("failed compile-time assertion: %s", message);
+        } else {
+            throw new GraalInternalError("failed compile-time assertion (value %s): %s", value, message);
+        }
+    }
+
+    @SuppressWarnings("unused")
+    @NodeIntrinsic
+    public static void assertion(@ConstantNodeParameter boolean compileTimeAssertion, boolean value, @ConstantNodeParameter String message) {
+        assert value : message;
+    }
+}