changeset 46371:0337d0617e7b

8178088: Update Graal Summary: Update Graal, do appropriate changes to jaotc Reviewed-by: kvn
author iveresov
date Thu, 06 Apr 2017 14:31:32 -0700
parents b9a1aa504eb5
children 721b8f969cc8
files hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTBackend.java hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompilationTask.java hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTHotSpotResolvedJavaMethod.java hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTStub.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/ProbabilityDirectiveTest.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.sparc/src/org/graalvm/compiler/asm/sparc/SPARCAssembler.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/TraceStatisticsPrinter.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/calc/Condition.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/FloatStamp.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IllegalStamp.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IntegerStamp.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/Stamp.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/StampFactory.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/VoidStamp.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/FrequencyEncoder.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCArithmeticLIRGenerator.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCLIRGenerator.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/BoxingEliminationTest.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CompareCanonicalizerTest3.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationMulTest.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest1.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest11.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest13.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest5.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTestBase.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/DeMorganCanonicalizationTest.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/DegeneratedLoopsTest.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/FindUniqueDefaultMethodTest.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/FloatingReadTest.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/IfCanonicalizerTest.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/LockEliminationTest.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MemoryScheduleTest.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MergeCanonicalizerTest.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/NestedLoopTest.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/NodePropertiesTest.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/PhiCreationTests.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/PushThroughIfTest.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ReadAfterCheckCastTest.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ScalarTypeSystemTest.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SchedulingTest2.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SimpleCFGTest.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StraighteningTest.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/TypeSystemTest.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyDebugUsageTest.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PartialEscapeAnalysisTest.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/inlining/InliningTest.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/inlining/NestedLoopEffectsPhaseComplexityTest.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/tutorial/GraalTutorial.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompiler.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompilerOptions.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/GraphChangeMonitoringPhase.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/Debug.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugFilter.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugRetryableTask.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/GraalDebugConfig.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/DebugScope.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Graph.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Node.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeBitMap.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeClass.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeStack.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeWorkList.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/iterators/NodePredicate.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/iterators/NodePredicates.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRGenerator.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ClassSubstitutionsTests.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorldTest.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ConstantPoolSubstitutionsTests.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/JVMCIInfopointErrorTest.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/LoadJavaMirrorWithKlassTest.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/RetryableCompilationTest.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/WriteBarrierAdditionTest.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationTask.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackend.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotCompiledCodeBuilder.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotDebugInfoBuilder.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompiler.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompilerFactory.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalJVMCIServiceLocator.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntimeProvider.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalVMEventListener.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/PrintStreamOptionKey.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotSuitesProvider.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotWordOperationPlugin.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/GraalHotSpotVMConfigNode.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/StubForeignCallNode.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/EncodedSymbolNode.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/LoadJavaMirrorWithKlassPhase.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/OnStackReplacementPhase.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/EliminateRedundantInitializationPhase.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ClassGetHubNode.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotReplacementsUtil.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HubGetClassNode.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/KlassLayoutHelperNode.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/LoadExceptionObjectSnippets.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/NewObjectSnippets.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ReflectionGetCallerClassNode.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopyNode.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopySnippets.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/ExceptionHandlerStub.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/ForeignCallStub.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/Stub.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/UnwindExceptionToCallerStub.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BciBlockMapping.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParserOptions.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCControlFlow.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/RedundantMoveElimination.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/SwitchStrategy.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScan.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanOptimizeSpillPositionPhase.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanWalker.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/GlobalLivenessAnalysisPhase.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceBuilderPhase.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceRegisterAllocationPhase.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanPhase.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanWalker.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/asm/CompilationResultBuilder.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/constopt/ConstantLoadOptimization.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/constopt/ConstantTreeAnalyzer.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/LIRPhase.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/ssa/SSAVerifier.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/stackslotalloc/LSStackSlotAllocator.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopFullUnrollPhase.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopPeelingPhase.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopUnswitchingPhase.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.test/src/org/graalvm/compiler/loop/test/LoopsDataTest.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/DerivedOffsetInductionVariable.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/micro/benchmarks/ArrayListBenchmark.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/lir/GraalCompilerState.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/lir/trace/TraceLSRAIntervalBuildingBench.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FixedGuardNode.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FrameState.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphDecoder.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphEncoder.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GuardedValueNode.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/IfNode.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/PiArrayNode.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/PiNode.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/SimplifyingGraphDecoder.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StructuredGraph.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/AddNode.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/AndNode.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/CompareNode.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ConditionalNode.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/DivNode.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/FloatEqualsNode.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/FloatLessThanNode.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerBelowNode.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerEqualsNode.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerLessThanNode.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerLowerThanNode.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IsNullNode.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/LeftShiftNode.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/MulNode.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/NegateNode.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/NormalizeCompareNode.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/OrNode.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/RightShiftNode.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ShiftNode.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SignExtendNode.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SignedDivNode.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SubNode.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/XorNode.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ZeroExtendNode.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/ControlFlowGraph.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/BranchProbabilityNode.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/IntegerSwitchNode.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawLoadNode.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnsafeCopyNode.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderContext.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/NodeIntrinsicPluginFactory.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LoadFieldNode.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/MethodCallTargetNode.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/MonitorIdNode.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/NodeValueMap.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/type/StampTool.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/util/GraphUtil.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/ModifiableOptionValues.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionValues.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionsParser.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/UniquePathUtilities.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/AbstractInliningPhase.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/CanonicalizerPhase.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/DominatorConditionalEliminationPhase.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/LockEliminationPhase.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/NewConditionalEliminationPhase.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/InliningData.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/BasePhase.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/MergeableState.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/verify/VerifyDebugUsage.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraphPrinter.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraphPrinterDumpHandler.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/InstanceOfTest.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/MethodSubstitutionTest.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PEGraphDecoderTest.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/SubstitutionsTest.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/GeneratedNodeIntrinsicPlugin.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/InjectedDependencies.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/NodeIntrinsicVerifier.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/CachingPEGraphDecoder.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/DefaultJavaLoweringProvider.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/GraphKit.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/NodeIntrinsificationProvider.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ReplacementsImpl.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetTemplate.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BasicArrayCopyNode.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroNode.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MethodHandleNode.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ReadRegisterNode.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider.processor/src/org/graalvm/compiler/serviceprovider/processor/ServiceProviderProcessor.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/GraalTest.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/SubprocessUtil.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsClosure.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsPhase.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PartialEscapeBlockState.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PartialEscapeClosure.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/VirtualUtil.java hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/EconomicMap.java
diffstat 226 files changed, 4090 insertions(+), 2177 deletions(-) [+]
line wrap: on
line diff
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTBackend.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTBackend.java	Thu Apr 06 14:31:32 2017 -0700
@@ -54,12 +54,9 @@
 import jdk.vm.ci.meta.TriState;
 
 public class AOTBackend {
-
     private final Main main;
     private final OptionValues graalOptions;
-
     private final HotSpotBackend backend;
-
     private final HotSpotProviders providers;
     private final HotSpotCodeCacheProvider codeCache;
     private final PhaseSuite<HighTierContext> graphBuilderSuite;
@@ -81,6 +78,10 @@
         return graphBuilderSuite;
     }
 
+    public HotSpotBackend getBackend() {
+        return backend;
+    }
+
     private Suites getSuites() {
         // create suites every time, as we modify options for the compiler
         return backend.getSuites().getDefaultSuites(graalOptions);
@@ -189,7 +190,7 @@
 
     public void printCompiledMethod(HotSpotResolvedJavaMethod resolvedMethod, CompilationResult compResult) {
         // This is really not installing the method.
-        InstalledCode installedCode = codeCache.addCode(resolvedMethod, HotSpotCompiledCodeBuilder.createCompiledCode(null, null, compResult), null, null);
+        InstalledCode installedCode = codeCache.addCode(resolvedMethod, HotSpotCompiledCodeBuilder.createCompiledCode(codeCache, null, null, compResult), null, null);
         String disassembly = codeCache.disassemble(installedCode);
         if (disassembly != null) {
             main.printlnDebug(disassembly);
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompilationTask.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompilationTask.java	Thu Apr 06 14:31:32 2017 -0700
@@ -145,7 +145,7 @@
             aotBackend.printCompiledMethod((HotSpotResolvedJavaMethod) method, compResult);
         }
 
-        result = new CompiledMethodInfo(compResult, new AOTHotSpotResolvedJavaMethod((HotSpotResolvedJavaMethod) method));
+        result = new CompiledMethodInfo(compResult, new AOTHotSpotResolvedJavaMethod((HotSpotResolvedJavaMethod) method, aotBackend.getBackend()));
     }
 
     private String getMethodDescription() {
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTHotSpotResolvedJavaMethod.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTHotSpotResolvedJavaMethod.java	Thu Apr 06 14:31:32 2017 -0700
@@ -24,6 +24,7 @@
 package jdk.tools.jaotc;
 
 import org.graalvm.compiler.code.CompilationResult;
+import org.graalvm.compiler.core.target.Backend;
 import org.graalvm.compiler.hotspot.HotSpotCompiledCodeBuilder;
 import jdk.vm.ci.hotspot.HotSpotCompiledCode;
 import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
@@ -31,9 +32,11 @@
 public class AOTHotSpotResolvedJavaMethod implements JavaMethodInfo {
 
     private final HotSpotResolvedJavaMethod method;
+    private final Backend backend;
 
-    public AOTHotSpotResolvedJavaMethod(HotSpotResolvedJavaMethod method) {
+    public AOTHotSpotResolvedJavaMethod(HotSpotResolvedJavaMethod method, Backend backend) {
         this.method = method;
+        this.backend = backend;
     }
 
     public String getSymbolName() {
@@ -46,7 +49,7 @@
     }
 
     public HotSpotCompiledCode compiledCode(CompilationResult result) {
-        return HotSpotCompiledCodeBuilder.createCompiledCode(method, null, result);
+        return HotSpotCompiledCodeBuilder.createCompiledCode(backend.getCodeCache(), method, null, result);
     }
 
 }
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTStub.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTStub.java	Thu Apr 06 14:31:32 2017 -0700
@@ -49,7 +49,7 @@
     }
 
     public HotSpotCompiledCode compiledCode(CompilationResult result) {
-        return HotSpotCompiledCodeBuilder.createCompiledCode(null, null, result);
+        return HotSpotCompiledCodeBuilder.createCompiledCode(backend.getCodeCache(), null, null, result);
     }
 
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/ProbabilityDirectiveTest.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/ProbabilityDirectiveTest.java	Thu Apr 06 14:31:32 2017 -0700
@@ -22,15 +22,16 @@
  */
 package org.graalvm.compiler.api.directives.test;
 
-import org.junit.Assert;
-import org.junit.Test;
-
 import org.graalvm.compiler.api.directives.GraalDirectives;
 import org.graalvm.compiler.core.test.GraalCompilerTest;
 import org.graalvm.compiler.graph.iterators.NodeIterable;
 import org.graalvm.compiler.nodes.AbstractBeginNode;
 import org.graalvm.compiler.nodes.IfNode;
+import org.graalvm.compiler.nodes.ReturnNode;
 import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.debug.ControlFlowAnchorNode;
+import org.junit.Assert;
+import org.junit.Test;
 
 public class ProbabilityDirectiveTest extends GraalCompilerTest {
 
@@ -55,9 +56,21 @@
         Assert.assertEquals("IfNode count", 1, ifNodes.count());
 
         IfNode ifNode = ifNodes.first();
-        AbstractBeginNode trueSuccessor = ifNode.trueSuccessor();
-        Assert.assertEquals("branch probability of " + ifNode, 0.125, ifNode.probability(trueSuccessor), 0);
+        AbstractBeginNode oneSuccessor;
+        if (returnValue(ifNode.trueSuccessor()) == 1) {
+            oneSuccessor = ifNode.trueSuccessor();
+        } else {
+            assert returnValue(ifNode.falseSuccessor()) == 1;
+            oneSuccessor = ifNode.falseSuccessor();
+        }
+        Assert.assertEquals("branch probability of " + ifNode, 0.125, ifNode.probability(oneSuccessor), 0);
 
         return true;
     }
+
+    private static int returnValue(AbstractBeginNode b) {
+        ControlFlowAnchorNode anchor = (ControlFlowAnchorNode) b.next();
+        ReturnNode returnNode = (ReturnNode) anchor.next();
+        return returnNode.result().asJavaConstant().asInt();
+    }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.sparc/src/org/graalvm/compiler/asm/sparc/SPARCAssembler.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.sparc/src/org/graalvm/compiler/asm/sparc/SPARCAssembler.java	Thu Apr 06 14:31:32 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2017, 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
@@ -1757,6 +1757,10 @@
         return constant.isNull() || isSimm(constant.asLong(), 5);
     }
 
+    public static boolean isSimm5(long imm) {
+        return isSimm(imm, 5);
+    }
+
     public static boolean isSimm13(int imm) {
         return isSimm(imm, 13);
     }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/TraceStatisticsPrinter.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/TraceStatisticsPrinter.java	Thu Apr 06 14:31:32 2017 -0700
@@ -35,7 +35,7 @@
     @SuppressWarnings("try")
     public static void printTraceStatistics(TraceBuilderResult result, String compilationUnitName) {
         try (Scope s = Debug.scope("DumpTraceStatistics")) {
-            if (Debug.isLogEnabled(Debug.VERBOSE_LOG_LEVEL)) {
+            if (Debug.isLogEnabled(Debug.VERBOSE_LEVEL)) {
                 print(result, compilationUnitName);
             }
         } catch (Throwable e) {
@@ -48,9 +48,9 @@
         List<Trace> traces = result.getTraces();
         int numTraces = traces.size();
 
-        try (Indent indent0 = Debug.logAndIndent(Debug.VERBOSE_LOG_LEVEL, "<tracestatistics>")) {
-            Debug.log(Debug.VERBOSE_LOG_LEVEL, "<name>%s</name>", compilationUnitName != null ? compilationUnitName : "null");
-            try (Indent indent1 = Debug.logAndIndent(Debug.VERBOSE_LOG_LEVEL, "<traces>")) {
+        try (Indent indent0 = Debug.logAndIndent(Debug.VERBOSE_LEVEL, "<tracestatistics>")) {
+            Debug.log(Debug.VERBOSE_LEVEL, "<name>%s</name>", compilationUnitName != null ? compilationUnitName : "null");
+            try (Indent indent1 = Debug.logAndIndent(Debug.VERBOSE_LEVEL, "<traces>")) {
                 printRawLine("tracenumber", "total", "min", "max", "numBlocks");
                 for (int i = 0; i < numTraces; i++) {
                     AbstractBlockBase<?>[] t = traces.get(i).getBlocks();
@@ -70,14 +70,14 @@
                     printLine(i, total, min, max, t.length);
                 }
             }
-            Debug.log(Debug.VERBOSE_LOG_LEVEL, "</traces>");
+            Debug.log(Debug.VERBOSE_LEVEL, "</traces>");
         }
-        Debug.log(Debug.VERBOSE_LOG_LEVEL, "</tracestatistics>");
+        Debug.log(Debug.VERBOSE_LEVEL, "</tracestatistics>");
 
     }
 
     private static void printRawLine(Object tracenr, Object totalTime, Object minProb, Object maxProb, Object numBlocks) {
-        Debug.log(Debug.VERBOSE_LOG_LEVEL, "%s", String.join(SEP, tracenr.toString(), totalTime.toString(), minProb.toString(), maxProb.toString(), numBlocks.toString()));
+        Debug.log(Debug.VERBOSE_LEVEL, "%s", String.join(SEP, tracenr.toString(), totalTime.toString(), minProb.toString(), maxProb.toString(), numBlocks.toString()));
     }
 
     private static void printLine(int tracenr, double totalTime, double minProb, double maxProb, int numBlocks) {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/calc/Condition.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/calc/Condition.java	Thu Apr 06 14:31:32 2017 -0700
@@ -343,116 +343,7 @@
         if (lt instanceof PrimitiveConstant) {
             PrimitiveConstant lp = (PrimitiveConstant) lt;
             PrimitiveConstant rp = (PrimitiveConstant) rt;
-            switch (lp.getJavaKind()) {
-                case Boolean:
-                case Byte:
-                case Char:
-                case Short:
-                case Int: {
-                    int x = lp.asInt();
-                    int y = rp.asInt();
-                    switch (this) {
-                        case EQ:
-                            return x == y;
-                        case NE:
-                            return x != y;
-                        case LT:
-                            return x < y;
-                        case LE:
-                            return x <= y;
-                        case GT:
-                            return x > y;
-                        case GE:
-                            return x >= y;
-                        case AE:
-                            return UnsignedMath.aboveOrEqual(x, y);
-                        case BE:
-                            return UnsignedMath.belowOrEqual(x, y);
-                        case AT:
-                            return UnsignedMath.aboveThan(x, y);
-                        case BT:
-                            return UnsignedMath.belowThan(x, y);
-                        default:
-                            throw new GraalError("expected condition: %s", this);
-                    }
-                }
-                case Long: {
-                    long x = lp.asLong();
-                    long y = rp.asLong();
-                    switch (this) {
-                        case EQ:
-                            return x == y;
-                        case NE:
-                            return x != y;
-                        case LT:
-                            return x < y;
-                        case LE:
-                            return x <= y;
-                        case GT:
-                            return x > y;
-                        case GE:
-                            return x >= y;
-                        case AE:
-                            return UnsignedMath.aboveOrEqual(x, y);
-                        case BE:
-                            return UnsignedMath.belowOrEqual(x, y);
-                        case AT:
-                            return UnsignedMath.aboveThan(x, y);
-                        case BT:
-                            return UnsignedMath.belowThan(x, y);
-                        default:
-                            throw new GraalError("expected condition: %s", this);
-                    }
-                }
-                case Float: {
-                    float x = lp.asFloat();
-                    float y = rp.asFloat();
-                    if (Float.isNaN(x) || Float.isNaN(y)) {
-                        return unorderedIsTrue;
-                    }
-                    switch (this) {
-                        case EQ:
-                            return x == y;
-                        case NE:
-                            return x != y;
-                        case LT:
-                            return x < y;
-                        case LE:
-                            return x <= y;
-                        case GT:
-                            return x > y;
-                        case GE:
-                            return x >= y;
-                        default:
-                            throw new GraalError("expected condition: %s", this);
-                    }
-                }
-                case Double: {
-                    double x = lp.asDouble();
-                    double y = rp.asDouble();
-                    if (Double.isNaN(x) || Double.isNaN(y)) {
-                        return unorderedIsTrue;
-                    }
-                    switch (this) {
-                        case EQ:
-                            return x == y;
-                        case NE:
-                            return x != y;
-                        case LT:
-                            return x < y;
-                        case LE:
-                            return x <= y;
-                        case GT:
-                            return x > y;
-                        case GE:
-                            return x >= y;
-                        default:
-                            throw new GraalError("expected condition: %s", this);
-                    }
-                }
-                default:
-                    throw new GraalError("expected value kind %s while folding condition: %s", lp.getJavaKind(), this);
-            }
+            return foldCondition(lp, rp, unorderedIsTrue);
         } else {
             Boolean equal = constantReflection.constantEquals(lt, rt);
             if (equal == null) {
@@ -469,6 +360,128 @@
         }
     }
 
+    /**
+     * Attempts to fold a comparison between two primitive constants and return the result.
+     *
+     * @param lp the constant on the left side of the comparison
+     * @param rp the constant on the right side of the comparison
+     * @param unorderedIsTrue true if an undecided float comparison should result in "true"
+     * @return true if the comparison is known to be true, false if the comparison is known to be
+     *         false
+     */
+    public boolean foldCondition(PrimitiveConstant lp, PrimitiveConstant rp, boolean unorderedIsTrue) {
+        switch (lp.getJavaKind()) {
+            case Boolean:
+            case Byte:
+            case Char:
+            case Short:
+            case Int: {
+                int x = lp.asInt();
+                int y = rp.asInt();
+                switch (this) {
+                    case EQ:
+                        return x == y;
+                    case NE:
+                        return x != y;
+                    case LT:
+                        return x < y;
+                    case LE:
+                        return x <= y;
+                    case GT:
+                        return x > y;
+                    case GE:
+                        return x >= y;
+                    case AE:
+                        return UnsignedMath.aboveOrEqual(x, y);
+                    case BE:
+                        return UnsignedMath.belowOrEqual(x, y);
+                    case AT:
+                        return UnsignedMath.aboveThan(x, y);
+                    case BT:
+                        return UnsignedMath.belowThan(x, y);
+                    default:
+                        throw new GraalError("expected condition: %s", this);
+                }
+            }
+            case Long: {
+                long x = lp.asLong();
+                long y = rp.asLong();
+                switch (this) {
+                    case EQ:
+                        return x == y;
+                    case NE:
+                        return x != y;
+                    case LT:
+                        return x < y;
+                    case LE:
+                        return x <= y;
+                    case GT:
+                        return x > y;
+                    case GE:
+                        return x >= y;
+                    case AE:
+                        return UnsignedMath.aboveOrEqual(x, y);
+                    case BE:
+                        return UnsignedMath.belowOrEqual(x, y);
+                    case AT:
+                        return UnsignedMath.aboveThan(x, y);
+                    case BT:
+                        return UnsignedMath.belowThan(x, y);
+                    default:
+                        throw new GraalError("expected condition: %s", this);
+                }
+            }
+            case Float: {
+                float x = lp.asFloat();
+                float y = rp.asFloat();
+                if (Float.isNaN(x) || Float.isNaN(y)) {
+                    return unorderedIsTrue;
+                }
+                switch (this) {
+                    case EQ:
+                        return x == y;
+                    case NE:
+                        return x != y;
+                    case LT:
+                        return x < y;
+                    case LE:
+                        return x <= y;
+                    case GT:
+                        return x > y;
+                    case GE:
+                        return x >= y;
+                    default:
+                        throw new GraalError("expected condition: %s", this);
+                }
+            }
+            case Double: {
+                double x = lp.asDouble();
+                double y = rp.asDouble();
+                if (Double.isNaN(x) || Double.isNaN(y)) {
+                    return unorderedIsTrue;
+                }
+                switch (this) {
+                    case EQ:
+                        return x == y;
+                    case NE:
+                        return x != y;
+                    case LT:
+                        return x < y;
+                    case LE:
+                        return x <= y;
+                    case GT:
+                        return x > y;
+                    case GE:
+                        return x >= y;
+                    default:
+                        throw new GraalError("expected condition: %s", this);
+                }
+            }
+            default:
+                throw new GraalError("expected value kind %s while folding condition: %s", lp.getJavaKind(), this);
+        }
+    }
+
     public Condition join(Condition other) {
         if (other == this) {
             return this;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/FloatStamp.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/FloatStamp.java	Thu Apr 06 14:31:32 2017 -0700
@@ -154,6 +154,7 @@
         return Double.isNaN(lowerBound);
     }
 
+    @Override
     public boolean isUnrestricted() {
         return lowerBound == Double.NEGATIVE_INFINITY && upperBound == Double.POSITIVE_INFINITY && !nonNaN;
     }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IllegalStamp.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IllegalStamp.java	Thu Apr 06 14:31:32 2017 -0700
@@ -59,6 +59,11 @@
     }
 
     @Override
+    public boolean isUnrestricted() {
+        return true;
+    }
+
+    @Override
     public Stamp empty() {
         return this;
     }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IntegerStamp.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IntegerStamp.java	Thu Apr 06 14:31:32 2017 -0700
@@ -254,6 +254,7 @@
         return upMask;
     }
 
+    @Override
     public boolean isUnrestricted() {
         return lowerBound == CodeUtil.minValue(getBits()) && upperBound == CodeUtil.maxValue(getBits()) && downMask == 0 && upMask == CodeUtil.mask(getBits());
     }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/Stamp.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/Stamp.java	Thu Apr 06 14:31:32 2017 -0700
@@ -126,6 +126,13 @@
     }
 
     /**
+     * Tests whether this stamp represents all values of this kind.
+     */
+    public boolean isUnrestricted() {
+        return this.equals(this.unrestricted());
+    }
+
+    /**
      * If this stamp represents a single value, the methods returns this single value. It returns
      * null otherwise.
      *
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/StampFactory.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/StampFactory.java	Thu Apr 06 14:31:32 2017 -0700
@@ -39,33 +39,6 @@
 
 public class StampFactory {
 
-    /*
-     * The marker stamp for node intrinsics must be its own class, so that it is never equal() to a
-     * regular ObjectStamp.
-     */
-    static final class NodeIntrinsicStamp extends ObjectStamp {
-        protected static final Stamp SINGLETON = new NodeIntrinsicStamp();
-
-        private NodeIntrinsicStamp() {
-            super(null, false, false, false);
-        }
-
-        @Override
-        public int hashCode() {
-            return System.identityHashCode(this);
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            return this == obj;
-        }
-
-        @Override
-        public String toString() {
-            return "NodeIntrinsicStamp";
-        }
-    }
-
     // JaCoCo Exclude
 
     private static final Stamp[] stampCache = new Stamp[JavaKind.values().length];
@@ -143,14 +116,6 @@
         return VoidStamp.getInstance();
     }
 
-    /**
-     * A stamp used only in the graph of intrinsics, e.g., snippets. It is then replaced by an
-     * actual stamp when the intrinsic is used, i.e., when the snippet template is instantiated.
-     */
-    public static Stamp forNodeIntrinsic() {
-        return NodeIntrinsicStamp.SINGLETON;
-    }
-
     public static Stamp intValue() {
         return forKind(JavaKind.Int);
     }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/VoidStamp.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/VoidStamp.java	Thu Apr 06 14:31:32 2017 -0700
@@ -46,6 +46,11 @@
     }
 
     @Override
+    public boolean isUnrestricted() {
+        return true;
+    }
+
+    @Override
     public JavaKind getStackKind() {
         return JavaKind.Void;
     }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/FrequencyEncoder.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/FrequencyEncoder.java	Thu Apr 06 14:31:32 2017 -0700
@@ -23,10 +23,10 @@
 package org.graalvm.compiler.core.common.util;
 
 import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.IdentityHashMap;
 import java.util.List;
-import java.util.Map;
+
+import org.graalvm.util.EconomicMap;
+import org.graalvm.util.Equivalence;
 
 /**
  * Creates an array of T objects order by the occurrence frequency of each object. The most
@@ -49,24 +49,24 @@
         }
     }
 
-    protected final Map<T, Entry<T>> map;
+    protected final EconomicMap<T, Entry<T>> map;
     protected boolean containsNull;
 
     /**
      * Creates an encoder that uses object identity.
      */
     public static <T> FrequencyEncoder<T> createIdentityEncoder() {
-        return new FrequencyEncoder<>(new IdentityHashMap<>());
+        return new FrequencyEncoder<>(EconomicMap.create(Equivalence.IDENTITY_WITH_SYSTEM_HASHCODE));
     }
 
     /**
      * Creates an encoder that uses {@link Object#equals(Object) object equality}.
      */
     public static <T> FrequencyEncoder<T> createEqualityEncoder() {
-        return new FrequencyEncoder<>(new HashMap<>());
+        return new FrequencyEncoder<>(EconomicMap.create(Equivalence.DEFAULT));
     }
 
-    protected FrequencyEncoder(Map<T, Entry<T>> map) {
+    protected FrequencyEncoder(EconomicMap<T, Entry<T>> map) {
         this.map = map;
     }
 
@@ -91,7 +91,7 @@
      * Returns the index of an object in the array. The object must have been
      * {@link #addObject(Object) added} before.
      */
-    public int getIndex(Object object) {
+    public int getIndex(T object) {
         if (object == null) {
             assert containsNull;
             return 0;
@@ -114,7 +114,10 @@
      */
     public T[] encodeAll(T[] allObjects) {
         assert allObjects.length == getLength();
-        List<Entry<T>> sortedEntries = new ArrayList<>(map.values());
+        List<Entry<T>> sortedEntries = new ArrayList<>(allObjects.length);
+        for (Entry<T> value : map.getValues()) {
+            sortedEntries.add(value);
+        }
         sortedEntries.sort((e1, e2) -> -Integer.compare(e1.frequency, e2.frequency));
 
         int offset = 0;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCArithmeticLIRGenerator.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCArithmeticLIRGenerator.java	Thu Apr 06 14:31:32 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2017, 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
@@ -202,7 +202,7 @@
 
     private Variable emitUnary(Op3s op3, Value input) {
         Variable result = getLIRGen().newVariable(LIRKind.combine(input));
-        getLIRGen().append(SPARCOP3Op.newUnary(op3, input, result));
+        getLIRGen().append(SPARCOP3Op.newUnary(op3, getLIRGen().loadSimm13(input), result));
         return result;
     }
 
@@ -227,9 +227,9 @@
     private Variable emitBinary(ValueKind<?> resultKind, Op3s op3, Value a, Value b, LIRFrameState state) {
         Variable result = getLIRGen().newVariable(resultKind);
         if (op3.isCommutative() && isJavaConstant(a) && getLIRGen().getMoveFactory().canInlineConstant(asJavaConstant(a))) {
-            getLIRGen().append(new SPARCOP3Op(op3, getLIRGen().load(b), a, result, state));
+            getLIRGen().append(new SPARCOP3Op(op3, getLIRGen().load(b), getLIRGen().loadSimm13(a), result, state));
         } else {
-            getLIRGen().append(new SPARCOP3Op(op3, getLIRGen().load(a), b, result, state));
+            getLIRGen().append(new SPARCOP3Op(op3, getLIRGen().load(a), getLIRGen().loadSimm13(b), result, state));
         }
         return result;
     }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCLIRGenerator.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCLIRGenerator.java	Thu Apr 06 14:31:32 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2017, 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
@@ -199,11 +199,11 @@
         Condition actualCondition;
         if (isJavaConstant(x)) {
             left = load(y);
-            right = loadNonConst(x);
+            right = loadSimm13(x);
             actualCondition = cond.mirror();
         } else {
             left = load(x);
-            right = loadNonConst(y);
+            right = loadSimm13(y);
             actualCondition = cond;
         }
         SPARCKind actualCmpKind = (SPARCKind) cmpKind;
@@ -250,7 +250,7 @@
         return load(value);
     }
 
-    private Value loadSimm13(Value value) {
+    public Value loadSimm13(Value value) {
         if (isJavaConstant(value)) {
             JavaConstant c = asJavaConstant(value);
             if (c.isNull() || SPARCAssembler.isSimm13(c)) {
@@ -261,6 +261,13 @@
     }
 
     @Override
+    public Value loadNonConst(Value value) {
+        // SPARC does not support a proper way of loadNonConst. Please use the appropriate
+        // loadSimm11 or loadSimm13 variants.
+        throw GraalError.shouldNotReachHere("This operation is not available for SPARC.");
+    }
+
+    @Override
     public Variable emitConditionalMove(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, Value trueValue, Value falseValue) {
         // Emit compare
         SPARCKind cmpSPARCKind = (SPARCKind) cmpKind;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/BoxingEliminationTest.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/BoxingEliminationTest.java	Thu Apr 06 14:31:32 2017 -0700
@@ -22,10 +22,6 @@
  */
 package org.graalvm.compiler.core.test;
 
-import org.junit.Assert;
-import org.junit.Ignore;
-import org.junit.Test;
-
 import org.graalvm.compiler.loop.DefaultLoopPolicies;
 import org.graalvm.compiler.loop.phases.LoopPeelingPhase;
 import org.graalvm.compiler.nodes.ReturnNode;
@@ -37,6 +33,9 @@
 import org.graalvm.compiler.phases.common.inlining.InliningPhase;
 import org.graalvm.compiler.phases.tiers.HighTierContext;
 import org.graalvm.compiler.virtual.phases.ea.PartialEscapePhase;
+import org.junit.Assert;
+import org.junit.Ignore;
+import org.junit.Test;
 
 /**
  * In the following tests, the usages of local variable "a" are replaced with the integer constant
@@ -162,7 +161,7 @@
             sum0 = a;
         } else {
             int sum = a;
-            for (int i = 0; i < n; i++) {
+            for (int i = 1; i < n; i++) {
                 sum += i;
             }
             sum0 = sum;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CompareCanonicalizerTest3.java	Thu Apr 06 14:31:32 2017 -0700
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 2012, 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 org.graalvm.compiler.core.test;
+
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
+import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+public class CompareCanonicalizerTest3 extends GraalCompilerTest {
+
+    @SuppressWarnings("unused") private static int sink0;
+    @SuppressWarnings("unused") private static int sink1;
+
+    @Test
+    public void test00() {
+        assertCanonicallyEqual("integerTestCanonicalization00", "referenceSnippet00");
+    }
+
+    public static void integerTestCanonicalization00(char a) {
+        if (a - 1 < a) {
+            sink1 = 0;
+        } else {
+            sink0 = -1;
+        }
+    }
+
+    @SuppressWarnings("unused")
+    public static void referenceSnippet00(char a) {
+        sink1 = 0;
+    }
+
+    @Ignore("Needs better stamp support for unsigned ranges")
+    @Test
+    public void test01() {
+        assertCanonicallyEqual("integerTestCanonicalization01", "referenceSnippet01");
+    }
+
+    public static void integerTestCanonicalization01(char a) {
+        if (Integer.compareUnsigned(a - 1, a) < 0) {
+            sink1 = 0;
+        } else {
+            sink0 = -1;
+        }
+    }
+
+    public static void referenceSnippet01(char a) {
+        if (a != 0) {
+            sink1 = 0;
+        } else {
+            sink0 = -1;
+        }
+    }
+
+    @Ignore("Needs better stamp support for unsigned ranges")
+    @Test
+    public void test1() {
+        assertCanonicallyEqual("integerTestCanonicalization1", "referenceSnippet1");
+    }
+
+    public static void integerTestCanonicalization1(char a) {
+        if (Integer.compareUnsigned(a - 2, a) < 0) {
+            sink1 = 0;
+        } else {
+            sink0 = -1;
+        }
+    }
+
+    public static void referenceSnippet1(char a) {
+        if (Integer.compareUnsigned(a, 2) >= 0) {
+            sink1 = 0;
+        } else {
+            sink0 = -1;
+        }
+    }
+
+    @Test
+    public void test2() {
+        assertCanonicallyEqual("integerTestCanonicalization2", "referenceSnippet2");
+    }
+
+    public static void integerTestCanonicalization2(int a) {
+        if (a - 1 < a) {
+            sink1 = 0;
+        } else {
+            sink0 = -1;
+        }
+    }
+
+    public static void referenceSnippet2(int a) {
+        if (a != Integer.MIN_VALUE) {
+            sink1 = 0;
+        } else {
+            sink0 = -1;
+        }
+    }
+
+    @Test
+    public void test3() {
+        assertCanonicallyEqual("integerTestCanonicalization3", "referenceSnippet3");
+    }
+
+    public static void integerTestCanonicalization3(int a) {
+        if (a - 2 < a) {
+            sink1 = 0;
+        } else {
+            sink0 = -1;
+        }
+    }
+
+    public static void referenceSnippet3(int a) {
+        if (a >= Integer.MIN_VALUE + 2) {
+            sink1 = 0;
+        } else {
+            sink0 = -1;
+        }
+    }
+
+    @Test
+    public void test4() {
+        assertCanonicallyEqual("integerTestCanonicalization4", "referenceSnippet4");
+    }
+
+    public static void integerTestCanonicalization4(int a) {
+        if (a + 1 < a) {
+            sink1 = 0;
+        } else {
+            sink0 = -1;
+        }
+    }
+
+    public static void referenceSnippet4(int a) {
+        if (a == Integer.MAX_VALUE) {
+            sink1 = 0;
+        } else {
+            sink0 = -1;
+        }
+    }
+
+    @Test
+    public void test5() {
+        assertCanonicallyEqual("integerTestCanonicalization5", "referenceSnippet5");
+    }
+
+    public static void integerTestCanonicalization5(int a) {
+        if (a + 2 < a) {
+            sink1 = 0;
+        } else {
+            sink0 = -1;
+        }
+    }
+
+    public static void referenceSnippet5(int a) {
+        if (a > Integer.MAX_VALUE - 2) {
+            sink1 = 0;
+        } else {
+            sink0 = -1;
+        }
+    }
+
+    @Test
+    public void test6() {
+        assertCanonicallyEqual("integerTestCanonicalization6", "referenceSnippet6");
+    }
+
+    public static void integerTestCanonicalization6(int a) {
+        if (a < a + 1) {
+            sink1 = 0;
+        } else {
+            sink0 = -1;
+        }
+    }
+
+    public static void referenceSnippet6(int a) {
+        if (a != Integer.MAX_VALUE) {
+            sink1 = 0;
+        } else {
+            sink0 = -1;
+        }
+    }
+
+    @Test
+    public void test7() {
+        assertCanonicallyEqual("integerTestCanonicalization7", "referenceSnippet7");
+    }
+
+    public static void integerTestCanonicalization7(int a) {
+        if (a < a + 2) {
+            sink1 = 0;
+        } else {
+            sink0 = -1;
+        }
+    }
+
+    public static void referenceSnippet7(int a) {
+        if (a <= Integer.MAX_VALUE - 2) {
+            sink1 = 0;
+        } else {
+            sink0 = -1;
+        }
+    }
+
+    protected void assertCanonicallyEqual(String snippet, String reference) {
+        StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
+        PhaseContext context = new PhaseContext(getProviders());
+        CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+        canonicalizer.apply(graph, context);
+        canonicalizer.apply(graph, context);
+        StructuredGraph referenceGraph = parseEager(reference, AllowAssumptions.YES);
+        canonicalizer.apply(referenceGraph, context);
+        canonicalizer.apply(referenceGraph, context);
+        assertEquals(referenceGraph, graph, true, true);
+    }
+
+    @Override
+    protected InlineInvokePlugin.InlineInfo bytecodeParserShouldInlineInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) {
+        return InlineInvokePlugin.InlineInfo.createStandardInlineInfo(method);
+    }
+}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationMulTest.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationMulTest.java	Thu Apr 06 14:31:32 2017 -0700
@@ -32,8 +32,8 @@
 public class ConditionalEliminationMulTest extends GraalCompilerTest {
 
     public static void snippet01(int a) {
-        if (a == 2) {
-            if (a * 3 != 6) {
+        if (a == 3) {
+            if (a * 11 != 33) {
                 shouldBeOptimizedAway();
             }
         }
@@ -41,7 +41,7 @@
 
     public static void snippet02(int a) {
         if (a == 0) {
-            if (a * 3 != 0) {
+            if (a * 11 != 0) {
                 shouldBeOptimizedAway();
             }
         }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest1.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest1.java	Thu Apr 06 14:31:32 2017 -0700
@@ -22,25 +22,25 @@
  */
 package org.graalvm.compiler.core.test;
 
+import org.graalvm.compiler.api.directives.GraalDirectives;
 import org.junit.Test;
 
-import org.graalvm.compiler.api.directives.GraalDirectives;
-
 /**
  * Collection of tests for
  * {@link org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase} including those
  * that triggered bugs in this phase.
  */
 public class ConditionalEliminationTest1 extends ConditionalEliminationTestBase {
+    protected static int sink3;
 
     private static final String REFERENCE_SNIPPET = "referenceSnippet";
 
     @SuppressWarnings("all")
-    public static int referenceSnippet(int a) {
+    public static void referenceSnippet(int a) {
         if (a == 0) {
-            return 1;
+            sink1 = 1;
         }
-        return 0;
+        sink0 = 0;
     }
 
     @Test
@@ -49,21 +49,21 @@
     }
 
     @SuppressWarnings("all")
-    public static int test1Snippet(int a) {
+    public static void test1Snippet(int a) {
         if (a == 0) {
             if (a == 5) {
-                return 100;
+                sink2 = 100;
             }
             if (a > 100) {
                 if (a == 0) {
-                    return 200;
+                    sink3 = 200;
                 }
             }
             if (a != 2) {
-                return 1;
+                sink1 = 1;
             }
         }
-        return 0;
+        sink0 = 0;
     }
 
     @Test
@@ -72,18 +72,18 @@
     }
 
     @SuppressWarnings("all")
-    public static int test2Snippet(int a) {
+    public static void test2Snippet(int a) {
         if (a == 0) {
             if (a > 100) {
                 if (a == 0) {
-                    return 200;
+                    sink3 = 200;
                 }
             }
             if (a != 2) {
-                return 1;
+                sink1 = 1;
             }
         }
-        return 0;
+        sink0 = 0;
     }
 
     @Test
@@ -92,7 +92,7 @@
     }
 
     @SuppressWarnings("all")
-    public static int test3Snippet(int a) {
+    public static void test3Snippet(int a) {
         if (a == 0) {
             if (a < 1) {
                 if (a < 2) {
@@ -101,9 +101,9 @@
                             if (a > -2) {
                                 if (a > -3) {
                                     if (a == 1) {
-                                        return 42;
+                                        sink2 = 42;
                                     } else {
-                                        return 1;
+                                        sink1 = 1;
                                     }
                                 }
                             }
@@ -112,18 +112,18 @@
                 }
             }
         }
-        return 0;
+        sink0 = 0;
     }
 
     @SuppressWarnings("all")
-    public static int test4Snippet(int a, int b) {
+    public static void test4Snippet(int a, int b) {
         if (b < 1) {
             GraalDirectives.controlFlowAnchor();
             if (b < 0) {
-                return 1;
+                sink1 = 1;
             }
         }
-        return 0;
+        sink0 = 0;
     }
 
     @Test
@@ -132,21 +132,21 @@
     }
 
     @SuppressWarnings("all")
-    public static int test5Snippet(int a, int b) {
+    public static void test5Snippet(int a, int b) {
         if ((b & 3) == 0) {
             GraalDirectives.controlFlowAnchor();
             if ((b & 7) == 0) {
                 GraalDirectives.controlFlowAnchor();
-                return 1;
+                sink1 = 1;
             }
         } else {
             GraalDirectives.controlFlowAnchor();
             if ((b & 1) == 0) {
                 GraalDirectives.controlFlowAnchor();
-                return 2;
+                sink2 = 2;
             }
         }
-        return 0;
+        sink0 = 0;
     }
 
     @Test
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest11.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest11.java	Thu Apr 06 14:31:32 2017 -0700
@@ -22,22 +22,16 @@
  */
 package org.graalvm.compiler.core.test;
 
+import org.graalvm.compiler.api.directives.GraalDirectives;
 import org.junit.Ignore;
 import org.junit.Test;
 
-import org.graalvm.compiler.api.directives.GraalDirectives;
-
 /**
  * Collection of tests for
  * {@link org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase} including those
  * that triggered bugs in this phase.
  */
 public class ConditionalEliminationTest11 extends ConditionalEliminationTestBase {
-    public ConditionalEliminationTest11() {
-        // Don't disable simplification
-        super(false);
-    }
-
     @SuppressWarnings("all")
     public static int referenceSnippet(int a) {
         if ((a & 15) != 15) {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest13.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest13.java	Thu Apr 06 14:31:32 2017 -0700
@@ -34,13 +34,6 @@
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 
 public class ConditionalEliminationTest13 extends ConditionalEliminationTestBase {
-    public ConditionalEliminationTest13() {
-        super(false);
-    }
-
-    private static int sink0;
-    private static int sink1;
-    private static int sink2;
 
     @Override
     protected InlineInvokePlugin.InlineInfo bytecodeParserShouldInlineInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) {
@@ -317,7 +310,7 @@
         super.prepareGraph(graph, canonicalizer, context, applyLowering);
         graph.clearAllStateAfter();
         graph.setGuardsStage(StructuredGraph.GuardsStage.AFTER_FSA);
-        Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "After preparation");
+        Debug.dump(Debug.BASIC_LEVEL, graph, "After preparation");
         canonicalizer.apply(graph, context);
     }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest5.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest5.java	Thu Apr 06 14:31:32 2017 -0700
@@ -22,11 +22,10 @@
  */
 package org.graalvm.compiler.core.test;
 
+import org.graalvm.compiler.api.directives.GraalDirectives;
 import org.junit.Ignore;
 import org.junit.Test;
 
-import org.graalvm.compiler.api.directives.GraalDirectives;
-
 /**
  * Collection of tests for
  * {@link org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase} including those
@@ -50,20 +49,20 @@
     static final class DistinctB {
     }
 
-    public static int reference1Snippet(Object a) {
+    public static void reference1Snippet(Object a) {
         if (a instanceof B) {
-            return 1;
+            sink1 = 1;
         }
-        return 2;
+        sink2 = 2;
     }
 
-    public static int test1Snippet(Object a) {
+    public static void test1Snippet(Object a) {
         if (a instanceof B) {
             if (a instanceof A) {
-                return 1;
+                sink1 = 1;
             }
         }
-        return 2;
+        sink2 = 2;
     }
 
     @Test
@@ -71,21 +70,21 @@
         testConditionalElimination("test1Snippet", "reference1Snippet");
     }
 
-    public static int reference2Snippet(A a) {
+    public static void reference2Snippet(A a) {
         if (a instanceof B) {
-            return 1;
+            sink1 = 1;
         }
-        return 2;
+        sink2 = 2;
     }
 
-    public static int test2Snippet(A a) {
+    public static void test2Snippet(A a) {
         if (a instanceof B) {
             B newVal = (B) a;
             if (newVal != null) {
-                return 1;
+                sink1 = 1;
             }
         }
-        return 2;
+        sink2 = 2;
     }
 
     @Test
@@ -94,28 +93,28 @@
     }
 
     @SuppressWarnings("unused")
-    public static int reference3Snippet(Object a, Object b) {
+    public static void reference3Snippet(Object a, Object b) {
         if (a instanceof DistinctA) {
             DistinctA proxyA = (DistinctA) a;
             if (b instanceof DistinctB) {
-                return 1;
+                sink1 = 1;
             }
         }
-        return 2;
+        sink2 = 2;
     }
 
     @SuppressWarnings("all")
-    public static int test3Snippet(Object a, Object b) {
+    public static void test3Snippet(Object a, Object b) {
         if (a instanceof DistinctA) {
             DistinctA proxyA = (DistinctA) a;
             if (b instanceof DistinctB) {
                 if (proxyA == b) {
-                    return 42;
+                    sink0 = 42;
                 }
-                return 1;
+                sink1 = 1;
             }
         }
-        return 2;
+        sink2 = 2;
     }
 
     @Test
@@ -123,54 +122,54 @@
         testConditionalElimination("test3Snippet", "reference3Snippet", true, false);
     }
 
-    public static int reference4Snippet(Object a) {
+    public static void reference4Snippet(Object a) {
         if (!(a instanceof B)) {
             GraalDirectives.deoptimizeAndInvalidate();
         }
-        return 1;
+        sink1 = 1;
     }
 
-    public static int test4Snippet1(Object a) {
+    public static void test4Snippet1(Object a) {
         if (!(a instanceof B)) {
             GraalDirectives.deoptimizeAndInvalidate();
         }
         if (!(a instanceof A)) {
             GraalDirectives.deoptimizeAndInvalidate();
         }
-        return 1;
+        sink1 = 1;
     }
 
-    public static int test4Snippet2(Object a) {
+    public static void test4Snippet2(Object a) {
         if (!(a instanceof A)) {
             GraalDirectives.deoptimizeAndInvalidate();
         }
         if (!(a instanceof B)) {
             GraalDirectives.deoptimizeAndInvalidate();
         }
-        return 1;
+        sink1 = 1;
     }
 
     @SuppressWarnings({"cast", "unused"})
-    public static int test4Snippet3(Object a) {
+    public static void test4Snippet3(Object a) {
         Object pi = (A) a;
         if (!(a instanceof B)) {
             GraalDirectives.deoptimizeAndInvalidate();
         }
-        return 1;
+        sink1 = 1;
     }
 
-    public static int test4Snippet4(Object a) {
+    public static void test4Snippet4(Object a) {
         if (!(a instanceof A)) {
             GraalDirectives.deoptimizeAndInvalidate();
         }
         if (!(((A) a) instanceof B)) {
             GraalDirectives.deoptimizeAndInvalidate();
         }
-        return 1;
+        sink1 = 1;
     }
 
     @SuppressWarnings({"cast"})
-    public static int test4Snippet5(Object a) {
+    public static void test4Snippet5(Object a) {
         Object pi = (A) a;
         if (pi == null) {
             GraalDirectives.deoptimizeAndInvalidate();
@@ -178,7 +177,7 @@
         if (!(a instanceof B)) {
             GraalDirectives.deoptimizeAndInvalidate();
         }
-        return 1;
+        sink1 = 1;
     }
 
     @Test
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTestBase.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTestBase.java	Thu Apr 06 14:31:32 2017 -0700
@@ -42,15 +42,9 @@
  * that triggered bugs in this phase.
  */
 public class ConditionalEliminationTestBase extends GraalCompilerTest {
-    private final boolean disableSimplification;
-
-    protected ConditionalEliminationTestBase() {
-        this(true);
-    }
-
-    protected ConditionalEliminationTestBase(boolean disableSimplification) {
-        this.disableSimplification = disableSimplification;
-    }
+    protected static int sink0;
+    protected static int sink1;
+    protected static int sink2;
 
     protected void testConditionalElimination(String snippet, String referenceSnippet) {
         testConditionalElimination(snippet, referenceSnippet, false, false);
@@ -59,15 +53,9 @@
     @SuppressWarnings("try")
     protected void testConditionalElimination(String snippet, String referenceSnippet, boolean applyConditionalEliminationOnReference, boolean applyLowering) {
         StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
-        Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph");
+        Debug.dump(Debug.BASIC_LEVEL, graph, "Graph");
         PhaseContext context = new PhaseContext(getProviders());
         CanonicalizerPhase canonicalizer1 = new CanonicalizerPhase();
-        if (disableSimplification) {
-            /**
-             * Some tests break if simplification is done so only do it when needed.
-             */
-            canonicalizer1.disableSimplification();
-        }
         CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
         try (Debug.Scope scope = Debug.scope("ConditionalEliminationTest", graph)) {
             prepareGraph(graph, canonicalizer1, context, applyLowering);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/DeMorganCanonicalizationTest.java	Thu Apr 06 14:31:32 2017 -0700
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2017, 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 org.graalvm.compiler.core.test;
+
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.calc.AndNode;
+import org.graalvm.compiler.nodes.calc.NotNode;
+import org.graalvm.compiler.nodes.calc.OrNode;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class DeMorganCanonicalizationTest extends GraalCompilerTest {
+
+    public static int or(int a, int b) {
+        return ~a | ~b;
+    }
+
+    public static int and(int a, int b) {
+        return ~a & ~b;
+    }
+
+    @Test
+    public void testAnd() {
+        StructuredGraph g = parseEager("and", AllowAssumptions.NO, getInitialOptions());
+        new CanonicalizerPhase().apply(g, getDefaultHighTierContext());
+        Assert.assertEquals(1, g.getNodes().filter(OrNode.class).count());
+        Assert.assertEquals(1, g.getNodes().filter(NotNode.class).count());
+
+        testAgainstExpected(g.method(), new Result(and(-1, 17), null), (Object) null, -1, 17);
+        testAgainstExpected(g.method(), new Result(and(-1, 1), null), (Object) null, -1, 1);
+        testAgainstExpected(g.method(), new Result(and(-1, -1), null), (Object) null, -1, -1);
+        testAgainstExpected(g.method(), new Result(and(Integer.MIN_VALUE, Integer.MIN_VALUE), null), (Object) null, Integer.MIN_VALUE, Integer.MIN_VALUE);
+    }
+
+    @Test
+    public void testOr() {
+        StructuredGraph g = parseEager("or", AllowAssumptions.NO, getInitialOptions());
+        new CanonicalizerPhase().apply(g, getDefaultHighTierContext());
+        Assert.assertEquals(1, g.getNodes().filter(AndNode.class).count());
+        Assert.assertEquals(1, g.getNodes().filter(NotNode.class).count());
+
+        testAgainstExpected(g.method(), new Result(or(-1, 17), null), (Object) null, -1, 17);
+        testAgainstExpected(g.method(), new Result(or(-1, 1), null), (Object) null, -1, 1);
+        testAgainstExpected(g.method(), new Result(or(-1, -1), null), (Object) null, -1, -1);
+        testAgainstExpected(g.method(), new Result(or(Integer.MIN_VALUE, Integer.MIN_VALUE), null), (Object) null, Integer.MIN_VALUE, Integer.MIN_VALUE);
+    }
+
+}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/DegeneratedLoopsTest.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/DegeneratedLoopsTest.java	Thu Apr 06 14:31:32 2017 -0700
@@ -86,9 +86,9 @@
             HighTierContext context = getDefaultHighTierContext();
             new InliningPhase(new CanonicalizerPhase()).apply(graph, context);
             new CanonicalizerPhase().apply(graph, context);
-            Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph");
+            Debug.dump(Debug.BASIC_LEVEL, graph, "Graph");
             StructuredGraph referenceGraph = parseEager(REFERENCE_SNIPPET, AllowAssumptions.YES);
-            Debug.dump(Debug.BASIC_LOG_LEVEL, referenceGraph, "ReferenceGraph");
+            Debug.dump(Debug.BASIC_LEVEL, referenceGraph, "ReferenceGraph");
             assertEquals(referenceGraph, graph);
         } catch (Throwable e) {
             throw Debug.handle(e);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/FindUniqueDefaultMethodTest.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/FindUniqueDefaultMethodTest.java	Thu Apr 06 14:31:32 2017 -0700
@@ -142,7 +142,7 @@
         try (Scope s = Debug.scope("InstanceOfTest", getMetaAccess().lookupJavaMethod(getMethod(snippet)))) {
             StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
             compile(graph.method(), graph);
-            Debug.dump(Debug.BASIC_LOG_LEVEL, graph, snippet);
+            Debug.dump(Debug.BASIC_LEVEL, graph, snippet);
             return graph;
         } catch (Throwable e) {
             throw Debug.handle(e);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/FloatingReadTest.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/FloatingReadTest.java	Thu Apr 06 14:31:32 2017 -0700
@@ -82,7 +82,7 @@
                 }
             }
 
-            Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "After lowering");
+            Debug.dump(Debug.BASIC_LEVEL, graph, "After lowering");
 
             Assert.assertNotNull(returnNode);
             Assert.assertNotNull(monitorexit);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java	Thu Apr 06 14:31:32 2017 -0700
@@ -78,6 +78,7 @@
 import org.graalvm.compiler.nodes.FullInfopointNode;
 import org.graalvm.compiler.nodes.InvokeNode;
 import org.graalvm.compiler.nodes.InvokeWithExceptionNode;
+import org.graalvm.compiler.nodes.ParameterNode;
 import org.graalvm.compiler.nodes.ProxyNode;
 import org.graalvm.compiler.nodes.ReturnNode;
 import org.graalvm.compiler.nodes.StructuredGraph;
@@ -91,6 +92,7 @@
 import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin;
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
+import org.graalvm.compiler.nodes.java.AccessFieldNode;
 import org.graalvm.compiler.nodes.spi.LoweringProvider;
 import org.graalvm.compiler.nodes.spi.Replacements;
 import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
@@ -121,6 +123,7 @@
 import jdk.vm.ci.code.CodeCacheProvider;
 import jdk.vm.ci.code.InstalledCode;
 import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.Assumptions.Assumption;
 import jdk.vm.ci.meta.ConstantReflectionProvider;
 import jdk.vm.ci.meta.DeoptimizationReason;
 import jdk.vm.ci.meta.JavaKind;
@@ -130,7 +133,6 @@
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 import jdk.vm.ci.meta.ResolvedJavaType;
 import jdk.vm.ci.meta.SpeculationLog;
-import jdk.vm.ci.meta.Assumptions.Assumption;
 import jdk.vm.ci.services.Services;
 
 /**
@@ -410,13 +412,13 @@
         String mismatchString = compareGraphStrings(expected, expectedString, graph, actualString);
 
         if (!excludeVirtual && getNodeCountExcludingUnusedConstants(expected) != getNodeCountExcludingUnusedConstants(graph)) {
-            Debug.dump(Debug.BASIC_LOG_LEVEL, expected, "Node count not matching - expected");
-            Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Node count not matching - actual");
+            Debug.dump(Debug.BASIC_LEVEL, expected, "Node count not matching - expected");
+            Debug.dump(Debug.BASIC_LEVEL, graph, "Node count not matching - actual");
             Assert.fail("Graphs do not have the same number of nodes: " + expected.getNodeCount() + " vs. " + graph.getNodeCount() + "\n" + mismatchString);
         }
         if (!expectedString.equals(actualString)) {
-            Debug.dump(Debug.BASIC_LOG_LEVEL, expected, "mismatching graphs - expected");
-            Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "mismatching graphs - actual");
+            Debug.dump(Debug.BASIC_LEVEL, expected, "mismatching graphs - expected");
+            Debug.dump(Debug.BASIC_LEVEL, graph, "mismatching graphs - actual");
             Assert.fail(mismatchString);
         }
     }
@@ -482,22 +484,25 @@
 
         StringBuilder result = new StringBuilder();
         for (Block block : scheduleResult.getCFG().getBlocks()) {
-            result.append("Block " + block + " ");
+            result.append("Block ").append(block).append(' ');
             if (block == scheduleResult.getCFG().getStartBlock()) {
                 result.append("* ");
             }
             result.append("-> ");
             for (Block succ : block.getSuccessors()) {
-                result.append(succ + " ");
+                result.append(succ).append(' ');
             }
-            result.append("\n");
+            result.append('\n');
             for (Node node : scheduleResult.getBlockToNodesMap().get(block)) {
                 if (node instanceof ValueNode && node.isAlive()) {
-                    if (!excludeVirtual || !(node instanceof VirtualObjectNode || node instanceof ProxyNode || node instanceof FullInfopointNode)) {
+                    if (!excludeVirtual || !(node instanceof VirtualObjectNode || node instanceof ProxyNode || node instanceof FullInfopointNode || node instanceof ParameterNode)) {
                         if (node instanceof ConstantNode) {
                             String name = checkConstants ? node.toString(Verbosity.Name) : node.getClass().getSimpleName();
-                            String str = name + (excludeVirtual ? "\n" : "    (" + filteredUsageCount(node) + ")\n");
-                            constantsLines.add(str);
+                            if (excludeVirtual) {
+                                constantsLines.add(name);
+                            } else {
+                                constantsLines.add(name + "    (" + filteredUsageCount(node) + ")");
+                            }
                         } else {
                             int id;
                             if (canonicalId.get(node) != null) {
@@ -507,8 +512,17 @@
                                 canonicalId.set(node, id);
                             }
                             String name = node.getClass().getSimpleName();
-                            String str = "  " + id + "|" + name + (excludeVirtual ? "\n" : "    (" + filteredUsageCount(node) + ")\n");
-                            result.append(str);
+                            result.append("  ").append(id).append('|').append(name);
+                            if (node instanceof AccessFieldNode) {
+                                result.append('#');
+                                result.append(((AccessFieldNode) node).field());
+                            }
+                            if (!excludeVirtual) {
+                                result.append("    (");
+                                result.append(filteredUsageCount(node));
+                                result.append(')');
+                            }
+                            result.append('\n');
                         }
                     }
                 }
@@ -516,14 +530,14 @@
         }
 
         StringBuilder constantsLinesResult = new StringBuilder();
-        constantsLinesResult.append(constantsLines.size() + " constants:\n");
+        constantsLinesResult.append(constantsLines.size()).append(" constants:\n");
         Collections.sort(constantsLines);
         for (String s : constantsLines) {
             constantsLinesResult.append(s);
-            constantsLinesResult.append("\n");
+            constantsLinesResult.append('\n');
         }
 
-        return constantsLines.toString() + result.toString();
+        return constantsLinesResult.toString() + result.toString();
     }
 
     /**
@@ -545,15 +559,15 @@
         StringBuilder result = new StringBuilder();
         Block[] blocks = scheduleResult.getCFG().getBlocks();
         for (Block block : blocks) {
-            result.append("Block " + block + " ");
+            result.append("Block ").append(block).append(' ');
             if (block == scheduleResult.getCFG().getStartBlock()) {
                 result.append("* ");
             }
             result.append("-> ");
             for (Block succ : block.getSuccessors()) {
-                result.append(succ + " ");
+                result.append(succ).append(' ');
             }
-            result.append("\n");
+            result.append('\n');
             for (Node node : scheduleResult.getBlockToNodesMap().get(block)) {
                 result.append(String.format("%1S\n", node));
             }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/IfCanonicalizerTest.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/IfCanonicalizerTest.java	Thu Apr 06 14:31:32 2017 -0700
@@ -217,7 +217,7 @@
                 n.replaceFirstInput(param, constant);
             }
         }
-        Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph");
+        Debug.dump(Debug.BASIC_LEVEL, graph, "Graph");
         new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
         for (FrameState fs : param.usages().filter(FrameState.class).snapshot()) {
             fs.replaceFirstInput(param, null);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/LockEliminationTest.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/LockEliminationTest.java	Thu Apr 06 14:31:32 2017 -0700
@@ -25,7 +25,8 @@
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 
 import org.junit.Test;
-
+import org.graalvm.compiler.loop.DefaultLoopPolicies;
+import org.graalvm.compiler.loop.phases.LoopFullUnrollPhase;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
 import org.graalvm.compiler.nodes.java.MonitorExitNode;
@@ -91,6 +92,26 @@
         assertDeepEquals(1, graph.getNodes().filter(MonitorExitNode.class).count());
     }
 
+    public void testUnrolledSyncSnippet(Object a) {
+        for (int i = 0; i < 3; i++) {
+            synchronized (a) {
+
+            }
+        }
+    }
+
+    @Test
+    public void testUnrolledSync() {
+        StructuredGraph graph = getGraph("testUnrolledSyncSnippet");
+        CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+        canonicalizer.apply(graph, new PhaseContext(getProviders()));
+        HighTierContext context = getDefaultHighTierContext();
+        new LoopFullUnrollPhase(canonicalizer, new DefaultLoopPolicies()).apply(graph, context);
+        new LockEliminationPhase().apply(graph);
+        assertDeepEquals(1, graph.getNodes().filter(RawMonitorEnterNode.class).count());
+        assertDeepEquals(1, graph.getNodes().filter(MonitorExitNode.class).count());
+    }
+
     private StructuredGraph getGraph(String snippet) {
         ResolvedJavaMethod method = getResolvedJavaMethod(snippet);
         StructuredGraph graph = parseEager(method, AllowAssumptions.YES);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MemoryScheduleTest.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MemoryScheduleTest.java	Thu Apr 06 14:31:32 2017 -0700
@@ -717,7 +717,7 @@
             if (mode == TestMode.WITHOUT_FRAMESTATES || mode == TestMode.INLINED_WITHOUT_FRAMESTATES) {
                 graph.clearAllStateAfter();
             }
-            Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "after removal of framestates");
+            Debug.dump(Debug.BASIC_LEVEL, graph, "after removal of framestates");
 
             new FloatingReadPhase().apply(graph);
             new RemoveValueProxyPhase().apply(graph);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MergeCanonicalizerTest.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MergeCanonicalizerTest.java	Thu Apr 06 14:31:32 2017 -0700
@@ -61,7 +61,7 @@
         StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
         new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
         new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
-        Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph");
+        Debug.dump(Debug.BASIC_LEVEL, graph, "Graph");
         assertDeepEquals(returnCount, graph.getNodes(ReturnNode.TYPE).count());
     }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/NestedLoopTest.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/NestedLoopTest.java	Thu Apr 06 14:31:32 2017 -0700
@@ -142,7 +142,7 @@
 
     private void test(String snippet, int rootExits, int nestedExits, int innerExits) {
         StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
-        Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph");
+        Debug.dump(Debug.BASIC_LEVEL, graph, "Graph");
         ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, true, true);
 
         Assert.assertEquals(3, cfg.getLoops().size());
@@ -162,7 +162,7 @@
         Assert.assertEquals(rootExits, rootLoop.getExits().size());
         Assert.assertEquals(nestedExits, nestedLoop.getExits().size());
         Assert.assertEquals(innerExits, innerMostLoop.getExits().size());
-        Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph");
+        Debug.dump(Debug.BASIC_LEVEL, graph, "Graph");
     }
 
     private static boolean contains(Loop<Block> loop, Invoke node, ControlFlowGraph cfg) {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/NodePropertiesTest.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/NodePropertiesTest.java	Thu Apr 06 14:31:32 2017 -0700
@@ -58,9 +58,11 @@
             x = 2;
             sideEffect = null;
         }
+        int b = 4;
         sideEffect = null;
+        int c = b % 5;
         // can shift
-        return a * x * 4;
+        return a * x * c;
     }
 
     public static int test2Snippet(int a) {
@@ -249,7 +251,7 @@
         gc2.apply(g2, htc);
         Debug.log("Test Graph Cost --> 1.Graph cost:%f vs. 2.Graph cost:%f\n", gc1.finalCycles, gc2.finalCycles);
         Assert.assertTrue(gc2.finalCycles > gc1.finalCycles);
-        Assert.assertTrue(gc2.finalSize == gc1.finalSize + 1/* mul has 3 const input */);
+        Assert.assertTrue(gc2.finalSize == gc1.finalSize);
     }
 
     @Test
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/PhiCreationTests.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/PhiCreationTests.java	Thu Apr 06 14:31:32 2017 -0700
@@ -70,7 +70,7 @@
     @Test
     public void test3() {
         StructuredGraph graph = parseEager("test3Snippet", AllowAssumptions.YES);
-        Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph");
+        Debug.dump(Debug.BASIC_LEVEL, graph, "Graph");
         Assert.assertFalse(graph.getNodes().filter(ValuePhiNode.class).iterator().hasNext());
     }
 
@@ -86,7 +86,7 @@
     @Test
     public void test4() {
         StructuredGraph graph = parseEager("test4Snippet", AllowAssumptions.YES);
-        Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph");
+        Debug.dump(Debug.BASIC_LEVEL, graph, "Graph");
         Assert.assertFalse(graph.getNodes().filter(ValuePhiNode.class).iterator().hasNext());
     }
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/PushThroughIfTest.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/PushThroughIfTest.java	Thu Apr 06 14:31:32 2017 -0700
@@ -59,7 +59,7 @@
 
     private void test(String snippet, String reference) {
         StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
-        Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph");
+        Debug.dump(Debug.BASIC_LEVEL, graph, "Graph");
         for (FrameState fs : graph.getNodes(FrameState.TYPE).snapshot()) {
             fs.replaceAtUsages(null);
             GraphUtil.killWithUnusedFloatingInputs(fs);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ReadAfterCheckCastTest.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ReadAfterCheckCastTest.java	Thu Apr 06 14:31:32 2017 -0700
@@ -94,7 +94,7 @@
             new FloatingReadPhase().apply(graph);
             canonicalizer.apply(graph, context);
 
-            Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "After lowering");
+            Debug.dump(Debug.BASIC_LEVEL, graph, "After lowering");
 
             for (FloatingReadNode node : graph.getNodes(ParameterNode.TYPE).first().usages().filter(FloatingReadNode.class)) {
                 // Checking that the parameter a is not directly used for the access to field
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ScalarTypeSystemTest.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ScalarTypeSystemTest.java	Thu Apr 06 14:31:32 2017 -0700
@@ -131,7 +131,7 @@
     private void test(final String snippet, final String referenceSnippet) {
         // No debug scope to reduce console noise for @Test(expected = ...) tests
         StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO);
-        Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph");
+        Debug.dump(Debug.BASIC_LEVEL, graph, "Graph");
         PhaseContext context = new PhaseContext(getProviders());
         new CanonicalizerPhase().apply(graph, context);
         StructuredGraph referenceGraph = parseEager(referenceSnippet, AllowAssumptions.NO);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SchedulingTest2.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SchedulingTest2.java	Thu Apr 06 14:31:32 2017 -0700
@@ -69,7 +69,7 @@
         BeginNode beginNode = graph.add(new BeginNode());
         returnNode.replaceAtPredecessor(beginNode);
         beginNode.setNext(returnNode);
-        Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph");
+        Debug.dump(Debug.BASIC_LEVEL, graph, "Graph");
         SchedulePhase schedulePhase = new SchedulePhase(SchedulingStrategy.EARLIEST);
         schedulePhase.apply(graph);
         ScheduleResult schedule = graph.getLastSchedule();
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SimpleCFGTest.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SimpleCFGTest.java	Thu Apr 06 14:31:32 2017 -0700
@@ -41,7 +41,7 @@
 public class SimpleCFGTest extends GraalCompilerTest {
 
     private static void dumpGraph(final StructuredGraph graph) {
-        Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph");
+        Debug.dump(Debug.BASIC_LEVEL, graph, "Graph");
     }
 
     @Test
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StraighteningTest.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StraighteningTest.java	Thu Apr 06 14:31:32 2017 -0700
@@ -88,7 +88,7 @@
     private void test(final String snippet) {
         // No debug scope to reduce console noise for @Test(expected = ...) tests
         StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
-        Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph");
+        Debug.dump(Debug.BASIC_LEVEL, graph, "Graph");
         new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
         StructuredGraph referenceGraph = parseEager(REFERENCE_SNIPPET, AllowAssumptions.YES);
         assertEquals(referenceGraph, graph);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/TypeSystemTest.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/TypeSystemTest.java	Thu Apr 06 14:31:32 2017 -0700
@@ -180,7 +180,7 @@
 
     private void test(String snippet, String referenceSnippet) {
         StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO);
-        Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph");
+        Debug.dump(Debug.BASIC_LEVEL, graph, "Graph");
         /*
          * When using FlowSensitiveReductionPhase instead of ConditionalEliminationPhase,
          * tail-duplication gets activated thus resulting in a graph with more nodes than the
@@ -200,8 +200,8 @@
     @Override
     protected void assertEquals(StructuredGraph expected, StructuredGraph graph) {
         if (getNodeCountExcludingUnusedConstants(expected) != getNodeCountExcludingUnusedConstants(graph)) {
-            Debug.dump(Debug.BASIC_LOG_LEVEL, expected, "expected (node count)");
-            Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "graph (node count)");
+            Debug.dump(Debug.BASIC_LEVEL, expected, "expected (node count)");
+            Debug.dump(Debug.BASIC_LEVEL, graph, "graph (node count)");
             Assert.fail("Graphs do not have the same number of nodes: " + expected.getNodeCount() + " vs. " + graph.getNodeCount());
         }
     }
@@ -244,7 +244,7 @@
         StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO);
         new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
         new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
-        Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph " + snippet);
+        Debug.dump(Debug.BASIC_LEVEL, graph, "Graph " + snippet);
         Assert.assertFalse("shouldn't have nodes of type " + clazz, graph.getNodes().filter(clazz).iterator().hasNext());
     }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyDebugUsageTest.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyDebugUsageTest.java	Thu Apr 06 14:31:32 2017 -0700
@@ -83,9 +83,28 @@
 
         @Override
         protected void run(StructuredGraph graph) {
-            Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "%s", graph.toString());
+            Debug.dump(Debug.BASIC_LEVEL, graph, "%s", graph.toString());
+        }
+    }
+
+    private static class InvalidDumpLevelPhase extends Phase {
+
+        @Override
+        protected void run(StructuredGraph graph) {
+            Debug.dump(Debug.VERY_DETAILED_LEVEL + 1, graph, "%s", graph);
+        }
+    }
+
+    private static class NonConstantDumpLevelPhase extends Phase {
+
+        @Override
+        protected void run(StructuredGraph graph) {
+            Debug.dump(getLevel(), graph, "%s", graph);
         }
 
+        int getLevel() {
+            return 10;
+        }
     }
 
     private static class InvalidVerifyUsagePhase extends Phase {
@@ -126,7 +145,7 @@
 
         @Override
         protected void run(StructuredGraph graph) {
-            Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "error " + graph);
+            Debug.dump(Debug.BASIC_LEVEL, graph, "error " + graph);
         }
 
     }
@@ -169,7 +188,7 @@
 
         @Override
         protected void run(StructuredGraph graph) {
-            Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "%s", graph);
+            Debug.dump(Debug.BASIC_LEVEL, graph, "%s", graph);
         }
 
     }
@@ -234,6 +253,16 @@
     }
 
     @Test(expected = VerificationError.class)
+    public void testDumpLevelInvalid() {
+        testDebugUsageClass(InvalidDumpLevelPhase.class);
+    }
+
+    @Test(expected = VerificationError.class)
+    public void testDumpNonConstantLevelInvalid() {
+        testDebugUsageClass(NonConstantDumpLevelPhase.class);
+    }
+
+    @Test(expected = VerificationError.class)
     public void testLogInvalidConcat() {
         testDebugUsageClass(InvalidConcatLogUsagePhase.class);
     }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PartialEscapeAnalysisTest.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PartialEscapeAnalysisTest.java	Thu Apr 06 14:31:32 2017 -0700
@@ -135,6 +135,7 @@
     }
 
     public static Object[] array = new Object[]{1, 2, 3, 4, 5, "asdf", "asdf"};
+    public static char[] charArray = new char[]{1, 2, 3, 4, 5, 'a', 'f'};
 
     public static Object testArrayCopySnippet(int a) {
         Object[] tmp = new Object[]{a != 1 ? array[a] : null};
@@ -144,6 +145,18 @@
     }
 
     @Test
+    public void testPrimitiveArraycopy() {
+        testPartialEscapeAnalysis("testPrimitiveArraycopySnippet", 0, 0);
+    }
+
+    public static Object testPrimitiveArraycopySnippet(int a) {
+        char[] tmp = new char[]{a != 1 ? charArray[a] : 0};
+        char[] tmp2 = new char[5];
+        System.arraycopy(tmp, 0, tmp2, 4, 1);
+        return tmp2[4];
+    }
+
+    @Test
     @Ignore
     public void testCache() {
         testPartialEscapeAnalysis("testCacheSnippet", 0.75, 1);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/inlining/InliningTest.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/inlining/InliningTest.java	Thu Apr 06 14:31:32 2017 -0700
@@ -244,10 +244,10 @@
                                 ? getCustomGraphBuilderSuite(GraphBuilderConfiguration.getDefault(getDefaultGraphBuilderPlugins()).withFullInfopoints(true))
                                 : getDefaultGraphBuilderSuite();
                 HighTierContext context = new HighTierContext(getProviders(), graphBuilderSuite, OptimisticOptimizations.ALL);
-                Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph");
+                Debug.dump(Debug.BASIC_LEVEL, graph, "Graph");
                 new CanonicalizerPhase().apply(graph, context);
                 new InliningPhase(new CanonicalizerPhase()).apply(graph, context);
-                Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph");
+                Debug.dump(Debug.BASIC_LEVEL, graph, "Graph");
                 new CanonicalizerPhase().apply(graph, context);
                 new DeadCodeEliminationPhase().apply(graph);
                 return graph;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/inlining/NestedLoopEffectsPhaseComplexityTest.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/inlining/NestedLoopEffectsPhaseComplexityTest.java	Thu Apr 06 14:31:32 2017 -0700
@@ -121,7 +121,7 @@
         long start = System.currentTimeMillis();
         phase.apply(g, context);
         long end = System.currentTimeMillis();
-        Debug.dump(Debug.DETAILED_LOG_LEVEL, g, "After %s", phase.contractorName());
+        Debug.dump(Debug.DETAILED_LEVEL, g, "After %s", phase.contractorName());
         return end - start;
     }
 
@@ -138,7 +138,7 @@
             next = callerGraph.getNodes(MethodCallTargetNode.TYPE).first().invoke();
             EconomicSet<Node> canonicalizeNodes = InliningUtil.inlineForCanonicalization(next, calleeGraph, false, calleeMethod);
             canonicalizer.applyIncremental(callerGraph, context, canonicalizeNodes);
-            Debug.dump(Debug.DETAILED_LOG_LEVEL, callerGraph, "After inlining %s into %s iteration %d", calleeMethod, callerMethod, i);
+            Debug.dump(Debug.DETAILED_LEVEL, callerGraph, "After inlining %s into %s iteration %d", calleeMethod, callerMethod, i);
         }
         return callerGraph;
     }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/tutorial/GraalTutorial.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/tutorial/GraalTutorial.java	Thu Apr 06 14:31:32 2017 -0700
@@ -25,6 +25,8 @@
 import org.junit.Assert;
 import org.junit.Test;
 
+import java.util.regex.Pattern;
+
 import org.graalvm.compiler.bytecode.Bytecode;
 import org.graalvm.compiler.bytecode.BytecodeDisassembler;
 import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecode;
@@ -56,7 +58,11 @@
         byte[] bytecodes = bytecode.getCode();
         Assert.assertNotNull(bytecodes);
 
-        System.out.println(new BytecodeDisassembler().disassemble(bytecode));
+        Pattern disassemblyLineRE = Pattern.compile(" *\\d+: [a-z][\\w_]+");
+        String disassembly = new BytecodeDisassembler().disassemble(bytecode);
+        for (String line : disassembly.split("\\n")) {
+            Assert.assertTrue(line, disassemblyLineRE.matcher(line).find());
+        }
     }
 
     /*
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompiler.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompiler.java	Thu Apr 06 14:31:32 2017 -0700
@@ -39,6 +39,7 @@
 import org.graalvm.compiler.debug.DebugCounter;
 import org.graalvm.compiler.debug.DebugTimer;
 import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.debug.MethodFilter;
 import org.graalvm.compiler.debug.internal.method.MethodMetricsRootScopeInfo;
 import org.graalvm.compiler.lir.LIR;
 import org.graalvm.compiler.lir.alloc.OutOfRegistersException;
@@ -175,11 +176,43 @@
             } catch (Throwable e) {
                 throw Debug.handle(e);
             }
+            checkForRequestedCrash(r.graph);
             return r.compilationResult;
         }
     }
 
     /**
+     * Checks whether the {@link GraalCompilerOptions#CrashAt} option indicates that the compilation
+     * of {@code graph} should result in an exception.
+     *
+     * @param graph a graph currently being compiled
+     * @throws RuntimeException if the value of {@link GraalCompilerOptions#CrashAt} matches
+     *             {@code graph.method()} or {@code graph.name}
+     */
+    private static void checkForRequestedCrash(StructuredGraph graph) {
+        String methodPattern = GraalCompilerOptions.CrashAt.getValue(graph.getOptions());
+        if (methodPattern != null) {
+            String crashLabel = null;
+            ResolvedJavaMethod method = graph.method();
+            if (method == null) {
+                if (graph.name.contains(methodPattern)) {
+                    crashLabel = graph.name;
+                }
+            } else {
+                MethodFilter[] filters = MethodFilter.parse(methodPattern);
+                for (MethodFilter filter : filters) {
+                    if (filter.matches(method)) {
+                        crashLabel = method.format("%H.%n(%p)");
+                    }
+                }
+            }
+            if (crashLabel != null) {
+                throw new RuntimeException("Forced crash after compiling " + crashLabel);
+            }
+        }
+    }
+
+    /**
      * Builds the graph, optimizes it.
      */
     @SuppressWarnings("try")
@@ -190,21 +223,25 @@
             if (graph.start().next() == null) {
                 graphBuilderSuite.apply(graph, highTierContext);
                 new DeadCodeEliminationPhase(DeadCodeEliminationPhase.Optionality.Optional).apply(graph);
+                Debug.dump(Debug.BASIC_LEVEL, graph, "After parsing");
             } else {
-                Debug.dump(Debug.INFO_LOG_LEVEL, graph, "initial state");
+                Debug.dump(Debug.INFO_LEVEL, graph, "initial state");
             }
 
             suites.getHighTier().apply(graph, highTierContext);
             graph.maybeCompress();
+            Debug.dump(Debug.BASIC_LEVEL, graph, "After high tier");
 
             MidTierContext midTierContext = new MidTierContext(providers, target, optimisticOpts, profilingInfo);
             suites.getMidTier().apply(graph, midTierContext);
             graph.maybeCompress();
+            Debug.dump(Debug.BASIC_LEVEL, graph, "After mid tier");
 
             LowTierContext lowTierContext = new LowTierContext(providers, target);
             suites.getLowTier().apply(graph, lowTierContext);
+            Debug.dump(Debug.BASIC_LEVEL, graph, "After low tier");
 
-            Debug.dump(Debug.BASIC_LOG_LEVEL, graph.getLastSchedule(), "Final HIR schedule");
+            Debug.dump(Debug.BASIC_LEVEL, graph.getLastSchedule(), "Final HIR schedule");
         } catch (Throwable e) {
             throw Debug.handle(e);
         } finally {
@@ -269,7 +306,7 @@
                 linearScanOrder = ComputeBlockOrder.computeLinearScanOrder(blocks.length, startBlock);
 
                 lir = new LIR(schedule.getCFG(), linearScanOrder, codeEmittingOrder, graph.getOptions());
-                Debug.dump(Debug.INFO_LOG_LEVEL, lir, "After linear scan order");
+                Debug.dump(Debug.INFO_LEVEL, lir, "After linear scan order");
             } catch (Throwable e) {
                 throw Debug.handle(e);
             }
@@ -283,9 +320,9 @@
             new LIRGenerationPhase().apply(backend.getTarget(), lirGenRes, context);
 
             try (Scope s = Debug.scope("LIRStages", nodeLirGen, lir)) {
-                Debug.dump(Debug.BASIC_LOG_LEVEL, lir, "After LIR generation");
+                Debug.dump(Debug.BASIC_LEVEL, lir, "After LIR generation");
                 LIRGenerationResult result = emitLowLevel(backend.getTarget(), lirGenRes, lirGen, lirSuites, backend.newRegisterAllocationConfig(registerConfig, allocationRestrictedTo));
-                Debug.dump(Debug.BASIC_LOG_LEVEL, lir, "Before code generation");
+                Debug.dump(Debug.BASIC_LEVEL, lir, "Before code generation");
                 return result;
             } catch (Throwable e) {
                 throw Debug.handle(e);
@@ -365,7 +402,7 @@
                 Debug.counter("ExceptionHandlersEmitted").add(compilationResult.getExceptionHandlers().size());
             }
 
-            Debug.dump(Debug.BASIC_LOG_LEVEL, compilationResult, "After code generation");
+            Debug.dump(Debug.BASIC_LEVEL, compilationResult, "After code generation");
         }
     }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompilerOptions.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompilerOptions.java	Thu Apr 06 14:31:32 2017 -0700
@@ -46,6 +46,8 @@
     public static final OptionKey<Boolean> ExitVMOnException = new OptionKey<>(false);
     @Option(help = "", type = OptionType.Debug)
     public static final OptionKey<Boolean> PrintStackTraceOnException = new OptionKey<>(false);
+    @Option(help = "Pattern (see MethodFilter for format) for method that will trigger an exception when compiled. " +
+                   "This option exists to test handling compilation crashes gracefully.", type = OptionType.Debug)
+    public static final OptionKey<String> CrashAt = new OptionKey<>(null);
     // @formatter:on
-
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/GraphChangeMonitoringPhase.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/GraphChangeMonitoringPhase.java	Thu Apr 06 14:31:32 2017 -0700
@@ -91,12 +91,12 @@
             listener = new HashSetNodeEventListener();
             try (NodeEventScope s = graph.trackNodeEvents(listener)) {
                 try (Scope s2 = Debug.scope("WithGraphChangeMonitoring")) {
-                    if (Debug.isDumpEnabled(Debug.BASIC_LOG_LEVEL)) {
-                        Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "*** Before phase %s", getName());
+                    if (Debug.isDumpEnabled(Debug.DETAILED_LEVEL)) {
+                        Debug.dump(Debug.DETAILED_LEVEL, graph, "*** Before phase %s", getName());
                     }
                     super.run(graph, context);
-                    if (Debug.isDumpEnabled(Debug.BASIC_LOG_LEVEL)) {
-                        Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "*** After phase %s %s", getName(), filteredNodes);
+                    if (Debug.isDumpEnabled(Debug.DETAILED_LEVEL)) {
+                        Debug.dump(Debug.DETAILED_LEVEL, graph, "*** After phase %s %s", getName(), filteredNodes);
                     }
                     Debug.log("*** %s %s %s\n", message, graph, filteredNodes);
                 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/Debug.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/Debug.java	Thu Apr 06 14:31:32 2017 -0700
@@ -122,11 +122,41 @@
         return config.isDumpEnabledForMethod();
     }
 
-    public static final int BASIC_LOG_LEVEL = 1;
-    public static final int INFO_LOG_LEVEL = 2;
-    public static final int VERBOSE_LOG_LEVEL = 3;
-    public static final int DETAILED_LOG_LEVEL = 4;
-    public static final int VERY_DETAILED_LOG_LEVEL = 5;
+    /**
+     * Basic debug level.
+     *
+     * For HIR dumping, only ~5 graphs per method: after parsing, after inlining, after high tier,
+     * after mid tier, after low tier.
+     */
+    public static final int BASIC_LEVEL = 1;
+
+    /**
+     * Informational debug level.
+     *
+     * HIR dumping: One graph after each applied top-level phase.
+     */
+    public static final int INFO_LEVEL = 2;
+
+    /**
+     * Verbose debug level.
+     *
+     * HIR dumping: One graph after each phase (including sub phases).
+     */
+    public static final int VERBOSE_LEVEL = 3;
+
+    /**
+     * Detailed debug level.
+     *
+     * HIR dumping: Graphs within phases where interesting for a phase, max ~5 per phase.
+     */
+    public static final int DETAILED_LEVEL = 4;
+
+    /**
+     * Very detailed debug level.
+     *
+     * HIR dumping: Graphs per node granularity graph change (before/after change).
+     */
+    public static final int VERY_DETAILED_LEVEL = 5;
 
     public static boolean isDumpEnabled(int dumpLevel) {
         return ENABLED && DebugScope.getInstance().isDumpEnabled(dumpLevel);
@@ -183,7 +213,7 @@
     }
 
     public static boolean isLogEnabled() {
-        return isLogEnabled(BASIC_LOG_LEVEL);
+        return isLogEnabled(BASIC_LEVEL);
     }
 
     public static boolean isLogEnabled(int logLevel) {
@@ -420,7 +450,7 @@
     }
 
     public static void log(String msg) {
-        log(BASIC_LOG_LEVEL, msg);
+        log(BASIC_LEVEL, msg);
     }
 
     /**
@@ -435,7 +465,7 @@
     }
 
     public static void log(String format, Object arg) {
-        log(BASIC_LOG_LEVEL, format, arg);
+        log(BASIC_LEVEL, format, arg);
     }
 
     /**
@@ -451,7 +481,7 @@
     }
 
     public static void log(String format, int arg) {
-        log(BASIC_LOG_LEVEL, format, arg);
+        log(BASIC_LEVEL, format, arg);
     }
 
     /**
@@ -467,7 +497,7 @@
     }
 
     public static void log(String format, Object arg1, Object arg2) {
-        log(BASIC_LOG_LEVEL, format, arg1, arg2);
+        log(BASIC_LEVEL, format, arg1, arg2);
     }
 
     /**
@@ -480,7 +510,7 @@
     }
 
     public static void log(String format, int arg1, Object arg2) {
-        log(BASIC_LOG_LEVEL, format, arg1, arg2);
+        log(BASIC_LEVEL, format, arg1, arg2);
     }
 
     /**
@@ -493,7 +523,7 @@
     }
 
     public static void log(String format, Object arg1, int arg2) {
-        log(BASIC_LOG_LEVEL, format, arg1, arg2);
+        log(BASIC_LEVEL, format, arg1, arg2);
     }
 
     /**
@@ -506,7 +536,7 @@
     }
 
     public static void log(String format, int arg1, int arg2) {
-        log(BASIC_LOG_LEVEL, format, arg1, arg2);
+        log(BASIC_LEVEL, format, arg1, arg2);
     }
 
     /**
@@ -519,7 +549,7 @@
     }
 
     public static void log(String format, Object arg1, Object arg2, Object arg3) {
-        log(BASIC_LOG_LEVEL, format, arg1, arg2, arg3);
+        log(BASIC_LEVEL, format, arg1, arg2, arg3);
     }
 
     /**
@@ -532,7 +562,7 @@
     }
 
     public static void log(String format, int arg1, int arg2, int arg3) {
-        log(BASIC_LOG_LEVEL, format, arg1, arg2, arg3);
+        log(BASIC_LEVEL, format, arg1, arg2, arg3);
     }
 
     /**
@@ -545,7 +575,7 @@
     }
 
     public static void log(String format, Object arg1, Object arg2, Object arg3, Object arg4) {
-        log(BASIC_LOG_LEVEL, format, arg1, arg2, arg3, arg4);
+        log(BASIC_LEVEL, format, arg1, arg2, arg3, arg4);
     }
 
     /**
@@ -558,7 +588,7 @@
     }
 
     public static void log(String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5) {
-        log(BASIC_LOG_LEVEL, format, arg1, arg2, arg3, arg4, arg5);
+        log(BASIC_LEVEL, format, arg1, arg2, arg3, arg4, arg5);
     }
 
     /**
@@ -571,7 +601,7 @@
     }
 
     public static void log(String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6) {
-        log(BASIC_LOG_LEVEL, format, arg1, arg2, arg3, arg4, arg5, arg6);
+        log(BASIC_LEVEL, format, arg1, arg2, arg3, arg4, arg5, arg6);
     }
 
     /**
@@ -584,11 +614,11 @@
     }
 
     public static void log(String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7) {
-        log(BASIC_LOG_LEVEL, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
+        log(BASIC_LEVEL, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
     }
 
     public static void log(String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8) {
-        log(BASIC_LOG_LEVEL, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
+        log(BASIC_LEVEL, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
     }
 
     /**
@@ -607,7 +637,7 @@
     }
 
     public static void log(String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9) {
-        log(BASIC_LOG_LEVEL, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
+        log(BASIC_LEVEL, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
     }
 
     public static void log(int logLevel, String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9) {
@@ -617,7 +647,7 @@
     }
 
     public static void log(String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10) {
-        log(BASIC_LOG_LEVEL, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10);
+        log(BASIC_LEVEL, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10);
     }
 
     public static void log(int logLevel, String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10) {
@@ -627,7 +657,7 @@
     }
 
     public static void logv(String format, Object... args) {
-        logv(BASIC_LOG_LEVEL, format, args);
+        logv(BASIC_LEVEL, format, args);
     }
 
     /**
@@ -655,7 +685,7 @@
     @Deprecated
     public static void log(String format, Object[] args) {
         assert false : "shouldn't use this";
-        log(BASIC_LOG_LEVEL, format, args);
+        log(BASIC_LEVEL, format, args);
     }
 
     /**
@@ -670,6 +700,14 @@
         logv(logLevel, format, args);
     }
 
+    /**
+     * Forces an unconditional dump. This method exists mainly for debugging. It can also be used to
+     * force a graph dump from IDEs that support invoking a Java method while at a breakpoint.
+     */
+    public static void forceDump(Object object, String format, Object... args) {
+        DebugScope.forceDump(object, format, args);
+    }
+
     public static void dump(int dumpLevel, Object object, String msg) {
         if (ENABLED && DebugScope.getInstance().isDumpEnabled(dumpLevel)) {
             DebugScope.getInstance().dump(dumpLevel, object, msg);
@@ -771,7 +809,7 @@
     }
 
     public static Indent logAndIndent(String msg) {
-        return logAndIndent(BASIC_LOG_LEVEL, msg);
+        return logAndIndent(BASIC_LEVEL, msg);
     }
 
     /**
@@ -789,7 +827,7 @@
     }
 
     public static Indent logAndIndent(String format, Object arg) {
-        return logAndIndent(BASIC_LOG_LEVEL, format, arg);
+        return logAndIndent(BASIC_LEVEL, format, arg);
     }
 
     /**
@@ -808,7 +846,7 @@
     }
 
     public static Indent logAndIndent(String format, int arg) {
-        return logAndIndent(BASIC_LOG_LEVEL, format, arg);
+        return logAndIndent(BASIC_LEVEL, format, arg);
     }
 
     /**
@@ -827,7 +865,7 @@
     }
 
     public static Indent logAndIndent(String format, int arg1, Object arg2) {
-        return logAndIndent(BASIC_LOG_LEVEL, format, arg1, arg2);
+        return logAndIndent(BASIC_LEVEL, format, arg1, arg2);
     }
 
     /**
@@ -841,7 +879,7 @@
     }
 
     public static Indent logAndIndent(String format, Object arg1, int arg2) {
-        return logAndIndent(BASIC_LOG_LEVEL, format, arg1, arg2);
+        return logAndIndent(BASIC_LEVEL, format, arg1, arg2);
     }
 
     /**
@@ -855,7 +893,7 @@
     }
 
     public static Indent logAndIndent(String format, int arg1, int arg2) {
-        return logAndIndent(BASIC_LOG_LEVEL, format, arg1, arg2);
+        return logAndIndent(BASIC_LEVEL, format, arg1, arg2);
     }
 
     /**
@@ -869,7 +907,7 @@
     }
 
     public static Indent logAndIndent(String format, Object arg1, Object arg2) {
-        return logAndIndent(BASIC_LOG_LEVEL, format, arg1, arg2);
+        return logAndIndent(BASIC_LEVEL, format, arg1, arg2);
     }
 
     /**
@@ -883,7 +921,7 @@
     }
 
     public static Indent logAndIndent(String format, Object arg1, Object arg2, Object arg3) {
-        return logAndIndent(BASIC_LOG_LEVEL, format, arg1, arg2, arg3);
+        return logAndIndent(BASIC_LEVEL, format, arg1, arg2, arg3);
     }
 
     /**
@@ -897,7 +935,7 @@
     }
 
     public static Indent logAndIndent(String format, int arg1, int arg2, int arg3) {
-        return logAndIndent(BASIC_LOG_LEVEL, format, arg1, arg2, arg3);
+        return logAndIndent(BASIC_LEVEL, format, arg1, arg2, arg3);
     }
 
     /**
@@ -911,7 +949,7 @@
     }
 
     public static Indent logAndIndent(String format, Object arg1, int arg2, int arg3) {
-        return logAndIndent(BASIC_LOG_LEVEL, format, arg1, arg2, arg3);
+        return logAndIndent(BASIC_LEVEL, format, arg1, arg2, arg3);
     }
 
     /**
@@ -925,7 +963,7 @@
     }
 
     public static Indent logAndIndent(String format, Object arg1, Object arg2, Object arg3, Object arg4) {
-        return logAndIndent(BASIC_LOG_LEVEL, format, arg1, arg2, arg3, arg4);
+        return logAndIndent(BASIC_LEVEL, format, arg1, arg2, arg3, arg4);
     }
 
     /**
@@ -939,7 +977,7 @@
     }
 
     public static Indent logAndIndent(String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5) {
-        return logAndIndent(BASIC_LOG_LEVEL, format, arg1, arg2, arg3, arg4, arg5);
+        return logAndIndent(BASIC_LEVEL, format, arg1, arg2, arg3, arg4, arg5);
     }
 
     /**
@@ -953,7 +991,7 @@
     }
 
     public static Indent logAndIndent(String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6) {
-        return logAndIndent(BASIC_LOG_LEVEL, format, arg1, arg2, arg3, arg4, arg5, arg6);
+        return logAndIndent(BASIC_LEVEL, format, arg1, arg2, arg3, arg4, arg5, arg6);
     }
 
     /**
@@ -1001,7 +1039,7 @@
     @Deprecated
     public static void logAndIndent(String format, Object[] args) {
         assert false : "shouldn't use this";
-        logAndIndent(BASIC_LOG_LEVEL, format, args);
+        logAndIndent(BASIC_LEVEL, format, args);
     }
 
     /**
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugFilter.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugFilter.java	Thu Apr 06 14:31:32 2017 -0700
@@ -41,28 +41,28 @@
  * A filter is a list of comma-separated terms of the form {@code <pattern>[:<level>]}. {@code
  * <pattern>} is interpreted as a glob pattern if it contains a "*" or "?" character. Otherwise, it
  * is interpreted as a substring. If {@code <pattern>} is empty, it matches every scope. If {@code :
- * <level>} is omitted, it defaults to {@link Debug#BASIC_LOG_LEVEL}. The term {@code ~<pattern>} is
- * a shorthand for {@code <pattern>:0} to disable a debug facility for a pattern.
+ * <level>} is omitted, it defaults to {@link Debug#BASIC_LEVEL}. The term {@code ~<pattern>} is a
+ * shorthand for {@code <pattern>:0} to disable a debug facility for a pattern.
  * <p>
  * The resulting log level of a scope is determined by the <em>last</em> matching term. If no term
  * matches, the log level is 0 (disabled). A filter with no terms matches every scope with a log
- * level of {@link Debug#BASIC_LOG_LEVEL}.
+ * level of {@link Debug#BASIC_LEVEL}.
  *
  * <h2>Examples of filters</h2>
  *
  * <ul>
  * <li>(empty string)<br>
- * Matches any scope with log level {@link Debug#BASIC_LOG_LEVEL}.
+ * Matches any scope with log level {@link Debug#BASIC_LEVEL}.
  *
  * <li>{@code :1}<br>
  * Matches any scope with log level 1.
  *
  * <li>{@code *}<br>
- * Matches any scope with log level {@link Debug#BASIC_LOG_LEVEL}.
+ * Matches any scope with log level {@link Debug#BASIC_LEVEL}.
  *
  * <li>{@code CodeGen,CodeInstall}<br>
  * Matches scopes containing "CodeGen" or "CodeInstall", both with log level
- * {@link Debug#BASIC_LOG_LEVEL}.
+ * {@link Debug#BASIC_LEVEL}.
  *
  * <li>{@code CodeGen:2,CodeInstall:1}<br>
  * Matches scopes containing "CodeGen" with log level 2, or "CodeInstall" with log level 1.
@@ -74,10 +74,10 @@
  * Matches all scopes with log level 1, except those containing "Dead".
  *
  * <li>{@code Code*}<br>
- * Matches scopes starting with "Code" with log level {@link Debug#BASIC_LOG_LEVEL}.
+ * Matches scopes starting with "Code" with log level {@link Debug#BASIC_LEVEL}.
  *
  * <li>{@code Code,~Dead}<br>
- * Matches scopes containing "Code" but not "Dead", with log level {@link Debug#BASIC_LOG_LEVEL}.
+ * Matches scopes containing "Code" but not "Dead", with log level {@link Debug#BASIC_LEVEL}.
  * </ul>
  */
 final class DebugFilter {
@@ -108,7 +108,7 @@
                         level = 0;
                     } else {
                         pattern = t;
-                        level = Debug.BASIC_LOG_LEVEL;
+                        level = Debug.BASIC_LEVEL;
                     }
                 } else {
                     pattern = t.substring(0, idx);
@@ -119,13 +119,13 @@
                         } catch (NumberFormatException e) {
                             switch (levelString) {
                                 case "basic":
-                                    level = Debug.BASIC_LOG_LEVEL;
+                                    level = Debug.BASIC_LEVEL;
                                     break;
                                 case "info":
-                                    level = Debug.INFO_LOG_LEVEL;
+                                    level = Debug.INFO_LEVEL;
                                     break;
                                 case "verbose":
-                                    level = Debug.VERBOSE_LOG_LEVEL;
+                                    level = Debug.VERBOSE_LEVEL;
                                     break;
                                 default:
                                     throw new IllegalArgumentException("Unknown dump level: \"" + levelString + "\" expected basic, info, verbose or an integer");
@@ -133,7 +133,7 @@
                         }
 
                     } else {
-                        level = Debug.BASIC_LOG_LEVEL;
+                        level = Debug.BASIC_LEVEL;
                     }
                 }
 
@@ -147,7 +147,7 @@
      */
     public int matchLevel(String input) {
         if (terms == null) {
-            return Debug.BASIC_LOG_LEVEL;
+            return Debug.BASIC_LEVEL;
         } else {
             int level = 0;
             for (Term t : terms) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugRetryableTask.java	Thu Apr 06 14:31:32 2017 -0700
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2017, 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 org.graalvm.compiler.debug;
+
+import org.graalvm.compiler.debug.Debug.Scope;
+
+/**
+ * A mechanism for re-executing a task upon failure.
+ */
+public abstract class DebugRetryableTask<T> extends DelegatingDebugConfig {
+
+    /**
+     * Calls {@link #run} on this task and if it results in an exception, calls
+     * {@link #onRetry(Throwable)} and if that returns {@code true}, calls {@link #run}.
+     */
+    @SuppressWarnings("try")
+    public final T execute() {
+        try {
+            return run(null);
+        } catch (Throwable t) {
+            if (onRetry(t)) {
+                try (Scope d = Debug.sandbox("Retrying: " + this, this)) {
+                    return run(t);
+                } catch (Throwable t2) {
+                    throw Debug.handle(t2);
+                }
+            } else {
+                throw t;
+            }
+        }
+    }
+
+    /**
+     * Runs this task.
+     *
+     * @param failure the cause of the first execution to fail or {@code null} if this is the first
+     *            execution of {@link #run(Throwable)}
+     */
+    protected abstract T run(Throwable failure);
+
+    /**
+     * Notifies this object that the initial execution failed with exception {@code t} and is about
+     * to be re-executed. The re-execution will use this object as the active {@link DebugConfig}.
+     * As such, this method can be overridden to enable more detailed debug facilities.
+     *
+     * @param t an exception that terminated the first execution of this task
+     * @return whether this task should be re-executed. If false, {@code t} will be re-thrown.
+     */
+    protected boolean onRetry(Throwable t) {
+        return true;
+    }
+}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/GraalDebugConfig.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/GraalDebugConfig.java	Thu Apr 06 14:31:32 2017 -0700
@@ -79,7 +79,9 @@
         @Option(help = "Write debug values into a file instead of the terminal. " +
                        "If DebugValueSummary is Thread, the thread name will be prepended.", type = OptionType.Debug)
         public static final OptionKey<String> DebugValueFile = new OptionKey<>(null);
-        @Option(help = "Send Graal compiler IR to dump handlers on error", type = OptionType.Debug)
+        @Option(help = "Enable debug output for stub code generation and snippet preparation.", type = OptionType.Debug)
+        public static final OptionKey<Boolean> DebugStubsAndSnippets = new OptionKey<>(false);
+        @Option(help = "Send Graal compiler IR to dump handlers on error.", type = OptionType.Debug)
         public static final OptionKey<Boolean> DumpOnError = new OptionKey<>(false);
         @Option(help = "Intercept also bailout exceptions", type = OptionType.Debug)
         public static final OptionKey<Boolean> InterceptBailout = new OptionKey<>(false);
@@ -406,7 +408,7 @@
         if (e instanceof BailoutException && !Options.InterceptBailout.getValue(options)) {
             return null;
         }
-        Debug.setConfig(Debug.fixedConfig(options, Debug.BASIC_LOG_LEVEL, Debug.BASIC_LOG_LEVEL, false, false, false, false, false, dumpHandlers, verifyHandlers, output));
+        Debug.setConfig(Debug.fixedConfig(options, Debug.BASIC_LEVEL, Debug.BASIC_LEVEL, false, false, false, false, false, dumpHandlers, verifyHandlers, output));
         Debug.log("Exception occurred in scope: %s", Debug.currentScope());
         Map<Object, Object> firstSeen = new IdentityHashMap<>();
         for (Object o : Debug.context()) {
@@ -414,7 +416,7 @@
             if (!firstSeen.containsKey(o)) {
                 firstSeen.put(o, o);
                 if (Options.DumpOnError.getValue(options) || Options.Dump.getValue(options) != null) {
-                    Debug.dump(Debug.BASIC_LOG_LEVEL, o, "Exception: %s", e);
+                    Debug.dump(Debug.BASIC_LEVEL, o, "Exception: %s", e);
                 } else {
                     Debug.log("Context obj %s", o);
                 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/DebugScope.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/DebugScope.java	Thu Apr 06 14:31:32 2017 -0700
@@ -352,7 +352,7 @@
                 dumpHandler.dump(object, message);
             }
         } else {
-            TTY.println("Forced dump ignored because debugging is disabled - use -Dgraal.Dump=xxx");
+            TTY.println("Forced dump ignored because debugging is disabled - use -Dgraal.ForceDebugEnable=true");
         }
     }
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Graph.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Graph.java	Thu Apr 06 14:31:32 2017 -0700
@@ -405,6 +405,13 @@
         return add(node);
     }
 
+    public <T extends Node> T maybeAddOrUnique(T node) {
+        if (node.isAlive()) {
+            return node;
+        }
+        return addOrUnique(node);
+    }
+
     public <T extends Node> T addOrUniqueWithInputs(T node) {
         if (node.isAlive()) {
             assert node.graph() == this;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Node.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Node.java	Thu Apr 06 14:31:32 2017 -0700
@@ -40,6 +40,8 @@
 import java.util.function.Predicate;
 
 import org.graalvm.compiler.core.common.Fields;
+import org.graalvm.compiler.core.common.type.AbstractPointerStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.debug.DebugCloseable;
 import org.graalvm.compiler.debug.Fingerprint;
 import org.graalvm.compiler.graph.Graph.NodeEvent;
@@ -131,7 +133,9 @@
      * Denotes an injected parameter in a {@linkplain NodeIntrinsic node intrinsic} constructor. If
      * the constructor is called as part of node intrinsification, the node intrinsifier will inject
      * an argument for the annotated parameter. Injected parameters must precede all non-injected
-     * parameters in a constructor.
+     * parameters in a constructor. If the type of the annotated parameter is {@link Stamp}, the
+     * {@linkplain Stamp#javaType type} of the injected stamp is the return type of the annotated
+     * method (which cannot be {@code void}).
      */
     @java.lang.annotation.Retention(RetentionPolicy.RUNTIME)
     @java.lang.annotation.Target(ElementType.PARAMETER)
@@ -140,40 +144,45 @@
 
     /**
      * Annotates a method that can be replaced by a compiler intrinsic. A (resolved) call to the
-     * annotated method can be replaced with an instance of the node class denoted by
-     * {@link #value()}. For this reason, the signature of the annotated method must match the
-     * signature (excluding a prefix of {@linkplain InjectedNodeParameter injected} parameters) of a
-     * constructor in the node class.
+     * annotated method will be processed by a generated {@code InvocationPlugin} that calls either
+     * a factory method or a constructor corresponding with the annotated method.
      * <p>
-     * If the node class has a static method {@code intrinsify} with a matching signature plus a
-     * {@code GraphBuilderContext} as first argument, this method is called instead of creating the
-     * node.
+     * A factory method corresponding to an annotated method is a static method named
+     * {@code intrinsify} defined in the class denoted by {@link #value()}. In order, its signature
+     * is as follows:
+     * <ol>
+     * <li>A {@code GraphBuilderContext} parameter.</li>
+     * <li>A {@code ResolvedJavaMethod} parameter.</li>
+     * <li>A sequence of zero or more {@linkplain InjectedNodeParameter injected} parameters.</li>
+     * <li>Remaining parameters that match the declared parameters of the annotated method.</li>
+     * </ol>
+     * A constructor corresponding to an annotated method is defined in the class denoted by
+     * {@link #value()}. In order, its signature is as follows:
+     * <ol>
+     * <li>A sequence of zero or more {@linkplain InjectedNodeParameter injected} parameters.</li>
+     * <li>Remaining parameters that match the declared parameters of the annotated method.</li>
+     * </ol>
+     * There must be exactly one such factory method or constructor corresponding to a
+     * {@link NodeIntrinsic} annotated method.
      */
     @java.lang.annotation.Retention(RetentionPolicy.RUNTIME)
     @java.lang.annotation.Target(ElementType.METHOD)
     public static @interface NodeIntrinsic {
 
         /**
-         * Gets the {@link Node} subclass instantiated when intrinsifying a call to the annotated
-         * method. If not specified, then the class in which the annotated method is declared is
-         * used (and is assumed to be a {@link Node} subclass).
+         * The class declaring the factory method or {@link Node} subclass declaring the constructor
+         * used to intrinsify a call to the annotated method. The default value is the class in
+         * which the annotated method is declared.
          */
         Class<?> value() default NodeIntrinsic.class;
 
         /**
-         * 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}.
+         * If {@code true}, the factory method or constructor selected by the annotation must have
+         * an {@linkplain InjectedNodeParameter injected} {@link Stamp} parameter. Calling
+         * {@link AbstractPointerStamp#nonNull()} on the injected stamp is guaranteed to return
+         * {@code true}.
          */
-        boolean setStampFromReturnType() default false;
-
-        /**
-         * Determines if the stamp of the instantiated intrinsic node is guaranteed to be non-null.
-         * Generally used in conjunction with {@link #setStampFromReturnType()}.
-         */
-        boolean returnStampIsNonNull() default false;
+        boolean injectedStampIsNonNull() default false;
     }
 
     /**
@@ -304,7 +313,7 @@
      * @return an {@link NodeIterable iterable} for all non-null successor edges.
      */
     public NodeIterable<Node> successors() {
-        assert !this.isDeleted();
+        assert !this.isDeleted() : this;
         return nodeClass.getSuccessorIterable(this);
     }
 
@@ -328,7 +337,7 @@
         if (usage1 == null) {
             return 1;
         }
-        return 2 + extraUsagesCount;
+        return INLINE_USAGE_COUNT + extraUsagesCount;
     }
 
     /**
@@ -391,30 +400,45 @@
     }
 
     private void movUsageFromEndTo(int destIndex) {
-        int lastIndex = this.getUsageCount() - 1;
-        if (destIndex == 0) {
-            if (lastIndex == 0) {
-                usage0 = null;
-                return;
-            } else if (lastIndex == 1) {
-                usage0 = usage1;
-                usage1 = null;
-                return;
-            } else {
-                usage0 = extraUsages[lastIndex - INLINE_USAGE_COUNT];
-            }
+        if (destIndex >= INLINE_USAGE_COUNT) {
+            movUsageFromEndToExtraUsages(destIndex - INLINE_USAGE_COUNT);
         } else if (destIndex == 1) {
-            if (lastIndex == 1) {
-                usage1 = null;
-                return;
-            }
-            usage1 = extraUsages[lastIndex - INLINE_USAGE_COUNT];
+            movUsageFromEndToIndexOne();
         } else {
-            Node n = extraUsages[lastIndex - INLINE_USAGE_COUNT];
-            extraUsages[destIndex - INLINE_USAGE_COUNT] = n;
+            assert destIndex == 0;
+            movUsageFromEndToIndexZero();
         }
-        extraUsages[lastIndex - INLINE_USAGE_COUNT] = null;
+    }
+
+    private void movUsageFromEndToExtraUsages(int destExtraIndex) {
         this.extraUsagesCount--;
+        Node n = extraUsages[extraUsagesCount];
+        extraUsages[destExtraIndex] = n;
+        extraUsages[extraUsagesCount] = null;
+    }
+
+    private void movUsageFromEndToIndexZero() {
+        if (extraUsagesCount > 0) {
+            this.extraUsagesCount--;
+            usage0 = extraUsages[extraUsagesCount];
+            extraUsages[extraUsagesCount] = null;
+        } else if (usage1 != null) {
+            usage0 = usage1;
+            usage1 = null;
+        } else {
+            usage0 = null;
+        }
+    }
+
+    private void movUsageFromEndToIndexOne() {
+        if (extraUsagesCount > 0) {
+            this.extraUsagesCount--;
+            usage1 = extraUsages[extraUsagesCount];
+            extraUsages[extraUsagesCount] = null;
+        } else {
+            assert usage1 != null;
+            usage1 = null;
+        }
     }
 
     /**
@@ -425,20 +449,21 @@
      */
     public boolean removeUsage(Node node) {
         assert node != null;
-        // It is critical that this method maintains the invariant that
-        // the usage list has no null element preceding a non-null element
+        // For large graphs, usage removal is performance critical.
+        // Furthermore, it is critical that this method maintains the invariant that the usage list
+        // has no null element preceding a non-null element.
         incUsageModCount();
         if (usage0 == node) {
-            this.movUsageFromEndTo(0);
+            movUsageFromEndToIndexZero();
             return true;
         }
         if (usage1 == node) {
-            this.movUsageFromEndTo(1);
+            movUsageFromEndToIndexOne();
             return true;
         }
         for (int i = this.extraUsagesCount - 1; i >= 0; i--) {
             if (extraUsages[i] == node) {
-                this.movUsageFromEndTo(i + INLINE_USAGE_COUNT);
+                movUsageFromEndToExtraUsages(i);
                 return true;
             }
         }
@@ -537,8 +562,9 @@
         assert assertTrue(id == INITIAL_ID, "unexpected id: %d", id);
         this.graph = newGraph;
         newGraph.register(this);
-        this.getNodeClass().registerAtInputsAsUsage(this);
-        this.getNodeClass().registerAtSuccessorsAsPredecessor(this);
+        NodeClass<? extends Node> nc = nodeClass;
+        nc.registerAtInputsAsUsage(this);
+        nc.registerAtSuccessorsAsPredecessor(this);
     }
 
     /**
@@ -588,7 +614,7 @@
     }
 
     public final void replaceAtUsages(Node other) {
-        replaceAtUsages(other, null, null);
+        replaceAtAllUsages(other, (Node) null);
     }
 
     public final void replaceAtUsages(Node other, Predicate<Node> filter) {
@@ -606,22 +632,60 @@
     }
 
     protected void replaceAtUsages(Node other, Predicate<Node> filter, Node toBeDeleted) {
+        if (filter == null) {
+            replaceAtAllUsages(other, toBeDeleted);
+        } else {
+            replaceAtMatchingUsages(other, filter, toBeDeleted);
+        }
+    }
+
+    protected void replaceAtAllUsages(Node other, Node toBeDeleted) {
+        assert checkReplaceWith(other);
+        if (usage0 == null) {
+            return;
+        }
+        replaceAtUsage(other, toBeDeleted, usage0);
+        usage0 = null;
+
+        if (usage1 == null) {
+            return;
+        }
+        replaceAtUsage(other, toBeDeleted, usage1);
+        usage1 = null;
+
+        if (extraUsagesCount <= 0) {
+            return;
+        }
+        for (int i = 0; i < extraUsagesCount; i++) {
+            Node usage = extraUsages[i];
+            replaceAtUsage(other, toBeDeleted, usage);
+        }
+        this.extraUsages = NO_NODES;
+        this.extraUsagesCount = 0;
+    }
+
+    private void replaceAtUsage(Node other, Node toBeDeleted, Node usage) {
+        boolean result = usage.getNodeClass().replaceFirstInput(usage, this, other);
+        assert assertTrue(result, "not found in inputs, usage: %s", usage);
+        /*
+         * Don't notify for nodes which are about to be deleted.
+         */
+        if (toBeDeleted == null || usage != toBeDeleted) {
+            maybeNotifyInputChanged(usage);
+        }
+        if (other != null) {
+            other.addUsage(usage);
+        }
+    }
+
+    private void replaceAtMatchingUsages(Node other, Predicate<Node> filter, Node toBeDeleted) {
+        assert filter != null;
         assert checkReplaceWith(other);
         int i = 0;
         while (i < this.getUsageCount()) {
             Node usage = this.getUsageAt(i);
             if (filter == null || filter.test(usage)) {
-                boolean result = usage.getNodeClass().replaceFirstInput(usage, this, other);
-                assert assertTrue(result, "not found in inputs, usage: %s", usage);
-                /*
-                 * Don't notify for nodes which are about to be deleted.
-                 */
-                if (toBeDeleted == null || usage != toBeDeleted) {
-                    maybeNotifyInputChanged(usage);
-                }
-                if (other != null) {
-                    other.addUsage(usage);
-                }
+                replaceAtUsage(other, toBeDeleted, usage);
                 this.movUsageFromEndTo(i);
             } else {
                 ++i;
@@ -641,21 +705,7 @@
 
     public void replaceAtMatchingUsages(Node other, NodePredicate usagePredicate) {
         assert checkReplaceWith(other);
-        int index = 0;
-        while (index < this.getUsageCount()) {
-            Node usage = getUsageAt(index);
-            if (usagePredicate.apply(usage)) {
-                boolean result = usage.getNodeClass().replaceFirstInput(usage, this, other);
-                assert assertTrue(result, "not found in inputs, usage: %s", usage);
-                if (other != null) {
-                    maybeNotifyInputChanged(usage);
-                    other.addUsage(usage);
-                }
-                this.movUsageFromEndTo(index);
-            } else {
-                index++;
-            }
-        }
+        replaceAtMatchingUsages(other, usagePredicate, null);
     }
 
     public void replaceAtUsages(InputType type, Node other) {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeBitMap.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeBitMap.java	Thu Apr 06 14:31:32 2017 -0700
@@ -154,7 +154,7 @@
         if (bits.length < other.bits.length) {
             bits = Arrays.copyOf(bits, other.bits.length);
         }
-        for (int i = 0; i < bits.length; i++) {
+        for (int i = 0; i < Math.min(bits.length, other.bits.length); i++) {
             bits[i] |= other.bits[i];
         }
     }
@@ -181,44 +181,47 @@
         }
     }
 
-    private static class MarkedNodeIterator implements Iterator<Node> {
+    protected int nextMarkedNodeId(int fromNodeId) {
+        assert fromNodeId >= 0;
+        int wordIndex = fromNodeId >> SHIFT;
+        int wordsInUse = bits.length;
+        if (wordIndex < wordsInUse) {
+            long word = bits[wordIndex] & (0xFFFFFFFFFFFFFFFFL << fromNodeId);
+            while (true) {
+                if (word != 0) {
+                    return wordIndex * Long.SIZE + Long.numberOfTrailingZeros(word);
+                }
+                if (++wordIndex == wordsInUse) {
+                    break;
+                }
+                word = bits[wordIndex];
+            }
+        }
+        return -2;
+    }
 
-        private final NodeBitMap visited;
-        private Iterator<Node> nodes;
-        private Node nextNode;
+    private class MarkedNodeIterator implements Iterator<Node> {
+        private int nextNodeId;
 
-        MarkedNodeIterator(NodeBitMap visited, Iterator<Node> nodes) {
-            this.visited = visited;
-            this.nodes = nodes;
+        MarkedNodeIterator() {
+            nextNodeId = -1;
             forward();
         }
 
         private void forward() {
-            do {
-                if (!nodes.hasNext()) {
-                    nextNode = null;
-                    return;
-                }
-                nextNode = nodes.next();
-                if (visited.isNew(nextNode)) {
-                    nextNode = null;
-                    return;
-                }
-            } while (!visited.isMarked(nextNode));
+            nextNodeId = NodeBitMap.this.nextMarkedNodeId(nextNodeId + 1);
         }
 
         @Override
         public boolean hasNext() {
-            return nextNode != null;
+            return nextNodeId >= 0;
         }
 
         @Override
         public Node next() {
-            try {
-                return nextNode;
-            } finally {
-                forward();
-            }
+            Node result = graph.getNode(nextNodeId);
+            forward();
+            return result;
         }
 
         @Override
@@ -230,7 +233,7 @@
 
     @Override
     public Iterator<Node> iterator() {
-        return new MarkedNodeIterator(NodeBitMap.this, graph().getNodes().iterator());
+        return new MarkedNodeIterator();
     }
 
     public NodeBitMap copy() {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeClass.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeClass.java	Thu Apr 06 14:31:32 2017 -0700
@@ -599,23 +599,24 @@
     }
 
     private static boolean deepEquals0(Object e1, Object e2) {
-        assert e1 != null;
-        if (e2 == null) {
+        if (e1 == e2) {
+            return true;
+        } else if (e1 == null || e2 == null) {
             return false;
-        } else if (e1 instanceof Object[] && e2 instanceof Object[]) {
-            return Arrays.deepEquals((Object[]) e1, (Object[]) e2);
         } else if (!e1.getClass().isArray() || e1.getClass() != e2.getClass()) {
             return e1.equals(e2);
-        } else if (e1 instanceof byte[]) {
-            return Arrays.equals((byte[]) e1, (byte[]) e2);
-        } else if (e1 instanceof short[]) {
-            return Arrays.equals((short[]) e1, (short[]) e2);
+        } else if (e1 instanceof Object[] && e2 instanceof Object[]) {
+            return deepEquals((Object[]) e1, (Object[]) e2);
         } else if (e1 instanceof int[]) {
             return Arrays.equals((int[]) e1, (int[]) e2);
         } else if (e1 instanceof long[]) {
             return Arrays.equals((long[]) e1, (long[]) e2);
+        } else if (e1 instanceof byte[]) {
+            return Arrays.equals((byte[]) e1, (byte[]) e2);
         } else if (e1 instanceof char[]) {
             return Arrays.equals((char[]) e1, (char[]) e2);
+        } else if (e1 instanceof short[]) {
+            return Arrays.equals((short[]) e1, (short[]) e2);
         } else if (e1 instanceof float[]) {
             return Arrays.equals((float[]) e1, (float[]) e2);
         } else if (e1 instanceof double[]) {
@@ -627,6 +628,20 @@
         }
     }
 
+    private static boolean deepEquals(Object[] a1, Object[] a2) {
+        int length = a1.length;
+        if (a2.length != length) {
+            return false;
+        }
+
+        for (int i = 0; i < length; i++) {
+            if (!deepEquals0(a1[i], a2[i])) {
+                return false;
+            }
+        }
+        return true;
+    }
+
     public boolean dataEquals(Node a, Node b) {
         assert a.getClass() == b.getClass();
         for (int i = 0; i < data.getCount(); ++i) {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeStack.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeStack.java	Thu Apr 06 14:31:32 2017 -0700
@@ -23,14 +23,17 @@
 package org.graalvm.compiler.graph;
 
 public final class NodeStack {
-
-    private static final int INITIAL_SIZE = 8;
+    private static final int DEFAULT_INITIAL_SIZE = 8;
 
     protected Node[] values;
     public int tos;
 
     public NodeStack() {
-        values = new Node[INITIAL_SIZE];
+        this(DEFAULT_INITIAL_SIZE);
+    }
+
+    public NodeStack(int initialSize) {
+        values = new Node[initialSize];
     }
 
     public int size() {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeWorkList.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeWorkList.java	Thu Apr 06 14:31:32 2017 -0700
@@ -27,7 +27,7 @@
 import java.util.NoSuchElementException;
 import java.util.Queue;
 
-import org.graalvm.compiler.core.common.PermanentBailoutException;
+import org.graalvm.compiler.debug.Debug;
 
 public abstract class NodeWorkList implements Iterable<Node> {
 
@@ -72,26 +72,19 @@
     }
 
     public static final class IterativeNodeWorkList extends NodeWorkList {
-        private static final int HARD_ITERATION_LIMIT = 1_000_000;
         private static final int EXPLICIT_BITMAP_THRESHOLD = 10;
         protected NodeBitMap inQueue;
 
         private int iterationLimit;
-        private boolean hardLimit;
         private Node firstNoChange;
         private Node lastPull;
         private Node lastChain;
 
         public IterativeNodeWorkList(Graph graph, boolean fill, int iterationLimitPerNode) {
             super(graph, fill);
-            if (iterationLimitPerNode > 0) {
-                long limit = (long) iterationLimitPerNode * graph.getNodeCount();
-                iterationLimit = (int) Long.min(Integer.MAX_VALUE, limit);
-                hardLimit = false;
-            } else {
-                iterationLimit = HARD_ITERATION_LIMIT;
-                hardLimit = true;
-            }
+            assert iterationLimitPerNode > 0;
+            long limit = (long) iterationLimitPerNode * graph.getNodeCount();
+            iterationLimit = (int) Long.min(Integer.MAX_VALUE, limit);
         }
 
         @Override
@@ -101,11 +94,8 @@
                 public boolean hasNext() {
                     dropDeleted();
                     if (iterationLimit <= 0) {
-                        if (hardLimit) {
-                            throw new PermanentBailoutException("Iteration limit reached");
-                        } else {
-                            return false;
-                        }
+                        Debug.log(Debug.INFO_LEVEL, "Exceeded iteration limit in IterativeNodeWorkList");
+                        return false;
                     }
                     return !worklist.isEmpty();
                 }
@@ -152,7 +142,7 @@
                         }
                     }
                 }
-                assert checkInfiniteWork(node) : "Readded " + node;
+                assert checkInfiniteWork(node) : "Re-added " + node;
                 if (inQueue != null) {
                     inQueue.markAndGrow(node);
                 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/iterators/NodePredicate.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/iterators/NodePredicate.java	Thu Apr 06 14:31:32 2017 -0700
@@ -22,13 +22,20 @@
  */
 package org.graalvm.compiler.graph.iterators;
 
+import java.util.function.Predicate;
+
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.graph.iterators.NodePredicates.AndPredicate;
 
-public interface NodePredicate {
+public interface NodePredicate extends Predicate<Node> {
 
     boolean apply(Node n);
 
+    @Override
+    default boolean test(Node n) {
+        return apply(n);
+    }
+
     default NodePredicate and(NodePredicate np) {
         return new AndPredicate(this, np);
     }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/iterators/NodePredicates.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/iterators/NodePredicates.java	Thu Apr 06 14:31:32 2017 -0700
@@ -105,6 +105,7 @@
             return !a.apply(n);
         }
 
+        @Override
         public NodePredicate negate() {
             return a;
         }
@@ -148,6 +149,7 @@
             return this;
         }
 
+        @Override
         public NodePredicate negate() {
             return new NegativeTypePredicate(this);
         }
@@ -183,6 +185,7 @@
             return this;
         }
 
+        @Override
         public NodePredicate negate() {
             return new PositiveTypePredicate(this);
         }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Thu Apr 06 14:31:32 2017 -0700
@@ -557,7 +557,7 @@
             LIR lir = getResult().getLIR();
             ArrayList<LIRInstruction> instructions = lir.getLIRforBlock(lir.getControlFlowGraph().getStartBlock());
             instructions.add(1, op);
-            Debug.dump(Debug.INFO_LOG_LEVEL, lir, "created rescue dummy op");
+            Debug.dump(Debug.INFO_LEVEL, lir, "created rescue dummy op");
         }
     }
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ClassSubstitutionsTests.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ClassSubstitutionsTests.java	Thu Apr 06 14:31:32 2017 -0700
@@ -48,7 +48,7 @@
             StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
             compile(graph.method(), graph);
             assertNotInGraph(graph, Invoke.class);
-            Debug.dump(Debug.BASIC_LOG_LEVEL, graph, snippet);
+            Debug.dump(Debug.BASIC_LEVEL, graph, snippet);
             return graph;
         } catch (Throwable e) {
             throw Debug.handle(e);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorldTest.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorldTest.java	Thu Apr 06 14:31:32 2017 -0700
@@ -47,7 +47,7 @@
         System.setProperty(CompileTheWorld.LIMITMODS_PROPERTY_NAME, "java.base");
         OptionValues initialOptions = getInitialOptions();
         EconomicMap<OptionKey<?>, Object> compilationOptions = CompileTheWorld.parseOptions("Inline=false");
-        new CompileTheWorld(runtime, (HotSpotGraalCompiler) runtime.getCompiler(), CompileTheWorld.SUN_BOOT_CLASS_PATH, 1, 5, null, null, true, initialOptions, compilationOptions).compile();
+        new CompileTheWorld(runtime, (HotSpotGraalCompiler) runtime.getCompiler(), CompileTheWorld.SUN_BOOT_CLASS_PATH, 1, 5, null, null, false, initialOptions, compilationOptions).compile();
         assert ExitVMOnException.getValue(initialOptions) == originalSetting;
     }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ConstantPoolSubstitutionsTests.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ConstantPoolSubstitutionsTests.java	Thu Apr 06 14:31:32 2017 -0700
@@ -57,7 +57,7 @@
             StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
             compile(graph.method(), graph);
             assertNotInGraph(graph, Invoke.class);
-            Debug.dump(Debug.BASIC_LOG_LEVEL, graph, snippet);
+            Debug.dump(Debug.BASIC_LEVEL, graph, snippet);
             return graph;
         } catch (Throwable e) {
             throw Debug.handle(e);
@@ -117,59 +117,32 @@
         }
     }
 
-    /**
-     * Disables these tests until we know how to dynamically export the {@code jdk.internal.reflect}
-     * package from the {@code java.base} module to the unnamed module associated with
-     * {@link AsmLoader}. Without such an export, the test fails as follows:
-     *
-     * <pre>
-     * Caused by: java.lang.IllegalAccessError: class org.graalvm.compiler.hotspot.test.ConstantPoolTest
-     * (in unnamed module @0x57599b23) cannot access class jdk.internal.reflect.ConstantPool (in
-     * module java.base) because module java.base does not export jdk.internal.reflect to unnamed
-     * module @0x57599b23
-     * </pre>
-     */
-    private static void assumeJDK8() {
-        // Assume.assumeTrue(Java8OrEarlier);
-    }
-
     @Test
     public void testGetSize() {
-        assumeJDK8();
         Object cp = getConstantPoolForObject();
         test("getSize", cp);
     }
 
     @Test
     public void testGetIntAt() {
-        assumeJDK8();
         test("getIntAt");
     }
 
     @Test
     public void testGetLongAt() {
-        assumeJDK8();
         test("getLongAt");
     }
 
     @Test
     public void testGetFloatAt() {
-        assumeJDK8();
         test("getFloatAt");
     }
 
     @Test
     public void testGetDoubleAt() {
-        assumeJDK8();
         test("getDoubleAt");
     }
 
-    // @Test
-    public void testGetUTF8At() {
-        assumeJDK8();
-        test("getUTF8At");
-    }
-
     private static final String PACKAGE_NAME = ConstantPoolSubstitutionsTests.class.getPackage().getName();
     private static final String PACKAGE_NAME_INTERNAL = PACKAGE_NAME.replace('.', '/');
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/JVMCIInfopointErrorTest.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/JVMCIInfopointErrorTest.java	Thu Apr 06 14:31:32 2017 -0700
@@ -53,6 +53,7 @@
 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
 
 import jdk.vm.ci.code.BytecodeFrame;
+import jdk.vm.ci.code.CodeCacheProvider;
 import jdk.vm.ci.code.VirtualObject;
 import jdk.vm.ci.code.site.InfopointReason;
 import jdk.vm.ci.common.JVMCIError;
@@ -140,8 +141,9 @@
         graph.addAfterFixed(graph.start(), test);
 
         CompilationResult compResult = compile(method, graph);
-        HotSpotCompiledCode compiledCode = HotSpotCompiledCodeBuilder.createCompiledCode(method, null, compResult);
-        getCodeCache().addCode(method, compiledCode, null, null);
+        CodeCacheProvider codeCache = getCodeCache();
+        HotSpotCompiledCode compiledCode = HotSpotCompiledCodeBuilder.createCompiledCode(codeCache, method, null, compResult);
+        codeCache.addCode(method, compiledCode, null, null);
     }
 
     @Test(expected = JVMCIError.class)
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/LoadJavaMirrorWithKlassTest.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/LoadJavaMirrorWithKlassTest.java	Thu Apr 06 14:31:32 2017 -0700
@@ -58,7 +58,11 @@
     @Override
     @SuppressWarnings("try")
     protected Suites createSuites(OptionValues options) {
-        return super.createSuites(new OptionValues(options, GraalOptions.ImmutableCode, true));
+        return super.createSuites(getOptions());
+    }
+
+    private static OptionValues getOptions() {
+        return new OptionValues(getInitialOptions(), GraalOptions.ImmutableCode, true);
     }
 
     @Override
@@ -77,7 +81,7 @@
 
     @Test
     public void testClassConstant() {
-        test("classConstant");
+        test(getOptions(), "classConstant");
     }
 
     public static Class<?> primitiveClassConstant() {
@@ -86,7 +90,7 @@
 
     @Test
     public void testPrimitiveClassConstant() {
-        test("primitiveClassConstant");
+        test(getOptions(), "primitiveClassConstant");
     }
 
     public static Wrapper compressedClassConstant(Wrapper w) {
@@ -97,7 +101,7 @@
     @Test
     public void testCompressedClassConstant() {
         ArgSupplier arg = () -> new Wrapper();
-        test("compressedClassConstant", arg);
+        test(getOptions(), "compressedClassConstant", arg);
     }
 
     public static Wrapper compressedPrimitiveClassConstant(Wrapper w) {
@@ -108,6 +112,6 @@
     @Test
     public void testCompressedPrimitiveClassConstant() {
         ArgSupplier arg = () -> new Wrapper();
-        test("compressedPrimitiveClassConstant", arg);
+        test(getOptions(), "compressedPrimitiveClassConstant", arg);
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/RetryableCompilationTest.java	Thu Apr 06 14:31:32 2017 -0700
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2013, 2016, 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 org.graalvm.compiler.hotspot.test;
+
+import static org.graalvm.compiler.test.SubprocessUtil.formatExecutedCommand;
+import static org.graalvm.compiler.test.SubprocessUtil.getVMCommandLine;
+import static org.graalvm.compiler.test.SubprocessUtil.withoutDebuggerArguments;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.hotspot.CompilationTask;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * Tests {@link CompilationTask} support for dumping graphs and other info useful for debugging a
+ * compiler crash.
+ */
+public class RetryableCompilationTest extends GraalCompilerTest {
+    @Test
+    public void test() throws IOException {
+        List<String> args = withoutDebuggerArguments(getVMCommandLine());
+
+        args.add("-XX:+BootstrapJVMCI");
+        args.add("-XX:+UseJVMCICompiler");
+        args.add("-Dgraal.CrashAt=Object.*,String.*");
+        args.add("-version");
+
+        ProcessBuilder processBuilder = new ProcessBuilder(args);
+        processBuilder.redirectErrorStream(true);
+        Process process = processBuilder.start();
+        BufferedReader stdout = new BufferedReader(new InputStreamReader(process.getInputStream()));
+
+        String forcedCrashString = "Forced crash after compiling";
+        String diagnosticOutputFilePrefix = "Graal diagnostic output saved in ";
+
+        boolean seenForcedCrashString = false;
+        String diagnosticOutputZip = null;
+
+        List<String> outputLines = new ArrayList<>();
+
+        String line;
+        while ((line = stdout.readLine()) != null) {
+            outputLines.add(line);
+            if (line.contains(forcedCrashString)) {
+                seenForcedCrashString = true;
+            } else if (diagnosticOutputZip == null) {
+                int index = line.indexOf(diagnosticOutputFilePrefix);
+                if (index != -1) {
+                    diagnosticOutputZip = line.substring(diagnosticOutputFilePrefix.length()).trim();
+                }
+            }
+        }
+        String dashes = "-------------------------------------------------------";
+        if (!seenForcedCrashString) {
+            Assert.fail(String.format("Did not find '%s' in output of command:%n%s", forcedCrashString, formatExecutedCommand(args, outputLines, dashes, dashes)));
+        }
+        if (diagnosticOutputZip == null) {
+            Assert.fail(String.format("Did not find '%s' in output of command:%n%s", diagnosticOutputFilePrefix, formatExecutedCommand(args, outputLines, dashes, dashes)));
+        }
+
+        File zip = new File(diagnosticOutputZip).getAbsoluteFile();
+        Assert.assertTrue(zip.toString(), zip.exists());
+        try {
+            int bgv = 0;
+            int cfg = 0;
+            ZipFile dd = new ZipFile(diagnosticOutputZip);
+            List<String> entries = new ArrayList<>();
+            for (Enumeration<? extends ZipEntry> e = dd.entries(); e.hasMoreElements();) {
+                ZipEntry ze = e.nextElement();
+                String name = ze.getName();
+                entries.add(name);
+                if (name.endsWith(".bgv")) {
+                    bgv++;
+                } else if (name.endsWith(".cfg")) {
+                    cfg++;
+                }
+            }
+            if (bgv == 0) {
+                Assert.fail(String.format("Expected at least one .bgv file in %s: %s", diagnosticOutputZip, entries));
+            }
+            if (cfg == 0) {
+                Assert.fail(String.format("Expected at least one .cfg file in %s: %s", diagnosticOutputZip, entries));
+            }
+        } finally {
+            zip.delete();
+        }
+    }
+}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/WriteBarrierAdditionTest.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/WriteBarrierAdditionTest.java	Thu Apr 06 14:31:32 2017 -0700
@@ -266,7 +266,7 @@
             new GuardLoweringPhase().apply(graph, midContext);
             new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.MID_TIER).apply(graph, midContext);
             new WriteBarrierAdditionPhase(config).apply(graph);
-            Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "After Write Barrier Addition");
+            Debug.dump(Debug.BASIC_LEVEL, graph, "After Write Barrier Addition");
 
             int barriers = 0;
             if (config.useG1GC) {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationTask.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationTask.java	Thu Apr 06 14:31:32 2017 -0700
@@ -30,7 +30,20 @@
 import static org.graalvm.compiler.core.GraalCompilerOptions.PrintFilter;
 import static org.graalvm.compiler.core.GraalCompilerOptions.PrintStackTraceOnException;
 import static org.graalvm.compiler.core.phases.HighTier.Options.Inline;
+import static org.graalvm.compiler.debug.Debug.INFO_LEVEL;
+import static org.graalvm.compiler.debug.DelegatingDebugConfig.Feature.DUMP_METHOD;
+import static org.graalvm.compiler.debug.DelegatingDebugConfig.Level.DUMP;
+import static org.graalvm.compiler.debug.GraalDebugConfig.Options.Dump;
+import static org.graalvm.compiler.debug.GraalDebugConfig.Options.DumpPath;
+import static org.graalvm.compiler.debug.GraalDebugConfig.Options.ForceDebugEnable;
+import static org.graalvm.compiler.debug.GraalDebugConfig.Options.PrintCFGFileName;
+import static org.graalvm.compiler.debug.GraalDebugConfig.Options.PrintGraphFile;
+import static org.graalvm.compiler.debug.GraalDebugConfig.Options.PrintGraphFileName;
 import static org.graalvm.compiler.java.BytecodeParserOptions.InlineDuringParsing;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collection;
 import java.util.List;
 
 import org.graalvm.compiler.code.CompilationResult;
@@ -38,7 +51,9 @@
 import org.graalvm.compiler.debug.Debug.Scope;
 import org.graalvm.compiler.debug.DebugCloseable;
 import org.graalvm.compiler.debug.DebugCounter;
+import org.graalvm.compiler.debug.DebugDumpHandler;
 import org.graalvm.compiler.debug.DebugDumpScope;
+import org.graalvm.compiler.debug.DebugRetryableTask;
 import org.graalvm.compiler.debug.DebugTimer;
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.debug.Management;
@@ -46,6 +61,7 @@
 import org.graalvm.compiler.debug.TimeSource;
 import org.graalvm.compiler.options.OptionKey;
 import org.graalvm.compiler.options.OptionValues;
+import org.graalvm.compiler.printer.GraalDebugConfigCustomizer;
 import org.graalvm.util.EconomicMap;
 
 import jdk.vm.ci.code.BailoutException;
@@ -96,6 +112,136 @@
     private final boolean useProfilingInfo;
     private final OptionValues options;
 
+    final class RetryableCompilation extends DebugRetryableTask<HotSpotCompilationRequestResult> {
+        private final EventProvider.CompilationEvent compilationEvent;
+        CompilationResult result;
+
+        RetryableCompilation(EventProvider.CompilationEvent compilationEvent) {
+            this.compilationEvent = compilationEvent;
+        }
+
+        @SuppressWarnings("try")
+        @Override
+        protected HotSpotCompilationRequestResult run(Throwable retryCause) {
+            HotSpotResolvedJavaMethod method = getMethod();
+            int entryBCI = getEntryBCI();
+            final boolean isOSR = entryBCI != JVMCICompiler.INVOCATION_ENTRY_BCI;
+            CompilationStatistics stats = CompilationStatistics.create(options, method, isOSR);
+            final boolean printCompilation = PrintCompilation.getValue(options) && !TTY.isSuppressed();
+            final boolean printAfterCompilation = PrintAfterCompilation.getValue(options) && !TTY.isSuppressed();
+            if (printCompilation) {
+                TTY.println(getMethodDescription() + "...");
+            }
+
+            TTY.Filter filter = new TTY.Filter(PrintFilter.getValue(options), method);
+            final long start;
+            final long allocatedBytesBefore;
+            if (printAfterCompilation || printCompilation) {
+                final long threadId = Thread.currentThread().getId();
+                start = TimeSource.getTimeNS();
+                allocatedBytesBefore = printAfterCompilation || printCompilation ? Lazy.threadMXBean.getThreadAllocatedBytes(threadId) : 0L;
+            } else {
+                start = 0L;
+                allocatedBytesBefore = 0L;
+            }
+
+            try (Scope s = Debug.scope("Compiling", new DebugDumpScope(getIdString(), true))) {
+                // Begin the compilation event.
+                compilationEvent.begin();
+                result = compiler.compile(method, entryBCI, useProfilingInfo, compilationId, options);
+            } catch (Throwable e) {
+                throw Debug.handle(e);
+            } finally {
+                // End the compilation event.
+                compilationEvent.end();
+
+                filter.remove();
+
+                if (printAfterCompilation || printCompilation) {
+                    final long threadId = Thread.currentThread().getId();
+                    final long stop = TimeSource.getTimeNS();
+                    final long duration = (stop - start) / 1000000;
+                    final int targetCodeSize = result != null ? result.getTargetCodeSize() : -1;
+                    final int bytecodeSize = result != null ? result.getBytecodeSize() : 0;
+                    final long allocatedBytesAfter = Lazy.threadMXBean.getThreadAllocatedBytes(threadId);
+                    final long allocatedKBytes = (allocatedBytesAfter - allocatedBytesBefore) / 1024;
+
+                    if (printAfterCompilation) {
+                        TTY.println(getMethodDescription() + String.format(" | %4dms %5dB %5dB %5dkB", duration, bytecodeSize, targetCodeSize, allocatedKBytes));
+                    } else if (printCompilation) {
+                        TTY.println(String.format("%-6d JVMCI %-70s %-45s %-50s | %4dms %5dB %5dB %5dkB", getId(), "", "", "", duration, bytecodeSize, targetCodeSize, allocatedKBytes));
+                    }
+                }
+            }
+
+            if (result != null) {
+                try (DebugCloseable b = CodeInstallationTime.start()) {
+                    installMethod(result);
+                }
+            }
+            stats.finish(method, installedCode);
+            if (result != null) {
+                return HotSpotCompilationRequestResult.success(result.getBytecodeSize() - method.getCodeSize());
+            }
+            return null;
+        }
+
+        @Override
+        protected boolean onRetry(Throwable t) {
+            if (t instanceof BailoutException) {
+                return false;
+            }
+
+            if (!Debug.isEnabled()) {
+                TTY.printf("Error while processing %s.%nRe-run with -D%s%s=true to capture graph dumps upon a compilation failure.%n", CompilationTask.this,
+                                HotSpotGraalOptionValues.GRAAL_OPTION_PROPERTY_PREFIX, ForceDebugEnable.getName());
+                return false;
+            }
+
+            if (Dump.hasBeenSet(options)) {
+                // If dumping is explicitly enabled, Graal is being debugged
+                // so don't interfere with what the user is expecting to see.
+                return false;
+            }
+
+            String outputDirectory = compiler.getGraalRuntime().getOutputDirectory();
+            if (outputDirectory == null) {
+                return false;
+            }
+            String methodFQN = getMethod().format("%H.%n");
+            File dumpPath = new File(outputDirectory, methodFQN);
+            dumpPath.mkdirs();
+            if (!dumpPath.exists()) {
+                TTY.println("Warning: could not create dump directory " + dumpPath);
+                return false;
+            }
+
+            TTY.println("Retrying " + CompilationTask.this);
+            retryDumpHandlers = new ArrayList<>();
+            retryOptions = new OptionValues(options,
+                            PrintGraphFile, true,
+                            PrintCFGFileName, methodFQN,
+                            PrintGraphFileName, methodFQN,
+                            DumpPath, dumpPath.getPath());
+            override(DUMP, INFO_LEVEL).enable(DUMP_METHOD);
+            new GraalDebugConfigCustomizer().customize(this);
+            return true;
+        }
+
+        private Collection<DebugDumpHandler> retryDumpHandlers;
+        private OptionValues retryOptions;
+
+        @Override
+        public Collection<DebugDumpHandler> dumpHandlers() {
+            return retryDumpHandlers;
+        }
+
+        @Override
+        public OptionValues getOptions() {
+            return retryOptions;
+        }
+    }
+
     static class Lazy {
         /**
          * A {@link com.sun.management.ThreadMXBean} to be able to query some information about the
@@ -196,9 +342,8 @@
     public HotSpotCompilationRequestResult runCompilation() {
         HotSpotGraalRuntimeProvider graalRuntime = compiler.getGraalRuntime();
         GraalHotSpotVMConfig config = graalRuntime.getVMConfig();
-        final long threadId = Thread.currentThread().getId();
         int entryBCI = getEntryBCI();
-        final boolean isOSR = entryBCI != JVMCICompiler.INVOCATION_ENTRY_BCI;
+        boolean isOSR = entryBCI != JVMCICompiler.INVOCATION_ENTRY_BCI;
         HotSpotResolvedJavaMethod method = getMethod();
 
         // register the compilation id in the method metrics
@@ -220,64 +365,9 @@
             return null;
         }
 
-        CompilationResult result = null;
+        RetryableCompilation compilation = new RetryableCompilation(compilationEvent);
         try (DebugCloseable a = CompilationTime.start()) {
-            CompilationStatistics stats = CompilationStatistics.create(options, method, isOSR);
-            final boolean printCompilation = PrintCompilation.getValue(options) && !TTY.isSuppressed();
-            final boolean printAfterCompilation = PrintAfterCompilation.getValue(options) && !TTY.isSuppressed();
-            if (printCompilation) {
-                TTY.println(getMethodDescription() + "...");
-            }
-
-            TTY.Filter filter = new TTY.Filter(PrintFilter.getValue(options), method);
-            final long start;
-            final long allocatedBytesBefore;
-            if (printAfterCompilation || printCompilation) {
-                start = TimeSource.getTimeNS();
-                allocatedBytesBefore = printAfterCompilation || printCompilation ? Lazy.threadMXBean.getThreadAllocatedBytes(threadId) : 0L;
-            } else {
-                start = 0L;
-                allocatedBytesBefore = 0L;
-            }
-
-            try (Scope s = Debug.scope("Compiling", new DebugDumpScope(getIdString(), true))) {
-                // Begin the compilation event.
-                compilationEvent.begin();
-                result = compiler.compile(method, entryBCI, useProfilingInfo, compilationId, options);
-            } catch (Throwable e) {
-                throw Debug.handle(e);
-            } finally {
-                // End the compilation event.
-                compilationEvent.end();
-
-                filter.remove();
-
-                if (printAfterCompilation || printCompilation) {
-                    final long stop = TimeSource.getTimeNS();
-                    final long duration = (stop - start) / 1000000;
-                    final int targetCodeSize = result != null ? result.getTargetCodeSize() : -1;
-                    final int bytecodeSize = result != null ? result.getBytecodeSize() : 0;
-                    final long allocatedBytesAfter = Lazy.threadMXBean.getThreadAllocatedBytes(threadId);
-                    final long allocatedKBytes = (allocatedBytesAfter - allocatedBytesBefore) / 1024;
-
-                    if (printAfterCompilation) {
-                        TTY.println(getMethodDescription() + String.format(" | %4dms %5dB %5dB %5dkB", duration, bytecodeSize, targetCodeSize, allocatedKBytes));
-                    } else if (printCompilation) {
-                        TTY.println(String.format("%-6d JVMCI %-70s %-45s %-50s | %4dms %5dB %5dB %5dkB", getId(), "", "", "", duration, bytecodeSize, targetCodeSize, allocatedKBytes));
-                    }
-                }
-            }
-
-            if (result != null) {
-                try (DebugCloseable b = CodeInstallationTime.start()) {
-                    installMethod(result);
-                }
-            }
-            stats.finish(method, installedCode);
-            if (result != null) {
-                return HotSpotCompilationRequestResult.success(result.getBytecodeSize() - method.getCodeSize());
-            }
-            return null;
+            return compilation.execute();
         } catch (BailoutException bailout) {
             BAILOUTS.increment();
             if (ExitVMOnBailout.getValue(options)) {
@@ -319,8 +409,9 @@
             try {
                 int compiledBytecodes = 0;
                 int codeSize = 0;
-                if (result != null) {
-                    compiledBytecodes = result.getBytecodeSize();
+
+                if (compilation.result != null) {
+                    compiledBytecodes = compilation.result.getBytecodeSize();
                     CompiledBytecodes.add(compiledBytecodes);
                     if (installedCode != null) {
                         codeSize = installedCode.getSize();
@@ -334,7 +425,7 @@
                     compilationEvent.setMethod(method.format("%H.%n(%p)"));
                     compilationEvent.setCompileId(getId());
                     compilationEvent.setCompileLevel(config.compilationLevelFullOptimization);
-                    compilationEvent.setSucceeded(result != null && installedCode != null);
+                    compilationEvent.setSucceeded(compilation.result != null && installedCode != null);
                     compilationEvent.setIsOsr(isOSR);
                     compilationEvent.setCodeSize(codeSize);
                     compilationEvent.setInlinedBytes(compiledBytecodes);
@@ -387,7 +478,7 @@
         installedCode = null;
         Object[] context = {new DebugDumpScope(getIdString(), true), codeCache, getMethod(), compResult};
         try (Scope s = Debug.scope("CodeInstall", context)) {
-            HotSpotCompiledCode compiledCode = HotSpotCompiledCodeBuilder.createCompiledCode(getRequest().getMethod(), getRequest(), compResult);
+            HotSpotCompiledCode compiledCode = HotSpotCompiledCodeBuilder.createCompiledCode(codeCache, getRequest().getMethod(), getRequest(), compResult);
             installedCode = (HotSpotInstalledCode) codeCache.installCode(getRequest().getMethod(), compiledCode, null, getRequest().getMethod().getSpeculationLog(), installAsDefault);
         } catch (Throwable e) {
             throw Debug.handle(e);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java	Thu Apr 06 14:31:32 2017 -0700
@@ -267,7 +267,31 @@
     public final int secondarySuperCacheOffset = getFieldOffset("Klass::_secondary_super_cache", Integer.class, "Klass*");
     public final int secondarySupersOffset = getFieldOffset("Klass::_secondary_supers", Integer.class, "Array<Klass*>*");
 
-    public final int classMirrorOffset = getFieldOffset("Klass::_java_mirror", Integer.class, "oop");
+    public final boolean classMirrorIsHandle;
+    public final int classMirrorOffset;
+    {
+        String name = "Klass::_java_mirror";
+        int offset = -1;
+        boolean isHandle = false;
+        try {
+            offset = getFieldOffset(name, Integer.class, "oop");
+        } catch (JVMCIError e) {
+
+        }
+        if (offset == -1) {
+            try {
+                offset = getFieldOffset(name, Integer.class, "jobject");
+                isHandle = true;
+            } catch (JVMCIError e) {
+
+            }
+        }
+        if (offset == -1) {
+            throw new JVMCIError("cannot get offset of field " + name + " with type oop or jobject");
+        }
+        classMirrorOffset = offset;
+        classMirrorIsHandle = isHandle;
+    }
 
     public final int klassSuperKlassOffset = getFieldOffset("Klass::_super", Integer.class, "Klass*");
     public final int klassModifierFlagsOffset = getFieldOffset("Klass::_modifier_flags", Integer.class, "jint");
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackend.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackend.java	Thu Apr 06 14:31:32 2017 -0700
@@ -406,7 +406,7 @@
     @Override
     public CompiledCode createCompiledCode(ResolvedJavaMethod method, CompilationRequest compilationRequest, CompilationResult compResult) {
         HotSpotCompilationRequest compRequest = compilationRequest instanceof HotSpotCompilationRequest ? (HotSpotCompilationRequest) compilationRequest : null;
-        return HotSpotCompiledCodeBuilder.createCompiledCode(method, compRequest, compResult);
+        return HotSpotCompiledCodeBuilder.createCompiledCode(getCodeCache(), method, compRequest, compResult);
     }
 
     @Override
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotCompiledCodeBuilder.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotCompiledCodeBuilder.java	Thu Apr 06 14:31:32 2017 -0700
@@ -42,6 +42,7 @@
 import org.graalvm.compiler.code.SourceMapping;
 import org.graalvm.compiler.graph.NodeSourcePosition;
 
+import jdk.vm.ci.code.CodeCacheProvider;
 import jdk.vm.ci.code.DebugInfo;
 import jdk.vm.ci.code.StackSlot;
 import jdk.vm.ci.code.site.ConstantReference;
@@ -61,13 +62,13 @@
 
 public class HotSpotCompiledCodeBuilder {
 
-    public static HotSpotCompiledCode createCompiledCode(ResolvedJavaMethod method, HotSpotCompilationRequest compRequest, CompilationResult compResult) {
+    public static HotSpotCompiledCode createCompiledCode(CodeCacheProvider codeCache, ResolvedJavaMethod method, HotSpotCompilationRequest compRequest, CompilationResult compResult) {
         String name = compResult.getName();
 
         byte[] targetCode = compResult.getTargetCode();
         int targetCodeSize = compResult.getTargetCodeSize();
 
-        Site[] sites = getSortedSites(compResult);
+        Site[] sites = getSortedSites(codeCache, compResult);
 
         Assumption[] assumptions = compResult.getAssumptions();
 
@@ -201,7 +202,7 @@
      * {@code DebugInformationRecorder::add_new_pc_offset}). In addition, it expects
      * {@link Infopoint} PCs to be unique.
      */
-    private static Site[] getSortedSites(CompilationResult target) {
+    private static Site[] getSortedSites(CodeCacheProvider codeCache, CompilationResult target) {
         List<Site> sites = new ArrayList<>(
                         target.getExceptionHandlers().size() + target.getInfopoints().size() + target.getDataPatches().size() + target.getMarks().size() + target.getSourceMappings().size());
         sites.addAll(target.getExceptionHandlers());
@@ -214,9 +215,11 @@
          * can really be represented and recording the end PC seems to give the best results and
          * corresponds with what C1 and C2 do.
          */
-        for (SourceMapping source : target.getSourceMappings()) {
-            sites.add(new Infopoint(source.getEndOffset(), new DebugInfo(source.getSourcePosition()), InfopointReason.BYTECODE_POSITION));
-            assert verifySourcePositionReceivers(source.getSourcePosition());
+        if (codeCache.shouldDebugNonSafepoints()) {
+            for (SourceMapping source : target.getSourceMappings()) {
+                sites.add(new Infopoint(source.getEndOffset(), new DebugInfo(source.getSourcePosition()), InfopointReason.BYTECODE_POSITION));
+                assert verifySourcePositionReceivers(source.getSourcePosition());
+            }
         }
 
         SiteComparator c = new SiteComparator();
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotDebugInfoBuilder.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotDebugInfoBuilder.java	Thu Apr 06 14:31:32 2017 -0700
@@ -71,8 +71,8 @@
         VirtualStackSlot slot = lockStack.makeLockSlot(lockDepth);
         ValueNode lock = state.lockAt(lockIndex);
         JavaValue object = toJavaValue(lock);
-        boolean eliminated = object instanceof VirtualObject || state.monitorIdAt(lockIndex) == null;
-        assert state.monitorIdAt(lockIndex) == null || state.monitorIdAt(lockIndex).getLockDepth() == lockDepth;
+        boolean eliminated = object instanceof VirtualObject || state.monitorIdAt(lockIndex).isEliminated();
+        assert state.monitorIdAt(lockIndex).getLockDepth() == lockDepth;
         return new StackLockValue(object, slot, eliminated);
     }
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompiler.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompiler.java	Thu Apr 06 14:31:32 2017 -0700
@@ -24,6 +24,7 @@
 
 import static org.graalvm.compiler.core.common.GraalOptions.OptAssumptions;
 import static org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.ROOT_COMPILATION;
+
 import java.io.ByteArrayOutputStream;
 import java.io.PrintStream;
 import java.util.Formattable;
@@ -98,6 +99,9 @@
     @Override
     @SuppressWarnings("try")
     public CompilationRequestResult compileMethod(CompilationRequest request) {
+        if (graalRuntime.isShutdown()) {
+            return HotSpotCompilationRequestResult.failure(String.format("Shutdown entered"), false);
+        }
         OptionValues options = graalRuntime.getOptions();
         if (graalRuntime.isBootstrapping()) {
             if (GraalDebugConfig.Options.BootstrapInitializeOnly.getValue(options)) {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompilerFactory.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompilerFactory.java	Thu Apr 06 14:31:32 2017 -0700
@@ -45,6 +45,7 @@
 public final class HotSpotGraalCompilerFactory extends HotSpotJVMCICompilerFactory {
 
     private static MethodFilter[] graalCompileOnlyFilter;
+    private static boolean compileGraalWithC1Only;
 
     private final HotSpotGraalJVMCIServiceLocator locator;
 
@@ -67,18 +68,17 @@
         JVMCIVersionCheck.check(false);
         assert options == null : "cannot select " + getClass() + " service more than once";
         options = HotSpotGraalOptionValues.HOTSPOT_OPTIONS;
-        initializeGraalCompileOnlyFilter(options);
-        if (graalCompileOnlyFilter != null || !Options.UseTrivialPrefixes.getValue(options)) {
-            /*
-             * Exercise this code path early to encourage loading now. This doesn't solve problem of
-             * deadlock during class loading but seems to eliminate it in practice.
-             */
-            adjustCompilationLevelInternal(Object.class, "hashCode", "()I", CompilationLevel.FullOptimization);
-            adjustCompilationLevelInternal(Object.class, "hashCode", "()I", CompilationLevel.Simple);
-        }
+        initializeGraalCompilePolicyFields(options);
+        /*
+         * Exercise this code path early to encourage loading now. This doesn't solve problem of
+         * deadlock during class loading but seems to eliminate it in practice.
+         */
+        adjustCompilationLevelInternal(Object.class, "hashCode", "()I", CompilationLevel.FullOptimization);
+        adjustCompilationLevelInternal(Object.class, "hashCode", "()I", CompilationLevel.Simple);
     }
 
-    private static void initializeGraalCompileOnlyFilter(OptionValues options) {
+    private static void initializeGraalCompilePolicyFields(OptionValues options) {
+        compileGraalWithC1Only = Options.CompileGraalWithC1Only.getValue(options);
         String optionValue = Options.GraalCompileOnly.getValue(options);
         if (optionValue != null) {
             MethodFilter[] filter = MethodFilter.parse(optionValue);
@@ -101,9 +101,6 @@
         @Option(help = "In tiered mode compile Graal and JVMCI using optimized first tier code.", type = OptionType.Expert)
         public static final OptionKey<Boolean> CompileGraalWithC1Only = new OptionKey<>(true);
 
-        @Option(help = "Hook into VM-level mechanism for denoting compilations to be performed in first tier.", type = OptionType.Expert)
-        public static final OptionKey<Boolean> UseTrivialPrefixes = new OptionKey<>(false);
-
         @Option(help = "A method filter selecting what should be compiled by Graal.  All other requests will be reduced to CompilationLevel.Simple.", type = OptionType.Expert)
         public static final OptionKey<String> GraalCompileOnly = new OptionKey<>(null);
         // @formatter:on
@@ -137,27 +134,15 @@
     }
 
     @Override
-    public String[] getTrivialPrefixes() {
-        if (Options.UseTrivialPrefixes.getValue(options)) {
-            if (Options.CompileGraalWithC1Only.getValue(options)) {
-                return new String[]{"jdk/vm/ci", "org/graalvm/compiler", "com/oracle/graal"};
-            }
-        }
-        return null;
-    }
-
-    @Override
     public CompilationLevelAdjustment getCompilationLevelAdjustment() {
         if (graalCompileOnlyFilter != null) {
             return CompilationLevelAdjustment.ByFullSignature;
         }
-        if (!Options.UseTrivialPrefixes.getValue(options)) {
-            if (Options.CompileGraalWithC1Only.getValue(options)) {
-                // We only decide using the class declaring the method
-                // so no need to have the method name and signature
-                // symbols converted to a String.
-                return CompilationLevelAdjustment.ByHolder;
-            }
+        if (compileGraalWithC1Only) {
+            // We only decide using the class declaring the method
+            // so no need to have the method name and signature
+            // symbols converted to a String.
+            return CompilationLevelAdjustment.ByHolder;
         }
         return CompilationLevelAdjustment.None;
     }
@@ -193,10 +178,12 @@
                 return CompilationLevel.Simple;
             }
         }
-        if (level.ordinal() > CompilationLevel.Simple.ordinal()) {
-            String declaringClassName = declaringClass.getName();
-            if (declaringClassName.startsWith("jdk.vm.ci") || declaringClassName.startsWith("org.graalvm.compiler") || declaringClassName.startsWith("com.oracle.graal")) {
-                return CompilationLevel.Simple;
+        if (compileGraalWithC1Only) {
+            if (level.ordinal() > CompilationLevel.Simple.ordinal()) {
+                String declaringClassName = declaringClass.getName();
+                if (declaringClassName.startsWith("jdk.vm.ci") || declaringClassName.startsWith("org.graalvm") || declaringClassName.startsWith("com.oracle.graal")) {
+                    return CompilationLevel.Simple;
+                }
             }
         }
         return level;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalJVMCIServiceLocator.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalJVMCIServiceLocator.java	Thu Apr 06 14:31:32 2017 -0700
@@ -30,68 +30,77 @@
 import org.graalvm.compiler.serviceprovider.ServiceProvider;
 
 import jdk.vm.ci.hotspot.HotSpotVMEventListener;
-import jdk.vm.ci.runtime.JVMCICompiler;
 import jdk.vm.ci.runtime.JVMCICompilerFactory;
 import jdk.vm.ci.services.JVMCIServiceLocator;
+import jdk.vm.ci.services.Services;
 
 @ServiceProvider(JVMCIServiceLocator.class)
 public final class HotSpotGraalJVMCIServiceLocator extends JVMCIServiceLocator {
 
-    private boolean exportsAdded;
+    /**
+     * Holds the state shared between all {@link HotSpotGraalJVMCIServiceLocator} instances. This is
+     * necessary as {@link Services} can create a new instance of a service provider each time
+     * {@link Services#load(Class)} or {@link Services#loadSingle(Class, boolean)} is called.
+     */
+    private static final class Shared {
+        static final Shared SINGLETON = new Shared();
 
-    /**
-     * Dynamically exports and opens various internal JDK packages to the Graal module. This
-     * requires only a single {@code --add-exports=java.base/jdk.internal.module=<Graal module>} on
-     * the VM command line instead of a {@code --add-exports} instance for each JDK internal package
-     * used by Graal.
-     */
-    private void addExports() {
-        if (JAVA_SPECIFICATION_VERSION >= 9 && !exportsAdded) {
-            Object javaBaseModule = getModule.invoke(String.class);
-            Object graalModule = getModule.invoke(getClass());
-            addExports.invokeStatic(javaBaseModule, "jdk.internal.misc", graalModule);
-            addExports.invokeStatic(javaBaseModule, "jdk.internal.jimage", graalModule);
-            addExports.invokeStatic(javaBaseModule, "com.sun.crypto.provider", graalModule);
-            addOpens.invokeStatic(javaBaseModule, "jdk.internal.misc", graalModule);
-            addOpens.invokeStatic(javaBaseModule, "jdk.internal.jimage", graalModule);
-            addOpens.invokeStatic(javaBaseModule, "com.sun.crypto.provider", graalModule);
-            exportsAdded = true;
+        private boolean exportsAdded;
+
+        /**
+         * Dynamically exports and opens various internal JDK packages to the Graal module. This
+         * requires only a single {@code --add-exports=java.base/jdk.internal.module=<Graal module>}
+         * on the VM command line instead of a {@code --add-exports} instance for each JDK internal
+         * package used by Graal.
+         */
+        private void addExports() {
+            if (JAVA_SPECIFICATION_VERSION >= 9 && !exportsAdded) {
+                Object javaBaseModule = getModule.invoke(String.class);
+                Object graalModule = getModule.invoke(getClass());
+                addExports.invokeStatic(javaBaseModule, "jdk.internal.misc", graalModule);
+                addExports.invokeStatic(javaBaseModule, "jdk.internal.jimage", graalModule);
+                addExports.invokeStatic(javaBaseModule, "com.sun.crypto.provider", graalModule);
+                addOpens.invokeStatic(javaBaseModule, "jdk.internal.misc", graalModule);
+                addOpens.invokeStatic(javaBaseModule, "jdk.internal.jimage", graalModule);
+                addOpens.invokeStatic(javaBaseModule, "com.sun.crypto.provider", graalModule);
+                exportsAdded = true;
+            }
+        }
+
+        <T> T getProvider(Class<T> service, HotSpotGraalJVMCIServiceLocator locator) {
+            if (service == JVMCICompilerFactory.class) {
+                addExports();
+                return service.cast(new HotSpotGraalCompilerFactory(locator));
+            } else if (service == HotSpotVMEventListener.class) {
+                if (graalRuntime != null) {
+                    addExports();
+                    return service.cast(new HotSpotGraalVMEventListener(graalRuntime));
+                }
+            }
+            return null;
+        }
+
+        private HotSpotGraalRuntime graalRuntime;
+
+        /**
+         * Notifies this object of the compiler created via {@link HotSpotGraalJVMCIServiceLocator}.
+         */
+        void onCompilerCreation(HotSpotGraalCompiler compiler) {
+            assert this.graalRuntime == null : "only expect a single JVMCICompiler to be created";
+            this.graalRuntime = (HotSpotGraalRuntime) compiler.getGraalRuntime();
         }
     }
 
-    private HotSpotGraalRuntime graalRuntime;
-
     @Override
     public <T> T getProvider(Class<T> service) {
-        if (service == JVMCICompilerFactory.class) {
-            addExports();
-            return service.cast(new HotSpotGraalCompilerFactory(this));
-        } else if (service == HotSpotVMEventListener.class) {
-            if (graalRuntime != null) {
-                addExports();
-                return service.cast(new HotSpotGraalVMEventListener(graalRuntime));
-            }
-        }
-        return null;
+        return Shared.SINGLETON.getProvider(service, this);
     }
 
     /**
-     * The signature cannot mention HotSpotGraalCompiler since it indirectly references
-     * JVMCICompiler which is in a non-exported JVMCI package. This causes an IllegalAccessError
-     * while looking for the
-     * <a href="http://hg.openjdk.java.net/jdk9/hs/jdk/rev/89ef4b822745#l32.65">provider</a> factory
-     * method:
-     *
-     * <pre>
-     * java.util.ServiceConfigurationError: jdk.vm.ci.services.JVMCIServiceLocator: Unable to get public provider() method
-     * ...
-     * Caused by: java.lang.IllegalAccessError: superinterface check failed: class org.graalvm.compiler.api.runtime.GraalJVMCICompiler
-     * (in module org.graalvm.compiler.graal_core) cannot access class jdk.vm.ci.runtime.JVMCICompiler (in module jdk.vm.ci) because
-     * module jdk.vm.ci does not export jdk.vm.ci.runtime to module org.graalvm.compiler.graal_core
-     * </pre>
+     * Notifies this object of the compiler created via {@link HotSpotGraalJVMCIServiceLocator}.
      */
-    void onCompilerCreation(JVMCICompiler compiler) {
-        assert this.graalRuntime == null : "only expect a single JVMCICompiler to be created";
-        this.graalRuntime = (HotSpotGraalRuntime) ((HotSpotGraalCompiler) compiler).getGraalRuntime();
+    @SuppressWarnings("static-method")
+    void onCompilerCreation(HotSpotGraalCompiler compiler) {
+        Shared.SINGLETON.onCompilerCreation(compiler);
     }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java	Thu Apr 06 14:31:32 2017 -0700
@@ -34,8 +34,22 @@
 import static org.graalvm.compiler.debug.GraalDebugConfig.Options.MethodFilter;
 import static org.graalvm.compiler.debug.GraalDebugConfig.Options.Verify;
 
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.lang.management.ManagementFactory;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
+import java.util.zip.Deflater;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
 
 import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
 import org.graalvm.compiler.api.runtime.GraalRuntime;
@@ -278,6 +292,7 @@
     }
 
     private long runtimeStartTime;
+    private boolean shutdown;
 
     /**
      * Take action related to entering a new execution phase.
@@ -291,6 +306,7 @@
     }
 
     void shutdown() {
+        shutdown = true;
         if (debugValuesPrinter != null) {
             debugValuesPrinter.printDebugValues(options);
         }
@@ -302,6 +318,8 @@
             }
         }
         BenchmarkCounters.shutdown(runtime(), options, runtimeStartTime);
+
+        archiveAndDeleteOutputDirectory();
     }
 
     void clearMeters() {
@@ -321,4 +339,95 @@
     public boolean isBootstrapping() {
         return bootstrapJVMCI && !bootstrapFinished;
     }
+
+    @Override
+    public boolean isShutdown() {
+        return shutdown;
+    }
+
+    /**
+     * Gets a unique identifier for this execution such as a process ID.
+     */
+    private static String getExecutionID() {
+        String runtimeName = ManagementFactory.getRuntimeMXBean().getName();
+        try {
+            int index = runtimeName.indexOf('@');
+            if (index != -1) {
+                long pid = Long.parseLong(runtimeName.substring(0, index));
+                return Long.toString(pid);
+            }
+        } catch (NumberFormatException e) {
+        }
+        return runtimeName;
+    }
+
+    private String outputDirectory;
+
+    @Override
+    public String getOutputDirectory() {
+        if (outputDirectory == null) {
+            outputDirectory = "graal_output_" + getExecutionID();
+            File dir = new File(outputDirectory).getAbsoluteFile();
+            if (!dir.exists()) {
+                dir.mkdirs();
+                if (!dir.exists()) {
+                    TTY.println("Warning: could not create Graal diagnostic directory " + dir);
+                    return null;
+                }
+            }
+        }
+        return outputDirectory;
+    }
+
+    /**
+     * Archives and deletes the {@linkplain #getOutputDirectory() output directory} if it exists.
+     */
+    private void archiveAndDeleteOutputDirectory() {
+        if (outputDirectory != null) {
+            Path dir = Paths.get(outputDirectory);
+            if (dir.toFile().exists()) {
+                try {
+                    // Give compiler threads a chance to finishing dumping
+                    Thread.sleep(1000);
+                } catch (InterruptedException e1) {
+                }
+                File zip = new File(outputDirectory + ".zip").getAbsoluteFile();
+                List<Path> toDelete = new ArrayList<>();
+                try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zip))) {
+                    zos.setLevel(Deflater.BEST_COMPRESSION);
+                    Files.walkFileTree(dir, Collections.emptySet(), Integer.MAX_VALUE, new SimpleFileVisitor<Path>() {
+                        @Override
+                        public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+                            if (attrs.isRegularFile()) {
+                                ZipEntry ze = new ZipEntry(file.toString());
+                                zos.putNextEntry(ze);
+                                zos.write(Files.readAllBytes(file));
+                                zos.closeEntry();
+                            }
+                            toDelete.add(file);
+                            return FileVisitResult.CONTINUE;
+                        }
+
+                        @Override
+                        public FileVisitResult postVisitDirectory(Path d, IOException exc) throws IOException {
+                            toDelete.add(d);
+                            return FileVisitResult.CONTINUE;
+                        }
+                    });
+                    TTY.println("Graal diagnostic output saved in %s", zip);
+                } catch (IOException e) {
+                    TTY.printf("IO error archiving %s:%n", dir);
+                    e.printStackTrace(TTY.out);
+                }
+                for (Path p : toDelete) {
+                    try {
+                        Files.delete(p);
+                    } catch (IOException e) {
+                        TTY.printf("IO error deleting %s:%n", p);
+                        e.printStackTrace(TTY.out);
+                    }
+                }
+            }
+        }
+    }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntimeProvider.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntimeProvider.java	Thu Apr 06 14:31:32 2017 -0700
@@ -62,4 +62,19 @@
      * Determines if the VM is currently bootstrapping the JVMCI compiler.
      */
     boolean isBootstrapping();
+
+    /**
+     * This runtime has been requested to shutdown.
+     */
+    boolean isShutdown();
+
+    /**
+     * Gets a directory into which diagnostics such crash reports and dumps should be written. This
+     * method will create the directory if it doesn't exist so it should only be called if
+     * diagnostics are about to be generated.
+     *
+     * @return the directory into which diagnostics can be written or {@code null} if the directory
+     *         does not exist and could not be created
+     */
+    String getOutputDirectory();
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalVMEventListener.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalVMEventListener.java	Thu Apr 06 14:31:32 2017 -0700
@@ -46,10 +46,10 @@
 
     @Override
     public void notifyInstall(HotSpotCodeCacheProvider codeCache, InstalledCode installedCode, CompiledCode compiledCode) {
-        if (Debug.isDumpEnabled(Debug.BASIC_LOG_LEVEL)) {
+        if (Debug.isDumpEnabled(Debug.BASIC_LEVEL)) {
             CompilationResult compResult = Debug.contextLookup(CompilationResult.class);
             assert compResult != null : "can't dump installed code properly without CompilationResult";
-            Debug.dump(Debug.BASIC_LOG_LEVEL, installedCode, "After code installation");
+            Debug.dump(Debug.BASIC_LEVEL, installedCode, "After code installation");
         }
         if (Debug.isLogEnabled()) {
             Debug.log("%s", codeCache.disassemble(installedCode));
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/PrintStreamOptionKey.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/PrintStreamOptionKey.java	Thu Apr 06 14:31:32 2017 -0700
@@ -45,7 +45,7 @@
     }
 
     /**
-     * Replace any instance of %p with a an identifying name. Try to get it from the RuntimeMXBean
+     * Replace any instance of %p with an identifying name. Try to get it from the RuntimeMXBean
      * name.
      *
      * @return the name of the file to log to
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java	Thu Apr 06 14:31:32 2017 -0700
@@ -31,6 +31,7 @@
 import static org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProviderImpl.OSR_MIGRATION_END;
 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.CLASS_KLASS_LOCATION;
 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.CLASS_MIRROR_LOCATION;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.CLASS_MIRROR_HANDLE_LOCATION;
 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.COMPRESSED_HUB_LOCATION;
 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.DISPLACED_MARK_WORD_LOCATION;
 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.HUB_LOCATION;
@@ -40,6 +41,7 @@
 import java.lang.ref.Reference;
 
 import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.core.common.GraalOptions;
 import org.graalvm.compiler.core.common.LocationIdentity;
 import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
 import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
@@ -409,10 +411,17 @@
             return;
         }
 
+        ValueNode hub = n.getHub();
+        GraalHotSpotVMConfig vmConfig = runtime.getVMConfig();
         StructuredGraph graph = n.graph();
-        assert !n.getHub().isConstant();
-        AddressNode address = createOffsetAddress(graph, n.getHub(), runtime.getVMConfig().classMirrorOffset);
-        FloatingReadNode read = graph.unique(new FloatingReadNode(address, CLASS_MIRROR_LOCATION, null, n.stamp(), null, BarrierType.NONE));
+        assert !hub.isConstant() || GraalOptions.ImmutableCode.getValue(graph.getOptions());
+        AddressNode mirrorAddress = createOffsetAddress(graph, hub, vmConfig.classMirrorOffset);
+        FloatingReadNode read = graph.unique(new FloatingReadNode(mirrorAddress, CLASS_MIRROR_LOCATION, null, vmConfig.classMirrorIsHandle ? StampFactory.forKind(target.wordJavaKind) : n.stamp(),
+                        null, BarrierType.NONE));
+        if (vmConfig.classMirrorIsHandle) {
+            AddressNode address = createOffsetAddress(graph, read, 0);
+            read = graph.unique(new FloatingReadNode(address, CLASS_MIRROR_HANDLE_LOCATION, null, n.stamp(), null, BarrierType.NONE));
+        }
         n.replaceAtUsagesAndDelete(read);
     }
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java	Thu Apr 06 14:31:32 2017 -0700
@@ -323,7 +323,8 @@
      */
     private static ValueNode getMetaspaceConstantPool(GraphBuilderContext b, ValueNode constantPoolOop, WordTypes wordTypes, GraalHotSpotVMConfig config) {
         // ConstantPool.constantPoolOop is in fact the holder class.
-        ClassGetHubNode klass = b.add(new ClassGetHubNode(b.nullCheckedValue(constantPoolOop, DeoptimizationAction.None)));
+        ValueNode value = b.nullCheckedValue(constantPoolOop, DeoptimizationAction.None);
+        ValueNode klass = b.add(ClassGetHubNode.create(value, b.getMetaAccess(), b.getConstantReflection(), false));
 
         boolean notCompressible = false;
         AddressNode constantsAddress = b.add(new OffsetAddressNode(klass, b.add(ConstantNode.forLong(config.instanceKlassConstantsOffset))));
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotSuitesProvider.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotSuitesProvider.java	Thu Apr 06 14:31:32 2017 -0700
@@ -90,7 +90,7 @@
 
         if (ImmutableCode.getValue(options)) {
             // lowering introduces class constants, therefore it must be after lowering
-            ret.getHighTier().appendPhase(new LoadJavaMirrorWithKlassPhase(config.classMirrorOffset, config.useCompressedOops ? config.getOopEncoding() : null));
+            ret.getHighTier().appendPhase(new LoadJavaMirrorWithKlassPhase(config));
             if (VerifyPhases.getValue(options)) {
                 ret.getHighTier().appendPhase(new AheadOfTimeVerificationPhase());
             }
@@ -146,10 +146,10 @@
             protected void run(StructuredGraph graph, HighTierContext context) {
                 EncodedGraph encodedGraph = GraphEncoder.encodeSingleGraph(graph, runtime.getTarget().arch);
 
-                SimplifyingGraphDecoder graphDecoder = new SimplifyingGraphDecoder(context.getMetaAccess(), context.getConstantReflection(), context.getConstantFieldProvider(),
-                                context.getStampProvider(), !ImmutableCode.getValue(graph.getOptions()), runtime.getTarget().arch);
                 StructuredGraph targetGraph = new StructuredGraph.Builder(graph.getOptions(), AllowAssumptions.YES).method(graph.method()).build();
-                graphDecoder.decode(targetGraph, encodedGraph);
+                SimplifyingGraphDecoder graphDecoder = new SimplifyingGraphDecoder(runtime.getTarget().arch, targetGraph, context.getMetaAccess(), context.getConstantReflection(),
+                                context.getConstantFieldProvider(), context.getStampProvider(), !ImmutableCode.getValue(graph.getOptions()));
+                graphDecoder.decode(encodedGraph);
             }
 
             @Override
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotWordOperationPlugin.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotWordOperationPlugin.java	Thu Apr 06 14:31:32 2017 -0700
@@ -109,7 +109,7 @@
                 PointerEqualsNode comparison = b.add(new PointerEqualsNode(left, right));
                 ValueNode eqValue = b.add(forBoolean(opcode == POINTER_EQ));
                 ValueNode neValue = b.add(forBoolean(opcode == POINTER_NE));
-                b.addPush(returnKind, new ConditionalNode(comparison, eqValue, neValue));
+                b.addPush(returnKind, ConditionalNode.create(comparison, eqValue, neValue));
                 break;
 
             case IS_NULL:
@@ -118,7 +118,7 @@
                 assert pointer.stamp() instanceof MetaspacePointerStamp;
 
                 LogicNode isNull = b.add(IsNullNode.create(pointer));
-                b.addPush(returnKind, new ConditionalNode(isNull, b.add(forBoolean(true)), b.add(forBoolean(false))));
+                b.addPush(returnKind, ConditionalNode.create(isNull, b.add(forBoolean(true)), b.add(forBoolean(false))));
                 break;
 
             case FROM_POINTER:
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/GraalHotSpotVMConfigNode.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/GraalHotSpotVMConfigNode.java	Thu Apr 06 14:31:32 2017 -0700
@@ -29,6 +29,7 @@
 
 import org.graalvm.compiler.api.replacements.Fold;
 import org.graalvm.compiler.api.replacements.Fold.InjectedParameter;
+import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.graph.NodeClass;
@@ -72,8 +73,8 @@
      * @param config
      * @param markId id of the config value
      */
-    public GraalHotSpotVMConfigNode(@InjectedNodeParameter GraalHotSpotVMConfig config, int markId) {
-        super(TYPE, StampFactory.forNodeIntrinsic());
+    public GraalHotSpotVMConfigNode(@InjectedNodeParameter Stamp stamp, @InjectedNodeParameter GraalHotSpotVMConfig config, int markId) {
+        super(TYPE, stamp);
         this.config = config;
         this.markId = markId;
     }
@@ -85,7 +86,7 @@
      * @param markId id of the config value
      * @param kind explicit type of the node
      */
-    public GraalHotSpotVMConfigNode(@InjectedNodeParameter GraalHotSpotVMConfig config, int markId, JavaKind kind) {
+    public GraalHotSpotVMConfigNode(GraalHotSpotVMConfig config, int markId, JavaKind kind) {
         super(TYPE, StampFactory.forKind(kind));
         this.config = config;
         this.markId = markId;
@@ -100,13 +101,13 @@
     @NodeIntrinsic
     private static native boolean areConfigValuesConstant();
 
-    @NodeIntrinsic(setStampFromReturnType = true)
+    @NodeIntrinsic
     private static native long loadLongConfigValue(@ConstantNodeParameter int markId);
 
-    @NodeIntrinsic(setStampFromReturnType = true)
+    @NodeIntrinsic
     private static native int loadIntConfigValue(@ConstantNodeParameter int markId);
 
-    @NodeIntrinsic(setStampFromReturnType = true)
+    @NodeIntrinsic
     private static native byte loadByteConfigValue(@ConstantNodeParameter int markId);
 
     public static long cardTableAddress() {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/StubForeignCallNode.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/StubForeignCallNode.java	Thu Apr 06 14:31:32 2017 -0700
@@ -32,7 +32,7 @@
 import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
 import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
 import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
-import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.graph.NodeInputList;
 import org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil;
@@ -44,7 +44,6 @@
 import org.graalvm.compiler.nodes.spi.LIRLowerable;
 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
 
-import jdk.vm.ci.meta.JavaKind;
 import jdk.vm.ci.meta.Value;
 
 /**
@@ -59,8 +58,8 @@
 
     protected final ForeignCallDescriptor descriptor;
 
-    public StubForeignCallNode(@InjectedNodeParameter ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, ValueNode... arguments) {
-        super(TYPE, StampFactory.forKind(JavaKind.fromJavaClass(descriptor.getResultType())));
+    public StubForeignCallNode(@InjectedNodeParameter ForeignCallsProvider foreignCalls, @InjectedNodeParameter Stamp stamp, ForeignCallDescriptor descriptor, ValueNode... arguments) {
+        super(TYPE, stamp);
         this.arguments = new NodeInputList<>(this, arguments);
         this.descriptor = descriptor;
         this.foreignCalls = foreignCalls;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/EncodedSymbolNode.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/EncodedSymbolNode.java	Thu Apr 06 14:31:32 2017 -0700
@@ -22,6 +22,7 @@
  */
 package org.graalvm.compiler.hotspot.nodes.aot;
 
+import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.graph.NodeClass;
@@ -44,8 +45,8 @@
 
     @OptionalInput protected ValueNode value;
 
-    public EncodedSymbolNode(ValueNode value) {
-        super(TYPE, null);
+    public EncodedSymbolNode(@InjectedNodeParameter Stamp stamp, ValueNode value) {
+        super(TYPE, stamp);
         assert value != null;
         this.value = value;
     }
@@ -61,6 +62,6 @@
         return this;
     }
 
-    @NodeIntrinsic(setStampFromReturnType = true)
+    @NodeIntrinsic
     public static native Word encode(Object constant);
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/LoadJavaMirrorWithKlassPhase.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/LoadJavaMirrorWithKlassPhase.java	Thu Apr 06 14:31:32 2017 -0700
@@ -22,7 +22,6 @@
  */
 package org.graalvm.compiler.hotspot.phases;
 
-import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.CLASS_MIRROR_LOCATION;
 import static org.graalvm.compiler.nodes.ConstantNode.getConstantNodes;
 import static org.graalvm.compiler.nodes.NamedLocationIdentity.FINAL_LOCATION;
 
@@ -32,9 +31,11 @@
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.core.common.type.TypeReference;
 import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
 import org.graalvm.compiler.hotspot.nodes.CompressionNode;
 import org.graalvm.compiler.hotspot.nodes.type.KlassPointerStamp;
 import org.graalvm.compiler.hotspot.nodes.type.NarrowOopStamp;
+import org.graalvm.compiler.hotspot.replacements.HubGetClassNode;
 import org.graalvm.compiler.nodes.ConstantNode;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.ValueNode;
@@ -67,12 +68,10 @@
  */
 public class LoadJavaMirrorWithKlassPhase extends BasePhase<PhaseContext> {
 
-    private final int classMirrorOffset;
     private final CompressEncoding oopEncoding;
 
-    public LoadJavaMirrorWithKlassPhase(int classMirrorOffset, CompressEncoding oopEncoding) {
-        this.classMirrorOffset = classMirrorOffset;
-        this.oopEncoding = oopEncoding;
+    public LoadJavaMirrorWithKlassPhase(GraalHotSpotVMConfig config) {
+        this.oopEncoding = config.useCompressedOops ? config.getOopEncoding() : null;
     }
 
     private ValueNode getClassConstantReplacement(StructuredGraph graph, PhaseContext context, JavaConstant constant) {
@@ -85,13 +84,12 @@
 
                 if (type instanceof HotSpotResolvedObjectType) {
                     ConstantNode klass = ConstantNode.forConstant(KlassPointerStamp.klassNonNull(), ((HotSpotResolvedObjectType) type).klass(), metaAccess, graph);
-                    AddressNode address = graph.unique(new OffsetAddressNode(klass, ConstantNode.forLong(classMirrorOffset, graph)));
-                    ValueNode read = graph.unique(new FloatingReadNode(address, CLASS_MIRROR_LOCATION, null, stamp));
+                    ValueNode getClass = graph.unique(new HubGetClassNode(metaAccess, klass));
 
                     if (((HotSpotObjectConstant) constant).isCompressed()) {
-                        return CompressionNode.compress(read, oopEncoding);
+                        return CompressionNode.compress(getClass, oopEncoding);
                     } else {
-                        return read;
+                        return getClass;
                     }
                 } else {
                     /*
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/OnStackReplacementPhase.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/OnStackReplacementPhase.java	Thu Apr 06 14:31:32 2017 -0700
@@ -94,7 +94,7 @@
             assert graph.getNodes(EntryMarkerNode.TYPE).isEmpty();
             return;
         }
-        Debug.dump(Debug.INFO_LOG_LEVEL, graph, "OnStackReplacement initial at bci %d", graph.getEntryBCI());
+        Debug.dump(Debug.DETAILED_LEVEL, graph, "OnStackReplacement initial at bci %d", graph.getEntryBCI());
 
         EntryMarkerNode osr;
         int maxIterations = -1;
@@ -144,7 +144,7 @@
                 proxy.replaceAndDelete(proxy.value());
             }
             GraphUtil.removeFixedWithUnusedInputs(osr);
-            Debug.dump(Debug.INFO_LOG_LEVEL, graph, "OnStackReplacement loop peeling result");
+            Debug.dump(Debug.DETAILED_LEVEL, graph, "OnStackReplacement loop peeling result");
         } while (true);
 
         FrameState osrState = osr.stateAfter();
@@ -157,7 +157,7 @@
         graph.setStart(osrStart);
         osrStart.setStateAfter(osrState);
 
-        Debug.dump(Debug.INFO_LOG_LEVEL, graph, "OnStackReplacement after setting OSR start");
+        Debug.dump(Debug.DETAILED_LEVEL, graph, "OnStackReplacement after setting OSR start");
         final int localsSize = osrState.localsSize();
         final int locksSize = osrState.locksSize();
 
@@ -188,9 +188,9 @@
         }
 
         osr.replaceAtUsages(InputType.Guard, osrStart);
-        Debug.dump(Debug.INFO_LOG_LEVEL, graph, "OnStackReplacement after replacing entry proxies");
+        Debug.dump(Debug.DETAILED_LEVEL, graph, "OnStackReplacement after replacing entry proxies");
         GraphUtil.killCFG(start);
-        Debug.dump(Debug.INFO_LOG_LEVEL, graph, "OnStackReplacement result");
+        Debug.dump(Debug.DETAILED_LEVEL, graph, "OnStackReplacement result");
         new DeadCodeEliminationPhase(Required).apply(graph);
 
         if (currentOSRWithLocks) {
@@ -210,7 +210,7 @@
                 osrMonitorEnter.setNext(oldNext);
                 osrStart.setNext(osrMonitorEnter);
             }
-            Debug.dump(Debug.INFO_LOG_LEVEL, graph, "After inserting OSR monitor enters");
+            Debug.dump(Debug.DETAILED_LEVEL, graph, "After inserting OSR monitor enters");
             /*
              * Ensure balanced monitorenter - monitorexit
              *
@@ -226,7 +226,7 @@
                 }
             }
         }
-        Debug.dump(Debug.INFO_LOG_LEVEL, graph, "OnStackReplacement result");
+        Debug.dump(Debug.DETAILED_LEVEL, graph, "OnStackReplacement result");
         new DeadCodeEliminationPhase(Required).apply(graph);
         /*
          * There must not be any parameter nodes left after OSR compilation.
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/EliminateRedundantInitializationPhase.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/EliminateRedundantInitializationPhase.java	Thu Apr 06 14:31:32 2017 -0700
@@ -28,9 +28,6 @@
 import java.util.HashMap;
 import java.util.Map.Entry;
 
-import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant;
-import jdk.vm.ci.meta.JavaConstant;
-
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.graph.iterators.NodeIterable;
 import org.graalvm.compiler.hotspot.nodes.aot.InitializeKlassNode;
@@ -43,6 +40,9 @@
 import org.graalvm.compiler.phases.BasePhase;
 import org.graalvm.compiler.phases.tiers.PhaseContext;
 
+import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant;
+import jdk.vm.ci.meta.Constant;
+
 public class EliminateRedundantInitializationPhase extends BasePhase<PhaseContext> {
     /**
      * Find blocks with class initializing nodes for the class identified the by the constant node.
@@ -204,7 +204,7 @@
         ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, false, true, false);
         ArrayList<Node> redundantInits = new ArrayList<>();
         for (ConstantNode node : getConstantNodes(graph)) {
-            JavaConstant constant = node.asJavaConstant();
+            Constant constant = node.asConstant();
             if (constant instanceof HotSpotMetaspaceConstant) {
                 redundantInits.addAll(processConstantNode(cfg, node));
             }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ClassGetHubNode.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ClassGetHubNode.java	Thu Apr 06 14:31:32 2017 -0700
@@ -25,8 +25,11 @@
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_4;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
 
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
 import org.graalvm.compiler.core.common.LocationIdentity;
 import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.graph.spi.Canonicalizable;
@@ -42,6 +45,7 @@
 import org.graalvm.compiler.nodes.extended.GetClassNode;
 import org.graalvm.compiler.nodes.extended.GuardingNode;
 import org.graalvm.compiler.nodes.extended.LoadHubNode;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
 import org.graalvm.compiler.nodes.memory.ReadNode;
 import org.graalvm.compiler.nodes.memory.address.AddressNode;
 import org.graalvm.compiler.nodes.spi.Lowerable;
@@ -69,19 +73,30 @@
         this.clazz = clazz;
     }
 
-    @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (tool.allUsagesAvailable() && hasNoUsages()) {
+    public static ValueNode create(ValueNode clazz, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, boolean allUsagesAvailable) {
+        return canonical(null, metaAccess, constantReflection, allUsagesAvailable, KlassPointerStamp.klass(), clazz);
+    }
+
+    @SuppressWarnings("unused")
+    public static boolean intrinsify(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode clazz) {
+        ValueNode clazzValue = create(clazz, b.getMetaAccess(), b.getConstantReflection(), false);
+        b.push(JavaKind.Object, b.recursiveAppend(clazzValue));
+        return true;
+    }
+
+    public static ValueNode canonical(ClassGetHubNode classGetHubNode, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, boolean allUsagesAvailable, Stamp stamp,
+                    ValueNode clazz) {
+        ClassGetHubNode self = classGetHubNode;
+        if (allUsagesAvailable && self != null && self.hasNoUsages()) {
             return null;
         } else {
             if (clazz.isConstant()) {
-                MetaAccessProvider metaAccess = tool.getMetaAccess();
                 if (metaAccess != null) {
-                    ResolvedJavaType exactType = tool.getConstantReflection().asJavaType(clazz.asJavaConstant());
+                    ResolvedJavaType exactType = constantReflection.asJavaType(clazz.asJavaConstant());
                     if (exactType.isPrimitive()) {
-                        return ConstantNode.forConstant(stamp(), JavaConstant.NULL_POINTER, metaAccess);
+                        return ConstantNode.forConstant(stamp, JavaConstant.NULL_POINTER, metaAccess);
                     } else {
-                        return ConstantNode.forConstant(stamp(), tool.getConstantReflection().asObjectHub(exactType), metaAccess);
+                        return ConstantNode.forConstant(stamp, constantReflection.asObjectHub(exactType), metaAccess);
                     }
                 }
             }
@@ -90,14 +105,22 @@
                 return new LoadHubNode(KlassPointerStamp.klassNonNull(), getClass.getObject());
             }
             if (clazz instanceof HubGetClassNode) {
-                // replace _klass._java_mirror._klass -> _klass
+                // Replace: _klass._java_mirror._klass -> _klass
                 return ((HubGetClassNode) clazz).getHub();
             }
-            return this;
+            if (self == null) {
+                self = new ClassGetHubNode(clazz);
+            }
+            return self;
         }
     }
 
     @Override
+    public Node canonical(CanonicalizerTool tool) {
+        return canonical(this, tool.getMetaAccess(), tool.getConstantReflection(), tool.allUsagesAvailable(), stamp(), clazz);
+    }
+
+    @Override
     public void lower(LoweringTool tool) {
         tool.getLowerer().lower(this, tool);
     }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotReplacementsUtil.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotReplacementsUtil.java	Thu Apr 06 14:31:32 2017 -0700
@@ -702,17 +702,17 @@
 
     public static Word loadWordFromObject(Object object, int offset) {
         ReplacementsUtil.staticAssert(offset != hubOffset(INJECTED_VMCONFIG), "Use loadHubIntrinsic instead of loadWordFromObject");
-        return loadWordFromObjectIntrinsic(object, offset, getWordKind(), LocationIdentity.any());
+        return loadWordFromObjectIntrinsic(object, offset, LocationIdentity.any(), getWordKind());
     }
 
     public static Word loadWordFromObject(Object object, int offset, LocationIdentity identity) {
         ReplacementsUtil.staticAssert(offset != hubOffset(INJECTED_VMCONFIG), "Use loadHubIntrinsic instead of loadWordFromObject");
-        return loadWordFromObjectIntrinsic(object, offset, getWordKind(), identity);
+        return loadWordFromObjectIntrinsic(object, offset, identity, getWordKind());
     }
 
     public static KlassPointer loadKlassFromObject(Object object, int offset, LocationIdentity identity) {
         ReplacementsUtil.staticAssert(offset != hubOffset(INJECTED_VMCONFIG), "Use loadHubIntrinsic instead of loadWordFromObject");
-        return loadKlassFromObjectIntrinsic(object, offset, getWordKind(), identity);
+        return loadKlassFromObjectIntrinsic(object, offset, identity, getWordKind());
     }
 
     /**
@@ -725,17 +725,17 @@
         return registerAsWord(register, true, false);
     }
 
-    @NodeIntrinsic(value = ReadRegisterNode.class, setStampFromReturnType = true)
+    @NodeIntrinsic(value = ReadRegisterNode.class)
     public static native Word registerAsWord(@ConstantNodeParameter Register register, @ConstantNodeParameter boolean directUse, @ConstantNodeParameter boolean incoming);
 
-    @NodeIntrinsic(value = WriteRegisterNode.class, setStampFromReturnType = true)
+    @NodeIntrinsic(value = WriteRegisterNode.class)
     public static native void writeRegisterAsWord(@ConstantNodeParameter Register register, Word value);
 
-    @NodeIntrinsic(value = RawLoadNode.class, setStampFromReturnType = true)
-    private static native Word loadWordFromObjectIntrinsic(Object object, long offset, @ConstantNodeParameter JavaKind wordKind, @ConstantNodeParameter LocationIdentity locationIdentity);
+    @NodeIntrinsic(value = RawLoadNode.class)
+    private static native Word loadWordFromObjectIntrinsic(Object object, long offset, @ConstantNodeParameter LocationIdentity locationIdentity, @ConstantNodeParameter JavaKind wordKind);
 
-    @NodeIntrinsic(value = RawLoadNode.class, setStampFromReturnType = true)
-    private static native KlassPointer loadKlassFromObjectIntrinsic(Object object, long offset, @ConstantNodeParameter JavaKind wordKind, @ConstantNodeParameter LocationIdentity locationIdentity);
+    @NodeIntrinsic(value = RawLoadNode.class)
+    private static native KlassPointer loadKlassFromObjectIntrinsic(Object object, long offset, @ConstantNodeParameter LocationIdentity locationIdentity, @ConstantNodeParameter JavaKind wordKind);
 
     @NodeIntrinsic(value = LoadHubNode.class)
     public static native KlassPointer loadHubIntrinsic(Object object);
@@ -803,6 +803,8 @@
 
     public static final LocationIdentity CLASS_MIRROR_LOCATION = NamedLocationIdentity.immutable("Klass::_java_mirror");
 
+    public static final LocationIdentity CLASS_MIRROR_HANDLE_LOCATION = NamedLocationIdentity.immutable("Klass::_java_mirror handle");
+
     public static final LocationIdentity HEAP_TOP_LOCATION = NamedLocationIdentity.mutable("HeapTop");
 
     @Fold
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HubGetClassNode.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HubGetClassNode.java	Thu Apr 06 14:31:32 2017 -0700
@@ -25,6 +25,7 @@
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_4;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
 
+import org.graalvm.compiler.core.common.GraalOptions;
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.core.common.type.TypeReference;
 import org.graalvm.compiler.graph.Node;
@@ -70,7 +71,7 @@
             return null;
         } else {
             MetaAccessProvider metaAccess = tool.getMetaAccess();
-            if (metaAccess != null && hub.isConstant()) {
+            if (metaAccess != null && hub.isConstant() && !GraalOptions.ImmutableCode.getValue(graph().getOptions())) {
                 ResolvedJavaType exactType = tool.getConstantReflection().asJavaType(hub.asConstant());
                 if (exactType != null) {
                     return ConstantNode.forConstant(tool.getConstantReflection().asJavaClass(exactType), metaAccess);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/KlassLayoutHelperNode.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/KlassLayoutHelperNode.java	Thu Apr 06 14:31:32 2017 -0700
@@ -25,6 +25,9 @@
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_4;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
 
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
 import org.graalvm.compiler.core.common.type.ObjectStamp;
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.core.common.type.StampFactory;
@@ -38,6 +41,7 @@
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.calc.FloatingNode;
 import org.graalvm.compiler.nodes.extended.LoadHubNode;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
 import org.graalvm.compiler.nodes.spi.Lowerable;
 import org.graalvm.compiler.nodes.spi.LoweringTool;
 
@@ -63,6 +67,18 @@
         this.klass = klass;
     }
 
+    public static ValueNode create(GraalHotSpotVMConfig config, ValueNode klass, ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess) {
+        Stamp stamp = StampFactory.forKind(JavaKind.Int);
+        return canonical(null, config, klass, stamp, constantReflection, metaAccess);
+    }
+
+    @SuppressWarnings("unused")
+    public static boolean intrinsify(GraphBuilderContext b, ResolvedJavaMethod method, @InjectedNodeParameter GraalHotSpotVMConfig config, ValueNode klass) {
+        ValueNode valueNode = create(config, klass, b.getConstantReflection(), b.getMetaAccess());
+        b.push(JavaKind.Int, b.recursiveAppend(valueNode));
+        return true;
+    }
+
     @Override
     public boolean inferStamp() {
         if (klass instanceof LoadHubNode) {
@@ -92,27 +108,36 @@
         if (tool.allUsagesAvailable() && hasNoUsages()) {
             return null;
         } else {
-            if (klass.isConstant()) {
-                if (!klass.asConstant().isDefaultForKind()) {
-                    Constant constant = stamp().readConstant(tool.getConstantReflection().getMemoryAccessProvider(), klass.asConstant(), config.klassLayoutHelperOffset);
-                    return ConstantNode.forConstant(stamp(), constant, tool.getMetaAccess());
+            return canonical(this, config, klass, stamp(), tool.getConstantReflection(), tool.getMetaAccess());
+        }
+    }
+
+    private static ValueNode canonical(KlassLayoutHelperNode klassLayoutHelperNode, GraalHotSpotVMConfig config, ValueNode klass, Stamp stamp, ConstantReflectionProvider constantReflection,
+                    MetaAccessProvider metaAccess) {
+        KlassLayoutHelperNode self = klassLayoutHelperNode;
+        if (klass.isConstant()) {
+            if (!klass.asConstant().isDefaultForKind()) {
+                Constant constant = stamp.readConstant(constantReflection.getMemoryAccessProvider(), klass.asConstant(), config.klassLayoutHelperOffset);
+                return ConstantNode.forConstant(stamp, constant, metaAccess);
+            }
+        }
+        if (klass instanceof LoadHubNode) {
+            LoadHubNode hub = (LoadHubNode) klass;
+            Stamp hubStamp = hub.getValue().stamp();
+            if (hubStamp instanceof ObjectStamp) {
+                ObjectStamp ostamp = (ObjectStamp) hubStamp;
+                HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) ostamp.type();
+                if (type != null && type.isArray() && !type.getComponentType().isPrimitive()) {
+                    // The layout for all object arrays is the same.
+                    Constant constant = stamp.readConstant(constantReflection.getMemoryAccessProvider(), type.klass(), config.klassLayoutHelperOffset);
+                    return ConstantNode.forConstant(stamp, constant, metaAccess);
                 }
             }
-            if (klass instanceof LoadHubNode) {
-                LoadHubNode hub = (LoadHubNode) klass;
-                Stamp hubStamp = hub.getValue().stamp();
-                if (hubStamp instanceof ObjectStamp) {
-                    ObjectStamp ostamp = (ObjectStamp) hubStamp;
-                    HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) ostamp.type();
-                    if (type != null && type.isArray() && !type.getComponentType().isPrimitive()) {
-                        // The layout for all object arrays is the same.
-                        Constant constant = stamp().readConstant(tool.getConstantReflection().getMemoryAccessProvider(), type.klass(), config.klassLayoutHelperOffset);
-                        return ConstantNode.forConstant(stamp(), constant, tool.getMetaAccess());
-                    }
-                }
-            }
-            return this;
         }
+        if (self == null) {
+            self = new KlassLayoutHelperNode(config, klass);
+        }
+        return self;
     }
 
     @Override
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/LoadExceptionObjectSnippets.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/LoadExceptionObjectSnippets.java	Thu Apr 06 14:31:32 2017 -0700
@@ -35,8 +35,10 @@
 
 import org.graalvm.compiler.api.replacements.Snippet;
 import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter;
+import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
 import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider;
+import org.graalvm.compiler.hotspot.word.HotSpotWordTypes;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.extended.ForeignCallNode;
 import org.graalvm.compiler.nodes.java.LoadExceptionObjectNode;
@@ -52,6 +54,7 @@
 import jdk.vm.ci.code.BytecodeFrame;
 import jdk.vm.ci.code.Register;
 import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.ResolvedJavaType;
 
 /**
  * Snippet for loading the exception object at the start of an exception dispatcher.
@@ -76,15 +79,19 @@
     public static class Templates extends AbstractTemplates {
 
         private final SnippetInfo loadException = snippet(LoadExceptionObjectSnippets.class, "loadException", EXCEPTION_OOP_LOCATION, EXCEPTION_PC_LOCATION);
+        private final HotSpotWordTypes wordTypes;
 
         public Templates(OptionValues options, HotSpotProviders providers, TargetDescription target) {
             super(options, providers, providers.getSnippetReflection(), target);
+            this.wordTypes = providers.getWordTypes();
         }
 
         public void lower(LoadExceptionObjectNode loadExceptionObject, HotSpotRegistersProvider registers, LoweringTool tool) {
             StructuredGraph graph = loadExceptionObject.graph();
             if (LoadExceptionObjectInVM.getValue(graph.getOptions())) {
-                ReadRegisterNode thread = graph.add(new ReadRegisterNode(registers.getThreadRegister(), true, false));
+                ResolvedJavaType wordType = providers.getMetaAccess().lookupJavaType(Word.class);
+                Stamp stamp = wordTypes.getWordStamp(wordType);
+                ReadRegisterNode thread = graph.add(new ReadRegisterNode(stamp, registers.getThreadRegister(), true, false));
                 graph.addBeforeFixed(loadExceptionObject, thread);
                 ForeignCallNode loadExceptionC = graph.add(new ForeignCallNode(providers.getForeignCalls(), LOAD_AND_CLEAR_EXCEPTION, thread));
                 loadExceptionC.setStateAfter(loadExceptionObject.stateAfter());
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/NewObjectSnippets.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/NewObjectSnippets.java	Thu Apr 06 14:31:32 2017 -0700
@@ -56,7 +56,7 @@
 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.writeTlabTop;
 import static org.graalvm.compiler.hotspot.replacements.HotspotSnippetsOptions.ProfileAllocations;
 import static org.graalvm.compiler.hotspot.replacements.HotspotSnippetsOptions.ProfileAllocationsContext;
-import static org.graalvm.compiler.nodes.PiArrayNode.piArrayCast;
+import static org.graalvm.compiler.nodes.PiArrayNode.piArrayCastToSnippetReplaceeStamp;
 import static org.graalvm.compiler.nodes.PiNode.piCastToSnippetReplaceeStamp;
 import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.FAST_PATH_PROBABILITY;
 import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.FREQUENT_PROBABILITY;
@@ -226,7 +226,7 @@
         return verifyOop(result);
     }
 
-    @NodeIntrinsic(value = ForeignCallNode.class, returnStampIsNonNull = true)
+    @NodeIntrinsic(value = ForeignCallNode.class, injectedStampIsNonNull = true)
     public static native Object newInstance(@ConstantNodeParameter ForeignCallDescriptor descriptor, KlassPointer hub);
 
     @Snippet
@@ -307,7 +307,7 @@
                     @ConstantParameter boolean fillContents, @ConstantParameter Register threadRegister, @ConstantParameter boolean maybeUnroll, @ConstantParameter String typeContext,
                     @ConstantParameter OptionValues options, @ConstantParameter Counters counters) {
         Object result = allocateArrayImpl(hub, length, prototypeMarkWord, headerSize, log2ElementSize, fillContents, threadRegister, maybeUnroll, typeContext, false, options, counters);
-        return piArrayCast(verifyOop(result), length);
+        return piArrayCastToSnippetReplaceeStamp(verifyOop(result), length);
     }
 
     private static Object allocateArrayImpl(KlassPointer hub, int length, Word prototypeMarkWord, int headerSize, int log2ElementSize, boolean fillContents, Register threadRegister,
@@ -334,20 +334,20 @@
         return result;
     }
 
-    @NodeIntrinsic(value = ForeignCallNode.class, returnStampIsNonNull = true)
+    @NodeIntrinsic(value = ForeignCallNode.class, injectedStampIsNonNull = true)
     public static native Object newArray(@ConstantNodeParameter ForeignCallDescriptor descriptor, KlassPointer hub, int length, boolean fillContents);
 
     public static final ForeignCallDescriptor DYNAMIC_NEW_ARRAY = new ForeignCallDescriptor("dynamic_new_array", Object.class, Class.class, int.class);
     public static final ForeignCallDescriptor DYNAMIC_NEW_INSTANCE = new ForeignCallDescriptor("dynamic_new_instance", Object.class, Class.class);
 
-    @NodeIntrinsic(value = ForeignCallNode.class, returnStampIsNonNull = true)
+    @NodeIntrinsic(value = ForeignCallNode.class, injectedStampIsNonNull = true)
     public static native Object dynamicNewArrayStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Class<?> elementType, int length);
 
     public static Object dynamicNewInstanceStub(Class<?> elementType) {
         return dynamicNewInstanceStubCall(DYNAMIC_NEW_INSTANCE, elementType);
     }
 
-    @NodeIntrinsic(value = ForeignCallNode.class, returnStampIsNonNull = true)
+    @NodeIntrinsic(value = ForeignCallNode.class, injectedStampIsNonNull = true)
     public static native Object dynamicNewInstanceStubCall(@ConstantNodeParameter ForeignCallDescriptor descriptor, Class<?> elementType);
 
     @Snippet
@@ -396,7 +396,7 @@
         int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift(INJECTED_VMCONFIG)) & layoutHelperLog2ElementSizeMask(INJECTED_VMCONFIG);
 
         Object result = allocateArrayImpl(nonNullKlass, length, prototypeMarkWord, headerSize, log2ElementSize, fillContents, threadRegister, false, "dynamic type", true, options, counters);
-        return piArrayCast(verifyOop(result), length);
+        return piArrayCastToSnippetReplaceeStamp(verifyOop(result), length);
     }
 
     /**
@@ -418,7 +418,7 @@
         return newmultiarray(hubPIC, rank, dimensions);
     }
 
-    @NodeIntrinsic(value = ForeignCallNode.class, returnStampIsNonNull = true)
+    @NodeIntrinsic(value = ForeignCallNode.class, injectedStampIsNonNull = true)
     public static native Object newArrayCall(@ConstantNodeParameter ForeignCallDescriptor descriptor, KlassPointer hub, int rank, Word dims);
 
     /**
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ReflectionGetCallerClassNode.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ReflectionGetCallerClassNode.java	Thu Apr 06 14:31:32 2017 -0700
@@ -80,7 +80,7 @@
 
     /**
      * If inlining is deep enough this method returns a {@link ConstantNode} of the caller class by
-     * walking the the stack.
+     * walking the stack.
      *
      * @param metaAccess
      * @return ConstantNode of the caller class, or null
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopyNode.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopyNode.java	Thu Apr 06 14:31:32 2017 -0700
@@ -22,8 +22,6 @@
  */
 package org.graalvm.compiler.hotspot.replacements.arraycopy;
 
-import jdk.vm.ci.meta.JavaKind;
-
 import static org.graalvm.compiler.core.common.LocationIdentity.any;
 
 import org.graalvm.compiler.core.common.LocationIdentity;
@@ -33,11 +31,12 @@
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.spi.Lowerable;
 import org.graalvm.compiler.nodes.spi.LoweringTool;
-import org.graalvm.compiler.nodes.spi.Virtualizable;
 import org.graalvm.compiler.replacements.nodes.BasicArrayCopyNode;
 
+import jdk.vm.ci.meta.JavaKind;
+
 @NodeInfo
-public final class ArrayCopyNode extends BasicArrayCopyNode implements Virtualizable, Lowerable {
+public final class ArrayCopyNode extends BasicArrayCopyNode implements Lowerable {
 
     public static final NodeClass<ArrayCopyNode> TYPE = NodeClass.create(ArrayCopyNode.class);
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopySnippets.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopySnippets.java	Thu Apr 06 14:31:32 2017 -0700
@@ -63,6 +63,7 @@
 import org.graalvm.compiler.nodes.java.ArrayLengthNode;
 import org.graalvm.compiler.nodes.spi.LoweringTool;
 import org.graalvm.compiler.nodes.type.StampTool;
+import org.graalvm.compiler.nodes.util.GraphUtil;
 import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.replacements.SnippetCounter;
 import org.graalvm.compiler.replacements.SnippetCounter.Group;
@@ -628,7 +629,7 @@
         private void instantiate(Arguments args, BasicArrayCopyNode arraycopy) {
             StructuredGraph graph = arraycopy.graph();
             SnippetTemplate template = template(args);
-            UnmodifiableEconomicMap<Node, Node> replacements = template.instantiate(providers.getMetaAccess(), arraycopy, SnippetTemplate.DEFAULT_REPLACER, args);
+            UnmodifiableEconomicMap<Node, Node> replacements = template.instantiate(providers.getMetaAccess(), arraycopy, SnippetTemplate.DEFAULT_REPLACER, args, false);
             for (Node originalNode : replacements.getKeys()) {
                 if (originalNode instanceof Invoke) {
                     Invoke invoke = (Invoke) replacements.get(originalNode);
@@ -643,17 +644,18 @@
                     if (arraycopy.stateDuring() != null) {
                         newInvoke.setStateDuring(arraycopy.stateDuring());
                     } else {
-                        assert arraycopy.stateAfter() != null;
+                        assert arraycopy.stateAfter() != null : arraycopy;
                         newInvoke.setStateAfter(arraycopy.stateAfter());
                     }
                     graph.replaceFixedWithFixed((InvokeNode) invoke.asNode(), newInvoke);
                 } else if (originalNode instanceof ArrayCopySlowPathNode) {
                     ArrayCopySlowPathNode slowPath = (ArrayCopySlowPathNode) replacements.get(originalNode);
-                    assert arraycopy.stateAfter() != null;
-                    slowPath.setStateAfter(arraycopy.stateAfter());
+                    assert arraycopy.stateAfter() != null : arraycopy;
+                    assert slowPath.stateAfter() == arraycopy.stateAfter();
                     slowPath.setBci(arraycopy.getBci());
                 }
             }
+            GraphUtil.killCFG(arraycopy);
         }
     }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/ExceptionHandlerStub.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/ExceptionHandlerStub.java	Thu Apr 06 14:31:32 2017 -0700
@@ -157,6 +157,6 @@
 
     public static final ForeignCallDescriptor EXCEPTION_HANDLER_FOR_PC = newDescriptor(ExceptionHandlerStub.class, "exceptionHandlerForPc", Word.class, Word.class);
 
-    @NodeIntrinsic(value = StubForeignCallNode.class, setStampFromReturnType = true)
+    @NodeIntrinsic(value = StubForeignCallNode.class)
     public static native Word exceptionHandlerForPc(@ConstantNodeParameter ForeignCallDescriptor exceptionHandlerForPc, Word thread);
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/ForeignCallStub.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/ForeignCallStub.java	Thu Apr 06 14:31:32 2017 -0700
@@ -32,6 +32,7 @@
 import org.graalvm.compiler.core.common.LIRKind;
 import org.graalvm.compiler.core.common.LocationIdentity;
 import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
+import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.core.common.type.StampPair;
 import org.graalvm.compiler.debug.Debug;
@@ -57,6 +58,7 @@
 
 import jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider;
 import jdk.vm.ci.hotspot.HotSpotSignature;
+import jdk.vm.ci.meta.JavaKind;
 import jdk.vm.ci.meta.JavaMethod;
 import jdk.vm.ci.meta.JavaType;
 import jdk.vm.ci.meta.MetaAccessProvider;
@@ -241,17 +243,13 @@
         }
         kit.append(new ReturnNode(linkage.getDescriptor().getResultType() == void.class ? null : result));
 
-        if (Debug.isDumpEnabled(Debug.INFO_LOG_LEVEL)) {
-            Debug.dump(Debug.INFO_LOG_LEVEL, graph, "Initial stub graph");
-        }
+        Debug.dump(Debug.VERBOSE_LEVEL, graph, "Initial stub graph");
 
         kit.inlineInvokes();
 
         new RemoveValueProxyPhase().apply(graph);
 
-        if (Debug.isDumpEnabled(Debug.INFO_LOG_LEVEL)) {
-            Debug.dump(Debug.INFO_LOG_LEVEL, graph, "Stub graph before compilation");
-        }
+        Debug.dump(Debug.VERBOSE_LEVEL, graph, "Stub graph before compilation");
 
         return graph;
     }
@@ -269,13 +267,14 @@
     }
 
     private StubForeignCallNode createTargetCall(GraphKit kit, ParameterNode[] params, ReadRegisterNode thread) {
+        Stamp stamp = StampFactory.forKind(JavaKind.fromJavaClass(target.getDescriptor().getResultType()));
         if (prependThread) {
             ValueNode[] targetArguments = new ValueNode[1 + params.length];
             targetArguments[0] = thread;
             System.arraycopy(params, 0, targetArguments, 1, params.length);
-            return kit.append(new StubForeignCallNode(providers.getForeignCalls(), target.getDescriptor(), targetArguments));
+            return kit.append(new StubForeignCallNode(providers.getForeignCalls(), stamp, target.getDescriptor(), targetArguments));
         } else {
-            return kit.append(new StubForeignCallNode(providers.getForeignCalls(), target.getDescriptor(), params));
+            return kit.append(new StubForeignCallNode(providers.getForeignCalls(), stamp, target.getDescriptor(), params));
         }
     }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/Stub.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/Stub.java	Thu Apr 06 14:31:32 2017 -0700
@@ -25,6 +25,7 @@
 import static org.graalvm.compiler.core.GraalCompiler.emitBackEnd;
 import static org.graalvm.compiler.core.GraalCompiler.emitFrontEnd;
 import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
+import static org.graalvm.compiler.debug.GraalDebugConfig.Options.DebugStubsAndSnippets;
 import static org.graalvm.compiler.hotspot.HotSpotHostBackend.UNCOMMON_TRAP_HANDLER;
 import static org.graalvm.util.CollectionsUtil.allMatch;
 
@@ -35,6 +36,7 @@
 import org.graalvm.compiler.core.target.Backend;
 import org.graalvm.compiler.debug.Debug;
 import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.debug.DebugConfig;
 import org.graalvm.compiler.debug.internal.DebugScope;
 import org.graalvm.compiler.hotspot.HotSpotCompiledCodeBuilder;
 import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage;
@@ -176,7 +178,8 @@
     @SuppressWarnings("try")
     public synchronized InstalledCode getCode(final Backend backend) {
         if (code == null) {
-            try (Scope d = Debug.sandbox("CompilingStub", DebugScope.getConfig(), providers.getCodeCache(), debugScopeContext())) {
+            DebugConfig config = DebugStubsAndSnippets.getValue(options) ? DebugScope.getConfig() : Debug.silentConfig();
+            try (Scope d = Debug.sandbox("CompilingStub", config, providers.getCodeCache(), debugScopeContext())) {
                 CodeCacheProvider codeCache = providers.getCodeCache();
 
                 CompilationResult compResult = buildCompilationResult(backend);
@@ -184,7 +187,7 @@
                     assert destroyedCallerRegisters != null;
                     // Add a GeneratePIC check here later, we don't want to install
                     // code if we don't have a corresponding VM global symbol.
-                    HotSpotCompiledCode compiledCode = HotSpotCompiledCodeBuilder.createCompiledCode(null, null, compResult);
+                    HotSpotCompiledCode compiledCode = HotSpotCompiledCodeBuilder.createCompiledCode(codeCache, null, null, compResult);
                     code = codeCache.installCode(null, compiledCode, null, null, false);
                 } catch (Throwable e) {
                     throw Debug.handle(e);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/UnwindExceptionToCallerStub.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/UnwindExceptionToCallerStub.java	Thu Apr 06 14:31:32 2017 -0700
@@ -122,6 +122,6 @@
     public static final ForeignCallDescriptor EXCEPTION_HANDLER_FOR_RETURN_ADDRESS = newDescriptor(UnwindExceptionToCallerStub.class, "exceptionHandlerForReturnAddress", Word.class, Word.class,
                     Word.class);
 
-    @NodeIntrinsic(value = StubForeignCallNode.class, setStampFromReturnType = true)
+    @NodeIntrinsic(value = StubForeignCallNode.class)
     public static native Word exceptionHandlerForReturnAddress(@ConstantNodeParameter ForeignCallDescriptor exceptionHandlerForReturnAddress, Word thread, Word returnAddress);
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BciBlockMapping.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BciBlockMapping.java	Thu Apr 06 14:31:32 2017 -0700
@@ -1051,8 +1051,8 @@
     public static BciBlockMapping create(BytecodeStream stream, Bytecode code, OptionValues options) {
         BciBlockMapping map = new BciBlockMapping(code);
         map.build(stream, options);
-        if (Debug.isDumpEnabled(Debug.INFO_LOG_LEVEL)) {
-            Debug.dump(Debug.INFO_LOG_LEVEL, map, code.getMethod().format("After block building %f %R %H.%n(%P)"));
+        if (Debug.isDumpEnabled(Debug.INFO_LEVEL)) {
+            Debug.dump(Debug.INFO_LEVEL, map, code.getMethod().format("After block building %f %R %H.%n(%P)"));
         }
 
         return map;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java	Thu Apr 06 14:31:32 2017 -0700
@@ -247,7 +247,6 @@
 import static org.graalvm.compiler.core.common.type.StampFactory.objectNonNull;
 import static org.graalvm.compiler.debug.GraalError.guarantee;
 import static org.graalvm.compiler.debug.GraalError.shouldNotReachHere;
-import static org.graalvm.compiler.java.BytecodeParserOptions.DumpDuringGraphBuilding;
 import static org.graalvm.compiler.java.BytecodeParserOptions.TraceBytecodeParserLevel;
 import static org.graalvm.compiler.java.BytecodeParserOptions.TraceInlineDuringParsing;
 import static org.graalvm.compiler.java.BytecodeParserOptions.TraceParserPlugins;
@@ -272,8 +271,8 @@
 import org.graalvm.compiler.bytecode.Bytes;
 import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecode;
 import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecodeProvider;
+import org.graalvm.compiler.core.common.LocationIdentity;
 import org.graalvm.compiler.core.common.PermanentBailoutException;
-import org.graalvm.compiler.core.common.LocationIdentity;
 import org.graalvm.compiler.core.common.calc.Condition;
 import org.graalvm.compiler.core.common.calc.FloatConvert;
 import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
@@ -770,10 +769,6 @@
             for (BciBlock block : blocks) {
                 processBlock(block);
             }
-
-            if (Debug.isDumpEnabled(Debug.INFO_LOG_LEVEL) && DumpDuringGraphBuilding.getValue(options) && this.beforeReturnNode != startInstruction) {
-                Debug.dump(Debug.INFO_LOG_LEVEL, graph, "Bytecodes parsed: %s.%s", method.getDeclaringClass().getUnqualifiedName(), method.getName());
-            }
         }
     }
 
@@ -890,7 +885,7 @@
      */
     protected void handleUnresolvedCheckCast(JavaType type, ValueNode object) {
         assert !graphBuilderConfig.eagerResolving();
-        append(new FixedGuardNode(graph.unique(IsNullNode.create(object)), Unresolved, InvalidateRecompile));
+        append(new FixedGuardNode(graph.addOrUniqueWithInputs(IsNullNode.create(object)), Unresolved, InvalidateRecompile));
         frameState.push(JavaKind.Object, appendConstant(JavaConstant.NULL_POINTER));
     }
 
@@ -902,7 +897,7 @@
         assert !graphBuilderConfig.eagerResolving();
         AbstractBeginNode successor = graph.add(new BeginNode());
         DeoptimizeNode deopt = graph.add(new DeoptimizeNode(InvalidateRecompile, Unresolved));
-        append(new IfNode(graph.unique(IsNullNode.create(object)), successor, deopt, 1));
+        append(new IfNode(graph.addOrUniqueWithInputs(IsNullNode.create(object)), successor, deopt, 1));
         lastInstr = successor;
         frameState.push(JavaKind.Int, appendConstant(JavaConstant.INT_0));
     }
@@ -1060,15 +1055,15 @@
     }
 
     protected ValueNode genNegateOp(ValueNode x) {
-        return (new NegateNode(x));
+        return NegateNode.create(x);
     }
 
     protected ValueNode genLeftShift(ValueNode x, ValueNode y) {
-        return new LeftShiftNode(x, y);
+        return LeftShiftNode.create(x, y);
     }
 
     protected ValueNode genRightShift(ValueNode x, ValueNode y) {
-        return new RightShiftNode(x, y);
+        return RightShiftNode.create(x, y);
     }
 
     protected ValueNode genUnsignedRightShift(ValueNode x, ValueNode y) {
@@ -1123,11 +1118,11 @@
     }
 
     protected LogicNode genIntegerEquals(ValueNode x, ValueNode y) {
-        return IntegerEqualsNode.create(x, y, constantReflection);
+        return IntegerEqualsNode.create(x, y);
     }
 
     protected LogicNode genIntegerLessThan(ValueNode x, ValueNode y) {
-        return IntegerLessThanNode.create(x, y, constantReflection);
+        return IntegerLessThanNode.create(x, y);
     }
 
     protected ValueNode genUnique(ValueNode x) {
@@ -1146,8 +1141,8 @@
         genInfoPointNode(InfopointReason.BYTECODE_POSITION, null);
 
         ValueNode exception = frameState.pop(JavaKind.Object);
-        FixedGuardNode nullCheck = append(new FixedGuardNode(graph.unique(IsNullNode.create(exception)), NullCheckException, InvalidateReprofile, true));
-        PiNode nonNullException = graph.unique(new PiNode(exception, exception.stamp().join(objectNonNull()), nullCheck));
+        FixedGuardNode nullCheck = append(new FixedGuardNode(graph.addOrUniqueWithInputs(IsNullNode.create(exception)), NullCheckException, InvalidateReprofile, true));
+        ValueNode nonNullException = graph.maybeAddOrUnique(PiNode.create(exception, exception.stamp().join(objectNonNull()), nullCheck));
         lastInstr.setNext(handleException(nonNullException, bci()));
     }
 
@@ -1172,7 +1167,7 @@
     }
 
     protected ValueNode genConditional(ValueNode x) {
-        return new ConditionalNode((LogicNode) x);
+        return ConditionalNode.create((LogicNode) x);
     }
 
     protected NewInstanceNode createNewInstance(ResolvedJavaType type, boolean fillContents) {
@@ -1190,9 +1185,11 @@
     protected ValueNode genLoadField(ValueNode receiver, ResolvedJavaField field) {
         StampPair stamp = graphBuilderConfig.getPlugins().getOverridingStamp(this, field.getType(), false);
         if (stamp == null) {
-            return LoadFieldNode.create(this.graph.getAssumptions(), receiver, field);
+            return LoadFieldNode.create(getConstantFieldProvider(), getConstantReflection(), getMetaAccess(), getOptions(),
+                            getAssumptions(), receiver, field, false, false);
         } else {
-            return LoadFieldNode.createOverrideStamp(stamp, receiver, field);
+            return LoadFieldNode.createOverrideStamp(getConstantFieldProvider(), getConstantReflection(), getMetaAccess(), getOptions(),
+                            stamp, receiver, field, false, false);
         }
     }
 
@@ -1202,8 +1199,8 @@
         }
         BytecodeExceptionNode exception = graph.add(new BytecodeExceptionNode(metaAccess, NullPointerException.class));
         AbstractBeginNode falseSucc = graph.add(new BeginNode());
-        PiNode nonNullReceiver = graph.unique(new PiNode(receiver, objectNonNull(), falseSucc));
-        append(new IfNode(graph.unique(IsNullNode.create(receiver)), exception, falseSucc, 0.01));
+        ValueNode nonNullReceiver = graph.addOrUnique(PiNode.create(receiver, objectNonNull(), falseSucc));
+        append(new IfNode(graph.addOrUniqueWithInputs(IsNullNode.create(receiver)), exception, falseSucc, 0.01));
         lastInstr = falseSucc;
 
         exception.setStateAfter(createFrameState(bci(), exception));
@@ -1215,7 +1212,7 @@
     protected void emitExplicitBoundsCheck(ValueNode index, ValueNode length) {
         AbstractBeginNode trueSucc = graph.add(new BeginNode());
         BytecodeExceptionNode exception = graph.add(new BytecodeExceptionNode(metaAccess, ArrayIndexOutOfBoundsException.class, index));
-        append(new IfNode(graph.unique(IntegerBelowNode.create(index, length, constantReflection)), trueSucc, exception, 0.99));
+        append(new IfNode(genUnique(IntegerBelowNode.create(index, length)), trueSucc, exception, 0.99));
         lastInstr = trueSucc;
 
         exception.setStateAfter(createFrameState(bci(), exception));
@@ -1401,11 +1398,6 @@
         }
         if (invokeKind.hasReceiver()) {
             args[0] = emitExplicitExceptions(args[0]);
-
-            if (args[0].isNullConstant()) {
-                append(new DeoptimizeNode(InvalidateRecompile, NullCheckException));
-                return null;
-            }
         }
 
         InlineInfo inlineInfo = null;
@@ -1419,6 +1411,11 @@
                 return null;
             }
 
+            if (invokeKind.hasReceiver() && args[0].isNullConstant()) {
+                append(new DeoptimizeNode(InvalidateRecompile, NullCheckException));
+                return null;
+            }
+
             if (!invokeKind.isIndirect() || (UseGuardedIntrinsics.getValue(options) && !GeneratePIC.getValue(options))) {
                 if (tryInvocationPlugin(invokeKind, args, targetMethod, resultType, returnType)) {
                     if (TraceParserPlugins.getValue(options)) {
@@ -1611,7 +1608,7 @@
             LoadHubNode hub = graph.unique(new LoadHubNode(stampProvider, nonNullReceiver));
             LoadMethodNode actual = append(new LoadMethodNode(methodStamp, targetMethod, receiverType, method.getDeclaringClass(), hub));
             ConstantNode expected = graph.unique(ConstantNode.forConstant(methodStamp, targetMethod.getEncoding(), getMetaAccess()));
-            LogicNode compare = graph.unique(CompareNode.createCompareNode(Condition.EQ, actual, expected, constantReflection));
+            LogicNode compare = graph.addOrUniqueWithInputs(CompareNode.createCompareNode(Condition.EQ, actual, expected, constantReflection));
 
             JavaTypeProfile profile = null;
             if (profilingInfo != null && this.optimisticOpts.useTypeCheckHints(getOptions())) {
@@ -2125,8 +2122,8 @@
         JsrScope scope = currentBlock.getJsrScope();
         int retAddress = scope.nextReturnAddress();
         ConstantNode returnBciNode = getJsrConstant(retAddress);
-        LogicNode guard = IntegerEqualsNode.create(local, returnBciNode, constantReflection);
-        guard = graph.unique(guard);
+        LogicNode guard = IntegerEqualsNode.create(local, returnBciNode);
+        guard = graph.addOrUniqueWithInputs(guard);
         append(new FixedGuardNode(guard, JavaSubroutineMismatch, InvalidateReprofile));
         if (!successor.getJsrScope().equals(scope.pop())) {
             throw new JsrNotSupportedBailout("unstructured control flow (ret leaves more than one scope)");
@@ -2656,7 +2653,7 @@
     }
 
     private DebugCloseable openNodeContext() {
-        if (graphBuilderConfig.trackNodeSourcePosition() && !parsingIntrinsic()) {
+        if ((graphBuilderConfig.trackNodeSourcePosition() || Debug.isDumpEnabledForMethod()) && !parsingIntrinsic()) {
             return graph.withNodeSourcePosition(createBytecodePosition());
         }
         return null;
@@ -2776,7 +2773,7 @@
             genConstantTargetIf(trueBlock, falseBlock, negate, condition);
         } else {
             if (condition.graph() == null) {
-                condition = graph.unique(condition);
+                condition = genUnique(condition);
             }
 
             // Need to get probability based on current bci.
@@ -3048,7 +3045,7 @@
 
         int nextBCI = stream.nextBCI();
         int nextBC = stream.readUByte(nextBCI);
-        if (nextBC == Bytecodes.GETFIELD) {
+        if (nextBCI <= currentBlock.endBci && nextBC == Bytecodes.GETFIELD) {
             stream.next();
             genGetField(lookupField(stream.readCPI(), Bytecodes.GETFIELD), value);
         } else {
@@ -3147,7 +3144,7 @@
             default:
                 throw shouldNotReachHere();
         }
-        frameState.push(kind, append(v));
+        frameState.push(kind, recursiveAppend(v));
     }
 
     private void genIntegerDivOp(JavaKind kind, int opcode) {
@@ -3194,7 +3191,7 @@
             default:
                 throw shouldNotReachHere();
         }
-        frameState.push(kind, append(v));
+        frameState.push(kind, recursiveAppend(v));
     }
 
     private void genLogicOp(JavaKind kind, int opcode) {
@@ -3217,7 +3214,7 @@
             default:
                 throw shouldNotReachHere();
         }
-        frameState.push(kind, append(v));
+        frameState.push(kind, recursiveAppend(v));
     }
 
     private void genCompareOp(JavaKind kind, boolean isUnorderedLess) {
@@ -3236,7 +3233,7 @@
         if (from != from.getStackKind()) {
             input = append(genNarrow(input, from.getBitCount()));
         }
-        frameState.push(to, append(genSignExtend(input, to.getBitCount())));
+        frameState.push(to, recursiveAppend(genSignExtend(input, to.getBitCount())));
     }
 
     private void genZeroExtend(JavaKind from, JavaKind to) {
@@ -3257,7 +3254,7 @@
         int delta = getStream().readIncrement();
         ValueNode x = frameState.loadLocal(index, JavaKind.Int);
         ValueNode y = appendConstant(JavaConstant.forInt(delta));
-        frameState.storeLocal(index, JavaKind.Int, append(genIntegerAdd(x, y)));
+        frameState.storeLocal(index, JavaKind.Int, recursiveAppend(genIntegerAdd(x, y)));
     }
 
     private void genIfZero(Condition cond) {
@@ -3373,7 +3370,7 @@
                         castNode = object;
                     } else {
                         FixedGuardNode fixedGuard = append(new FixedGuardNode(typeCheck, DeoptimizationReason.TypeCheckedInliningViolated, DeoptimizationAction.InvalidateReprofile, false));
-                        castNode = append(new PiNode(object, StampFactory.objectNonNull(TypeReference.createExactTrusted(singleType)), fixedGuard));
+                        castNode = append(PiNode.create(object, StampFactory.objectNonNull(TypeReference.createExactTrusted(singleType)), fixedGuard));
                     }
                 }
             }
@@ -3386,7 +3383,7 @@
                 castNode = object;
             } else {
                 FixedGuardNode fixedGuard = append(new FixedGuardNode(condition, DeoptimizationReason.ClassCastException, DeoptimizationAction.InvalidateReprofile, false));
-                castNode = append(new PiNode(object, StampFactory.object(checkedType, nonNull), fixedGuard));
+                castNode = append(PiNode.create(object, StampFactory.object(checkedType, nonNull), fixedGuard));
             }
         }
         frameState.push(JavaKind.Object, castNode);
@@ -3431,7 +3428,7 @@
 
         int next = getStream().nextBCI();
         int value = getStream().readUByte(next);
-        if (value == Bytecodes.IFEQ || value == Bytecodes.IFNE) {
+        if (next <= currentBlock.endBci && (value == Bytecodes.IFEQ || value == Bytecodes.IFNE)) {
             getStream().next();
             BciBlock firstSucc = currentBlock.getSuccessor(0);
             BciBlock secondSucc = currentBlock.getSuccessor(1);
@@ -3678,11 +3675,10 @@
     }
 
     private void genGetStatic(JavaField field) {
-        if (!(field instanceof ResolvedJavaField) || !((ResolvedJavaType) field.getDeclaringClass()).isInitialized()) {
-            handleUnresolvedLoadField(field, null);
+        ResolvedJavaField resolvedField = resolveStaticFieldAccess(field, null);
+        if (resolvedField == null) {
             return;
         }
-        ResolvedJavaField resolvedField = (ResolvedJavaField) field;
 
         if (!parsingIntrinsic() && GeneratePIC.getValue(getOptions())) {
             graph.recordField(resolvedField);
@@ -3712,13 +3708,39 @@
         frameState.push(field.getJavaKind(), append(genLoadField(null, resolvedField)));
     }
 
+    private ResolvedJavaField resolveStaticFieldAccess(JavaField field, ValueNode value) {
+        if (field instanceof ResolvedJavaField) {
+            ResolvedJavaField resolvedField = (ResolvedJavaField) field;
+            if (resolvedField.getDeclaringClass().isInitialized()) {
+                return resolvedField;
+            }
+            /*
+             * Static fields have initialization semantics but may be safely accessed under certain
+             * conditions while the class is being initialized. Executing in the clinit or init of
+             * classes which are subtypes of the field holder are sure to be running in a context
+             * where the access is safe.
+             */
+            if (resolvedField.getDeclaringClass().isAssignableFrom(method.getDeclaringClass())) {
+                if (method.isClassInitializer() || method.isConstructor()) {
+                    return resolvedField;
+                }
+            }
+        }
+        if (value == null) {
+            handleUnresolvedLoadField(field, null);
+        } else {
+            handleUnresolvedStoreField(field, value, null);
+
+        }
+        return null;
+    }
+
     private void genPutStatic(JavaField field) {
         ValueNode value = frameState.pop(field.getJavaKind());
-        if (!(field instanceof ResolvedJavaField) || !((ResolvedJavaType) field.getDeclaringClass()).isInitialized()) {
-            handleUnresolvedStoreField(field, value, null);
+        ResolvedJavaField resolvedField = resolveStaticFieldAccess(field, value);
+        if (resolvedField == null) {
             return;
         }
-        ResolvedJavaField resolvedField = (ResolvedJavaField) field;
 
         if (!parsingIntrinsic() && GeneratePIC.getValue(getOptions())) {
             graph.recordField(resolvedField);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParserOptions.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParserOptions.java	Thu Apr 06 14:31:32 2017 -0700
@@ -52,9 +52,6 @@
     @Option(help = "Maximum depth when inlining during bytecode parsing.", type = OptionType.Debug)
     public static final OptionKey<Integer> InlineDuringParsingMaxDepth = new OptionKey<>(10);
 
-    @Option(help = "Dump graphs after non-trivial changes during bytecode parsing.", type = OptionType.Debug)
-    public static final OptionKey<Boolean> DumpDuringGraphBuilding = new OptionKey<>(false);
-
     @Option(help = "When creating info points hide the methods of the substitutions.", type = OptionType.Debug)
     public static final OptionKey<Boolean> HideSubstitutionStates = new OptionKey<>(false);
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCControlFlow.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCControlFlow.java	Thu Apr 06 14:31:32 2017 -0700
@@ -22,6 +22,11 @@
  */
 package org.graalvm.compiler.lir.sparc;
 
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.sparc.SPARC.CPU;
+import static jdk.vm.ci.sparc.SPARC.g0;
+import static jdk.vm.ci.sparc.SPARCKind.WORD;
+import static jdk.vm.ci.sparc.SPARCKind.XWORD;
 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BPCC;
 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CBCOND;
 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.FBPCC;
@@ -68,19 +73,14 @@
 import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant;
 import static org.graalvm.compiler.lir.sparc.SPARCMove.const2reg;
 import static org.graalvm.compiler.lir.sparc.SPARCOP3Op.emitOp3;
-import static jdk.vm.ci.code.ValueUtil.asRegister;
-import static jdk.vm.ci.sparc.SPARC.CPU;
-import static jdk.vm.ci.sparc.SPARC.g0;
-import static jdk.vm.ci.sparc.SPARCKind.WORD;
-import static jdk.vm.ci.sparc.SPARCKind.XWORD;
 
 import java.util.ArrayList;
 import java.util.EnumSet;
 import java.util.List;
+
 import org.graalvm.compiler.asm.Assembler;
 import org.graalvm.compiler.asm.Assembler.LabelHint;
 import org.graalvm.compiler.asm.Label;
-import org.graalvm.compiler.core.common.NumUtil;
 import org.graalvm.compiler.asm.sparc.SPARCAssembler;
 import org.graalvm.compiler.asm.sparc.SPARCAssembler.BranchPredict;
 import org.graalvm.compiler.asm.sparc.SPARCAssembler.CC;
@@ -98,8 +98,8 @@
 import org.graalvm.compiler.lir.SwitchStrategy.BaseSwitchClosure;
 import org.graalvm.compiler.lir.Variable;
 import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+import org.graalvm.util.EconomicMap;
 import org.graalvm.util.Equivalence;
-import org.graalvm.util.EconomicMap;
 
 import jdk.vm.ci.code.Register;
 import jdk.vm.ci.meta.AllocatableValue;
@@ -159,6 +159,7 @@
         public CompareBranchOp(AllocatableValue x, Value y, Condition condition, LabelRef trueDestination, LabelRef falseDestination, SPARCKind kind, boolean unorderedIsTrue,
                         double trueDestinationProbability) {
             super(TYPE, SIZE);
+            assert x.getPlatformKind() == y.getPlatformKind() : String.format("PlatformKind of x must match PlatformKind of y. %s!=%s", x.getPlatformKind(), y.getPlatformKind());
             this.x = x;
             this.y = y;
             this.trueDestination = trueDestination;
@@ -250,6 +251,7 @@
          * @return true if the branch could be emitted
          */
         private boolean emitShortCompareBranch(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+            boolean isLong = kind == SPARCKind.XWORD;
             ConditionFlag actualConditionFlag = conditionFlag;
             Label actualTrueTarget = trueDestination.label();
             Label actualFalseTarget = falseDestination.label();
@@ -274,7 +276,7 @@
                     actualFalseTarget = tmpTarget;
                 }
             }
-            emitCBCond(masm, x, y, actualTrueTarget, actualConditionFlag);
+            emitCBCond(masm, x, y, actualTrueTarget, actualConditionFlag, isLong);
             if (needJump) {
                 masm.jmp(actualFalseTarget);
                 masm.nop();
@@ -282,16 +284,24 @@
             return true;
         }
 
-        private void emitCBCond(SPARCMacroAssembler masm, Value actualX, Value actualY, Label actualTrueTarget, ConditionFlag cFlag) {
+        private static void emitCBCond(SPARCMacroAssembler masm, Value actualX, Value actualY, Label actualTrueTarget, ConditionFlag cFlag, boolean isLong) {
             PlatformKind xKind = actualX.getPlatformKind();
-            boolean isLong = kind == SPARCKind.XWORD;
+            Register rs1 = asRegister(actualX, xKind);
             if (isJavaConstant(actualY)) {
                 JavaConstant c = asJavaConstant(actualY);
                 long constantY = c.isNull() ? 0 : c.asLong();
-                assert NumUtil.isInt(constantY);
-                CBCOND.emit(masm, cFlag, isLong, asRegister(actualX, xKind), (int) constantY, actualTrueTarget);
+                try (ScratchRegister scratch = masm.getScratchRegister()) {
+                    if (SPARCMacroAssembler.isSimm5(constantY)) {
+                        CBCOND.emit(masm, cFlag, isLong, rs1, (int) constantY, actualTrueTarget);
+                    } else { // !simm5
+                        Register rs2 = scratch.getRegister();
+                        masm.setx(constantY, rs2, false);
+                        CBCOND.emit(masm, cFlag, isLong, rs1, rs2, actualTrueTarget);
+                    }
+                }
             } else {
-                CBCOND.emit(masm, cFlag, isLong, asRegister(actualX, xKind), asRegister(actualY, xKind), actualTrueTarget);
+                Register rs2 = asRegister(actualY, xKind);
+                CBCOND.emit(masm, cFlag, isLong, rs1, rs2, actualTrueTarget);
             }
         }
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/RedundantMoveElimination.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/RedundantMoveElimination.java	Thu Apr 06 14:31:32 2017 -0700
@@ -217,7 +217,7 @@
         /**
          * Calculates the entry and exit states for all basic blocks.
          *
-         * @return Returns true on success and false if the the control flow is too complex.
+         * @return Returns true on success and false if the control flow is too complex.
          */
         @SuppressWarnings("try")
         private boolean solveDataFlow(LIR lir) {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/SwitchStrategy.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/SwitchStrategy.java	Thu Apr 06 14:31:32 2017 -0700
@@ -46,7 +46,7 @@
     private interface SwitchClosure {
         /**
          * Generates a conditional or unconditional jump. The jump will be unconditional if
-         * condition is null. If defaultTarget is true, then the jump will go the the default.
+         * condition is null. If defaultTarget is true, then the jump will go the default.
          *
          * @param index Index of the value and the jump target (only used if defaultTarget == false)
          * @param condition The condition on which to jump (can be null)
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScan.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScan.java	Thu Apr 06 14:31:32 2017 -0700
@@ -750,11 +750,11 @@
                 }
             }
         }
-        Debug.dump(Debug.BASIC_LOG_LEVEL, new LinearScanIntervalDumper(Arrays.copyOf(intervals, intervalsSize)), label);
+        Debug.dump(Debug.BASIC_LEVEL, new LinearScanIntervalDumper(Arrays.copyOf(intervals, intervalsSize)), label);
     }
 
     public void printLir(String label, @SuppressWarnings("unused") boolean hirValid) {
-        Debug.dump(Debug.INFO_LOG_LEVEL, ir, label);
+        Debug.dump(Debug.INFO_LEVEL, ir, label);
     }
 
     boolean verify() {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanOptimizeSpillPositionPhase.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanOptimizeSpillPositionPhase.java	Thu Apr 06 14:31:32 2017 -0700
@@ -110,12 +110,12 @@
                 interval.setSpillState(SpillState.StoreAtDefinition);
                 return;
             }
-            Debug.log(Debug.VERBOSE_LOG_LEVEL, "Spill block candidate (initial): %s", spillBlock);
+            Debug.log(Debug.VERBOSE_LEVEL, "Spill block candidate (initial): %s", spillBlock);
             // move out of loops
             if (defBlock.getLoopDepth() < spillBlock.getLoopDepth()) {
                 spillBlock = moveSpillOutOfLoop(defBlock, spillBlock);
             }
-            Debug.log(Debug.VERBOSE_LOG_LEVEL, "Spill block candidate (after loop optimizaton): %s", spillBlock);
+            Debug.log(Debug.VERBOSE_LEVEL, "Spill block candidate (after loop optimizaton): %s", spillBlock);
 
             /*
              * The spill block is the begin of the first split child (aka the value is on the
@@ -134,7 +134,7 @@
                 spillBlock = dom;
             }
             if (defBlock.equals(spillBlock)) {
-                Debug.log(Debug.VERBOSE_LOG_LEVEL, "Definition is the best choice: %s", defBlock);
+                Debug.log(Debug.VERBOSE_LEVEL, "Definition is the best choice: %s", defBlock);
                 // definition is the best choice
                 interval.setSpillState(SpillState.StoreAtDefinition);
                 return;
@@ -146,7 +146,7 @@
             }
 
             if (defBlock.probability() <= spillBlock.probability()) {
-                Debug.log(Debug.VERBOSE_LOG_LEVEL, "Definition has lower probability %s (%f) is lower than spill block %s (%f)", defBlock, defBlock.probability(), spillBlock,
+                Debug.log(Debug.VERBOSE_LEVEL, "Definition has lower probability %s (%f) is lower than spill block %s (%f)", defBlock, defBlock.probability(), spillBlock,
                                 spillBlock.probability());
                 // better spill block has the same probability -> do nothing
                 interval.setSpillState(SpillState.StoreAtDefinition);
@@ -164,7 +164,7 @@
             AllocatableValue fromLocation = interval.getSplitChildAtOpId(spillOpId, OperandMode.DEF, allocator).location();
             AllocatableValue toLocation = LinearScan.canonicalSpillOpr(interval);
             LIRInstruction move = allocator.getSpillMoveFactory().createMove(toLocation, fromLocation);
-            Debug.log(Debug.VERBOSE_LOG_LEVEL, "Insert spill move %s", move);
+            Debug.log(Debug.VERBOSE_LEVEL, "Insert spill move %s", move);
             move.setId(LinearScan.DOMINATOR_SPILL_MOVE_ID);
             /*
              * We can use the insertion buffer directly because we always insert at position 1.
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanWalker.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanWalker.java	Thu Apr 06 14:31:32 2017 -0700
@@ -861,7 +861,7 @@
                          * errors
                          */
                         allocator.assignSpillSlot(interval);
-                        Debug.dump(Debug.INFO_LOG_LEVEL, allocator.getLIR(), description);
+                        Debug.dump(Debug.INFO_LEVEL, allocator.getLIR(), description);
                         allocator.printIntervals(description);
                         throw new OutOfRegistersException("LinearScan: no register found", description);
                     }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/GlobalLivenessAnalysisPhase.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/GlobalLivenessAnalysisPhase.java	Thu Apr 06 14:31:32 2017 -0700
@@ -65,7 +65,7 @@
 
     private final class Analyser {
 
-        private static final int LOG_LEVEL = Debug.INFO_LOG_LEVEL;
+        private static final int LOG_LEVEL = Debug.INFO_LEVEL;
 
         /**
          * Bit map specifying which operands are live upon entry to this block. These are values
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceBuilderPhase.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceBuilderPhase.java	Thu Apr 06 14:31:32 2017 -0700
@@ -64,8 +64,8 @@
         // @formatter:on
     }
 
-    private static final int TRACE_LOG_LEVEL = 1;
-    public static final int TRACE_DUMP_LEVEL = 3;
+    private static final int TRACE_LOG_LEVEL = Debug.BASIC_LEVEL;
+    public static final int TRACE_DUMP_LEVEL = Debug.VERBOSE_LEVEL;
 
     @Override
     protected void run(TargetDescription target, LIRGenerationResult lirGenRes, AllocationContext context) {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceRegisterAllocationPhase.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceRegisterAllocationPhase.java	Thu Apr 06 14:31:32 2017 -0700
@@ -89,7 +89,7 @@
         final TraceRegisterAllocationPolicy plan = DefaultTraceRegisterAllocationPolicy.allocationPolicy(target, lirGenRes, spillMoveFactory, registerAllocationConfig, cachedStackSlots, resultTraces,
                         neverSpillConstant, livenessInfo, lir.getOptions());
 
-        Debug.dump(Debug.INFO_LOG_LEVEL, lir, "Before TraceRegisterAllocation");
+        Debug.dump(Debug.INFO_LEVEL, lir, "Before TraceRegisterAllocation");
         try (Scope s0 = Debug.scope("AllocateTraces", resultTraces, livenessInfo)) {
             for (Trace trace : resultTraces.getTraces()) {
                 tracesCounter.increment();
@@ -101,9 +101,9 @@
         } catch (Throwable e) {
             throw Debug.handle(e);
         }
-        if (Debug.isDumpEnabled(Debug.INFO_LOG_LEVEL)) {
+        if (Debug.isDumpEnabled(Debug.INFO_LEVEL)) {
             unnumberInstructions(lir);
-            Debug.dump(Debug.INFO_LOG_LEVEL, lir, "After trace allocation");
+            Debug.dump(Debug.INFO_LEVEL, lir, "After trace allocation");
         }
 
         TRACE_GLOBAL_MOVE_RESOLUTION_PHASE.apply(target, lirGenRes, traceContext);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanPhase.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanPhase.java	Thu Apr 06 14:31:32 2017 -0700
@@ -1073,7 +1073,7 @@
                         }
                     }
                 }
-                Debug.dump(Debug.INFO_LOG_LEVEL, this, label);
+                Debug.dump(Debug.INFO_LEVEL, this, label);
             }
         }
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanWalker.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanWalker.java	Thu Apr 06 14:31:32 2017 -0700
@@ -954,7 +954,7 @@
                              * avoid errors
                              */
                             allocator.assignSpillSlot(interval);
-                            if (Debug.isDumpEnabled(Debug.INFO_LOG_LEVEL)) {
+                            if (Debug.isDumpEnabled(Debug.INFO_LEVEL)) {
                                 dumpLIRAndIntervals(description);
                             }
                             throw new OutOfRegistersException("LinearScan: no register found", description);
@@ -991,7 +991,7 @@
     }
 
     protected void dumpLIRAndIntervals(String description) {
-        Debug.dump(Debug.INFO_LOG_LEVEL, allocator.getLIR(), description);
+        Debug.dump(Debug.INFO_LEVEL, allocator.getLIR(), description);
         allocator.printIntervals(description);
     }
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/asm/CompilationResultBuilder.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/asm/CompilationResultBuilder.java	Thu Apr 06 14:31:32 2017 -0700
@@ -461,7 +461,7 @@
         if (block == null) {
             return;
         }
-        boolean emitComment = Debug.isDumpEnabled(Debug.BASIC_LOG_LEVEL) || PrintLIRWithAssembly.getValue(getOptions());
+        boolean emitComment = Debug.isDumpEnabled(Debug.BASIC_LEVEL) || PrintLIRWithAssembly.getValue(getOptions());
         if (emitComment) {
             blockComment(String.format("block B%d %s", block.getId(), block.getLoop()));
         }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/constopt/ConstantLoadOptimization.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/constopt/ConstantLoadOptimization.java	Thu Apr 06 14:31:32 2017 -0700
@@ -214,7 +214,7 @@
                                     phiConstantsSkipped.increment();
                                 }
                                 phiConstants.set(var.index);
-                                Debug.log(Debug.VERBOSE_LOG_LEVEL, "Removing phi variable: %s", var);
+                                Debug.log(Debug.VERBOSE_LEVEL, "Removing phi variable: %s", var);
                             }
                         } else {
                             assert defined.get(var.index) : "phi but not defined? " + var;
@@ -291,7 +291,7 @@
                 // no better solution found
                 materializeAtDefinitionSkipped.increment();
             }
-            Debug.dump(Debug.INFO_LOG_LEVEL, constTree, "ConstantTree for %s", tree.getVariable());
+            Debug.dump(Debug.DETAILED_LEVEL, constTree, "ConstantTree for %s", tree.getVariable());
         }
 
         private void createLoads(DefUseTree tree, ConstantTree constTree, AbstractBlockBase<?> startBlock) {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/constopt/ConstantTreeAnalyzer.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/constopt/ConstantTreeAnalyzer.java	Thu Apr 06 14:31:32 2017 -0700
@@ -72,19 +72,19 @@
         worklist.offerLast(startBlock);
         while (!worklist.isEmpty()) {
             AbstractBlockBase<?> block = worklist.pollLast();
-            try (Indent i = Debug.logAndIndent(Debug.VERBOSE_LOG_LEVEL, "analyze: %s", block)) {
+            try (Indent i = Debug.logAndIndent(Debug.VERBOSE_LEVEL, "analyze: %s", block)) {
                 assert block != null : "worklist is empty!";
                 assert isMarked(block) : "Block not part of the dominator tree: " + block;
 
                 if (isLeafBlock(block)) {
-                    Debug.log(Debug.VERBOSE_LOG_LEVEL, "leaf block");
+                    Debug.log(Debug.VERBOSE_LEVEL, "leaf block");
                     leafCost(block);
                     continue;
                 }
 
                 if (!visited.get(block.getId())) {
                     // if not yet visited (and not a leaf block) process all children first!
-                    Debug.log(Debug.VERBOSE_LOG_LEVEL, "not marked");
+                    Debug.log(Debug.VERBOSE_LEVEL, "not marked");
                     worklist.offerLast(block);
                     AbstractBlockBase<?> dominated = block.getFirstDominated();
                     while (dominated != null) {
@@ -93,7 +93,7 @@
                     }
                     visited.set(block.getId());
                 } else {
-                    Debug.log(Debug.VERBOSE_LOG_LEVEL, "marked");
+                    Debug.log(Debug.VERBOSE_LEVEL, "marked");
                     // otherwise, process block
                     process(block);
                 }
@@ -162,7 +162,7 @@
 
     private void filteredPush(Deque<AbstractBlockBase<?>> worklist, AbstractBlockBase<?> block) {
         if (isMarked(block)) {
-            Debug.log(Debug.VERBOSE_LOG_LEVEL, "adding %s to the worklist", block);
+            Debug.log(Debug.VERBOSE_LEVEL, "adding %s to the worklist", block);
             worklist.offerLast(block);
         }
     }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/LIRPhase.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/LIRPhase.java	Thu Apr 06 14:31:32 2017 -0700
@@ -113,8 +113,8 @@
         try (Scope s = Debug.scope(getName(), this)) {
             try (DebugCloseable a = timer.start(); DebugCloseable c = memUseTracker.start()) {
                 run(target, lirGenRes, context);
-                if (dumpLIR && Debug.isDumpEnabled(Debug.BASIC_LOG_LEVEL)) {
-                    Debug.dump(Debug.BASIC_LOG_LEVEL, lirGenRes.getLIR(), "%s", getName());
+                if (dumpLIR && Debug.isDumpEnabled(Debug.BASIC_LEVEL)) {
+                    Debug.dump(Debug.BASIC_LEVEL, lirGenRes.getLIR(), "%s", getName());
                 }
             }
         } catch (Throwable e) {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/ssa/SSAVerifier.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/ssa/SSAVerifier.java	Thu Apr 06 14:31:32 2017 -0700
@@ -87,7 +87,7 @@
                 doBlock(pred);
             }
         }
-        try (Indent indent = Debug.logAndIndent(Debug.INFO_LOG_LEVEL, "handle block %s", b)) {
+        try (Indent indent = Debug.logAndIndent(Debug.INFO_LEVEL, "handle block %s", b)) {
             assert verifyBlock(b);
         }
     }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/stackslotalloc/LSStackSlotAllocator.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/stackslotalloc/LSStackSlotAllocator.java	Thu Apr 06 14:31:32 2017 -0700
@@ -131,7 +131,7 @@
 
         @SuppressWarnings("try")
         private void allocate() {
-            Debug.dump(Debug.INFO_LOG_LEVEL, lir, "After StackSlot numbering");
+            Debug.dump(Debug.INFO_LEVEL, lir, "After StackSlot numbering");
 
             long currentFrameSize = StackSlotAllocatorUtil.allocatedFramesize.isEnabled() ? frameMapBuilder.getFrameMap().currentFrameSize() : 0;
             EconomicSet<LIRInstruction> usePos;
@@ -145,14 +145,14 @@
                     assert verifyIntervals();
                 }
             }
-            if (Debug.isDumpEnabled(Debug.INFO_LOG_LEVEL)) {
+            if (Debug.isDumpEnabled(Debug.INFO_LEVEL)) {
                 dumpIntervals("Before stack slot allocation");
             }
             // step 4: allocate stack slots
             try (DebugCloseable t = AllocateSlotsTimer.start()) {
                 allocateStackSlots();
             }
-            if (Debug.isDumpEnabled(Debug.INFO_LOG_LEVEL)) {
+            if (Debug.isDumpEnabled(Debug.INFO_LEVEL)) {
                 dumpIntervals("After stack slot allocation");
             }
 
@@ -160,7 +160,7 @@
             try (DebugCloseable t = AssignSlotsTimer.start()) {
                 assignStackSlots(usePos);
             }
-            Debug.dump(Debug.INFO_LOG_LEVEL, lir, "After StackSlot assignment");
+            Debug.dump(Debug.INFO_LEVEL, lir, "After StackSlot assignment");
             if (StackSlotAllocatorUtil.allocatedFramesize.isEnabled()) {
                 StackSlotAllocatorUtil.allocatedFramesize.add(frameMapBuilder.getFrameMap().currentFrameSize() - currentFrameSize);
             }
@@ -256,13 +256,13 @@
                      */
                     location = StackSlot.get(current.kind(), slot.getRawOffset(), slot.getRawAddFrameSize());
                     StackSlotAllocatorUtil.reusedSlots.increment();
-                    Debug.log(Debug.BASIC_LOG_LEVEL, "Reuse stack slot %s (reallocated from %s) for virtual stack slot %s", location, slot, virtualSlot);
+                    Debug.log(Debug.BASIC_LEVEL, "Reuse stack slot %s (reallocated from %s) for virtual stack slot %s", location, slot, virtualSlot);
                 } else {
                     // Allocate new stack slot.
                     location = frameMapBuilder.getFrameMap().allocateSpillSlot(virtualSlot.getValueKind());
                     StackSlotAllocatorUtil.virtualFramesize.add(frameMapBuilder.getFrameMap().spillSlotSize(virtualSlot.getValueKind()));
                     StackSlotAllocatorUtil.allocatedSlots.increment();
-                    Debug.log(Debug.BASIC_LOG_LEVEL, "New stack slot %s for virtual stack slot %s", location, virtualSlot);
+                    Debug.log(Debug.BASIC_LEVEL, "New stack slot %s for virtual stack slot %s", location, virtualSlot);
                 }
             }
             Debug.log("Allocate location %s for interval %s", location, current);
@@ -434,7 +434,7 @@
         }
 
         private void dumpIntervals(String label) {
-            Debug.dump(Debug.INFO_LOG_LEVEL, new StackIntervalDumper(Arrays.copyOf(stackSlotMap, stackSlotMap.length)), label);
+            Debug.dump(Debug.INFO_LEVEL, new StackIntervalDumper(Arrays.copyOf(stackSlotMap, stackSlotMap.length)), label);
         }
 
     }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopFullUnrollPhase.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopFullUnrollPhase.java	Thu Apr 06 14:31:32 2017 -0700
@@ -54,7 +54,7 @@
                         Debug.log("FullUnroll %s", loop);
                         LoopTransformations.fullUnroll(loop, context, canonicalizer);
                         FULLY_UNROLLED_LOOPS.increment();
-                        Debug.dump(Debug.INFO_LOG_LEVEL, graph, "FullUnroll %s", loop);
+                        Debug.dump(Debug.DETAILED_LEVEL, graph, "FullUnroll %s", loop);
                         peeled = true;
                         break;
                     }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopPeelingPhase.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopPeelingPhase.java	Thu Apr 06 14:31:32 2017 -0700
@@ -45,7 +45,7 @@
                     if (getPolicies().shouldPeel(loop, data.getCFG(), context.getMetaAccess())) {
                         Debug.log("Peeling %s", loop);
                         LoopTransformations.peel(loop);
-                        Debug.dump(Debug.INFO_LOG_LEVEL, graph, "Peeling %s", loop);
+                        Debug.dump(Debug.DETAILED_LEVEL, graph, "Peeling %s", loop);
                     }
                 }
                 data.deleteUnusedNodes();
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopUnswitchingPhase.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopUnswitchingPhase.java	Thu Apr 06 14:31:32 2017 -0700
@@ -61,7 +61,7 @@
                                     logUnswitch(loop, controlSplits);
                                 }
                                 LoopTransformations.unswitch(loop, controlSplits);
-                                Debug.dump(Debug.INFO_LOG_LEVEL, graph, "After unswitch %s", controlSplits);
+                                Debug.dump(Debug.DETAILED_LEVEL, graph, "After unswitch %s", controlSplits);
                                 UNSWITCHED.increment();
                                 unswitched = true;
                                 break;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.test/src/org/graalvm/compiler/loop/test/LoopsDataTest.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.test/src/org/graalvm/compiler/loop/test/LoopsDataTest.java	Thu Apr 06 14:31:32 2017 -0700
@@ -77,8 +77,8 @@
         Assert.assertEquals(1, loops.outerFirst().get(0).loop().getDepth());
         Assert.assertEquals(1, loops.outerFirst().get(1).loop().getDepth());
         Assert.assertEquals(2, loops.outerFirst().get(2).loop().getDepth());
-        Assert.assertEquals(2, loops.outerFirst().get(3).loop().getDepth());
-        Assert.assertEquals(3, loops.outerFirst().get(4).loop().getDepth());
+        Assert.assertEquals(3, loops.outerFirst().get(3).loop().getDepth());
+        Assert.assertEquals(2, loops.outerFirst().get(4).loop().getDepth());
         Assert.assertEquals(2, loops.outerFirst().get(5).loop().getDepth());
         Assert.assertEquals(3, loops.outerFirst().get(6).loop().getDepth());
         Assert.assertEquals(4, loops.outerFirst().get(7).loop().getDepth());
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/DerivedOffsetInductionVariable.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/DerivedOffsetInductionVariable.java	Thu Apr 06 14:31:32 2017 -0700
@@ -90,7 +90,7 @@
     @Override
     public ValueNode strideNode() {
         if (value instanceof SubNode && base.valueNode() == value.getY()) {
-            return graph().unique(new NegateNode(base.strideNode()));
+            return graph().addOrUniqueWithInputs(NegateNode.create(base.strideNode()));
         }
         return base.strideNode();
     }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/micro/benchmarks/ArrayListBenchmark.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/micro/benchmarks/ArrayListBenchmark.java	Thu Apr 06 14:31:32 2017 -0700
@@ -24,13 +24,14 @@
 
 import java.util.ArrayList;
 
+import org.graalvm.compiler.microbenchmarks.graal.GraalBenchmark;
 import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.Level;
 import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.Setup;
 import org.openjdk.jmh.annotations.State;
 import org.openjdk.jmh.annotations.Warmup;
 
-import org.graalvm.compiler.microbenchmarks.graal.GraalBenchmark;
-
 /**
  * Benchmarks cost of ArrayList.
  */
@@ -40,7 +41,7 @@
 
     @State(Scope.Benchmark)
     public static class ThreadState {
-        ArrayList<Integer> list = new ArrayList<>(N);
+        final ArrayList<Integer> list = new ArrayList<>(N);
     }
 
     @Benchmark
@@ -61,9 +62,20 @@
         state.list.clear();
     }
 
+    @State(Scope.Benchmark)
+    public static class ClearedThreadState {
+        final ArrayList<Integer> list = new ArrayList<>(N);
+
+        // We don't want to measure the cost of list clearing
+        @Setup(Level.Invocation)
+        public void beforeInvocation() {
+            list.clear();
+        }
+    }
+
     @Benchmark
     @Warmup(iterations = 20)
-    public void addNull(ThreadState state) {
+    public void addNull(ClearedThreadState state) {
         for (int i = 0; i < N; ++i) {
             state.list.add(null);
         }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/lir/GraalCompilerState.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/lir/GraalCompilerState.java	Thu Apr 06 14:31:32 2017 -0700
@@ -374,13 +374,17 @@
         codeEmittingOrder = ComputeBlockOrder.computeCodeEmittingOrder(blocks.length, startBlock);
         linearScanOrder = ComputeBlockOrder.computeLinearScanOrder(blocks.length, startBlock);
 
-        LIR lir = new LIR(cfg, linearScanOrder, codeEmittingOrder, graph.getOptions());
+        LIR lir = new LIR(cfg, linearScanOrder, codeEmittingOrder, getGraphOptions());
         FrameMapBuilder frameMapBuilder = request.backend.newFrameMapBuilder(registerConfig);
         lirGenRes = request.backend.newLIRGenerationResult(graph.compilationId(), lir, frameMapBuilder, request.graph, stub);
         lirGenTool = request.backend.newLIRGenerator(lirGenRes);
         nodeLirGen = request.backend.newNodeLIRBuilder(request.graph, lirGenTool);
     }
 
+    protected OptionValues getGraphOptions() {
+        return graph.getOptions();
+    }
+
     private static ControlFlowGraph deepCopy(ControlFlowGraph cfg) {
         return ControlFlowGraph.compute(cfg.graph, true, true, true, true);
     }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/lir/trace/TraceLSRAIntervalBuildingBench.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/lir/trace/TraceLSRAIntervalBuildingBench.java	Thu Apr 06 14:31:32 2017 -0700
@@ -28,6 +28,7 @@
 import org.graalvm.compiler.lir.alloc.trace.GlobalLivenessAnalysisPhase;
 import org.graalvm.compiler.lir.alloc.trace.GlobalLivenessInfo;
 import org.graalvm.compiler.lir.alloc.trace.TraceBuilderPhase;
+import org.graalvm.compiler.lir.alloc.trace.TraceRegisterAllocationPhase;
 import org.graalvm.compiler.lir.alloc.trace.lsra.TraceLinearScanLifetimeAnalysisPhase;
 import org.graalvm.compiler.lir.alloc.trace.lsra.TraceLinearScanLifetimeAnalysisPhase.Analyser;
 import org.graalvm.compiler.lir.alloc.trace.lsra.TraceLinearScanPhase;
@@ -40,6 +41,7 @@
 import org.graalvm.compiler.lir.phases.LIRSuites;
 import org.graalvm.compiler.microbenchmarks.graal.GraalBenchmark;
 import org.graalvm.compiler.microbenchmarks.lir.GraalCompilerState;
+import org.graalvm.compiler.options.OptionValues;
 import org.openjdk.jmh.annotations.Benchmark;
 import org.openjdk.jmh.annotations.Level;
 import org.openjdk.jmh.annotations.Param;
@@ -90,6 +92,11 @@
             return new LIRSuites(ls.getPreAllocationOptimizationStage(), allocationStage, ls.getPostAllocationOptimizationStage());
         }
 
+        @Override
+        protected OptionValues getGraphOptions() {
+            return new OptionValues(super.getGraphOptions(), TraceRegisterAllocationPhase.Options.TraceRAuseInterTraceHints, false);
+        }
+
         @Setup(Level.Trial)
         public void setup() {
             initializeMethod();
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FixedGuardNode.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FixedGuardNode.java	Thu Apr 06 14:31:32 2017 -0700
@@ -86,8 +86,8 @@
             /*
              * Don't allow guards with action None and reason RuntimeConstraint to float. In cases
              * where 2 guards are testing equivalent conditions they might be lowered at the same
-             * location. If the guard with the None action is lowered before the the other guard
-             * then the code will be stuck repeatedly deoptimizing without invalidating the code.
+             * location. If the guard with the None action is lowered before the other guard then
+             * the code will be stuck repeatedly deoptimizing without invalidating the code.
              * Conditional elimination will eliminate the guard if it's truly redundant in this
              * case.
              */
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FrameState.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FrameState.java	Thu Apr 06 14:31:32 2017 -0700
@@ -105,7 +105,7 @@
      */
     @OptionalInput NodeInputList<ValueNode> values;
 
-    @OptionalInput(Association) NodeInputList<MonitorIdNode> monitorIds;
+    @Input(Association) NodeInputList<MonitorIdNode> monitorIds;
 
     @OptionalInput(State) NodeInputList<EscapeObjectState> virtualObjectMappings;
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphDecoder.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphDecoder.java	Thu Apr 06 14:31:32 2017 -0700
@@ -37,8 +37,8 @@
 import java.util.SortedMap;
 import java.util.TreeMap;
 
+import org.graalvm.compiler.core.common.Fields;
 import org.graalvm.compiler.core.common.PermanentBailoutException;
-import org.graalvm.compiler.core.common.Fields;
 import org.graalvm.compiler.core.common.util.TypeReader;
 import org.graalvm.compiler.core.common.util.UnsafeArrayTypeReader;
 import org.graalvm.compiler.debug.Debug;
@@ -61,9 +61,9 @@
 import org.graalvm.compiler.nodes.calc.FloatingNode;
 import org.graalvm.compiler.nodes.extended.IntegerSwitchNode;
 import org.graalvm.compiler.nodes.graphbuilderconf.LoopExplosionPlugin.LoopExplosionKind;
-import org.graalvm.util.Equivalence;
 import org.graalvm.util.EconomicMap;
 import org.graalvm.util.EconomicSet;
+import org.graalvm.util.Equivalence;
 
 import jdk.vm.ci.code.Architecture;
 import jdk.vm.ci.meta.DeoptimizationAction;
@@ -85,8 +85,6 @@
     protected class MethodScope {
         /** The loop that contains the call. Only non-null during method inlining. */
         public final LoopScope callerLoopScope;
-        /** The target graph where decoded nodes are added to. */
-        public final StructuredGraph graph;
         /**
          * Mark for nodes that were present before the decoding of this method started. Note that
          * nodes that were decoded after the mark can still be part of an outer method, since
@@ -95,20 +93,19 @@
         public final Graph.Mark methodStartMark;
         /** The encode graph that is decoded. */
         public final EncodedGraph encodedGraph;
+        /** The highest node order id that a fixed node has in the EncodedGraph. */
+        public final int maxFixedNodeOrderId;
         /** Access to the encoded graph. */
         public final TypeReader reader;
         /** The kind of loop explosion to be performed during decoding. */
         public final LoopExplosionKind loopExplosion;
-        /** A list of tasks to run before the method scope is closed. */
-        public final List<Runnable> cleanupTasks;
 
         /** All return nodes encountered during decoding. */
-        public final List<ReturnNode> returnNodes;
-        /** The exception unwind node encountered during decoding, or null. */
-        public final List<UnwindNode> unwindNodes;
+        public final List<ControlSinkNode> returnAndUnwindNodes;
 
         /** All merges created during loop explosion. */
         public final EconomicSet<Node> loopExplosionMerges;
+
         /**
          * The start of explosion, and the merge point for when irreducible loops are detected. Only
          * used when {@link MethodScope#loopExplosion} is {@link LoopExplosionKind#MERGE_EXPLODE}.
@@ -117,16 +114,14 @@
 
         protected MethodScope(LoopScope callerLoopScope, StructuredGraph graph, EncodedGraph encodedGraph, LoopExplosionKind loopExplosion) {
             this.callerLoopScope = callerLoopScope;
-            this.graph = graph;
             this.methodStartMark = graph.getMark();
             this.encodedGraph = encodedGraph;
             this.loopExplosion = loopExplosion;
-            this.cleanupTasks = new ArrayList<>(2);
-            this.returnNodes = new ArrayList<>(1);
-            this.unwindNodes = new ArrayList<>(0);
+            this.returnAndUnwindNodes = new ArrayList<>(2);
 
             if (encodedGraph != null) {
                 reader = UnsafeArrayTypeReader.create(encodedGraph.getEncoding(), encodedGraph.getStartOffset(), architecture.supportsUnalignedMemoryAccess());
+                maxFixedNodeOrderId = reader.getUVInt();
                 if (encodedGraph.nodeStartOffsets == null) {
                     int nodeCount = reader.getUVInt();
                     int[] nodeStartOffsets = new int[nodeCount];
@@ -137,6 +132,7 @@
                 }
             } else {
                 reader = null;
+                maxFixedNodeOrderId = 0;
             }
 
             if (loopExplosion != LoopExplosionKind.NONE) {
@@ -145,6 +141,10 @@
                 loopExplosionMerges = null;
             }
         }
+
+        public boolean isInlinedMethod() {
+            return false;
+        }
     }
 
     /** Decoding state maintained for each loop in the encoded graph. */
@@ -175,23 +175,24 @@
         public final Node[] createdNodes;
         /**
          * Nodes that have been created in outer loop scopes and existed before starting to process
-         * this loop, indexed by the orderId.
+         * this loop, indexed by the orderId. Only used when {@link MethodScope#loopExplosion} is
+         * not {@link LoopExplosionKind#NONE}.
          */
         public final Node[] initialCreatedNodes;
 
         protected LoopScope(MethodScope methodScope) {
             this.methodScope = methodScope;
             this.outer = null;
-            this.nextIterations = methodScope.loopExplosion == LoopExplosionKind.FULL_EXPLODE_UNTIL_RETURN ? new ArrayDeque<>() : null;
+            this.nextIterations = methodScope.loopExplosion == LoopExplosionKind.FULL_EXPLODE_UNTIL_RETURN ? new ArrayDeque<>(2) : null;
             this.loopDepth = 0;
             this.loopIteration = 0;
             this.iterationStates = null;
             this.loopBeginOrderId = -1;
 
             int nodeCount = methodScope.encodedGraph.nodeStartOffsets.length;
-            this.nodesToProcess = new BitSet(nodeCount);
-            this.initialCreatedNodes = new Node[nodeCount];
+            this.nodesToProcess = new BitSet(methodScope.maxFixedNodeOrderId);
             this.createdNodes = new Node[nodeCount];
+            this.initialCreatedNodes = null;
         }
 
         protected LoopScope(MethodScope methodScope, LoopScope outer, int loopDepth, int loopIteration, int loopBeginOrderId, Node[] initialCreatedNodes, Node[] createdNodes,
@@ -203,9 +204,9 @@
             this.nextIterations = nextIterations;
             this.iterationStates = iterationStates;
             this.loopBeginOrderId = loopBeginOrderId;
-            this.nodesToProcess = new BitSet(initialCreatedNodes.length);
+            this.nodesToProcess = new BitSet(methodScope.maxFixedNodeOrderId);
             this.initialCreatedNodes = initialCreatedNodes;
-            this.createdNodes = Arrays.copyOf(createdNodes, createdNodes.length);
+            this.createdNodes = createdNodes;
         }
 
         @Override
@@ -338,18 +339,23 @@
     }
 
     protected final Architecture architecture;
+    /** The target graph where decoded nodes are added to. */
+    protected final StructuredGraph graph;
+    private final EconomicMap<NodeClass<?>, ArrayDeque<Node>> reusableFloatingNodes;
 
-    public GraphDecoder(Architecture architecture) {
+    public GraphDecoder(Architecture architecture, StructuredGraph graph) {
         this.architecture = architecture;
+        this.graph = graph;
+        reusableFloatingNodes = EconomicMap.create(Equivalence.IDENTITY);
     }
 
     @SuppressWarnings("try")
-    public final void decode(StructuredGraph graph, EncodedGraph encodedGraph) {
+    public final void decode(EncodedGraph encodedGraph) {
         try (Debug.Scope scope = Debug.scope("GraphDecoder", graph)) {
             MethodScope methodScope = new MethodScope(null, graph, encodedGraph, LoopExplosionKind.NONE);
             decode(createInitialLoopScope(methodScope, null));
             cleanupGraph(methodScope);
-            assert methodScope.graph.verify();
+            assert graph.verify();
         } catch (Throwable ex) {
             Debug.handle(ex);
         }
@@ -370,14 +376,10 @@
             startNode.setNext(firstNode);
             loopScope.nodesToProcess.set(GraphEncoder.FIRST_NODE_ORDER_ID);
         } else {
-            firstNode = methodScope.graph.start();
+            firstNode = graph.start();
             registerNode(loopScope, GraphEncoder.START_NODE_ORDER_ID, firstNode, false, false);
             loopScope.nodesToProcess.set(GraphEncoder.START_NODE_ORDER_ID);
         }
-
-        if (methodScope.loopExplosion == LoopExplosionKind.MERGE_EXPLODE) {
-            methodScope.cleanupTasks.add(new LoopDetector(methodScope, startNode));
-        }
         return loopScope;
     }
 
@@ -411,18 +413,26 @@
             }
 
             /*
-             * Finished with an inlined method. Perform all registered end-of-method cleanup tasks
-             * and continue with loop that contained the call.
+             * Finished with an inlined method. Perform end-of-method cleanup tasks.
              */
-            for (Runnable task : methodScope.cleanupTasks) {
-                task.run();
+            if (methodScope.loopExplosion == LoopExplosionKind.MERGE_EXPLODE) {
+                LoopDetector loopDetector = new LoopDetector(graph, methodScope);
+                loopDetector.run();
             }
+            if (methodScope.isInlinedMethod()) {
+                finishInlining(methodScope);
+            }
+
+            /* continue with the caller */
             loopScope = methodScope.callerLoopScope;
         }
     }
 
+    protected void finishInlining(@SuppressWarnings("unused") MethodScope inlineScope) {
+    }
+
     private static void propagateCreatedNodes(LoopScope loopScope) {
-        if (loopScope.outer == null) {
+        if (loopScope.outer == null || loopScope.createdNodes != loopScope.outer.createdNodes) {
             return;
         }
 
@@ -474,7 +484,7 @@
                 LoopScope outerScope = loopScope.outer;
                 int nextIterationNumber = outerScope.nextIterations.isEmpty() ? outerScope.loopIteration + 1 : outerScope.nextIterations.getLast().loopIteration + 1;
                 successorAddScope = new LoopScope(methodScope, outerScope.outer, outerScope.loopDepth, nextIterationNumber, outerScope.loopBeginOrderId, outerScope.initialCreatedNodes,
-                                loopScope.initialCreatedNodes, outerScope.nextIterations, outerScope.iterationStates);
+                                Arrays.copyOf(loopScope.initialCreatedNodes, loopScope.initialCreatedNodes.length), outerScope.nextIterations, outerScope.iterationStates);
                 checkLoopExplosionIteration(methodScope, successorAddScope);
 
                 /*
@@ -496,8 +506,8 @@
         methodScope.reader.setByteIndex(methodScope.encodedGraph.nodeStartOffsets[nodeOrderId]);
         int typeId = methodScope.reader.getUVInt();
         assert node.getNodeClass() == methodScope.encodedGraph.getNodeClasses()[typeId];
+        makeFixedNodeInputs(methodScope, loopScope, node);
         readProperties(methodScope, node);
-        makeInputNodes(methodScope, loopScope, node, true);
         makeSuccessorStubs(methodScope, successorAddScope, node, updatePredecessors);
 
         LoopScope resultScope = loopScope;
@@ -533,13 +543,16 @@
                 if (merge instanceof LoopBeginNode) {
                     assert phiNodeScope == phiInputScope && phiNodeScope == loopScope;
                     resultScope = new LoopScope(methodScope, loopScope, loopScope.loopDepth + 1, 0, mergeOrderId,
-                                    Arrays.copyOf(loopScope.createdNodes, loopScope.createdNodes.length), loopScope.createdNodes, //
-                                    methodScope.loopExplosion != LoopExplosionKind.NONE ? new ArrayDeque<>() : null, //
+                                    methodScope.loopExplosion != LoopExplosionKind.NONE ? Arrays.copyOf(loopScope.createdNodes, loopScope.createdNodes.length) : null,
+                                    methodScope.loopExplosion != LoopExplosionKind.NONE ? Arrays.copyOf(loopScope.createdNodes, loopScope.createdNodes.length) : loopScope.createdNodes, //
+                                    methodScope.loopExplosion != LoopExplosionKind.NONE ? new ArrayDeque<>(2) : null, //
                                     methodScope.loopExplosion == LoopExplosionKind.MERGE_EXPLODE ? EconomicMap.create(Equivalence.DEFAULT) : null);
                     phiInputScope = resultScope;
                     phiNodeScope = resultScope;
 
-                    registerNode(loopScope, mergeOrderId, null, true, true);
+                    if (methodScope.loopExplosion != LoopExplosionKind.NONE) {
+                        registerNode(loopScope, mergeOrderId, null, true, true);
+                    }
                     loopScope.nodesToProcess.clear(mergeOrderId);
                     resultScope.nodesToProcess.set(mergeOrderId);
                 }
@@ -551,11 +564,8 @@
             InvokeData invokeData = readInvokeData(methodScope, nodeOrderId, (Invoke) node);
             resultScope = handleInvoke(methodScope, loopScope, invokeData);
 
-        } else if (node instanceof ReturnNode) {
-            methodScope.returnNodes.add((ReturnNode) node);
-        } else if (node instanceof UnwindNode) {
-            methodScope.unwindNodes.add((UnwindNode) node);
-
+        } else if (node instanceof ReturnNode || node instanceof UnwindNode) {
+            methodScope.returnAndUnwindNodes.add((ControlSinkNode) node);
         } else {
             handleFixedNode(methodScope, loopScope, nodeOrderId, node);
         }
@@ -642,7 +652,7 @@
             }
         }
 
-        MergeNode merge = methodScope.graph.add(new MergeNode());
+        MergeNode merge = graph.add(new MergeNode());
         methodScope.loopExplosionMerges.add(merge);
 
         if (methodScope.loopExplosion == LoopExplosionKind.MERGE_EXPLODE) {
@@ -655,11 +665,11 @@
 
             List<ValueNode> newFrameStateValues = new ArrayList<>();
             for (ValueNode frameStateValue : frameState.values) {
-                if (frameStateValue == null || frameStateValue.isConstant() || !methodScope.graph.isNew(methodScope.methodStartMark, frameStateValue)) {
+                if (frameStateValue == null || frameStateValue.isConstant() || !graph.isNew(methodScope.methodStartMark, frameStateValue)) {
                     newFrameStateValues.add(frameStateValue);
 
                 } else {
-                    ProxyPlaceholder newFrameStateValue = methodScope.graph.unique(new ProxyPlaceholder(frameStateValue, merge));
+                    ProxyPlaceholder newFrameStateValue = graph.unique(new ProxyPlaceholder(frameStateValue, merge));
                     newFrameStateValues.add(newFrameStateValue);
 
                     /*
@@ -670,14 +680,19 @@
                         if (loopScope.createdNodes[i] == frameStateValue) {
                             loopScope.createdNodes[i] = newFrameStateValue;
                         }
-                        if (loopScope.initialCreatedNodes[i] == frameStateValue) {
-                            loopScope.initialCreatedNodes[i] = newFrameStateValue;
+                    }
+
+                    if (loopScope.initialCreatedNodes != null) {
+                        for (int i = 0; i < loopScope.initialCreatedNodes.length; i++) {
+                            if (loopScope.initialCreatedNodes[i] == frameStateValue) {
+                                loopScope.initialCreatedNodes[i] = newFrameStateValue;
+                            }
                         }
                     }
                 }
             }
 
-            FrameState newFrameState = methodScope.graph.add(new FrameState(frameState.outerFrameState(), frameState.getCode(), frameState.bci, newFrameStateValues, frameState.localsSize(),
+            FrameState newFrameState = graph.add(new FrameState(frameState.outerFrameState(), frameState.getCode(), frameState.bci, newFrameStateValues, frameState.localsSize(),
                             frameState.stackSize(), frameState.rethrowException(), frameState.duringCall(), frameState.monitorIds(), frameState.virtualObjectMappings()));
 
             frameState.replaceAtUsagesAndDelete(newFrameState);
@@ -708,7 +723,7 @@
     }
 
     protected FixedNode handleLoopExplosionEnd(MethodScope methodScope, LoopScope loopScope, LoopEndNode loopEnd) {
-        EndNode replacementNode = methodScope.graph.add(new EndNode());
+        EndNode replacementNode = graph.add(new EndNode());
         loopEnd.replaceAtPredecessor(replacementNode);
         loopEnd.safeDelete();
 
@@ -716,7 +731,7 @@
         if (methodScope.loopExplosion != LoopExplosionKind.FULL_UNROLL || loopScope.nextIterations.isEmpty()) {
             int nextIterationNumber = loopScope.nextIterations.isEmpty() ? loopScope.loopIteration + 1 : loopScope.nextIterations.getLast().loopIteration + 1;
             LoopScope nextIterationScope = new LoopScope(methodScope, loopScope.outer, loopScope.loopDepth, nextIterationNumber, loopScope.loopBeginOrderId, loopScope.initialCreatedNodes,
-                            loopScope.initialCreatedNodes, loopScope.nextIterations, loopScope.iterationStates);
+                            Arrays.copyOf(loopScope.initialCreatedNodes, loopScope.initialCreatedNodes.length), loopScope.nextIterations, loopScope.iterationStates);
             checkLoopExplosionIteration(methodScope, nextIterationScope);
             loopScope.nextIterations.addLast(nextIterationScope);
             registerNode(nextIterationScope, loopScope.loopBeginOrderId, null, true, true);
@@ -749,7 +764,9 @@
              * The ProxyNode transports a value from the loop to the outer scope. We therefore
              * register it in the outer scope.
              */
-            registerNode(loopScope.outer, proxyOrderId, proxy, false, false);
+            if (loopScope.outer.createdNodes != loopScope.createdNodes) {
+                registerNode(loopScope.outer, proxyOrderId, proxy, false, false);
+            }
         }
     }
 
@@ -757,7 +774,7 @@
         assert loopExit.stateAfter() == null;
         int stateAfterOrderId = readOrderId(methodScope);
 
-        BeginNode begin = methodScope.graph.add(new BeginNode());
+        BeginNode begin = graph.add(new BeginNode());
 
         FixedNode loopExitSuccessor = loopExit.next();
         loopExit.replaceAtPredecessor(begin);
@@ -768,14 +785,14 @@
              * This exit might end up as a loop exit of a loop detected after partial evaluation. We
              * need to be able to create a FrameState and the necessary proxy nodes in this case.
              */
-            loopExitPlaceholder = methodScope.graph.add(new MergeNode());
+            loopExitPlaceholder = graph.add(new MergeNode());
             methodScope.loopExplosionMerges.add(loopExitPlaceholder);
 
-            EndNode end = methodScope.graph.add(new EndNode());
+            EndNode end = graph.add(new EndNode());
             begin.setNext(end);
             loopExitPlaceholder.addForwardEnd(end);
 
-            begin = methodScope.graph.add(new BeginNode());
+            begin = graph.add(new BeginNode());
             loopExitPlaceholder.setNext(begin);
         }
 
@@ -793,10 +810,10 @@
 
         } else if (existingExit instanceof BeginNode) {
             /* Second loop iteration that exits. Create the merge. */
-            merge = methodScope.graph.add(new MergeNode());
+            merge = graph.add(new MergeNode());
             registerNode(outerScope, loopExitOrderId, merge, true, false);
             /* Add the first iteration. */
-            EndNode firstEnd = methodScope.graph.add(new EndNode());
+            EndNode firstEnd = graph.add(new EndNode());
             ((BeginNode) existingExit).setNext(firstEnd);
             merge.addForwardEnd(firstEnd);
             merge.setNext(loopExitSuccessor);
@@ -807,7 +824,7 @@
         }
 
         if (merge != null) {
-            EndNode end = methodScope.graph.add(new EndNode());
+            EndNode end = graph.add(new EndNode());
             begin.setNext(end);
             merge.addForwardEnd(end);
         }
@@ -826,7 +843,7 @@
 
             if (loopExitPlaceholder != null) {
                 if (!phiInput.isConstant()) {
-                    phiInput = methodScope.graph.unique(new ProxyPlaceholder(phiInput, loopExitPlaceholder));
+                    phiInput = graph.unique(new ProxyPlaceholder(phiInput, loopExitPlaceholder));
                 }
                 registerNode(loopScope, proxyOrderId, phiInput, true, false);
             }
@@ -843,7 +860,14 @@
 
             } else if (!merge.isPhiAtMerge(existing)) {
                 /* Now we have two different values, so we need to create a phi node. */
-                PhiNode phi = methodScope.graph.addWithoutUnique(new ValuePhiNode(proxy.stamp(), merge));
+                PhiNode phi;
+                if (proxy instanceof ValueProxyNode) {
+                    phi = graph.addWithoutUnique(new ValuePhiNode(proxy.stamp(), merge));
+                } else if (proxy instanceof GuardProxyNode) {
+                    phi = graph.addWithoutUnique(new GuardPhiNode(merge));
+                } else {
+                    throw GraalError.shouldNotReachHere();
+                }
                 /* Add the inputs from all previous exits. */
                 for (int j = 0; j < merge.phiPredecessorCount() - 1; j++) {
                     phi.addInput(existing);
@@ -954,12 +978,6 @@
         return false;
     }
 
-    protected Node instantiateNode(MethodScope methodScope, int nodeOrderId) {
-        methodScope.reader.setByteIndex(methodScope.encodedGraph.nodeStartOffsets[nodeOrderId]);
-        NodeClass<?> nodeClass = methodScope.encodedGraph.getNodeClasses()[methodScope.reader.getUVInt()];
-        return nodeClass.allocateInstance();
-    }
-
     protected void readProperties(MethodScope methodScope, Node node) {
         node.setNodeSourcePosition((NodeSourcePosition) readObject(methodScope));
         Fields fields = node.getNodeClass().getData();
@@ -980,7 +998,7 @@
      * are created on demand (recursively since they can themselves reference not yet created
      * nodes).
      */
-    protected void makeInputNodes(MethodScope methodScope, LoopScope loopScope, Node node, boolean updateUsages) {
+    protected void makeFixedNodeInputs(MethodScope methodScope, LoopScope loopScope, Node node) {
         Edges edges = node.getNodeClass().getInputEdges();
         for (int index = 0; index < edges.getDirectCount(); index++) {
             if (skipDirectEdge(node, edges, index)) {
@@ -989,25 +1007,60 @@
             int orderId = readOrderId(methodScope);
             Node value = ensureNodeCreated(methodScope, loopScope, orderId);
             edges.initializeNode(node, index, value);
-            if (updateUsages && value != null && !value.isDeleted()) {
+            if (value != null && !value.isDeleted()) {
                 edges.update(node, null, value);
 
             }
         }
-        for (int index = edges.getDirectCount(); index < edges.getCount(); index++) {
-            if (skipIndirectEdge(node, edges, index, true)) {
-                continue;
+
+        if (node instanceof AbstractMergeNode) {
+            /* The ends of merge nodes are filled manually when the ends are processed. */
+            assert edges.getCount() - edges.getDirectCount() == 1 : "MergeNode has one variable size input (the ends)";
+            assert Edges.getNodeList(node, edges.getOffsets(), edges.getDirectCount()) != null : "Input list must have been already created";
+        } else {
+            for (int index = edges.getDirectCount(); index < edges.getCount(); index++) {
+                int size = methodScope.reader.getSVInt();
+                if (size != -1) {
+                    NodeList<Node> nodeList = new NodeInputList<>(node, size);
+                    edges.initializeList(node, index, nodeList);
+                    for (int idx = 0; idx < size; idx++) {
+                        int orderId = readOrderId(methodScope);
+                        Node value = ensureNodeCreated(methodScope, loopScope, orderId);
+                        nodeList.initialize(idx, value);
+                        if (value != null && !value.isDeleted()) {
+                            edges.update(node, null, value);
+                        }
+                    }
+                }
             }
-            int size = methodScope.reader.getSVInt();
-            if (size != -1) {
-                NodeList<Node> nodeList = new NodeInputList<>(node, size);
-                edges.initializeList(node, index, nodeList);
-                for (int idx = 0; idx < size; idx++) {
-                    int orderId = readOrderId(methodScope);
-                    Node value = ensureNodeCreated(methodScope, loopScope, orderId);
-                    nodeList.initialize(idx, value);
-                    if (updateUsages && value != null && !value.isDeleted()) {
-                        edges.update(node, null, value);
+        }
+    }
+
+    protected void makeFloatingNodeInputs(MethodScope methodScope, LoopScope loopScope, Node node) {
+        Edges edges = node.getNodeClass().getInputEdges();
+        if (node instanceof PhiNode) {
+            /*
+             * The inputs of phi functions are filled manually when the end nodes are processed.
+             * However, the values must not be null, so initialize them with an empty list.
+             */
+            assert edges.getDirectCount() == 1 : "PhiNode has one direct input (the MergeNode)";
+            assert edges.getCount() - edges.getDirectCount() == 1 : "PhiNode has one variable size input (the values)";
+            edges.initializeList(node, edges.getDirectCount(), new NodeInputList<>(node));
+        } else {
+            for (int index = 0; index < edges.getDirectCount(); index++) {
+                int orderId = readOrderId(methodScope);
+                Node value = ensureNodeCreated(methodScope, loopScope, orderId);
+                edges.initializeNode(node, index, value);
+            }
+            for (int index = edges.getDirectCount(); index < edges.getCount(); index++) {
+                int size = methodScope.reader.getSVInt();
+                if (size != -1) {
+                    NodeList<Node> nodeList = new NodeInputList<>(node, size);
+                    edges.initializeList(node, index, nodeList);
+                    for (int idx = 0; idx < size; idx++) {
+                        int orderId = readOrderId(methodScope);
+                        Node value = ensureNodeCreated(methodScope, loopScope, orderId);
+                        nodeList.initialize(idx, value);
                     }
                 }
             }
@@ -1024,31 +1077,34 @@
         }
 
         node = decodeFloatingNode(methodScope, loopScope, nodeOrderId);
-
         if (node instanceof ProxyNode || node instanceof PhiNode) {
             /*
              * We need these nodes as they were in the original graph, without any canonicalization
              * or value numbering.
              */
-            node = methodScope.graph.addWithoutUnique(node);
+            node = graph.addWithoutUnique(node);
         } else {
             /* Allow subclasses to canonicalize and intercept nodes. */
-            node = handleFloatingNodeBeforeAdd(methodScope, loopScope, node);
-            if (!node.isAlive()) {
-                node = addFloatingNode(methodScope, node);
+            Node newNode = handleFloatingNodeBeforeAdd(methodScope, loopScope, node);
+            if (newNode != node) {
+                releaseFloatingNode(node);
             }
-            node = handleFloatingNodeAfterAdd(methodScope, loopScope, node);
+
+            if (!newNode.isAlive()) {
+                newNode = addFloatingNode(methodScope, newNode);
+            }
+            node = handleFloatingNodeAfterAdd(methodScope, loopScope, newNode);
         }
         registerNode(loopScope, nodeOrderId, node, false, false);
         return node;
     }
 
-    protected Node addFloatingNode(MethodScope methodScope, Node node) {
+    protected Node addFloatingNode(@SuppressWarnings("unused") MethodScope methodScope, Node node) {
         /*
          * We want to exactly reproduce the encoded graph. Even though nodes should be unique in the
          * encoded graph, this is not always guaranteed.
          */
-        return methodScope.graph.addWithoutUnique(node);
+        return graph.addWithoutUnique(node);
     }
 
     /**
@@ -1056,7 +1112,10 @@
      */
     protected Node decodeFloatingNode(MethodScope methodScope, LoopScope loopScope, int nodeOrderId) {
         long readerByteIndex = methodScope.reader.getByteIndex();
-        Node node = instantiateNode(methodScope, nodeOrderId);
+
+        methodScope.reader.setByteIndex(methodScope.encodedGraph.nodeStartOffsets[nodeOrderId]);
+        NodeClass<?> nodeClass = methodScope.encodedGraph.getNodeClasses()[methodScope.reader.getUVInt()];
+        Node node = allocateFloatingNode(nodeClass);
         if (node instanceof FixedNode) {
             /*
              * This is a severe error that will lead to a corrupted graph, so it is better not to
@@ -1065,16 +1124,38 @@
             throw shouldNotReachHere("Not a floating node: " + node.getClass().getName());
         }
 
+        /* Read the inputs of the node, possibly creating them recursively. */
+        makeFloatingNodeInputs(methodScope, loopScope, node);
+
         /* Read the properties of the node. */
         readProperties(methodScope, node);
         /* There must not be any successors to read, since it is a non-fixed node. */
         assert node.getNodeClass().getEdges(Edges.Type.Successors).getCount() == 0;
-        /* Read the inputs of the node, possibly creating them recursively. */
-        makeInputNodes(methodScope, loopScope, node, false);
+
         methodScope.reader.setByteIndex(readerByteIndex);
         return node;
     }
 
+    private Node allocateFloatingNode(NodeClass<?> nodeClass) {
+        ArrayDeque<? extends Node> cachedNodes = reusableFloatingNodes.get(nodeClass);
+        if (cachedNodes != null) {
+            Node node = cachedNodes.poll();
+            if (node != null) {
+                return node;
+            }
+        }
+        return nodeClass.allocateInstance();
+    }
+
+    private void releaseFloatingNode(Node node) {
+        ArrayDeque<Node> cachedNodes = reusableFloatingNodes.get(node.getNodeClass());
+        if (cachedNodes == null) {
+            cachedNodes = new ArrayDeque<>(2);
+            reusableFloatingNodes.put(node.getNodeClass(), cachedNodes);
+        }
+        cachedNodes.push(node);
+    }
+
     /**
      * Hook for subclasses to process a non-fixed node before it is added to the graph.
      *
@@ -1121,9 +1202,6 @@
             }
         }
         for (int index = edges.getDirectCount(); index < edges.getCount(); index++) {
-            if (skipIndirectEdge(node, edges, index, true)) {
-                continue;
-            }
             int size = methodScope.reader.getSVInt();
             if (size != -1) {
                 NodeList<Node> nodeList = new NodeSuccessorList<>(node, size);
@@ -1150,7 +1228,9 @@
         }
 
         long readerByteIndex = methodScope.reader.getByteIndex();
-        node = (FixedNode) methodScope.graph.add(instantiateNode(methodScope, nodeOrderId));
+        methodScope.reader.setByteIndex(methodScope.encodedGraph.nodeStartOffsets[nodeOrderId]);
+        NodeClass<?> nodeClass = methodScope.encodedGraph.getNodeClasses()[methodScope.reader.getUVInt()];
+        node = (FixedNode) graph.add(nodeClass.allocateInstance());
         /* Properties and edges are not filled yet, the node remains uninitialized. */
         methodScope.reader.setByteIndex(readerByteIndex);
 
@@ -1174,12 +1254,6 @@
                     return true;
                 }
             }
-        } else if (node instanceof PhiNode) {
-            /* The inputs of phi functions are filled manually when the end nodes are processed. */
-            assert edges.type() == Edges.Type.Inputs;
-            assert index == edges.getDirectCount() - 1 : "PhiNode has one direct input (the MergeNode)";
-            return true;
-
         } else if (node instanceof LoopExitNode && edges.type() == Edges.Type.Inputs && edges.getType(index) == FrameState.class) {
             /* The stateAfter of the loop exit is filled manually. */
             return true;
@@ -1188,29 +1262,6 @@
         return false;
     }
 
-    protected static boolean skipIndirectEdge(Node node, Edges edges, int index, boolean decode) {
-        assert !(node instanceof Invoke);
-        assert !(node instanceof LoopExitNode && edges.type() == Edges.Type.Inputs && edges.getType(index) == FrameState.class);
-        if (node instanceof AbstractMergeNode && edges.type() == Edges.Type.Inputs) {
-            /* The ends of merge nodes are filled manually when the ends are processed. */
-            assert index == edges.getCount() - 1 : "MergeNode has one variable size input (the ends)";
-            assert Edges.getNodeList(node, edges.getOffsets(), index) != null : "Input list must have been already created";
-            return true;
-
-        } else if (node instanceof PhiNode) {
-            /* The inputs of phi functions are filled manually when the end nodes are processed. */
-            assert edges.type() == Edges.Type.Inputs;
-            assert index == edges.getCount() - 1 : "PhiNode has one variable size input (the values)";
-            if (decode) {
-                /* The values must not be null, so initialize with an empty list. */
-                edges.initializeList(node, index, new NodeInputList<>(node));
-            }
-            return true;
-
-        }
-        return false;
-    }
-
     protected Node lookupNode(LoopScope loopScope, int nodeOrderId) {
         return loopScope.createdNodes[nodeOrderId];
     }
@@ -1236,11 +1287,11 @@
      * @param methodScope The current method.
      */
     protected void cleanupGraph(MethodScope methodScope) {
-        assert verifyEdges(methodScope);
+        assert verifyEdges();
     }
 
-    protected boolean verifyEdges(MethodScope methodScope) {
-        for (Node node : methodScope.graph.getNodes()) {
+    protected boolean verifyEdges() {
+        for (Node node : graph.getNodes()) {
             assert node.isAlive();
             for (Node i : node.inputs()) {
                 assert i.isAlive();
@@ -1278,7 +1329,7 @@
          * The ends, i.e., the source of backward branches. The {@link EndNode#successors successor}
          * is the {@link #header loop header}.
          */
-        List<EndNode> ends = new ArrayList<>();
+        List<EndNode> ends = new ArrayList<>(2);
         /**
          * Exits of the loop. The successor is a {@link MergeNode} marked in
          * {@link MethodScope#loopExplosionMerges}.
@@ -1291,20 +1342,20 @@
         boolean irreducible;
     }
 
+    private final StructuredGraph graph;
     private final MethodScope methodScope;
-    private final FixedNode startInstruction;
 
     private Loop irreducibleLoopHandler;
     private IntegerSwitchNode irreducibleLoopSwitch;
 
-    protected LoopDetector(MethodScope methodScope, FixedNode startInstruction) {
+    protected LoopDetector(StructuredGraph graph, MethodScope methodScope) {
+        this.graph = graph;
         this.methodScope = methodScope;
-        this.startInstruction = startInstruction;
     }
 
     @Override
     public void run() {
-        Debug.dump(Debug.VERBOSE_LOG_LEVEL, methodScope.graph, "Before loop detection");
+        Debug.dump(Debug.DETAILED_LEVEL, graph, "Before loop detection");
 
         List<Loop> orderedLoops = findLoops();
         assert orderedLoops.get(orderedLoops.size() - 1) == irreducibleLoopHandler : "outermost loop must be the last element in the list";
@@ -1327,11 +1378,11 @@
             } else {
                 insertLoopNodes(loop);
             }
-            Debug.dump(Debug.VERBOSE_LOG_LEVEL, methodScope.graph, "After handling of loop %s", loop.header);
+            Debug.dump(Debug.DETAILED_LEVEL, graph, "After handling of loop %s", loop.header);
         }
 
         logIrreducibleLoops();
-        Debug.dump(Debug.VERBOSE_LOG_LEVEL, methodScope.graph, "After loop detection");
+        Debug.dump(Debug.DETAILED_LEVEL, graph, "After loop detection");
     }
 
     private List<Loop> findLoops() {
@@ -1346,11 +1397,11 @@
          */
         irreducibleLoopHandler = findOrCreateLoop(unorderedLoops, methodScope.loopExplosionHead);
 
-        NodeBitMap visited = methodScope.graph.createNodeBitMap();
-        NodeBitMap active = methodScope.graph.createNodeBitMap();
+        NodeBitMap visited = graph.createNodeBitMap();
+        NodeBitMap active = graph.createNodeBitMap();
         Deque<Node> stack = new ArrayDeque<>();
-        visited.mark(startInstruction);
-        stack.push(startInstruction);
+        visited.mark(methodScope.loopExplosionHead);
+        stack.push(methodScope.loopExplosionHead);
 
         while (!stack.isEmpty()) {
             Node current = stack.peek();
@@ -1421,7 +1472,7 @@
          */
 
         List<Node> possibleExits = new ArrayList<>();
-        NodeBitMap visited = methodScope.graph.createNodeBitMap();
+        NodeBitMap visited = graph.createNodeBitMap();
         Deque<Node> stack = new ArrayDeque<>();
         for (EndNode loopEnd : loop.ends) {
             stack.push(loopEnd);
@@ -1433,7 +1484,7 @@
             if (current == loop.header) {
                 continue;
             }
-            if (!methodScope.graph.isNew(methodScope.methodStartMark, current)) {
+            if (!graph.isNew(methodScope.methodStartMark, current)) {
                 /*
                  * The current node is before the method that contains the exploded loop. The loop
                  * must have a second entry point, i.e., it is an irreducible loop.
@@ -1498,7 +1549,6 @@
          * necessary into a loop because it computes loop information based on bytecodes, before the
          * actual parsing.
          */
-
         for (Node succ : possibleExits) {
             if (!visited.contains(succ)) {
                 stack.push(succ);
@@ -1541,8 +1591,8 @@
         FrameState stateAfter = merge.stateAfter().duplicate();
         FixedNode afterMerge = merge.next();
         merge.setNext(null);
-        EndNode preLoopEnd = methodScope.graph.add(new EndNode());
-        LoopBeginNode loopBegin = methodScope.graph.add(new LoopBeginNode());
+        EndNode preLoopEnd = graph.add(new EndNode());
+        LoopBeginNode loopBegin = graph.add(new LoopBeginNode());
 
         merge.setNext(preLoopEnd);
         /* Add the single non-loop predecessor of the loop header. */
@@ -1559,7 +1609,7 @@
         List<PhiNode> loopBeginPhis = new ArrayList<>(mergePhis.size());
         for (int i = 0; i < mergePhis.size(); i++) {
             PhiNode mergePhi = mergePhis.get(i);
-            PhiNode loopBeginPhi = methodScope.graph.addWithoutUnique(new ValuePhiNode(mergePhi.stamp(), loopBegin));
+            PhiNode loopBeginPhi = graph.addWithoutUnique(new ValuePhiNode(mergePhi.stamp(), loopBegin));
             mergePhi.replaceAtUsages(loopBeginPhi);
             /*
              * The first input of the new phi function is the original phi function, for the one
@@ -1577,7 +1627,7 @@
             }
 
             merge.removeEnd(endNode);
-            LoopEndNode loopEnd = methodScope.graph.add(new LoopEndNode(loopBegin));
+            LoopEndNode loopEnd = graph.add(new LoopEndNode(loopBegin));
             endNode.replaceAndDelete(loopEnd);
         }
 
@@ -1589,7 +1639,7 @@
             AbstractMergeNode loopExplosionMerge = exit.merge();
             assert methodScope.loopExplosionMerges.contains(loopExplosionMerge);
 
-            LoopExitNode loopExit = methodScope.graph.add(new LoopExitNode(loopBegin));
+            LoopExitNode loopExit = graph.add(new LoopExitNode(loopBegin));
             exit.replaceAtPredecessor(loopExit);
             loopExit.setNext(exit);
             assignLoopExitState(loopExit, loopExplosionMerge, exit);
@@ -1630,7 +1680,7 @@
                 realValue = ProxyPlaceholder.unwrap(value);
             }
 
-            if (realValue == null || realValue.isConstant() || loopBeginValues.contains(realValue) || !methodScope.graph.isNew(methodScope.methodStartMark, realValue)) {
+            if (realValue == null || realValue.isConstant() || loopBeginValues.contains(realValue) || !graph.isNew(methodScope.methodStartMark, realValue)) {
                 newValues.add(realValue);
             } else {
                 /*
@@ -1641,7 +1691,7 @@
                                 "Value flowing out of loop, but we are not prepared to insert a ProxyNode");
 
                 ProxyPlaceholder proxyPlaceholder = (ProxyPlaceholder) value;
-                ValueProxyNode proxy = ProxyNode.forValue(proxyPlaceholder.value, loopExit, methodScope.graph);
+                ValueProxyNode proxy = ProxyNode.forValue(proxyPlaceholder.value, loopExit, graph);
                 proxyPlaceholder.setValue(proxy);
                 newValues.add(proxy);
             }
@@ -1651,7 +1701,7 @@
                         oldState.duringCall(), oldState.monitorIds(), oldState.virtualObjectMappings());
 
         assert loopExit.stateAfter() == null;
-        loopExit.setStateAfter(methodScope.graph.add(newState));
+        loopExit.setStateAfter(graph.add(newState));
     }
 
     /**
@@ -1722,7 +1772,7 @@
             assert irreducibleLoopHandler.header.phis().isEmpty();
 
             /* The new phi function for the loop variable. */
-            loopVariablePhi = methodScope.graph.addWithoutUnique(new ValuePhiNode(explosionHeadValue.stamp().unrestricted(), irreducibleLoopHandler.header));
+            loopVariablePhi = graph.addWithoutUnique(new ValuePhiNode(explosionHeadValue.stamp().unrestricted(), irreducibleLoopHandler.header));
             for (int i = 0; i < irreducibleLoopHandler.header.phiPredecessorCount(); i++) {
                 loopVariablePhi.addInput(explosionHeadValue);
             }
@@ -1732,7 +1782,7 @@
              * to the old FrameState: the loop variable is replaced with the phi function.
              */
             FrameState oldFrameState = explosionHeadState;
-            List<ValueNode> newFrameStateValues = new ArrayList<>();
+            List<ValueNode> newFrameStateValues = new ArrayList<>(explosionHeadValues.size());
             for (int i = 0; i < explosionHeadValues.size(); i++) {
                 if (i == loopVariableIndex) {
                     newFrameStateValues.add(loopVariablePhi);
@@ -1740,7 +1790,8 @@
                     newFrameStateValues.add(explosionHeadValues.get(i));
                 }
             }
-            FrameState newFrameState = methodScope.graph.add(
+
+            FrameState newFrameState = graph.add(
                             new FrameState(oldFrameState.outerFrameState(), oldFrameState.getCode(), oldFrameState.bci, newFrameStateValues, oldFrameState.localsSize(),
                                             oldFrameState.stackSize(), oldFrameState.rethrowException(), oldFrameState.duringCall(), oldFrameState.monitorIds(),
                                             oldFrameState.virtualObjectMappings()));
@@ -1752,7 +1803,7 @@
              */
             FixedNode handlerNext = irreducibleLoopHandler.header.next();
             irreducibleLoopHandler.header.setNext(null);
-            BeginNode handlerBegin = methodScope.graph.add(new BeginNode());
+            BeginNode handlerBegin = graph.add(new BeginNode());
             handlerBegin.setNext(handlerNext);
             dispatchTable.put(asInt(explosionHeadValue), handlerBegin);
 
@@ -1760,8 +1811,8 @@
              * We know that there will always be a matching key in the switch. But Graal always
              * wants a default successor, so we build a dummy block that just deoptimizes.
              */
-            unreachableDefaultSuccessor = methodScope.graph.add(new BeginNode());
-            DeoptimizeNode deopt = methodScope.graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.UnreachedCode));
+            unreachableDefaultSuccessor = graph.add(new BeginNode());
+            DeoptimizeNode deopt = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.UnreachedCode));
             unreachableDefaultSuccessor.setNext(deopt);
 
         } else {
@@ -1796,8 +1847,8 @@
 
         /* Insert our loop into the dispatch state machine. */
         assert loop.header.phis().isEmpty();
-        BeginNode dispatchBegin = methodScope.graph.add(new BeginNode());
-        EndNode dispatchEnd = methodScope.graph.add(new EndNode());
+        BeginNode dispatchBegin = graph.add(new BeginNode());
+        EndNode dispatchEnd = graph.add(new EndNode());
         dispatchBegin.setNext(dispatchEnd);
         loop.header.addForwardEnd(dispatchEnd);
         int intLoopValue = asInt(loopValue);
@@ -1813,7 +1864,7 @@
         }
 
         /* Build and insert the switch node. */
-        irreducibleLoopSwitch = methodScope.graph.add(createSwitch(loopVariablePhi, dispatchTable, unreachableDefaultSuccessor));
+        irreducibleLoopSwitch = graph.add(createSwitch(loopVariablePhi, dispatchTable, unreachableDefaultSuccessor));
         irreducibleLoopHandler.header.setNext(irreducibleLoopSwitch);
     }
 
@@ -1859,14 +1910,14 @@
     @SuppressWarnings("try")
     private void logIrreducibleLoops() {
         try (Debug.Scope s = Debug.scope("IrreducibleLoops")) {
-            if (Debug.isLogEnabled(Debug.BASIC_LOG_LEVEL) && irreducibleLoopSwitch != null) {
+            if (Debug.isLogEnabled(Debug.BASIC_LEVEL) && irreducibleLoopSwitch != null) {
                 StringBuilder msg = new StringBuilder("Inserted state machine to remove irreducible loops. Dispatching to the following states: ");
                 String sep = "";
                 for (int i = 0; i < irreducibleLoopSwitch.keyCount(); i++) {
                     msg.append(sep).append(irreducibleLoopSwitch.keyAt(i).asInt());
                     sep = ", ";
                 }
-                Debug.log(Debug.BASIC_LOG_LEVEL, "%s", msg);
+                Debug.log(Debug.BASIC_LEVEL, "%s", msg);
             }
         }
     }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphEncoder.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphEncoder.java	Thu Apr 06 14:31:32 2017 -0700
@@ -67,10 +67,11 @@
  * encoding-local.
  *
  * The encoded graph has the following structure: First, all nodes and their edges are serialized.
- * The start offset of every node is then known. The raw node data is followed by a "table of
- * contents" that lists the start offset for every node.
+ * The start offset of every node is then known. The raw node data is followed by metadata, i.e.,
+ * the maximum fixed node order id and a "table of contents" that lists the start offset for every
+ * node.
  *
- * The beginning of that table of contents is the return value of {@link #encode} and stored in
+ * The beginning of this metadata is the return value of {@link #encode} and stored in
  * {@link EncodedGraph#getStartOffset()}. The order of nodes in the table of contents is the
  * {@link NodeOrder#orderIds orderId} of a node. Note that the orderId is not the regular node id
  * that every Graal graph node gets assigned. The orderId is computed and used just for encoding and
@@ -85,8 +86,8 @@
  * <pre>
  * struct Node {
  *   unsigned typeId
+ *   unsigned[] inputOrderIds
  *   signed[] properties
- *   unsigned[] inputOrderIds
  *   unsigned[] successorOrderIds
  * }
  * </pre>
@@ -168,9 +169,8 @@
      */
     public void prepare(StructuredGraph graph) {
         for (Node node : graph.getNodes()) {
-            nodeClasses.addObject(node.getNodeClass());
-
-            NodeClass<?> nodeClass = node.getNodeClass();
+            NodeClass<? extends Node> nodeClass = node.getNodeClass();
+            nodeClasses.addObject(nodeClass);
             objects.addObject(node.getNodeSourcePosition());
             for (int i = 0; i < nodeClass.getData().getCount(); i++) {
                 if (!nodeClass.getData().getType(i).isPrimitive()) {
@@ -223,8 +223,8 @@
             /* Write out the type, properties, and edges. */
             NodeClass<?> nodeClass = node.getNodeClass();
             writer.putUV(nodeClasses.getIndex(nodeClass));
+            writeEdges(node, nodeClass.getEdges(Edges.Type.Inputs), nodeOrder);
             writeProperties(node, nodeClass.getData());
-            writeEdges(node, nodeClass.getEdges(Edges.Type.Inputs), nodeOrder);
             writeEdges(node, nodeClass.getEdges(Edges.Type.Successors), nodeOrder);
 
             /* Special handling for some nodes that require additional information for decoding. */
@@ -276,18 +276,23 @@
             }
         }
 
-        /* Write out the table of contents with the start offset for all nodes. */
-        int nodeTableStart = TypeConversion.asS4(writer.getBytesWritten());
+        /*
+         * Write out the metadata (maximum fixed node order id and the table of contents with the
+         * start offset for all nodes).
+         */
+        int metadataStart = TypeConversion.asS4(writer.getBytesWritten());
+        writer.putUV(nodeOrder.maxFixedNodeOrderId);
         writer.putUV(nodeCount);
         for (int i = 0; i < nodeCount; i++) {
             assert i == NULL_ORDER_ID || i == START_NODE_ORDER_ID || nodeStartOffsets[i] > 0;
-            writer.putUV(nodeTableStart - nodeStartOffsets[i]);
+            writer.putUV(metadataStart - nodeStartOffsets[i]);
         }
 
         /* Check that the decoding of the encode graph is the same as the input. */
-        assert verifyEncoding(graph, new EncodedGraph(getEncoding(), nodeTableStart, getObjects(), getNodeClasses(), graph.getAssumptions(), graph.getMethods()), architecture);
+        assert verifyEncoding(graph, new EncodedGraph(getEncoding(), metadataStart, getObjects(), getNodeClasses(), graph.getAssumptions(), graph.getMethods()),
+                        architecture);
 
-        return nodeTableStart;
+        return metadataStart;
     }
 
     public byte[] getEncoding() {
@@ -297,6 +302,7 @@
     static class NodeOrder {
         protected final NodeMap<Integer> orderIds;
         protected int nextOrderId;
+        protected int maxFixedNodeOrderId;
 
         NodeOrder(StructuredGraph graph) {
             this.orderIds = new NodeMap<>(graph);
@@ -337,6 +343,7 @@
                 }
             } while (current != null);
 
+            maxFixedNodeOrderId = nextOrderId - 1;
             for (Node node : graph.getNodes()) {
                 assert (node instanceof FixedNode) == (orderIds.get(node) != null) : "all fixed nodes must be ordered: " + node;
                 add(node);
@@ -365,6 +372,11 @@
     }
 
     protected void writeEdges(Node node, Edges edges, NodeOrder nodeOrder) {
+        if (node instanceof PhiNode) {
+            /* Edges are not needed for decoding, so we must not write it. */
+            return;
+        }
+
         for (int idx = 0; idx < edges.getDirectCount(); idx++) {
             if (GraphDecoder.skipDirectEdge(node, edges, idx)) {
                 /* Edge is not needed for decoding, so we must not write it. */
@@ -373,21 +385,23 @@
             Node edge = Edges.getNode(node, edges.getOffsets(), idx);
             writeOrderId(edge, nodeOrder);
         }
-        for (int idx = edges.getDirectCount(); idx < edges.getCount(); idx++) {
-            if (GraphDecoder.skipIndirectEdge(node, edges, idx, false)) {
-                /* Edge is not needed for decoding, so we must not write it. */
-                continue;
-            }
-            NodeList<Node> edgeList = Edges.getNodeList(node, edges.getOffsets(), idx);
-            if (edgeList == null) {
-                writer.putSV(-1);
-            } else {
-                writer.putSV(edgeList.size());
-                for (Node edge : edgeList) {
-                    writeOrderId(edge, nodeOrder);
+
+        if (node instanceof AbstractMergeNode && edges.type() == Edges.Type.Inputs) {
+            /* The ends of merge nodes are decoded manually when the ends are processed. */
+        } else {
+            for (int idx = edges.getDirectCount(); idx < edges.getCount(); idx++) {
+                NodeList<Node> edgeList = Edges.getNodeList(node, edges.getOffsets(), idx);
+                if (edgeList == null) {
+                    writer.putSV(-1);
+                } else {
+                    writer.putSV(edgeList.size());
+                    for (Node edge : edgeList) {
+                        writeOrderId(edge, nodeOrder);
+                    }
                 }
             }
         }
+
     }
 
     protected void writeOrderId(Node node, NodeOrder nodeOrder) {
@@ -405,16 +419,16 @@
     @SuppressWarnings("try")
     public static boolean verifyEncoding(StructuredGraph originalGraph, EncodedGraph encodedGraph, Architecture architecture) {
         StructuredGraph decodedGraph = new StructuredGraph.Builder(originalGraph.getOptions(), AllowAssumptions.YES).method(originalGraph.method()).build();
-        GraphDecoder decoder = new GraphDecoder(architecture);
-        decoder.decode(decodedGraph, encodedGraph);
+        GraphDecoder decoder = new GraphDecoder(architecture, decodedGraph);
+        decoder.decode(encodedGraph);
 
         decodedGraph.verify();
         try {
             GraphComparison.verifyGraphsEqual(originalGraph, decodedGraph);
         } catch (Throwable ex) {
             try (Debug.Scope scope = Debug.scope("GraphEncoder")) {
-                Debug.dump(Debug.INFO_LOG_LEVEL, originalGraph, "Original Graph");
-                Debug.dump(Debug.INFO_LOG_LEVEL, decodedGraph, "Decoded Graph");
+                Debug.forceDump(originalGraph, "Original Graph");
+                Debug.forceDump(decodedGraph, "Decoded Graph");
             }
             throw ex;
         }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GuardedValueNode.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GuardedValueNode.java	Thu Apr 06 14:31:32 2017 -0700
@@ -87,7 +87,7 @@
             if (stamp().equals(object().stamp())) {
                 return object();
             } else {
-                return new PiNode(object(), stamp());
+                return PiNode.create(object(), stamp());
             }
         }
         return this;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/IfNode.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/IfNode.java	Thu Apr 06 14:31:32 2017 -0700
@@ -316,7 +316,10 @@
                 FixedWithNextNode falseNext = (FixedWithNextNode) falseSucc.next();
                 NodeClass<?> nodeClass = trueNext.getNodeClass();
                 if (trueNext.getClass() == falseNext.getClass()) {
-                    if (nodeClass.equalInputs(trueNext, falseNext) && trueNext.valueEquals(falseNext)) {
+                    if (trueNext instanceof AbstractBeginNode) {
+                        // Cannot do this optimization for begin nodes, because it could
+                        // move guards above the if that need to stay below a branch.
+                    } else if (nodeClass.equalInputs(trueNext, falseNext) && trueNext.valueEquals(falseNext)) {
                         falseNext.replaceAtUsages(trueNext);
                         graph().removeFixed(falseNext);
                         GraphUtil.unlinkFixedNode(trueNext);
@@ -600,7 +603,7 @@
 
     protected void removeThroughFalseBranch(SimplifierTool tool) {
         AbstractBeginNode trueBegin = trueSuccessor();
-        graph().removeSplitPropagate(this, trueBegin, tool);
+        graph().removeSplitPropagate(this, trueBegin);
         tool.addToWorkList(trueBegin);
         if (condition() != null) {
             GraphUtil.tryKillUnused(condition());
@@ -772,9 +775,9 @@
         transferProxies(trueSuccessor(), trueMerge);
         transferProxies(falseSuccessor(), falseMerge);
 
-        cleanupMerge(tool, merge);
-        cleanupMerge(tool, trueMerge);
-        cleanupMerge(tool, falseMerge);
+        cleanupMerge(merge);
+        cleanupMerge(trueMerge);
+        cleanupMerge(falseMerge);
 
         return true;
     }
@@ -869,10 +872,10 @@
         }
     }
 
-    private void cleanupMerge(SimplifierTool tool, MergeNode merge) {
+    private void cleanupMerge(MergeNode merge) {
         if (merge != null && merge.isAlive()) {
             if (merge.forwardEndCount() == 0) {
-                GraphUtil.killCFG(merge, tool);
+                GraphUtil.killCFG(merge);
             } else if (merge.forwardEndCount() == 1) {
                 graph().reduceTrivialMerge(merge);
             }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/PiArrayNode.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/PiArrayNode.java	Thu Apr 06 14:31:32 2017 -0700
@@ -26,7 +26,6 @@
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
 
 import org.graalvm.compiler.core.common.type.Stamp;
-import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.graph.spi.CanonicalizerTool;
@@ -69,12 +68,11 @@
      * snippet.
      */
     @NodeIntrinsic(Placeholder.class)
-    public static native Object piArrayCast(Object object, int length);
+    public static native Object piArrayCastToSnippetReplaceeStamp(Object object, int length);
 
     /**
-     * A placeholder node in a snippet that will be replaced with an appropriate {@link PiArrayNode}
-     * when the snippet is instantiated. Using a placeholder means that {@link PiArrayNode} never
-     * needs to deal with {@link StampFactory#forNodeIntrinsic()} stamps.
+     * A placeholder node in a snippet that will be replaced with a {@link PiArrayNode} when the
+     * snippet is instantiated.
      */
     @NodeInfo(cycles = CYCLES_0, size = SIZE_0)
     public static class Placeholder extends PiNode.Placeholder {
@@ -88,8 +86,9 @@
         }
 
         @Override
-        public PiNode getReplacement(Stamp stampForPi) {
-            return graph().addOrUnique(new PiArrayNode(object(), length, stampForPi));
+        public void makeReplacement(Stamp snippetReplaceeStamp) {
+            PiArrayNode piArray = graph().addOrUnique(new PiArrayNode(object(), length, snippetReplaceeStamp));
+            replaceAndDelete(piArray);
         }
     }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/PiNode.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/PiNode.java	Thu Apr 06 14:31:32 2017 -0700
@@ -25,7 +25,10 @@
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
 
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
 import org.graalvm.compiler.core.common.type.AbstractPointerStamp;
+import org.graalvm.compiler.core.common.type.ObjectStamp;
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.core.common.type.TypeReference;
@@ -36,6 +39,7 @@
 import org.graalvm.compiler.graph.spi.CanonicalizerTool;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
 import org.graalvm.compiler.nodes.extended.GuardingNode;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
 import org.graalvm.compiler.nodes.memory.ReadNode;
 import org.graalvm.compiler.nodes.spi.LIRLowerable;
 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
@@ -70,7 +74,6 @@
 
     protected PiNode(NodeClass<? extends PiNode> c, ValueNode object, Stamp stamp, GuardingNode guard) {
         super(c, stamp, guard);
-        assert stamp != StampFactory.forNodeIntrinsic();
         this.object = object;
         this.piStamp = stamp;
         assert piStamp.isCompatible(object.stamp()) : "Object stamp not compatible to piStamp";
@@ -93,6 +96,53 @@
         this(object, StampFactory.object(exactType ? TypeReference.createExactTrusted(toType) : TypeReference.createWithoutAssumptions(toType), nonNull || StampTool.isPointerNonNull(object.stamp())));
     }
 
+    public static ValueNode create(ValueNode object, Stamp stamp) {
+        ValueNode value = canonical(object, stamp, null);
+        if (value != null) {
+            return value;
+        }
+        return new PiNode(object, stamp);
+    }
+
+    public static ValueNode create(ValueNode object, Stamp stamp, ValueNode anchor) {
+        ValueNode value = canonical(object, stamp, (GuardingNode) anchor);
+        if (value != null) {
+            return value;
+        }
+        return new PiNode(object, stamp, anchor);
+    }
+
+    public static ValueNode create(ValueNode object, ValueNode anchor) {
+        Stamp stamp = AbstractPointerStamp.pointerNonNull(object.stamp());
+        ValueNode value = canonical(object, stamp, (GuardingNode) anchor);
+        if (value != null) {
+            return value;
+        }
+        return new PiNode(object, stamp, anchor);
+    }
+
+    @SuppressWarnings("unused")
+    public static boolean intrinsify(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode object, ValueNode anchor) {
+        Stamp stamp = AbstractPointerStamp.pointerNonNull(object.stamp());
+        ValueNode value = canonical(object, stamp, (GuardingNode) anchor);
+        if (value == null) {
+            value = new PiNode(object, stamp, anchor);
+        }
+        b.push(JavaKind.Object, b.recursiveAppend(value));
+        return true;
+    }
+
+    @SuppressWarnings("unused")
+    public static boolean intrinsify(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode object, ResolvedJavaType toType, boolean exactType, boolean nonNull) {
+        Stamp stamp = StampFactory.object(exactType ? TypeReference.createExactTrusted(toType) : TypeReference.createWithoutAssumptions(toType), nonNull || StampTool.isPointerNonNull(object.stamp()));
+        ValueNode value = canonical(object, stamp, null);
+        if (value == null) {
+            value = new PiNode(object, stamp);
+        }
+        b.push(JavaKind.Object, b.recursiveAppend(value));
+        return true;
+    }
+
     public final Stamp piStamp() {
         return piStamp;
     }
@@ -124,37 +174,32 @@
         }
     }
 
-    @Override
-    public Node canonical(CanonicalizerTool tool) {
+    public static ValueNode canonical(ValueNode object, Stamp stamp, GuardingNode guard) {
         // Use most up to date stamp.
-        Stamp computedStamp = computeStamp();
-
-        ValueNode o = object();
+        Stamp computedStamp = stamp.improveWith(object.stamp());
 
         // The pi node does not give any additional information => skip it.
-        if (computedStamp.equals(o.stamp())) {
-            return o;
+        if (computedStamp.equals(object.stamp())) {
+            return object;
         }
 
-        GuardingNode g = getGuard();
-        if (g == null) {
-
+        if (guard == null) {
             // Try to merge the pi node with a load node.
-            if (o instanceof ReadNode) {
-                ReadNode readNode = (ReadNode) o;
-                readNode.setStamp(readNode.stamp().improveWith(this.piStamp));
+            if (object instanceof ReadNode) {
+                ReadNode readNode = (ReadNode) object;
+                readNode.setStamp(readNode.stamp().improveWith(stamp));
                 return readNode;
             }
         } else {
-            for (Node n : g.asNode().usages()) {
+            for (Node n : guard.asNode().usages()) {
                 if (n instanceof PiNode) {
                     PiNode otherPi = (PiNode) n;
-                    if (o == otherPi.object() && computedStamp.equals(otherPi.stamp())) {
+                    if (object == otherPi.object() && computedStamp.equals(otherPi.stamp())) {
                         /*
                          * Two PiNodes with the same guard and same result, so return the one with
                          * the more precise piStamp.
                          */
-                        Stamp newStamp = piStamp.join(otherPi.piStamp);
+                        Stamp newStamp = stamp.join(otherPi.piStamp);
                         if (newStamp.equals(otherPi.piStamp)) {
                             return otherPi;
                         }
@@ -162,6 +207,15 @@
                 }
             }
         }
+        return null;
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        Node value = canonical(object(), stamp(), getGuard());
+        if (value != null) {
+            return value;
+        }
         return this;
     }
 
@@ -226,9 +280,8 @@
     public static native Object piCast(Object object, @ConstantNodeParameter Class<?> toType, @ConstantNodeParameter boolean exactType, @ConstantNodeParameter boolean nonNull);
 
     /**
-     * A placeholder node in a snippet that will be replaced with an appropriate {@link PiNode} when
-     * the snippet is instantiated. Using a placeholder means that {@link PiNode} never needs to
-     * deal with {@link StampFactory#forNodeIntrinsic()} stamps.
+     * A placeholder node in a snippet that will be replaced with a {@link PiNode} when the snippet
+     * is instantiated.
      */
     @NodeInfo(cycles = CYCLES_0, size = SIZE_0)
     public static class Placeholder extends FloatingGuardedNode {
@@ -241,7 +294,7 @@
         }
 
         protected Placeholder(NodeClass<? extends Placeholder> c, ValueNode object) {
-            super(c, StampFactory.forNodeIntrinsic(), null);
+            super(c, PlaceholderStamp.SINGLETON, null);
             this.object = object;
         }
 
@@ -250,12 +303,44 @@
         }
 
         /**
-         * Gets a new {@link PiNode} that replaces this placeholder during snippet instantiation.
+         * Replaces this node with a {@link PiNode} during snippet instantiation.
          *
          * @param snippetReplaceeStamp the stamp of the node being replace by the snippet
          */
-        public PiNode getReplacement(Stamp snippetReplaceeStamp) {
-            return graph().addOrUnique(new PiNode(object(), snippetReplaceeStamp, null));
+        public void makeReplacement(Stamp snippetReplaceeStamp) {
+            ValueNode value = graph().maybeAddOrUnique(PiNode.create(object(), snippetReplaceeStamp, null));
+            replaceAndDelete(value);
+        }
+    }
+
+    /**
+     * A stamp for {@link Placeholder} nodes which are only used in snippets. It is replaced by an
+     * actual stamp when the snippet is instantiated.
+     */
+    public static final class PlaceholderStamp extends ObjectStamp {
+        private static final PlaceholderStamp SINGLETON = new PlaceholderStamp();
+
+        public static PlaceholderStamp singleton() {
+            return SINGLETON;
+        }
+
+        private PlaceholderStamp() {
+            super(null, false, false, false);
+        }
+
+        @Override
+        public int hashCode() {
+            return System.identityHashCode(this);
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            return this == obj;
+        }
+
+        @Override
+        public String toString() {
+            return "PlaceholderStamp";
         }
     }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/SimplifyingGraphDecoder.java	Wed Apr 05 22:48:35 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/SimplifyingGraphDecoder.java	Thu Apr 06 14:31:32 2017 -0700
@@ -22,6 +22,7 @@
  */
 package org.graalvm.compiler.nodes;
 
+import static org.graalvm.compiler.nodeinfo.InputType.Guard;
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED;
 
@@ -37,6 +38,9 @@
 import org.graalvm.compiler.nodes.calc.FloatingNode;
 import org.graalvm.compiler.nodes.extended.GuardingNode;
 import org.graalvm.compiler.nodes.extended.IntegerSwitchNode;
+import org.graalvm.compiler.nodes.java.ArrayLengthNode;
+import org.graalvm.compiler.nodes.java.LoadFieldNode;
+import org.graalvm.compiler.nodes.java.LoadIndexedNode;
 import org.graalvm.compiler.nodes.spi.StampProvider;
 import org.graalvm.compiler.nodes.util.GraphUtil;
 import org.graalvm.compiler.options.OptionValues;
@@ -59,6 +63,7 @@
     protected final ConstantFieldProvider constantFieldProvider;
     protected final StampProvider stampProvider;
     protected final boolean canonicalizeReads;
+    protected final CanonicalizerTool canonicalizerTool;
 
     protected class PECanonicalizerTool implements CanonicalizerTool {
 
@@ -113,7 +118,7 @@
         }
     }
 
-    @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
+    @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED, allowedUsageTypes = {Guard})
     static class CanonicalizeToNullNode extends FloatingNode implements Canonicalizable, GuardingNode {
         public static final NodeClass<CanonicalizeToNullNode> TYPE = NodeClass.create(CanonicalizeToNullNode.class);
 
@@ -127,32 +132,30 @@
         }
     }
 
-    public SimplifyingGraphDecoder(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, ConstantFieldProvider constantFieldProvider, StampProvider stampProvider,
-                    boolean canonicalizeReads, Architecture architecture) {
-        super(architecture);
+    public SimplifyingGraphDecoder(Architecture architecture, StructuredGraph graph, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection,
+                    ConstantFieldProvider constantFieldProvider, StampProvider stampProvider,
+                    boolean canonicalizeReads) {
+        super(architecture, graph);
         this.metaAccess = metaAccess;
         this.constantReflection = constantReflection;
         this.constantFieldProvider = constantFieldProvider;
         this.stampProvider = stampProvider;
         this.canonicalizeReads = canonicalizeReads;
+        this.canonicalizerTool = new PECanonicalizerTool(graph.getAssumptions(), graph.getOptions());
     }
 
     @Override
     protected void cleanupGraph(MethodScope methodScope) {
-        GraphUtil.normalizeLoops(methodScope.graph);
+        GraphUtil.normalizeLoops(graph);
         super.cleanupGraph(methodScope);
 
-        for (Node node : methodScope.graph.getNewNodes(methodScope.methodStartMark)) {
+        for (Node node : graph.getNewNodes(methodScope.methodStartMark)) {
             if (node instanceof MergeNode) {
                 MergeNode mergeNode = (MergeNode) node;
                 if (mergeNode.forwardEndCount() == 1) {
-                    methodScope.graph.reduceTrivialMerge(mergeNode);
+                    graph.reduceTrivialMerge(mergeNode);
                 }
-            }
-        }
-
-        for (Node node : methodScope.graph.getNewNodes(methodScope.methodStartMark)) {
-            if (node instanceof BeginNode || node instanceof KillingBeginNode) {
+            } else if (node instanceof BeginNode || node instanceof KillingBeginNode) {
                 if (!(node.predecessor() instanceof ControlSplitNode) && node.hasNoUsages()) {
                     GraphUtil.unlinkFixedNode((AbstractBeginNode) node);
                     node.safeDelete();
@@ -160,7 +163,7 @@
             }
         }
 
-        for (Node node : methodScope.graph.getNewNodes(methodScope.methodStartMark)) {
+        for (Node node : graph.getNewNodes(methodScope.methodStartMark)) {
             GraphUtil.tryKillUnused(node);
         }
     }
@@ -187,7 +190,32 @@
 
     @Override
     protected void handleFixedNode(MethodScope methodScope, LoopScope loopScope, int nodeOrderId, FixedNode node) {
-        if (node instanceof IfNode) {
+        Node canonical = canonicalizeFixedNode(node);
+        if (canonical != node) {
+            handleCanonicalization(loopScope, nodeOrderId, node, canonical);
+        }
+    }
+
+    private Node canonicalizeFixedNode(FixedNode node) {
+        if (node instanceof LoadFieldNode) {
+            LoadFieldNode loadFieldNode = (LoadFieldNode) node;
+            return loadFieldNode.canonical(canonicalizerTool);
+        } else if (node instanceof FixedGuardNode) {
+            FixedGuardNode guard = (FixedGuardNode) node;
+            if (guard.getCondition() instanceof LogicConstantNode) {
+                LogicConstantNode condition = (LogicConstantNode) guard.getCondition();
+                if (condition.getValue() == guard.isNegated()) {
+                    DeoptimizeNode deopt = new DeoptimizeNode(guard.getAction(), guard.getReason(), guard.getSpeculation());
+                    if (guard.stateBefore() != null) {
+                        deopt.setStateBefore(guard.stateBefore());
+                    }
+                    return deopt;
+                } else {
+                    return null;
+                }
+            }
+            return node;
+        } else if (node instanceof IfNode) {
             IfNode ifNode = (IfNode) node;
             if (ifNode.condition() instanceof LogicNegationNode) {
                 ifNode.eliminateNegation();
@@ -197,73 +225,55 @@
                 AbstractBeginNode survivingSuccessor = ifNode.getSuccessor(condition);
                 AbstractBeginNode deadSuccessor = ifNode.getSuccessor(!condition);
 
-                methodScope.graph.removeSplit(ifNode, survivingSuccessor);
+                graph.removeSplit(ifNode, survivingSuccessor);
                 assert deadSuccessor.next() == null : "must not be parsed yet";
                 deadSuccessor.safeDelete();
             }
-
+            return node;
+        } else if (node instanceof LoadIndexedNode) {
+            LoadIndexedNode loadIndexedNode = (LoadIndexedNode) node;
+            return loadIndexedNode.canonical(canonicalizerTool);
+        } else if (node instanceof ArrayLengthNode) {
+            ArrayLengthNode arrayLengthNode = (ArrayLengthNode) node;
+            return arrayLengthNode.canonical(canonicalizerTool);
         } else if (node instanceof IntegerSwitchNode && ((IntegerSwitchNode) node).value().isConstant()) {
             IntegerSwitchNode switchNode = (IntegerSwitchNode) node;
             int value = switchNode.value().asJavaConstant().asInt();
             AbstractBeginNode survivingSuccessor = switchNode.successorAtKey(value);
             List<Node> allSuccessors = switchNode.successors().snapshot();
 
-            methodScope.graph.removeSplit(switchNode, survivingSuccessor);
+            graph.removeSplit(switchNode, survivingSuccessor);
             for (Node successor : allSuccessors) {
                 if (successor != survivingSuccessor) {
                     assert ((AbstractBeginNode) successor).next() == null : "must not be parsed yet";
                     successor.safeDelete();
                 }
             }
-
-        } else if (node instanceof FixedGuardNode) {
-            FixedGuardNode guard = (FixedGuardNode) node;
-            if (guard.getCondition() instanceof LogicConstantNode) {
-                LogicConstantNode condition = (LogicConstantNode) guard.getCondition();
-                Node canonical;
-                if (condition.getValue() == guard.isNegated()) {
-                    DeoptimizeNode deopt = new DeoptimizeNode(guard.getAction(), guard.getReason(), guard.getSpeculation());
-                    if (guard.stateBefore() != null) {
-                        deopt.setStateBefore(guard.stateBefore());