# HG changeset patch # User Lukas Stadler # Date 1402395108 -7200 # Node ID b37dbfdfbbfb90abc645ca4906932293fceeebd5 # Parent 640a875667fe42f5b33b5b294a46f66749f40786 assertion mechanism for snippets and stubs diff -r 640a875667fe -r b37dbfdfbbfb graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/replacements/HSAILNewObjectSnippets.java --- 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()); } diff -r 640a875667fe -r b37dbfdfbbfb graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java --- 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. diff -r 640a875667fe -r b37dbfdfbbfb graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java --- 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))); diff -r 640a875667fe -r b37dbfdfbbfb graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AssertionSnippets.java --- /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); + } + } +} diff -r 640a875667fe -r b37dbfdfbbfb graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java --- 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); } diff -r 640a875667fe -r b37dbfdfbbfb graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java --- 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(); } diff -r 640a875667fe -r b37dbfdfbbfb graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsUtil.java --- /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); + } + } +} diff -r 640a875667fe -r b37dbfdfbbfb graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/AssertionNode.java --- /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; + } +}