# HG changeset patch # User Tom Rodriguez # Date 1418765776 28800 # Node ID 08b17b73850070b05a67be72a243d6764f7b8e6e # Parent abd10b6ef99dca51fb088448aabbf48c694d1eea Add hooks for verifying heap from generated code diff -r abd10b6ef99d -r 08b17b738500 graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/GraalOptions.java --- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/GraalOptions.java Tue Dec 16 13:30:07 2014 -0800 +++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/GraalOptions.java Tue Dec 16 13:36:16 2014 -0800 @@ -153,6 +153,9 @@ @Option(help = "", type = OptionType.Debug) public static final OptionValue GCDebugStartCycle = new OptionValue<>(-1); + @Option(help = "Perform platform dependent validation of the Java heap at returns", type = OptionType.Debug) + public static final OptionValue VerifyHeapAtReturn = new OptionValue<>(false); + // Ideal graph visualizer output settings @Option(help = "Dump IdealGraphVisualizer output in binary format", type = OptionType.Debug) public static final OptionValue PrintBinaryGraphs = new OptionValue<>(true); diff -r abd10b6ef99d -r 08b17b738500 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/MidTier.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/MidTier.java Tue Dec 16 13:30:07 2014 -0800 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/MidTier.java Tue Dec 16 13:36:16 2014 -0800 @@ -81,6 +81,10 @@ appendPhase(new IncrementalCanonicalizerPhase<>(canonicalizer, new GuardLoweringPhase())); + if (VerifyHeapAtReturn.getValue()) { + appendPhase(new VerifyHeapAtReturnPhase()); + } + appendPhase(new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.MID_TIER)); appendPhase(new FrameStateAssignmentPhase()); diff -r abd10b6ef99d -r 08b17b738500 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 Tue Dec 16 13:30:07 2014 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java Tue Dec 16 13:36:16 2014 -0800 @@ -137,6 +137,10 @@ if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) { newObjectSnippets.lower((DynamicNewArrayNode) n, registers, tool); } + } else if (n instanceof VerifyHeapNode) { + if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) { + newObjectSnippets.lower((VerifyHeapNode) n, registers, runtime, tool); + } } else if (n instanceof MonitorEnterNode) { if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) { monitorSnippets.lower((MonitorEnterNode) n, registers, tool); diff -r abd10b6ef99d -r 08b17b738500 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AssertionSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AssertionSnippets.java Tue Dec 16 13:30:07 2014 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AssertionSnippets.java Tue Dec 16 13:36:16 2014 -0800 @@ -65,7 +65,7 @@ } @NodeIntrinsic(ForeignCallNode.class) - private static native void vmMessageC(@ConstantNodeParameter ForeignCallDescriptor stubPrintfC, boolean vmError, Word format, long v1, long v2, long v3); + static native void vmMessageC(@ConstantNodeParameter ForeignCallDescriptor stubPrintfC, boolean vmError, Word format, long v1, long v2, long v3); public static class Templates extends AbstractTemplates { diff -r abd10b6ef99d -r 08b17b738500 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 Tue Dec 16 13:30:07 2014 -0800 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java Tue Dec 16 13:36:16 2014 -0800 @@ -24,6 +24,7 @@ import static com.oracle.graal.api.code.UnsignedMath.*; import static com.oracle.graal.compiler.common.GraalOptions.*; +import static com.oracle.graal.hotspot.nodes.CStringNode.*; import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*; import static com.oracle.graal.hotspot.replacements.NewObjectSnippets.Options.*; import static com.oracle.graal.nodes.PiArrayNode.*; @@ -49,6 +50,7 @@ import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.util.*; import com.oracle.graal.options.*; import com.oracle.graal.replacements.*; import com.oracle.graal.replacements.Snippet.ConstantParameter; @@ -354,6 +356,18 @@ return memory.toObject(); } + @Snippet + protected static void verifyHeap(@ConstantParameter Register threadRegister) { + Word thread = registerAsWord(threadRegister); + Word topValue = readTlabTop(thread); + if (!topValue.equal(Word.zero())) { + Word topValueContents = topValue.readWord(0, MARK_WORD_LOCATION); + if (topValueContents.equal(Word.zero())) { + AssertionSnippets.vmMessageC(AssertionSnippets.ASSERTION_VM_MESSAGE_C, true, cstring("overzeroing of TLAB detected"), 0L, 0L, 0L); + } + } + } + /** * Formats some allocated memory with an object header and zeroes out the rest. */ @@ -378,6 +392,7 @@ private final SnippetInfo allocateArrayDynamic = snippet(NewObjectSnippets.class, "allocateArrayDynamic"); private final SnippetInfo allocateInstanceDynamic = snippet(NewObjectSnippets.class, "allocateInstanceDynamic"); private final SnippetInfo newmultiarray = snippet(NewObjectSnippets.class, "newmultiarray"); + private final SnippetInfo verifyHeap = snippet(NewObjectSnippets.class, "verifyHeap"); public Templates(HotSpotProviders providers, TargetDescription target) { super(providers, providers.getSnippetReflection(), target); @@ -482,6 +497,28 @@ assert size >= 0; return size; } + + static class WarnOnce { + static { + System.out.println("VerifyHeapNode requires a VM with asserts enabled."); + } + + static void warn() { + } + } + + public void lower(VerifyHeapNode verifyHeapNode, HotSpotRegistersProvider registers, HotSpotGraalRuntimeProvider runtime, LoweringTool tool) { + if (runtime.getConfig().cAssertions) { + Arguments args = new Arguments(verifyHeap, verifyHeapNode.graph().getGuardsStage(), tool.getLoweringStage()); + args.addConst("threadRegister", registers.getThreadRegister()); + + SnippetTemplate template = template(args); + template.instantiate(providers.getMetaAccess(), verifyHeapNode, DEFAULT_REPLACER, args); + } else { + WarnOnce.warn(); + GraphUtil.removeFixedWithUnusedInputs(verifyHeapNode); + } + } } private static final SnippetCounter.Group countersNew = SnippetCounters.getValue() ? new SnippetCounter.Group("NewInstance") : null; diff -r abd10b6ef99d -r 08b17b738500 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/VerifyHeapNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/VerifyHeapNode.java Tue Dec 16 13:36:16 2014 -0800 @@ -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.nodes.debug; + +import com.oracle.graal.compiler.common.type.*; +import com.oracle.graal.nodeinfo.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; + +/** + * A node for platform dependent verification of the Java heap. Intended to be used for debugging + * heap corruption issues. + */ +@NodeInfo +public class VerifyHeapNode extends FixedWithNextNode implements Lowerable { + + public static VerifyHeapNode create() { + return new VerifyHeapNode(); + } + + protected VerifyHeapNode() { + super(StampFactory.forVoid()); + } + + @Override + public void lower(LoweringTool tool) { + tool.getLowerer().lower(this, tool); + } + + public static void addBefore(FixedNode position) { + StructuredGraph graph = position.graph(); + graph.addBeforeFixed(position, graph.add(VerifyHeapNode.create())); + } + + public static void addAfter(FixedWithNextNode position) { + StructuredGraph graph = position.graph(); + graph.addAfterFixed(position, graph.add(VerifyHeapNode.create())); + } + +} diff -r abd10b6ef99d -r 08b17b738500 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/VerifyHeapAtReturnPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/VerifyHeapAtReturnPhase.java Tue Dec 16 13:36:16 2014 -0800 @@ -0,0 +1,37 @@ +/* + * 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.phases.common; + +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.debug.*; +import com.oracle.graal.phases.*; + +public class VerifyHeapAtReturnPhase extends Phase { + + @Override + protected void run(StructuredGraph graph) { + for (ReturnNode returnNode : graph.getNodes(ReturnNode.class)) { + VerifyHeapNode.addBefore(returnNode); + } + } +} diff -r abd10b6ef99d -r 08b17b738500 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultJavaLoweringProvider.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultJavaLoweringProvider.java Tue Dec 16 13:30:07 2014 -0800 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultJavaLoweringProvider.java Tue Dec 16 13:36:16 2014 -0800 @@ -40,10 +40,12 @@ import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.HeapAccess.BarrierType; import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.debug.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; +import com.oracle.graal.nodes.util.*; import com.oracle.graal.nodes.virtual.*; import com.oracle.graal.phases.util.*; @@ -99,11 +101,17 @@ boxingSnippets.lower((BoxNode) n, tool); } else if (n instanceof UnboxNode) { boxingSnippets.lower((UnboxNode) n, tool); + } else if (n instanceof VerifyHeapNode) { + lowerVerifyHeap((VerifyHeapNode) n); } else { throw GraalInternalError.shouldNotReachHere("Node implementing Lowerable not handled: " + n); } } + protected void lowerVerifyHeap(VerifyHeapNode n) { + GraphUtil.removeFixedWithUnusedInputs(n); + } + protected void lowerLoadFieldNode(LoadFieldNode loadField, LoweringTool tool) { assert loadField.getKind() != Kind.Illegal; StructuredGraph graph = loadField.graph();