8233273: Update Graal
authordlong
Thu, 31 Oct 2019 16:54:16 -0700
changeset 58877 aec7bf35d6f5
parent 58876 1a8d65e71a66
child 58878 452df727bebb
8233273: Update Graal Reviewed-by: kvn
src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/EconomicMap.java
src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/EconomicSet.java
src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/Equivalence.java
src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/MapCursor.java
src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/Pair.java
src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/UnmodifiableEconomicMap.java
src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/UnmodifiableEconomicSet.java
src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/UnmodifiableMapCursor.java
src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/package-info.java
src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/ComparableWord.java
src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/LocationIdentity.java
src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/Pointer.java
src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/PointerBase.java
src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/SignedWord.java
src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/UnsignedWord.java
src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/WordBase.java
src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/WordFactory.java
src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/package-info.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.replacements/src/org/graalvm/compiler/api/replacements/MethodSubstitution.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.replacements/src/org/graalvm/compiler/api/replacements/MethodSubstitutionRegistry.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.test/src/org/graalvm/compiler/api/test/ExportingClassLoader.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.test/src/org/graalvm/compiler/api/test/ModuleSupport.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64Assembler.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64MacroAssembler.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64.test/src/org/graalvm/compiler/core/aarch64/test/AArch64MultiplyLongTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64ArithmeticLIRGenerator.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64NodeMatchRules.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64NodeMatchRules.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/GraalOptions.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/cfg/AbstractBlockBase.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/cfg/AbstractControlFlowGraph.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/cfg/Loop.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IntegerStamp.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCNodeMatchRules.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/BoxingEliminationTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CheckGraalInvariants.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CompareCanonicalizerTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CompareCanonicalizerTest2.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CompareCanonicalizerTest3.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationMulTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest10.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest14.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest15.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest16.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest2.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTestBase.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CountedLoopTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/DeMorganCanonicalizationTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/DegeneratedLoopsTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/EnumSwitchTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/FinalizableSubclassTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/FloatingReadTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraphEncoderTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GuardPrioritiesTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/IfCanonicalizerTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ImplicitNullCheckTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/IntegerEqualsCanonicalizerTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/InterfaceMethodHandleTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/InvokeExceptionTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/InvokeHintsTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/LateMembarInsertionTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/LockEliminationTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/LongNodeChainTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/LoopFullUnrollTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/LoopUnswitchTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MarkUnsafeAccessTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MemoryGraphCanonicalizeTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MemoryScheduleTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MergeCanonicalizerTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MonitorGraphTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/NodePropertiesTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/PushNodesThroughPiTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/PushThroughIfTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ReadAfterCheckCastTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ReassociateAndCanonicalTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ScalarTypeSystemTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SchedulingTest2.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StampCanonicalizerTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StraighteningTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SwitchCanonicalizerTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SwitchDyingLoopTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SwitchFoldingTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/TypeSystemTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnsafeReadEliminationTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnsafeVirtualizationTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnusedArray.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/deopt/CompiledMethodTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/EATestBase.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/EarlyReadEliminationTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/EscapeAnalysisTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PEAReadEliminationTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PartialEscapeAnalysisIterationTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PartialEscapeAnalysisTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PartialEscapeAnalysisTreesTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PoorMansEATest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/TrufflePEATest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/UnsafeEATest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/inlining/InliningTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/inlining/NestedLoopEffectsPhaseComplexityTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/NodeMatchRules.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/BaseTier.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/EconomyHighTier.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/EconomyLowTier.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/EconomyMidTier.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/HighTier.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/LowTier.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/MidTier.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackendFactory.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackendFactory.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotBackendFactory.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CheckGraalIntrinsics.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorld.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ConstantPoolSubstitutionsTests.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/DeferredBarrierAdditionTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotCryptoSubstitutionTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotInvokeDynamicPluginTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ReplaceConstantNodesPhaseTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/TestSHASubstitutions.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/WriteBarrierAdditionTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotReplacementsImpl.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/SymbolicSnippetEncoder.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotSuitesProvider.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/BeginLockScopeNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/EndLockScopeNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/StubForeignCallNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/InitializeKlassNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/InitializeKlassStubCall.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveDynamicConstantNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveDynamicStubCall.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/AheadOfTimeVerificationPhase.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/IdentityHashCodeNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/SHA2Substitutions.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/SHA5Substitutions.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/SHASubstitutions.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/ForeignCallStub.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/SnippetStub.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/FrameStateBuilder.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/backend/LargeConstantSectionTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/UntrustedInterfaces.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/NestedLoop_EA.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/TrichotomyTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ArithmeticOp.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64Move.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64StringLatin1InflateOp.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64StringUTF16CompressOp.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/vector/AMD64VectorMove.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/LIRIntrospection.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanLifetimeAnalysisPhase.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/ConvertDeoptimizeToGuardPhase.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopPeelingPhase.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopTransformations.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.test/src/org/graalvm/compiler/loop/test/LoopPartialUnrollTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/CountedLoopInfo.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/DefaultLoopPolicies.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopEx.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragment.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragmentInside.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopPolicies.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/MathUtil.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/GraalBenchmark.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/TestJMHWhitebox.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/IfNodeCanonicalizationTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/LoopPhiCanonicalizerTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/ShortCircuitOrNodeTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FrameState.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphDecoder.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GuardProxyNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/IfNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InvokeNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InvokeWithExceptionNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/KillingBeginNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/LoopBeginNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/MemoryProxyNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ProxyNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StartNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StructuredGraph.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ValueProxyNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/AndNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/BinaryArithmeticNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/CompareNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/OrNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/XorNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/Block.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/ControlFlowGraph.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/StringToBytesNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/BytecodeExceptionNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/ForeignCallNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/JavaWriteNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/MembarNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawLoadNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawStoreNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/SwitchNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnsafeAccessNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnsafeMemoryStoreNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderConfiguration.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InvocationPlugins.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/MethodSubstitutionPlugin.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AbstractCompareAndSwapNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AbstractUnsafeCompareAndSwapNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AtomicReadAndAddNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AtomicReadAndWriteNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/ExceptionObjectNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LoweredAtomicReadAndWriteNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/MonitorEnterNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/MonitorExitNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/RawMonitorEnterNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/FixedAccessNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryCheckpoint.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/VolatileReadNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/WriteNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/DelegatingReplacements.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/Replacements.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/util/GraphUtil.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/AllocatedObjectNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/CommitAllocationNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/CanonicalizerPhase.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ConditionalEliminationPhase.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/FloatingReadPhase.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/GuardLoweringPhase.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/InsertMembarsPhase.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/LoweringPhase.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/InliningUtil.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/MultiTypeGuardInlineInfo.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/MemoryScheduleVerification.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/SchedulePhase.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/ScheduleVerification.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64GraphBuilderPlugins.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64CountLeadingZerosNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64CountTrailingZerosNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64GraphBuilderPlugins.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64IntegerSubstitutions.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64LongSubstitutions.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringLatin1InflateNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringUTF16CompressNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.jdk9.test/src/org/graalvm/compiler/replacements/jdk9/test/VarHandleTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.sparc/src/org/graalvm/compiler/replacements/sparc/SPARCGraphBuilderPlugins.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ArraysSubstitutionsTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/BitOpNodesTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/DeoptimizeOnExceptionTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/EdgesTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/FoldTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/IntegerExactFoldTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/MethodSubstitutionTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ObjectAccessTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PEGraphDecoderTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PointerTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ReplacementsParseTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/StandardMethodSubstitutionsTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/SubstitutionNodeSourcePositionTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/SubstitutionsTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/classfile/ClassfileBytecodeProviderTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/classfile/RedefineIntrinsicTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/CachingPEGraphDecoder.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/DefaultJavaLoweringProvider.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/NodeIntrinsificationProvider.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ReplacementsImpl.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetTemplate.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/TargetGraphBuilderPlugins.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/arraycopy/ArrayCopyCallNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/arraycopy/ArrayCopyNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/arraycopy/CheckcastArrayCopyCallNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/arraycopy/GenericArrayCopyCallNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BasicArrayCopyNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroStateSplitNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/ExportingClassLoader.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/ModuleSupport.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationClosure.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/ReadEliminationBlockState.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/ReadEliminationClosure.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/OptionsEncoder.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/TypedDataInputStream.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/TypedDataOutputStream.java
--- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/EconomicMap.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/EconomicMap.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2019, 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
--- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/EconomicSet.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/EconomicSet.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2019, 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
--- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/Equivalence.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/Equivalence.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2019, 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
--- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/MapCursor.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/MapCursor.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2019, 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
--- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/Pair.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/Pair.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2019, 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
--- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/UnmodifiableEconomicMap.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/UnmodifiableEconomicMap.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2019, 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
--- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/UnmodifiableEconomicSet.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/UnmodifiableEconomicSet.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2019, 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
--- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/UnmodifiableMapCursor.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/UnmodifiableMapCursor.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2019, 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
--- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/package-info.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/package-info.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2019, 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
--- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/ComparableWord.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/ComparableWord.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2019, 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
--- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/LocationIdentity.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/LocationIdentity.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2019, 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
--- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/Pointer.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/Pointer.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2019, 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
--- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/PointerBase.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/PointerBase.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2019, 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
--- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/SignedWord.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/SignedWord.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2019, 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
--- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/UnsignedWord.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/UnsignedWord.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2019, 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
--- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/WordBase.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/WordBase.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2019, 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
--- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/WordFactory.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/WordFactory.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2019, 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
--- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/package-info.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/package-info.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2019, 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
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.replacements/src/org/graalvm/compiler/api/replacements/MethodSubstitution.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.replacements/src/org/graalvm/compiler/api/replacements/MethodSubstitution.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2019, 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
@@ -35,9 +35,7 @@
 /**
  * Denotes a method whose body is used by a compiler as the substitute (or intrinsification) of
  * another method. The exact mechanism used to do the substitution is compiler dependent but every
- * compiler should require substitute methods to be annotated with {@link MethodSubstitution}. In
- * addition, a compiler is recommended to implement {@link MethodSubstitutionRegistry} to advertise
- * the mechanism by which it supports registration of method substitutes.
+ * compiler should require substitute methods to be annotated with {@link MethodSubstitution}.
  *
  * A compiler may support partial intrinsification where only a part of a method is implemented by
  * the compiler. The unsupported path is expressed by a call to either the original or substitute
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.replacements/src/org/graalvm/compiler/api/replacements/MethodSubstitutionRegistry.java	Thu Oct 31 14:23:06 2019 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,63 +0,0 @@
-/*
- * Copyright (c) 2013, 2018, 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.api.replacements;
-
-import java.lang.reflect.Type;
-
-/**
- * A registry for {@link MethodSubstitution}s.
- */
-public interface MethodSubstitutionRegistry {
-
-    /**
-     * Gets the type representing the receiver (i.e., {@code this}) argument in a non-static method.
-     */
-    Class<?> getReceiverType();
-
-    /**
-     * Registers a substitution method.
-     *
-     * @param substituteDeclaringClass the class declaring the substitute method
-     * @param name the name of both the original and substitute method
-     * @param argumentTypes the argument types of the method. Element 0 of this array must be
-     *            {@link #getReceiverType()} iff the method is non-static. Upon returning, element 0
-     *            will have been rewritten to {@code declaringClass}.
-     */
-    default void registerMethodSubstitution(Class<?> substituteDeclaringClass, String name, Type... argumentTypes) {
-        registerMethodSubstitution(substituteDeclaringClass, name, name, argumentTypes);
-    }
-
-    /**
-     * Registers a substitution method.
-     *
-     * @param substituteDeclaringClass the class declaring the substitute method
-     * @param name the name of both the original method
-     * @param substituteName the name of the substitute method
-     * @param argumentTypes the argument types of the method. Element 0 of this array must be
-     *            {@link #getReceiverType()} iff the method is non-static. Upon returning, element 0
-     *            will have been rewritten to {@code declaringClass}.
-     */
-    void registerMethodSubstitution(Class<?> substituteDeclaringClass, String name, String substituteName, Type... argumentTypes);
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.test/src/org/graalvm/compiler/api/test/ExportingClassLoader.java	Thu Oct 31 16:54:16 2019 -0700
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2016, 2019, 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.api.test;
+
+/**
+ * A class loader that exports all packages in the module defining the class loader to all classes
+ * in the unnamed module associated with the loader.
+ */
+public class ExportingClassLoader extends ClassLoader {
+    public ExportingClassLoader() {
+        ModuleSupport.exportAllPackagesTo(getClass(), this);
+    }
+
+    public ExportingClassLoader(ClassLoader parent) {
+        super(parent);
+        ModuleSupport.exportAllPackagesTo(getClass(), this);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.test/src/org/graalvm/compiler/api/test/ModuleSupport.java	Thu Oct 31 16:54:16 2019 -0700
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2019, 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.api.test;
+
+import java.io.IOException;
+import java.lang.module.ModuleDescriptor.Requires;
+import java.net.URI;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.graalvm.compiler.debug.DebugOptions;
+
+import jdk.internal.module.Modules;
+
+public class ModuleSupport {
+
+    public static void exportPackageTo(Class<?> moduleMember, String packageName, Class<?> requestor) {
+        Module moduleToExport = moduleMember.getModule();
+        Module requestorModule = requestor.getModule();
+        if (moduleToExport != requestorModule) {
+            Modules.addExports(moduleToExport, packageName, requestorModule);
+        }
+    }
+
+    public static void exportAllPackagesTo(Class<?> moduleMember, Class<?> requestor) {
+        Module moduleToExport = moduleMember.getModule();
+        Module requestorModule = requestor.getModule();
+        if (moduleToExport != requestorModule) {
+            for (String packageName : moduleToExport.getPackages()) {
+                Modules.addExports(moduleToExport, packageName, requestorModule);
+            }
+        }
+    }
+
+    public static void exportAllPackagesTo(Class<?> moduleMember, ClassLoader cl) {
+        Module moduleToExport = moduleMember.getModule();
+        Module unnamedModule = cl.getUnnamedModule();
+        for (String packageName : moduleToExport.getPackages()) {
+            Modules.addExports(moduleToExport, packageName, unnamedModule);
+        }
+    }
+
+    @SuppressWarnings("unused")
+    public static void exportAndOpenAllPackagesToUnnamed(String name) {
+        Module module = ModuleLayer.boot().findModule(name).orElseThrow();
+        Set<String> packages = module.getPackages();
+        for (String pkg : packages) {
+            Modules.addExportsToAllUnnamed(module, pkg);
+            Modules.addOpensToAllUnnamed(module, pkg);
+        }
+    }
+
+    public static List<String> getJRTGraalClassNames() throws IOException {
+        List<String> classNames = new ArrayList<>();
+        FileSystem fs = FileSystems.newFileSystem(URI.create("jrt:/"), Collections.emptyMap());
+        Module graalModule = DebugOptions.class.getModule();
+        Set<String> graalModuleSet = new HashSet<>();
+        graalModuleSet.add(graalModule.getName());
+        for (Module module : graalModule.getLayer().modules()) {
+            if (requires(module, graalModule)) {
+                graalModuleSet.add(module.getName());
+            }
+        }
+
+        Path top = fs.getPath("/modules/");
+        Files.find(top, Integer.MAX_VALUE,
+                        (path, attrs) -> attrs.isRegularFile()).forEach(p -> {
+                            int nameCount = p.getNameCount();
+                            if (nameCount > 2) {
+                                String base = p.getName(nameCount - 1).toString();
+                                if (base.endsWith(".class") && !base.equals("module-info.class")) {
+                                    String module = p.getName(1).toString();
+                                    if (graalModuleSet.contains(module)) {
+                                        // Strip module prefix and convert to dotted
+                                        // form
+                                        String className = p.subpath(2, nameCount).toString().replace('/', '.');
+                                        // Strip ".class" suffix
+                                        className = className.replace('/', '.').substring(0, className.length() - ".class".length());
+                                        classNames.add(className);
+                                    }
+                                }
+                            }
+                        });
+        return classNames;
+    }
+
+    private static boolean requires(Module module, Module graalModule) {
+        ModuleLayer graalLayer = graalModule.getLayer();
+        for (Requires r : module.getDescriptor().requires()) {
+            if (r.name().equals(graalModule.getName())) {
+                return true;
+            }
+            Module dep = graalLayer.findModule(r.name()).get();
+            if (requires(dep, graalModule)) {
+                return true;
+            }
+        }
+        return false;
+    }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64Assembler.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64Assembler.java	Thu Oct 31 16:54:16 2019 -0700
@@ -471,6 +471,7 @@
     private static final int AddSubExtendedOp = 0x0B200000;
 
     private static final int MulOp = 0x1B000000;
+    private static final int SignedMulLongOp = 0x9B200000;
     private static final int DataProcessing1SourceOp = 0x5AC00000;
     private static final int DataProcessing2SourceOp = 0x1AC00000;
 
@@ -2313,7 +2314,7 @@
     }
 
     /**
-     * unsigned multiply high. dst = (src1 * src2)[127:64]
+     * Unsigned multiply high. dst = (src1 * src2)[127:64]
      *
      * @param dst general purpose register. May not be null or the stackpointer.
      * @param src1 general purpose register. May not be null or the stackpointer.
@@ -2327,7 +2328,7 @@
     }
 
     /**
-     * unsigned multiply add-long. xDst = xSrc3 + (wSrc1 * wSrc2)
+     * Unsigned multiply add-long. xDst = xSrc3 + (wSrc1 * wSrc2)
      *
      * @param dst general purpose register. May not be null or the stackpointer.
      * @param src1 general purpose register. May not be null or the stackpointer.
@@ -2343,7 +2344,7 @@
     }
 
     /**
-     * signed multiply add-long. xDst = xSrc3 + (wSrc1 * wSrc2)
+     * Signed multiply-add long. xDst = xSrc3 + (wSrc1 * wSrc2)
      *
      * @param dst general purpose register. May not be null or the stackpointer.
      * @param src1 general purpose register. May not be null or the stackpointer.
@@ -2351,11 +2352,19 @@
      * @param src3 general purpose register. May not be null or the stackpointer.
      */
     public void smaddl(Register dst, Register src1, Register src2, Register src3) {
-        assert !dst.equals(sp);
-        assert !src1.equals(sp);
-        assert !src2.equals(sp);
-        assert !src3.equals(sp);
-        emitInt(0b10011011001 << 21 | dst.encoding | rs1(src1) | rs2(src2) | rs3(src3));
+        smullInstruction(MADD, dst, src1, src2, src3);
+    }
+
+    /**
+     * Signed multiply-sub long. xDst = xSrc3 - (wSrc1 * wSrc2)
+     *
+     * @param dst general purpose register. May not be null or the stackpointer.
+     * @param src1 general purpose register. May not be null or the stackpointer.
+     * @param src2 general purpose register. May not be null or the stackpointer.
+     * @param src3 general purpose register. May not be null or the stackpointer.
+     */
+    public void smsubl(Register dst, Register src1, Register src2, Register src3) {
+        smullInstruction(MSUB, dst, src1, src2, src3);
     }
 
     private void mulInstruction(Instruction instr, Register dst, Register src1, Register src2, Register src3, InstructionType type) {
@@ -2366,6 +2375,14 @@
         emitInt(type.encoding | instr.encoding | MulOp | rd(dst) | rs1(src1) | rs2(src2) | rs3(src3));
     }
 
+    private void smullInstruction(Instruction instr, Register dst, Register src1, Register src2, Register src3) {
+        assert !dst.equals(sp);
+        assert !src1.equals(sp);
+        assert !src2.equals(sp);
+        assert !src3.equals(sp);
+        emitInt(instr.encoding | SignedMulLongOp | rd(dst) | rs1(src1) | rs2(src2) | rs3(src3));
+    }
+
     /**
      * Signed divide. dst = src1 / src2.
      *
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64MacroAssembler.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64MacroAssembler.java	Thu Oct 31 16:54:16 2019 -0700
@@ -817,7 +817,7 @@
     }
 
     /**
-     * unsigned multiply high. dst = (src1 * src2) >> size
+     * Unsigned multiply high. dst = (src1 * src2) >> size
      *
      * @param size register size. Has to be 32 or 64.
      * @param dst general purpose register. May not be null or the stackpointer.
@@ -838,7 +838,7 @@
     }
 
     /**
-     * signed multiply high. dst = (src1 * src2) >> size
+     * Signed multiply high. dst = (src1 * src2) >> size
      *
      * @param size register size. Has to be 32 or 64.
      * @param dst general purpose register. May not be null or the stackpointer.
@@ -859,6 +859,60 @@
     }
 
     /**
+     * Signed multiply long. xDst = wSrc1 * wSrc2
+     *
+     * @param size destination register size. Has to be 64.
+     * @param dst 64-bit general purpose register. May not be null or the stackpointer.
+     * @param src1 32-bit general purpose register. May not be null or the stackpointer.
+     * @param src2 32-bit general purpose register. May not be null or the stackpointer.
+     */
+    public void smull(int size, Register dst, Register src1, Register src2) {
+        this.smaddl(size, dst, src1, src2, zr);
+    }
+
+    /**
+     * Signed multiply-negate long. xDst = -(wSrc1 * wSrc2)
+     *
+     * @param size destination register size. Has to be 64.
+     * @param dst 64-bit general purpose register. May not be null or the stackpointer.
+     * @param src1 32-bit general purpose register. May not be null or the stackpointer.
+     * @param src2 32-bit general purpose register. May not be null or the stackpointer.
+     */
+    public void smnegl(int size, Register dst, Register src1, Register src2) {
+        this.smsubl(size, dst, src1, src2, zr);
+    }
+
+    /**
+     * Signed multiply-add long. xDst = xSrc3 + (wSrc1 * wSrc2)
+     *
+     * @param size destination register size. Has to be 64.
+     * @param dst 64-bit general purpose register. May not be null or the stackpointer.
+     * @param src1 32-bit general purpose register. May not be null or the stackpointer.
+     * @param src2 32-bit general purpose register. May not be null or the stackpointer.
+     * @param src3 64-bit general purpose register. May not be null or the stackpointer.
+     */
+    public void smaddl(int size, Register dst, Register src1, Register src2, Register src3) {
+        assert (!dst.equals(sp) && !src1.equals(sp) && !src2.equals(sp) && !src3.equals(sp));
+        assert size == 64;
+        super.smaddl(dst, src1, src2, src3);
+    }
+
+    /**
+     * Signed multiply-sub long. xDst = xSrc3 - (wSrc1 * wSrc2)
+     *
+     * @param size destination register size. Has to be 64.
+     * @param dst 64-bit general purpose register. May not be null or the stackpointer.
+     * @param src1 32-bit general purpose register. May not be null or the stackpointer.
+     * @param src2 32-bit general purpose register. May not be null or the stackpointer.
+     * @param src3 64-bit general purpose register. May not be null or the stackpointer.
+     */
+    public void smsubl(int size, Register dst, Register src1, Register src2, Register src3) {
+        assert (!dst.equals(sp) && !src1.equals(sp) && !src2.equals(sp) && !src3.equals(sp));
+        assert size == 64;
+        super.smsubl(dst, src1, src2, src3);
+    }
+
+    /**
      * dst = src1 % src2. Signed.
      *
      * @param size register size. Has to be 32 or 64.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64.test/src/org/graalvm/compiler/core/aarch64/test/AArch64MultiplyLongTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, Arm Limited. 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.aarch64.test;
+
+import org.junit.Test;
+
+public class AArch64MultiplyLongTest extends AArch64MatchRuleTest {
+
+    public long signedMulLong(int a, int b) {
+        return a * (long) b;
+    }
+
+    public long signedMulLongFromShort(short a, short b) {
+        return (long) a * b;
+    }
+
+    public long signedMulLongFromChar(char a, char b) {
+        return a * (long) b;
+    }
+
+    public long signedMulLongFromByte(byte a, byte b) {
+        return (long) a * b;
+    }
+
+    @Test
+    public void testSignedMulLong() {
+        test("signedMulLong", 0x12345678, 0x87654321);
+        checkLIR("signedMulLong", op -> op.name().equals("SMULL"), 1);
+        test("signedMulLongFromShort", (short) 32767, (short) -32768);
+        checkLIR("signedMulLongFromShort", op -> op.name().equals("SMULL"), 1);
+        test("signedMulLongFromChar", (char) 59999, (char) 65535);
+        checkLIR("signedMulLongFromChar", op -> op.name().equals("SMULL"), 1);
+        test("signedMulLongFromByte", (byte) 10, (byte) -256);
+        checkLIR("signedMulLongFromByte", op -> op.name().equals("SMULL"), 1);
+    }
+
+    public long signedMNegLong1(int a, int b) {
+        return -(a * (long) b);
+    }
+
+    public long signedMNegLong2(int a, int b) {
+        return a * (-(long) b);
+    }
+
+    @Test
+    public void testSignedMNegLong() {
+        test("signedMNegLong1", 0x89abcdef, 0xfedcba98);
+        checkLIR("signedMNegLong1", op -> op.name().equals("SMNEGL"), 1);
+        test("signedMNegLong2", 0x89abcdef, 0xfedcba98);
+        checkLIR("signedMNegLong2", op -> op.name().equals("SMNEGL"), 1);
+    }
+
+    public long signedMAddLong1(int a, int b, long c) {
+        return c + a * (long) b;
+    }
+
+    public long signedMAddLong2(int a, int b, long c) {
+        return a * (long) b + c;
+    }
+
+    @Test
+    public void testSignedMAddLong() {
+        test("signedMAddLong1", 0x22228888, 0xaaaacccc, 0x123456789abcdL);
+        checkLIR("signedMAddLong1", op -> op.name().equals("SMADDL"), 1);
+        test("signedMAddLong2", 0x22228888, 0xaaaacccc, 0x123456789abcdL);
+        checkLIR("signedMAddLong2", op -> op.name().equals("SMADDL"), 1);
+    }
+
+    public long signedMSubLong(int a, int b, long c) {
+        return c - a * (long) b;
+    }
+
+    @Test
+    public void testSignedMSubLong() {
+        test("signedMSubLong", 0x99995555, 0xeeeebbbb, 0x3456789abcdefL);
+        checkLIR("signedMSubLong", op -> op.name().equals("SMSUBL"), 1);
+    }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64ArithmeticLIRGenerator.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64ArithmeticLIRGenerator.java	Thu Oct 31 16:54:16 2019 -0700
@@ -220,23 +220,34 @@
         return result;
     }
 
-    public Value emitMAdd(Value a, Value b, Value c) {
-        return emitMultiplyAddSub(AArch64ArithmeticOp.ADD, a, b, c);
+    Value emitIntegerMAdd(Value a, Value b, Value c, boolean isI2L) {
+        return emitMultiplyAddSub(isI2L ? AArch64ArithmeticOp.SMADDL : AArch64ArithmeticOp.MADD, a, b, c);
     }
 
-    public Value emitMSub(Value a, Value b, Value c) {
-        return emitMultiplyAddSub(AArch64ArithmeticOp.SUB, a, b, c);
+    Value emitIntegerMSub(Value a, Value b, Value c, boolean isI2L) {
+        return emitMultiplyAddSub(isI2L ? AArch64ArithmeticOp.SMSUBL : AArch64ArithmeticOp.MSUB, a, b, c);
     }
 
     private Value emitMultiplyAddSub(AArch64ArithmeticOp op, Value a, Value b, Value c) {
-        assert a.getPlatformKind() == b.getPlatformKind() && b.getPlatformKind() == c.getPlatformKind();
-        if (op == AArch64ArithmeticOp.ADD || op == AArch64ArithmeticOp.SUB) {
-            assert isNumericInteger(a.getPlatformKind());
-        } else if (op == AArch64ArithmeticOp.FADD) {
-            assert a.getPlatformKind() == AArch64Kind.SINGLE || a.getPlatformKind() == AArch64Kind.DOUBLE;
+        assert a.getPlatformKind() == b.getPlatformKind();
+        Variable result;
+        if (op == AArch64ArithmeticOp.SMADDL || op == AArch64ArithmeticOp.SMSUBL) {
+            // For signed multiply int and then add/sub long.
+            assert a.getPlatformKind() != c.getPlatformKind();
+            result = getLIRGen().newVariable(LIRKind.combine(c));
+        } else {
+            assert a.getPlatformKind() == c.getPlatformKind();
+            if (op == AArch64ArithmeticOp.FADD) {
+                // For floating-point Math.fma intrinsic.
+                assert a.getPlatformKind() == AArch64Kind.SINGLE || a.getPlatformKind() == AArch64Kind.DOUBLE;
+            } else {
+                // For int/long multiply add or sub.
+                assert op == AArch64ArithmeticOp.MADD || op == AArch64ArithmeticOp.MSUB;
+                assert isNumericInteger(a.getPlatformKind());
+            }
+            result = getLIRGen().newVariable(LIRKind.combine(a, b, c));
         }
 
-        Variable result = getLIRGen().newVariable(LIRKind.combine(a, b, c));
         AllocatableValue x = moveSp(asAllocatable(a));
         AllocatableValue y = moveSp(asAllocatable(b));
         AllocatableValue z = moveSp(asAllocatable(c));
@@ -451,7 +462,7 @@
 
     @Override
     public Value emitFusedMultiplyAdd(Value a, Value b, Value c) {
-        return emitMultiplyAddSub(AArch64ArithmeticOp.FADD, a, b, c);
+        return emitMultiplyAddSub(AArch64ArithmeticOp.FMADD, a, b, c);
     }
 
     @Override
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64NodeMatchRules.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64NodeMatchRules.java	Thu Oct 31 16:54:16 2019 -0700
@@ -57,6 +57,7 @@
 import org.graalvm.compiler.nodes.calc.BinaryNode;
 import org.graalvm.compiler.nodes.calc.IntegerLessThanNode;
 import org.graalvm.compiler.nodes.calc.LeftShiftNode;
+import org.graalvm.compiler.nodes.calc.MulNode;
 import org.graalvm.compiler.nodes.calc.NotNode;
 import org.graalvm.compiler.nodes.calc.OrNode;
 import org.graalvm.compiler.nodes.calc.RightShiftNode;
@@ -224,6 +225,33 @@
         return emitBinaryShift(op, a, shift, isShiftNot);
     }
 
+    @MatchRule("(Add=binary (Mul (SignExtend a) (SignExtend b)) c)")
+    @MatchRule("(Sub=binary c (Mul (SignExtend a) (SignExtend b)))")
+    public ComplexMatchResult signedMultiplyAddSubLong(BinaryNode binary, ValueNode a, ValueNode b, ValueNode c) {
+        assert a.getStackKind() == JavaKind.Int && b.getStackKind() == JavaKind.Int && c.getStackKind() == JavaKind.Long;
+        if (binary instanceof AddNode) {
+            return builder -> getArithmeticLIRGenerator().emitIntegerMAdd(operand(a), operand(b), operand(c), true);
+        }
+        return builder -> getArithmeticLIRGenerator().emitIntegerMSub(operand(a), operand(b), operand(c), true);
+    }
+
+    @MatchRule("(Negate (Mul=mul (SignExtend a) (SignExtend b)))")
+    @MatchRule("(Mul=mul (Negate (SignExtend a)) (SignExtend b))")
+    public ComplexMatchResult signedMultiplyNegLong(MulNode mul, ValueNode a, ValueNode b) {
+        assert a.getStackKind() == JavaKind.Int && b.getStackKind() == JavaKind.Int;
+        LIRKind resultKind = LIRKind.fromJavaKind(gen.target().arch, mul.getStackKind());
+        return builder -> getArithmeticLIRGenerator().emitBinary(
+                        resultKind, AArch64ArithmeticOp.SMNEGL, true, operand(a), operand(b));
+    }
+
+    @MatchRule("(Mul=mul (SignExtend a) (SignExtend b))")
+    public ComplexMatchResult signedMultiplyLong(MulNode mul, ValueNode a, ValueNode b) {
+        assert a.getStackKind() == JavaKind.Int && b.getStackKind() == JavaKind.Int;
+        LIRKind resultKind = LIRKind.fromJavaKind(gen.target().arch, mul.getStackKind());
+        return builder -> getArithmeticLIRGenerator().emitBinary(
+                        resultKind, AArch64ArithmeticOp.SMULL, true, operand(a), operand(b));
+    }
+
     @MatchRule("(Mul (Negate a) b)")
     @MatchRule("(Negate (Mul a b))")
     public ComplexMatchResult multiplyNegate(ValueNode a, ValueNode b) {
@@ -244,9 +272,9 @@
         }
 
         if (binary instanceof AddNode) {
-            return builder -> getArithmeticLIRGenerator().emitMAdd(operand(a), operand(b), operand(c));
+            return builder -> getArithmeticLIRGenerator().emitIntegerMAdd(operand(a), operand(b), operand(c), false);
         }
-        return builder -> getArithmeticLIRGenerator().emitMSub(operand(a), operand(b), operand(c));
+        return builder -> getArithmeticLIRGenerator().emitIntegerMSub(operand(a), operand(b), operand(c), false);
     }
 
     /**
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64NodeMatchRules.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64NodeMatchRules.java	Thu Oct 31 16:54:16 2019 -0700
@@ -359,6 +359,7 @@
 
     @MatchRule("(If (IntegerTest Read=access value))")
     @MatchRule("(If (IntegerTest FloatingRead=access value))")
+    @MatchRule("(If (IntegerTest VolatileRead=access value))")
     public ComplexMatchResult integerTestBranchMemory(IfNode root, LIRLowerableAccess access, ValueNode value) {
         return emitIntegerTestBranchMemory(root, value, access);
     }
@@ -369,14 +370,21 @@
     @MatchRule("(If (IntegerEquals=compare value FloatingRead=access))")
     @MatchRule("(If (IntegerLessThan=compare value FloatingRead=access))")
     @MatchRule("(If (IntegerBelow=compare value FloatingRead=access))")
+    @MatchRule("(If (IntegerEquals=compare value VolatileRead=access))")
+    @MatchRule("(If (IntegerLessThan=compare value VolatileRead=access))")
+    @MatchRule("(If (IntegerBelow=compare value VolatileRead=access))")
     @MatchRule("(If (FloatEquals=compare value Read=access))")
     @MatchRule("(If (FloatEquals=compare value FloatingRead=access))")
+    @MatchRule("(If (FloatEquals=compare value VolatileRead=access))")
     @MatchRule("(If (FloatLessThan=compare value Read=access))")
     @MatchRule("(If (FloatLessThan=compare value FloatingRead=access))")
+    @MatchRule("(If (FloatLessThan=compare value VolatileRead=access))")
     @MatchRule("(If (PointerEquals=compare value Read=access))")
     @MatchRule("(If (PointerEquals=compare value FloatingRead=access))")
+    @MatchRule("(If (PointerEquals=compare value VolatileRead=access))")
     @MatchRule("(If (ObjectEquals=compare value Read=access))")
     @MatchRule("(If (ObjectEquals=compare value FloatingRead=access))")
+    @MatchRule("(If (ObjectEquals=compare value VolatileRead=access))")
     public ComplexMatchResult ifCompareMemory(IfNode root, CompareNode compare, ValueNode value, LIRLowerableAccess access) {
         return emitCompareBranchMemory(root, compare, value, access);
     }
@@ -478,6 +486,7 @@
 
     @MatchRule("(Add value Read=access)")
     @MatchRule("(Add value FloatingRead=access)")
+    @MatchRule("(Add value VolatileRead=access)")
     public ComplexMatchResult addMemory(ValueNode value, LIRLowerableAccess access) {
         OperandSize size = getMemorySize(access);
         if (size.isXmmType()) {
@@ -493,6 +502,7 @@
 
     @MatchRule("(Sub value Read=access)")
     @MatchRule("(Sub value FloatingRead=access)")
+    @MatchRule("(Sub value VolatileRead=access)")
     public ComplexMatchResult subMemory(ValueNode value, LIRLowerableAccess access) {
         OperandSize size = getMemorySize(access);
         if (size.isXmmType()) {
@@ -508,6 +518,7 @@
 
     @MatchRule("(Mul value Read=access)")
     @MatchRule("(Mul value FloatingRead=access)")
+    @MatchRule("(Mul value VolatileRead=access)")
     public ComplexMatchResult mulMemory(ValueNode value, LIRLowerableAccess access) {
         OperandSize size = getMemorySize(access);
         if (size.isXmmType()) {
@@ -523,6 +534,7 @@
 
     @MatchRule("(And value Read=access)")
     @MatchRule("(And value FloatingRead=access)")
+    @MatchRule("(And value VolatileRead=access)")
     public ComplexMatchResult andMemory(ValueNode value, LIRLowerableAccess access) {
         OperandSize size = getMemorySize(access);
         if (size.isXmmType()) {
@@ -534,6 +546,7 @@
 
     @MatchRule("(Or value Read=access)")
     @MatchRule("(Or value FloatingRead=access)")
+    @MatchRule("(Or value VolatileRead=access)")
     public ComplexMatchResult orMemory(ValueNode value, LIRLowerableAccess access) {
         OperandSize size = getMemorySize(access);
         if (size.isXmmType()) {
@@ -545,6 +558,7 @@
 
     @MatchRule("(Xor value Read=access)")
     @MatchRule("(Xor value FloatingRead=access)")
+    @MatchRule("(Xor value VolatileRead=access)")
     public ComplexMatchResult xorMemory(ValueNode value, LIRLowerableAccess access) {
         OperandSize size = getMemorySize(access);
         if (size.isXmmType()) {
@@ -565,12 +579,14 @@
 
     @MatchRule("(SignExtend Read=access)")
     @MatchRule("(SignExtend FloatingRead=access)")
+    @MatchRule("(SignExtend VolatileRead=access)")
     public ComplexMatchResult signExtend(SignExtendNode root, LIRLowerableAccess access) {
         return emitSignExtendMemory(access, root.getInputBits(), root.getResultBits(), null);
     }
 
     @MatchRule("(ZeroExtend Read=access)")
     @MatchRule("(ZeroExtend FloatingRead=access)")
+    @MatchRule("(ZeroExtend VolatileRead=access)")
     public ComplexMatchResult zeroExtend(ZeroExtendNode root, LIRLowerableAccess access) {
         AMD64Kind memoryKind = getMemoryKind(access);
         return builder -> getArithmeticLIRGenerator().emitZeroExtendMemory(memoryKind, root.getResultBits(), (AMD64AddressValue) operand(access.getAddress()), getState(access));
@@ -578,6 +594,7 @@
 
     @MatchRule("(Narrow Read=access)")
     @MatchRule("(Narrow FloatingRead=access)")
+    @MatchRule("(Narrow VolatileRead=access)")
     public ComplexMatchResult narrowRead(NarrowNode root, LIRLowerableAccess access) {
         return new ComplexMatchResult() {
             @Override
@@ -595,6 +612,7 @@
 
     @MatchRule("(SignExtend (Narrow=narrow Read=access))")
     @MatchRule("(SignExtend (Narrow=narrow FloatingRead=access))")
+    @MatchRule("(SignExtend (Narrow=narrow VolatileRead=access))")
     public ComplexMatchResult signExtendNarrowRead(SignExtendNode root, NarrowNode narrow, LIRLowerableAccess access) {
         LIRKind kind = getLIRGeneratorTool().getLIRKind(narrow.stamp(NodeView.DEFAULT));
         return emitSignExtendMemory(access, narrow.getResultBits(), root.getResultBits(), kind);
@@ -602,6 +620,7 @@
 
     @MatchRule("(FloatConvert Read=access)")
     @MatchRule("(FloatConvert FloatingRead=access)")
+    @MatchRule("(FloatConvert VolatileRead=access)")
     public ComplexMatchResult floatConvert(FloatConvertNode root, LIRLowerableAccess access) {
         switch (root.getFloatConvert()) {
             case D2F:
@@ -631,6 +650,7 @@
 
     @MatchRule("(Reinterpret Read=access)")
     @MatchRule("(Reinterpret FloatingRead=access)")
+    @MatchRule("(Reinterpret VolatileRead=access)")
     public ComplexMatchResult reinterpret(ReinterpretNode root, LIRLowerableAccess access) {
         return builder -> {
             LIRKind kind = getLIRGeneratorTool().getLIRKind(root.stamp(NodeView.DEFAULT));
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/GraalOptions.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/GraalOptions.java	Thu Oct 31 16:54:16 2019 -0700
@@ -115,7 +115,7 @@
     public static final OptionKey<Boolean> PartialUnroll = new OptionKey<>(true);
 
     @Option(help = "", type = OptionType.Expert)
-    public static final OptionKey<Float> MinimumPeelProbability = new OptionKey<>(0.35f);
+    public static final OptionKey<Float> MinimumPeelFrequency = new OptionKey<>(0.35f);
 
     @Option(help = "", type = OptionType.Expert)
     public static final OptionKey<Integer> LoopMaxUnswitch = new OptionKey<>(3);
@@ -242,9 +242,6 @@
     public static final OptionKey<Boolean> OptImplicitNullChecks = new OptionKey<>(true);
 
     @Option(help = "", type = OptionType.Debug)
-    public static final OptionKey<Boolean> OptLoopTransform = new OptionKey<>(true);
-
-    @Option(help = "", type = OptionType.Debug)
     public static final OptionKey<Boolean> OptFloatingReads = new OptionKey<>(true);
 
     @Option(help = "", type = OptionType.Debug)
@@ -291,4 +288,7 @@
 
     @Option(help = "Alignment in bytes for loop header blocks.", type = OptionType.Expert)
     public static final OptionKey<Integer> LoopHeaderAlignment = new OptionKey<>(16);
+
+    @Option(help = "Do not include membars for volatile accesses until the end of optimizations.", type = OptionType.Expert)
+    public static final OptionKey<Boolean> LateMembars = new OptionKey<>(true);
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/cfg/AbstractBlockBase.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/cfg/AbstractBlockBase.java	Thu Oct 31 16:54:16 2019 -0700
@@ -94,6 +94,38 @@
         return dominator;
     }
 
+    /**
+     * Returns the next dominator of this block that is either in the same loop of this block or in
+     * an outer loop.
+     *
+     * @return the next dominator while skipping over loops
+     */
+    public T getDominatorSkipLoops() {
+        T d = getDominator();
+
+        if (d == null) {
+            // We are at the start block and don't have a dominator.
+            return null;
+        }
+
+        if (isLoopHeader()) {
+            // We are moving out of current loop => just return dominator.
+            assert d.getLoopDepth() == getLoopDepth() - 1;
+            assert d.getLoop() != getLoop();
+            return d;
+        }
+
+        while (d.getLoop() != getLoop()) {
+            // We have a case where our dominator is in a different loop. Move further along
+            // the domiantor tree until we hit our loop again.
+            d = d.getDominator();
+        }
+
+        assert d.getLoopDepth() <= getLoopDepth();
+
+        return d;
+    }
+
     public void setDominator(T dominator) {
         this.dominator = dominator;
         this.domDepth = dominator.domDepth + 1;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/cfg/AbstractControlFlowGraph.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/cfg/AbstractControlFlowGraph.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2019, 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
@@ -46,7 +46,7 @@
     T getStartBlock();
 
     /**
-     * True if block {@code a} is dominated by block {@code b}.
+     * True if block {@code a} is dominated by block {@code b} or {@code a} is equal to {@code b}.
      */
     static boolean isDominatedBy(AbstractBlockBase<?> a, AbstractBlockBase<?> b) {
         int domNumberA = a.getDominatorNumber();
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/cfg/Loop.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/cfg/Loop.java	Thu Oct 31 16:54:16 2019 -0700
@@ -177,25 +177,6 @@
         return true;
     }
 
-    /**
-     * Determines if one loop is a transitive parent of another loop.
-     *
-     * @param childLoop The loop for which parentLoop might be a transitive parent loop.
-     * @param parentLoop The loop which might be a transitive parent loop of child loop.
-     * @return {@code true} if parentLoop is a (transitive) parent loop of childLoop, {@code false}
-     *         otherwise
-     */
-    public static <T extends AbstractBlockBase<T>> boolean transitiveParentLoop(Loop<T> childLoop, Loop<T> parentLoop) {
-        Loop<T> curr = childLoop;
-        while (curr != null) {
-            if (curr == parentLoop) {
-                return true;
-            }
-            curr = curr.getParent();
-        }
-        return false;
-    }
-
     @Override
     public int hashCode() {
         return index + depth * 31;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IntegerStamp.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IntegerStamp.java	Thu Oct 31 16:54:16 2019 -0700
@@ -167,8 +167,15 @@
     @Override
     public Stamp constant(Constant c, MetaAccessProvider meta) {
         if (c instanceof PrimitiveConstant) {
-            long value = ((PrimitiveConstant) c).asLong();
-            return StampFactory.forInteger(getBits(), value, value);
+            PrimitiveConstant primitiveConstant = (PrimitiveConstant) c;
+            long value = primitiveConstant.asLong();
+            if (primitiveConstant.getJavaKind() == JavaKind.Boolean && value == 1) {
+                // Need to special case booleans as integer stamps are always signed values.
+                value = -1;
+            }
+            Stamp returnedStamp = StampFactory.forInteger(getBits(), value, value);
+            assert returnedStamp.hasValues();
+            return returnedStamp;
         }
         return this;
     }
@@ -1605,7 +1612,10 @@
                             long newUpMask = stamp.upMask() & defaultMask;
                             long newLowerBound = CodeUtil.signExtend((lowerBound | newDownMask) & newUpMask, resultBits);
                             long newUpperBound = CodeUtil.signExtend((upperBound | newDownMask) & newUpMask, resultBits);
-                            return new IntegerStamp(resultBits, newLowerBound, newUpperBound, newDownMask, newUpMask);
+
+                            IntegerStamp result = new IntegerStamp(resultBits, newLowerBound, newUpperBound, newDownMask, newUpMask);
+                            assert result.hasValues();
+                            return result;
                         }
                     },
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCNodeMatchRules.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCNodeMatchRules.java	Thu Oct 31 16:54:16 2019 -0700
@@ -134,12 +134,14 @@
 
     @MatchRule("(SignExtend Read=access)")
     @MatchRule("(SignExtend FloatingRead=access)")
+    @MatchRule("(SignExtend VolatileRead=access)")
     public ComplexMatchResult signExtend(SignExtendNode root, Access access) {
         return emitSignExtendMemory(access, root.getInputBits(), root.getResultBits());
     }
 
     @MatchRule("(ZeroExtend Read=access)")
     @MatchRule("(ZeroExtend FloatingRead=access)")
+    @MatchRule("(ZeroExtend VolatileRead=access)")
     public ComplexMatchResult zeroExtend(ZeroExtendNode root, Access access) {
         return emitZeroExtendMemory(access, root.getInputBits(), root.getResultBits());
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/BoxingEliminationTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/BoxingEliminationTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2019, 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
@@ -313,7 +313,7 @@
         graph = parseEager(snippet, AllowAssumptions.NO);
         HighTierContext context = getDefaultHighTierContext();
         createInliningPhase().apply(graph, context);
-        new PartialEscapePhase(false, new CanonicalizerPhase(), graph.getOptions()).apply(graph, context);
+        new PartialEscapePhase(false, createCanonicalizerPhase(), graph.getOptions()).apply(graph, context);
     }
 
     private void compareGraphs(final String snippet, final String referenceSnippet) {
@@ -323,7 +323,7 @@
     private void compareGraphs(final String snippet, final String referenceSnippet, final boolean loopPeeling, final boolean excludeVirtual) {
         graph = parseEager(snippet, AllowAssumptions.NO);
         HighTierContext context = getDefaultHighTierContext();
-        CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+        CanonicalizerPhase canonicalizer = this.createCanonicalizerPhase();
         canonicalizer.apply(graph, context);
         createInliningPhase().apply(graph, context);
         if (loopPeeling) {
@@ -339,7 +339,7 @@
         StructuredGraph referenceGraph = parseEager(referenceSnippet, AllowAssumptions.YES);
         createInliningPhase().apply(referenceGraph, context);
         new DeadCodeEliminationPhase().apply(referenceGraph);
-        new CanonicalizerPhase().apply(referenceGraph, context);
+        this.createCanonicalizerPhase().apply(referenceGraph, context);
 
         assertEquals(referenceGraph, graph, excludeVirtual, true);
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CheckGraalInvariants.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CheckGraalInvariants.java	Thu Oct 31 16:54:16 2019 -0700
@@ -78,7 +78,7 @@
 import org.graalvm.compiler.runtime.RuntimeProvider;
 import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
 import org.graalvm.compiler.test.AddExports;
-import org.graalvm.compiler.test.ModuleSupport;
+import org.graalvm.compiler.api.test.ModuleSupport;
 import jdk.internal.vm.compiler.word.LocationIdentity;
 import org.junit.Assert;
 import org.junit.Assume;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CompareCanonicalizerTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CompareCanonicalizerTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -31,14 +31,13 @@
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.calc.ConditionalNode;
 import org.graalvm.compiler.nodes.calc.IntegerTestNode;
-import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.junit.Test;
 
 public class CompareCanonicalizerTest extends GraalCompilerTest {
 
     private StructuredGraph getCanonicalizedGraph(String name) {
         StructuredGraph graph = parseEager(name, AllowAssumptions.YES);
-        new CanonicalizerPhase().apply(graph, getProviders());
+        createCanonicalizerPhase().apply(graph, getProviders());
         return graph;
     }
 
@@ -55,7 +54,7 @@
             StructuredGraph graph = parseEager("canonicalCompare" + i, AllowAssumptions.NO);
             assertEquals(referenceGraph, graph);
         }
-        new CanonicalizerPhase().apply(referenceGraph, getProviders());
+        createCanonicalizerPhase().apply(referenceGraph, getProviders());
         for (int i = 1; i < 4; i++) {
             StructuredGraph graph = getCanonicalizedGraph("canonicalCompare" + i);
             assertEquals(referenceGraph, graph);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CompareCanonicalizerTest2.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CompareCanonicalizerTest2.java	Thu Oct 31 16:54:16 2019 -0700
@@ -26,7 +26,6 @@
 
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
-import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.junit.Test;
 
 public class CompareCanonicalizerTest2 extends GraalCompilerTest {
@@ -35,7 +34,7 @@
 
     private StructuredGraph getCanonicalizedGraph(String name) {
         StructuredGraph graph = getRegularGraph(name);
-        new CanonicalizerPhase().apply(graph, getProviders());
+        createCanonicalizerPhase().apply(graph, getProviders());
         return graph;
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CompareCanonicalizerTest3.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CompareCanonicalizerTest3.java	Thu Oct 31 16:54:16 2019 -0700
@@ -239,7 +239,7 @@
     protected void assertCanonicallyEqual(String snippet, String reference) {
         StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
         CoreProviders context = getProviders();
-        CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+        CanonicalizerPhase canonicalizer = this.createCanonicalizerPhase();
 
         canonicalizer.apply(graph, context);
         new GuardLoweringPhase().apply(graph, new MidTierContext(getProviders(), getTargetProvider(), OptimisticOptimizations.ALL, graph.getProfilingInfo()));
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationMulTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationMulTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2019, 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
@@ -78,7 +78,7 @@
         StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO);
         HighTierContext context = getDefaultHighTierContext();
         new ConditionalEliminationPhase(false).apply(graph, context);
-        CanonicalizerPhase c = new CanonicalizerPhase();
+        CanonicalizerPhase c = createCanonicalizerPhase();
         c.apply(graph, context);
         new ConditionalEliminationPhase(false).apply(graph, context);
         c.apply(graph, context);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest10.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest10.java	Thu Oct 31 16:54:16 2019 -0700
@@ -30,7 +30,6 @@
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
 import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.nodes.spi.LoweringTool;
-import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.common.ConditionalEliminationPhase;
 import org.graalvm.compiler.phases.common.LoweringPhase;
 import org.junit.Assert;
@@ -95,7 +94,7 @@
     private void test(String snippet, int guardCount) {
         StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
         CoreProviders context = getProviders();
-        new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
+        new LoweringPhase(createCanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
         new ConditionalEliminationPhase(true).apply(graph, context);
         Assert.assertEquals(guardCount, graph.getNodes().filter(GuardNode.class).count());
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest14.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest14.java	Thu Oct 31 16:54:16 2019 -0700
@@ -70,7 +70,7 @@
     @Test
     public void test1() {
         StructuredGraph graph = parseEager("test1Snippet", AllowAssumptions.YES);
-        CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+        CanonicalizerPhase canonicalizer = createCanonicalizerPhase();
         CoreProviders context = getProviders();
 
         /* Convert the LoadIndexNode to ReadNode with floating guards. */
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest15.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest15.java	Thu Oct 31 16:54:16 2019 -0700
@@ -47,10 +47,10 @@
     private void checkNodeCount(String methodName, Class<? extends Node> nodeClass, int count) {
         StructuredGraph graph = parseEager(methodName, AllowAssumptions.YES);
 
-        CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+        CanonicalizerPhase canonicalizer = this.createCanonicalizerPhase();
         CoreProviders context = getProviders();
 
-        new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
+        new LoweringPhase(this.createCanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
         canonicalizer.apply(graph, context);
 
         // Merge arr.length reads.
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest16.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest16.java	Thu Oct 31 16:54:16 2019 -0700
@@ -31,7 +31,6 @@
 import org.graalvm.compiler.nodes.ParameterNode;
 import org.graalvm.compiler.nodes.PiNode;
 import org.graalvm.compiler.nodes.StructuredGraph;
-import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -69,7 +68,7 @@
                     break;
                 }
             }
-            new CanonicalizerPhase().apply(graph, getDefaultHighTierContext());
+            this.createCanonicalizerPhase().apply(graph, getDefaultHighTierContext());
         }
         super.checkHighTierGraph(graph);
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest2.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest2.java	Thu Oct 31 16:54:16 2019 -0700
@@ -109,7 +109,7 @@
     @Test
     public void testRedundantCompares() {
         StructuredGraph graph = parseEager("testRedundantComparesSnippet", AllowAssumptions.YES);
-        CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+        CanonicalizerPhase canonicalizer = createCanonicalizerPhase();
         CoreProviders context = getProviders();
 
         new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
@@ -132,7 +132,7 @@
     public void testInstanceOfCheckCastLowered() {
         StructuredGraph graph = parseEager("testInstanceOfCheckCastSnippet", AllowAssumptions.YES);
 
-        CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+        CanonicalizerPhase canonicalizer = createCanonicalizerPhase();
         CoreProviders context = getProviders();
 
         new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
@@ -146,7 +146,7 @@
     private void checkInstanceOfCount(String methodName, int count) {
         StructuredGraph graph = parseEager(methodName, AllowAssumptions.YES);
 
-        CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+        CanonicalizerPhase canonicalizer = this.createCanonicalizerPhase();
         CoreProviders context = getProviders();
 
         canonicalizer.apply(graph, context);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTestBase.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTestBase.java	Thu Oct 31 16:54:16 2019 -0700
@@ -69,8 +69,8 @@
         DebugContext debug = graph.getDebug();
         debug.dump(DebugContext.BASIC_LEVEL, graph, "Graph");
         CoreProviders context = getProviders();
-        CanonicalizerPhase canonicalizer1 = new CanonicalizerPhase();
-        CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+        CanonicalizerPhase canonicalizer1 = createCanonicalizerPhase();
+        CanonicalizerPhase canonicalizer = createCanonicalizerPhase();
         try (DebugContext.Scope scope = debug.scope("ConditionalEliminationTest", graph)) {
             prepareGraph(graph, canonicalizer1, context, applyLowering);
             new IterativeConditionalEliminationPhase(canonicalizer, true).apply(graph, context);
@@ -106,10 +106,9 @@
     public void testProxies(String snippet, int expectedProxiesCreated) {
         StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
         CoreProviders context = getProviders();
-        CanonicalizerPhase canonicalizer1 = new CanonicalizerPhase();
-        canonicalizer1.disableSimplification();
+        CanonicalizerPhase canonicalizer1 = CanonicalizerPhase.createWithoutCFGSimplification();
         canonicalizer1.apply(graph, context);
-        CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+        CanonicalizerPhase canonicalizer = createCanonicalizerPhase();
         new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
         canonicalizer.apply(graph, context);
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CountedLoopTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CountedLoopTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -43,6 +43,7 @@
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration;
 import org.graalvm.compiler.nodes.spi.LIRLowerable;
 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.nodes.util.GraphUtil;
 import org.graalvm.compiler.phases.OptimisticOptimizations;
 import org.graalvm.compiler.phases.tiers.HighTierContext;
 import org.junit.Test;
@@ -559,7 +560,7 @@
         }
 
         public void rewrite(LoopsData loops) {
-            InductionVariable inductionVariable = loops.getInductionVariable(iv);
+            InductionVariable inductionVariable = loops.getInductionVariable(GraphUtil.unproxify(iv));
             ValueNode node = null;
             if (inductionVariable == null) {
                 assert loopCanBeRemoved;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/DeMorganCanonicalizationTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/DeMorganCanonicalizationTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2019, 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
@@ -29,7 +29,6 @@
 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;
 
@@ -46,7 +45,7 @@
     @Test
     public void testAnd() {
         StructuredGraph g = parseEager("and", AllowAssumptions.NO, getInitialOptions());
-        new CanonicalizerPhase().apply(g, getDefaultHighTierContext());
+        createCanonicalizerPhase().apply(g, getDefaultHighTierContext());
         Assert.assertEquals(1, g.getNodes().filter(OrNode.class).count());
         Assert.assertEquals(1, g.getNodes().filter(NotNode.class).count());
 
@@ -59,7 +58,7 @@
     @Test
     public void testOr() {
         StructuredGraph g = parseEager("or", AllowAssumptions.NO, getInitialOptions());
-        new CanonicalizerPhase().apply(g, getDefaultHighTierContext());
+        createCanonicalizerPhase().apply(g, getDefaultHighTierContext());
         Assert.assertEquals(1, g.getNodes().filter(AndNode.class).count());
         Assert.assertEquals(1, g.getNodes().filter(NotNode.class).count());
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/DegeneratedLoopsTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/DegeneratedLoopsTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2019, 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
@@ -28,7 +28,6 @@
 import org.graalvm.compiler.debug.DebugDumpScope;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
-import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.tiers.HighTierContext;
 import org.junit.Test;
 
@@ -85,7 +84,7 @@
             StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
             HighTierContext context = getDefaultHighTierContext();
             createInliningPhase().apply(graph, context);
-            new CanonicalizerPhase().apply(graph, context);
+            createCanonicalizerPhase().apply(graph, context);
             debug.dump(DebugContext.BASIC_LEVEL, graph, "Graph");
             StructuredGraph referenceGraph = parseEager(REFERENCE_SNIPPET, AllowAssumptions.YES);
             debug.dump(DebugContext.BASIC_LEVEL, referenceGraph, "ReferenceGraph");
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/EnumSwitchTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/EnumSwitchTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -29,7 +29,6 @@
 import org.graalvm.compiler.nodes.java.LoadIndexedNode;
 import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.phases.Phase;
-import org.graalvm.compiler.phases.common.RemoveValueProxyPhase;
 import org.graalvm.compiler.phases.tiers.Suites;
 import org.junit.Assume;
 import org.junit.Test;
@@ -157,7 +156,7 @@
                 return "CheckGraphPhase";
             }
         });
-        ret.getHighTier().findPhase(RemoveValueProxyPhase.class).add(new Phase() {
+        ret.getHighTier().addBeforeLast(new Phase() {
             @Override
             protected void run(StructuredGraph graph) {
                 /* Re-writing of the switch cases eliminates the array load. */
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/FinalizableSubclassTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/FinalizableSubclassTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -38,7 +38,6 @@
 import org.graalvm.compiler.nodes.java.RegisterFinalizerNode;
 import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.phases.OptimisticOptimizations;
-import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.tiers.HighTierContext;
 import org.junit.Assert;
 import org.junit.Test;
@@ -80,7 +79,7 @@
         new GraphBuilderPhase.Instance(getProviders(), conf, OptimisticOptimizations.ALL, null).apply(graph);
         HighTierContext context = new HighTierContext(getProviders(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
         createInliningPhase().apply(graph, context);
-        new CanonicalizerPhase().apply(graph, context);
+        createCanonicalizerPhase().apply(graph, context);
         return graph;
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/FloatingReadTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/FloatingReadTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -34,7 +34,6 @@
 import org.graalvm.compiler.nodes.memory.FloatingReadNode;
 import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.nodes.spi.LoweringTool;
-import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.common.FloatingReadPhase;
 import org.graalvm.compiler.phases.common.LoweringPhase;
 import org.junit.Assert;
@@ -68,7 +67,7 @@
 
             StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
             CoreProviders context = getProviders();
-            new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
+            new LoweringPhase(createCanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
             new FloatingReadPhase().apply(graph);
 
             ReturnNode returnNode = null;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2019, 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
@@ -126,7 +126,7 @@
 import org.graalvm.compiler.runtime.RuntimeProvider;
 import org.graalvm.compiler.test.AddExports;
 import org.graalvm.compiler.test.GraalTest;
-import org.graalvm.compiler.test.ModuleSupport;
+import org.graalvm.compiler.api.test.ModuleSupport;
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.BeforeClass;
@@ -643,7 +643,7 @@
     }
 
     protected final BasePhase<HighTierContext> createInliningPhase() {
-        return createInliningPhase(new CanonicalizerPhase());
+        return createInliningPhase(this.createCanonicalizerPhase());
     }
 
     protected BasePhase<HighTierContext> createInliningPhase(CanonicalizerPhase canonicalizer) {
@@ -1119,6 +1119,12 @@
         return graph;
     }
 
+    protected StructuredGraph getFinalGraph(ResolvedJavaMethod method, OptionValues options) {
+        StructuredGraph graph = parseForCompile(method, options);
+        applyFrontEnd(graph);
+        return graph;
+    }
+
     @SuppressWarnings("try")
     protected void applyFrontEnd(StructuredGraph graph) {
         DebugContext debug = graph.getDebug();
@@ -1515,4 +1521,8 @@
     protected boolean isArchitecture(String name) {
         return name.equals(backend.getTarget().arch.getName());
     }
+
+    protected CanonicalizerPhase createCanonicalizerPhase() {
+        return CanonicalizerPhase.create();
+    }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraphEncoderTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraphEncoderTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -35,7 +35,6 @@
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
 import org.graalvm.compiler.nodes.spi.CoreProviders;
-import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.junit.Test;
 
 import jdk.vm.ci.meta.ResolvedJavaMethod;
@@ -61,7 +60,7 @@
                 StructuredGraph originalGraph = parseEager(javaMethod, AllowAssumptions.YES);
                 if (canonicalize) {
                     CoreProviders context = getProviders();
-                    new CanonicalizerPhase().apply(originalGraph, context);
+                    createCanonicalizerPhase().apply(originalGraph, context);
                 }
                 originalGraphs.add(originalGraph);
             }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GuardPrioritiesTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GuardPrioritiesTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -86,7 +86,7 @@
     private StructuredGraph prepareGraph(String method) {
         StructuredGraph graph = parseEager(method, StructuredGraph.AllowAssumptions.YES);
         HighTierContext highTierContext = getDefaultHighTierContext();
-        CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+        CanonicalizerPhase canonicalizer = createCanonicalizerPhase();
         new ConvertDeoptimizeToGuardPhase().apply(graph, highTierContext);
         new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, highTierContext);
         new FloatingReadPhase().apply(graph);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/IfCanonicalizerTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/IfCanonicalizerTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -35,7 +35,6 @@
 import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.nodes.spi.LoweringTool;
 import org.graalvm.compiler.phases.OptimisticOptimizations;
-import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.common.FloatingReadPhase;
 import org.graalvm.compiler.phases.common.GuardLoweringPhase;
 import org.graalvm.compiler.phases.common.LoweringPhase;
@@ -227,12 +226,12 @@
     private void testCombinedIf(String snippet, int count) {
         StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
         CoreProviders context = getProviders();
-        new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
+        new LoweringPhase(createCanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
         new FloatingReadPhase().apply(graph);
         MidTierContext midContext = new MidTierContext(getProviders(), getTargetProvider(), OptimisticOptimizations.ALL, graph.getProfilingInfo());
         new GuardLoweringPhase().apply(graph, midContext);
-        new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.MID_TIER).apply(graph, midContext);
-        new CanonicalizerPhase().apply(graph, context);
+        new LoweringPhase(createCanonicalizerPhase(), LoweringTool.StandardLoweringStage.MID_TIER).apply(graph, midContext);
+        createCanonicalizerPhase().apply(graph, context);
         assertDeepEquals(count, graph.getNodes().filter(IfNode.class).count());
     }
 
@@ -247,7 +246,7 @@
             }
         }
         debug.dump(DebugContext.BASIC_LEVEL, graph, "Graph");
-        new CanonicalizerPhase().apply(graph, getProviders());
+        createCanonicalizerPhase().apply(graph, getProviders());
         for (FrameState fs : param.usages().filter(FrameState.class).snapshot()) {
             fs.replaceFirstInput(param, null);
             param.safeDelete();
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ImplicitNullCheckTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ImplicitNullCheckTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -34,7 +34,6 @@
 import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.nodes.spi.LoweringTool;
 import org.graalvm.compiler.phases.OptimisticOptimizations;
-import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.common.FloatingReadPhase;
 import org.graalvm.compiler.phases.common.GuardLoweringPhase;
 import org.graalvm.compiler.phases.common.LoweringPhase;
@@ -72,7 +71,7 @@
         try (DebugContext.Scope s = debug.scope("FloatingReadTest", new DebugDumpScope(snippet))) {
             StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES, debug);
             CoreProviders context = getProviders();
-            new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
+            new LoweringPhase(createCanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
             new FloatingReadPhase().apply(graph);
             MidTierContext midTierContext = new MidTierContext(getProviders(), getTargetProvider(), OptimisticOptimizations.ALL, graph.getProfilingInfo());
             new GuardLoweringPhase().apply(graph, midTierContext);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/IntegerEqualsCanonicalizerTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/IntegerEqualsCanonicalizerTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -27,7 +27,6 @@
 import org.graalvm.compiler.nodes.FrameState;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
-import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.junit.Test;
 
 public class IntegerEqualsCanonicalizerTest extends GraalCompilerTest {
@@ -166,7 +165,7 @@
 
     private StructuredGraph getCanonicalizedGraph(String snippet) {
         StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
-        new CanonicalizerPhase().apply(graph, getProviders());
+        createCanonicalizerPhase().apply(graph, getProviders());
         for (FrameState state : graph.getNodes(FrameState.TYPE).snapshot()) {
             state.replaceAtUsages(null);
             state.safeDelete();
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/InterfaceMethodHandleTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/InterfaceMethodHandleTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, 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
@@ -30,7 +30,7 @@
 
 import org.graalvm.compiler.code.CompilationResult;
 import org.graalvm.compiler.debug.DebugContext;
-import org.graalvm.compiler.test.ExportingClassLoader;
+import org.graalvm.compiler.api.test.ExportingClassLoader;
 import org.junit.Test;
 import org.objectweb.asm.ClassWriter;
 import org.objectweb.asm.Label;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/InvokeExceptionTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/InvokeExceptionTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2019, 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
@@ -30,7 +30,6 @@
 import org.graalvm.compiler.nodes.Invoke;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
-import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
 import org.graalvm.compiler.phases.tiers.HighTierContext;
 import org.junit.Test;
@@ -69,8 +68,8 @@
             hints.put(invoke, 1000d);
         }
         HighTierContext context = getDefaultHighTierContext();
-        createInliningPhase(hints, new CanonicalizerPhase()).apply(graph, context);
-        new CanonicalizerPhase().apply(graph, context);
+        createInliningPhase(hints, createCanonicalizerPhase()).apply(graph, context);
+        createCanonicalizerPhase().apply(graph, context);
         new DeadCodeEliminationPhase().apply(graph);
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/InvokeHintsTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/InvokeHintsTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2019, 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
@@ -30,7 +30,6 @@
 import org.graalvm.compiler.nodes.Invoke;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
-import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
 import org.graalvm.compiler.phases.tiers.HighTierContext;
 import org.junit.Test;
@@ -80,8 +79,8 @@
         }
 
         HighTierContext context = getDefaultHighTierContext();
-        createInliningPhase(hints, new CanonicalizerPhase()).apply(graph, context);
-        new CanonicalizerPhase().apply(graph, context);
+        createInliningPhase(hints, createCanonicalizerPhase()).apply(graph, context);
+        createCanonicalizerPhase().apply(graph, context);
         new DeadCodeEliminationPhase().apply(graph);
         StructuredGraph referenceGraph = parseEager(REFERENCE_SNIPPET, AllowAssumptions.NO);
         assertEquals(referenceGraph, graph);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/LateMembarInsertionTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -0,0 +1,233 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, Red Hat Inc. 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 jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaType;
+import jdk.internal.vm.compiler.collections.EconomicMap;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.NodeView;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.cfg.Block;
+import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
+import org.graalvm.compiler.nodes.memory.FixedAccessNode;
+import org.graalvm.compiler.nodes.memory.MemoryAccess;
+import org.graalvm.compiler.nodes.memory.ReadNode;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+import org.graalvm.compiler.options.OptionKey;
+import org.graalvm.compiler.options.OptionValues;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static org.graalvm.compiler.core.common.GraalOptions.StressTestEarlyReads;
+
+public class LateMembarInsertionTest extends GraalCompilerTest {
+
+    private final ResolvedJavaType volatileAccessType = getMetaAccess().lookupJavaType(VolatileAccess.class);
+    private final ResolvedJavaType regularAccessField = getMetaAccess().lookupJavaType(RegularAccess.class);
+    private final ResolvedJavaType volatileAccess2Type = getMetaAccess().lookupJavaType(VolatileAccess2.class);
+
+    static class VolatileAccess {
+        static volatile int field;
+    }
+
+    static class VolatileAccess2 {
+        static volatile int field;
+    }
+
+    static class RegularAccess {
+        static int field;
+    }
+
+    public static int volatileFieldLoadFieldLoad() {
+        int v1 = VolatileAccess.field;
+        int v2 = RegularAccess.field;
+        return v1 + v2;
+    }
+
+    @Test
+    public void test01() {
+        List<TypePair> accesses = compile("volatileFieldLoadFieldLoad", stressTestEarlyReads());
+
+        Assert.assertEquals(accesses.size(), 2);
+        Assert.assertEquals(accesses.get(0).getType(), volatileAccessType);
+        Assert.assertEquals(accesses.get(1).getType(), regularAccessField);
+        Assert.assertTrue(accesses.get(0).isRead());
+        Assert.assertTrue(accesses.get(1).isRead());
+    }
+
+    public static int volatileFieldLoadVolatileFieldLoad() {
+        int v1 = VolatileAccess.field;
+        int v2 = VolatileAccess2.field;
+        return v1 + v2;
+    }
+
+    @Test
+    public void test02() {
+        List<TypePair> accesses = compile("volatileFieldLoadVolatileFieldLoad", stressTestEarlyReads());
+
+        Assert.assertEquals(accesses.size(), 2);
+        Assert.assertEquals(accesses.get(0).getType(), volatileAccessType);
+        Assert.assertEquals(accesses.get(1).getType(), volatileAccess2Type);
+        Assert.assertTrue(accesses.get(0).isRead());
+        Assert.assertTrue(accesses.get(1).isRead());
+    }
+
+    public static int volatileFieldLoadVolatileFieldStore(int v2) {
+        int v1 = VolatileAccess.field;
+        VolatileAccess2.field = v2;
+        return v1;
+    }
+
+    @Test
+    public void test03() {
+        List<TypePair> accesses = compile("volatileFieldLoadVolatileFieldStore");
+
+        Assert.assertEquals(accesses.size(), 2);
+        Assert.assertEquals(accesses.get(0).getType(), volatileAccessType);
+        Assert.assertEquals(accesses.get(1).getType(), volatileAccess2Type);
+        Assert.assertTrue(accesses.get(0).isRead());
+        Assert.assertTrue(accesses.get(1).isWrite());
+    }
+
+    public static int volatileFieldStoreVolatileFieldLoad(int v2) {
+        VolatileAccess.field = v2;
+        return VolatileAccess2.field;
+    }
+
+    @Test
+    public void test04() {
+        List<TypePair> accesses = compile("volatileFieldStoreVolatileFieldLoad", stressTestEarlyReads());
+
+        Assert.assertEquals(accesses.size(), 2);
+        Assert.assertEquals(accesses.get(0).getType(), volatileAccessType);
+        Assert.assertEquals(accesses.get(1).getType(), volatileAccess2Type);
+        Assert.assertTrue(accesses.get(0).isWrite());
+        Assert.assertTrue(accesses.get(1).isRead());
+    }
+
+    public static int fieldLoadVolatileFieldStore(int v2) {
+        int v1 = RegularAccess.field;
+        VolatileAccess2.field = v2;
+        return v1;
+    }
+
+    @Test
+    public void test05() {
+        List<TypePair> accesses = compile("fieldLoadVolatileFieldStore");
+
+        Assert.assertEquals(accesses.size(), 2);
+        Assert.assertEquals(accesses.get(0).getType(), regularAccessField);
+        Assert.assertEquals(accesses.get(1).getType(), volatileAccess2Type);
+        Assert.assertTrue(accesses.get(0).isRead());
+        Assert.assertTrue(accesses.get(1).isWrite());
+    }
+
+    public static void volatileFieldStoreVolatileFieldStore(int v1, int v2) {
+        VolatileAccess.field = v1;
+        VolatileAccess2.field = v2;
+    }
+
+    @Test
+    public void test06() {
+        List<TypePair> accesses = compile("volatileFieldStoreVolatileFieldStore");
+
+        Assert.assertEquals(accesses.size(), 2);
+        Assert.assertEquals(accesses.get(0).getType(), volatileAccessType);
+        Assert.assertEquals(accesses.get(1).getType(), volatileAccess2Type);
+        Assert.assertTrue(accesses.get(0).isWrite());
+        Assert.assertTrue(accesses.get(1).isWrite());
+    }
+
+    private static OptionValues stressTestEarlyReads() {
+        EconomicMap<OptionKey<?>, Object> overrides = OptionValues.newOptionMap();
+        overrides.put(StressTestEarlyReads, true);
+        return new OptionValues(getInitialOptions(), overrides);
+    }
+
+    static class TypePair {
+        private boolean isRead;
+        private ResolvedJavaType type;
+
+        TypePair(boolean isRead, ResolvedJavaType type) {
+            this.isRead = isRead;
+            this.type = type;
+        }
+
+        public boolean isRead() {
+            return isRead;
+        }
+
+        public boolean isWrite() {
+            return !isRead;
+        }
+
+        public ResolvedJavaType getType() {
+            return type;
+        }
+    }
+
+    private List<TypePair> compile(String test, OptionValues options) {
+        StructuredGraph graph = getFinalGraph(getResolvedJavaMethod(test), options);
+        return getAccesses(graph);
+    }
+
+    private List<TypePair> getAccesses(StructuredGraph graph) {
+        StructuredGraph.ScheduleResult schedule = graph.getLastSchedule();
+        ControlFlowGraph cfg = schedule.getCFG();
+        Block[] blocks = cfg.getBlocks();
+
+        return Arrays.stream(blocks).flatMap(b -> schedule.nodesFor(b).stream()).filter(n -> n instanceof MemoryAccess).map(
+                        n -> new TypePair(n instanceof ReadNode, classForAccess((FixedAccessNode) n))).collect(Collectors.toList());
+    }
+
+    private List<TypePair> compile(String test) {
+        StructuredGraph graph = getFinalGraph(getResolvedJavaMethod(test));
+        return getAccesses(graph);
+    }
+
+    private ResolvedJavaType classForAccess(FixedAccessNode n) {
+        AddressNode address = n.getAddress();
+        ValueNode base = address.getBase();
+        Stamp stamp = base.stamp(NodeView.DEFAULT);
+        MetaAccessProvider metaAccess = getMetaAccess();
+        ResolvedJavaType javaType = stamp.javaType(metaAccess);
+        if (javaType == metaAccess.lookupJavaType(Class.class) && base instanceof ConstantNode) {
+            ConstantReflectionProvider constantReflection = getConstantReflection();
+            javaType = constantReflection.asJavaType(base.asConstant());
+        }
+        return javaType;
+    }
+
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/LockEliminationTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/LockEliminationTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -69,7 +69,7 @@
         test("testSynchronizedSnippet", new A(), new A());
 
         StructuredGraph graph = getGraph("testSynchronizedSnippet", false);
-        new CanonicalizerPhase().apply(graph, getProviders());
+        createCanonicalizerPhase().apply(graph, getProviders());
         new LockEliminationPhase().apply(graph);
         assertDeepEquals(1, graph.getNodes().filter(RawMonitorEnterNode.class).count());
         assertDeepEquals(1, graph.getNodes().filter(MonitorExitNode.class).count());
@@ -87,7 +87,7 @@
         test("testSynchronizedMethodSnippet", new A());
 
         StructuredGraph graph = getGraph("testSynchronizedMethodSnippet", false);
-        new CanonicalizerPhase().apply(graph, getProviders());
+        createCanonicalizerPhase().apply(graph, getProviders());
         new LockEliminationPhase().apply(graph);
         assertDeepEquals(1, graph.getNodes().filter(RawMonitorEnterNode.class).count());
         assertDeepEquals(1, graph.getNodes().filter(MonitorExitNode.class).count());
@@ -104,7 +104,7 @@
     @Test
     public void testUnrolledSync() {
         StructuredGraph graph = getGraph("testUnrolledSyncSnippet", false);
-        CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+        CanonicalizerPhase canonicalizer = createCanonicalizerPhase();
         canonicalizer.apply(graph, getProviders());
         HighTierContext context = getDefaultHighTierContext();
         new LoopFullUnrollPhase(canonicalizer, new DefaultLoopPolicies()).apply(graph, context);
@@ -117,15 +117,15 @@
         ResolvedJavaMethod method = getResolvedJavaMethod(snippet);
         StructuredGraph graph = parseEager(method, AllowAssumptions.YES);
         HighTierContext context = getDefaultHighTierContext();
-        CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+        CanonicalizerPhase canonicalizer = createCanonicalizerPhase();
         canonicalizer.apply(graph, context);
         createInliningPhase().apply(graph, context);
-        new CanonicalizerPhase().apply(graph, context);
+        createCanonicalizerPhase().apply(graph, context);
         new DeadCodeEliminationPhase().apply(graph);
         if (doEscapeAnalysis) {
             new PartialEscapePhase(true, canonicalizer, graph.getOptions()).apply(graph, context);
         }
-        new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
+        new LoweringPhase(createCanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
         return graph;
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/LongNodeChainTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/LongNodeChainTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, 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
@@ -37,7 +37,6 @@
 import org.graalvm.compiler.nodes.calc.AddNode;
 import org.graalvm.compiler.nodes.extended.OpaqueNode;
 import org.graalvm.compiler.options.OptionValues;
-import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.schedule.SchedulePhase;
 import org.graalvm.compiler.phases.schedule.SchedulePhase.SchedulingStrategy;
 import org.graalvm.compiler.phases.tiers.HighTierContext;
@@ -85,7 +84,7 @@
             new SchedulePhase(s).apply(graph);
         }
 
-        new CanonicalizerPhase().apply(graph, context);
+        this.createCanonicalizerPhase().apply(graph, context);
         JavaConstant asConstant = (JavaConstant) returnNode.result().asConstant();
         Assert.assertEquals(N + 1, asConstant.asInt());
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/LoopFullUnrollTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/LoopFullUnrollTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -32,7 +32,6 @@
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
 import org.graalvm.compiler.nodes.spi.CoreProviders;
-import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.junit.Test;
 
 public class LoopFullUnrollTest extends GraalCompilerTest {
@@ -89,7 +88,7 @@
             final StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO, debug);
 
             CoreProviders context = getProviders();
-            new LoopFullUnrollPhase(new CanonicalizerPhase(), new DefaultLoopPolicies()).apply(graph, context);
+            new LoopFullUnrollPhase(createCanonicalizerPhase(), new DefaultLoopPolicies()).apply(graph, context);
 
             assertTrue(graph.getNodes().filter(LoopBeginNode.class).count() == loopCount);
         } catch (Throwable e) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/LoopUnswitchTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/LoopUnswitchTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -30,7 +30,6 @@
 import org.graalvm.compiler.loop.phases.LoopUnswitchingPhase;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
-import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.junit.Test;
 
 public class LoopUnswitchTest extends GraalCompilerTest {
@@ -133,8 +132,8 @@
         graph.clearAllStateAfter();
         referenceGraph.clearAllStateAfter();
 
-        new CanonicalizerPhase().apply(graph, getProviders());
-        new CanonicalizerPhase().apply(referenceGraph, getProviders());
+        createCanonicalizerPhase().apply(graph, getProviders());
+        createCanonicalizerPhase().apply(referenceGraph, getProviders());
         try (DebugContext.Scope s = debug.scope("Test", new DebugDumpScope("Test:" + snippet))) {
             assertEquals(referenceGraph, graph);
         } catch (Throwable e) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MarkUnsafeAccessTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MarkUnsafeAccessTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, 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
@@ -37,7 +37,6 @@
 import java.nio.file.Path;
 
 import org.graalvm.compiler.nodes.StructuredGraph;
-import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.common.inlining.InliningPhase;
 import org.graalvm.compiler.phases.common.inlining.policy.InlineEverythingPolicy;
 import org.graalvm.compiler.phases.tiers.HighTierContext;
@@ -125,8 +124,8 @@
         Assert.assertNotNull(getMethodImpl);
         StructuredGraph graph = parseForCompile(getMethodImpl);
         HighTierContext highContext = getDefaultHighTierContext();
-        new CanonicalizerPhase().apply(graph, highContext);
-        new InliningPhase(new InlineEverythingPolicy(), new CanonicalizerPhase()).apply(graph, highContext);
+        createCanonicalizerPhase().apply(graph, highContext);
+        new InliningPhase(new InlineEverythingPolicy(), createCanonicalizerPhase()).apply(graph, highContext);
         InstalledCode compiledCode = getCode(getMethodImpl, graph);
         testMappedByteBuffer(mbb -> {
             try {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MemoryGraphCanonicalizeTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MemoryGraphCanonicalizeTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2019, 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
@@ -28,7 +28,6 @@
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.memory.WriteNode;
 import org.graalvm.compiler.nodes.spi.LoweringTool;
-import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.common.FloatingReadPhase;
 import org.graalvm.compiler.phases.common.IncrementalCanonicalizerPhase;
 import org.graalvm.compiler.phases.common.LoweringPhase;
@@ -76,10 +75,9 @@
     public void testGraph(String name, int expectedWrites) {
         StructuredGraph graph = parseEager(name, StructuredGraph.AllowAssumptions.YES);
         HighTierContext context = getDefaultHighTierContext();
-        CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
-        new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
-        new IncrementalCanonicalizerPhase<>(canonicalizer, new FloatingReadPhase()).apply(graph, context);
-        new CanonicalizerPhase().apply(graph, context);
+        new LoweringPhase(createCanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
+        new IncrementalCanonicalizerPhase<>(createCanonicalizerPhase(), new FloatingReadPhase()).apply(graph, context);
+        createCanonicalizerPhase().apply(graph, context);
         int writes = graph.getNodes().filter(WriteNode.class).count();
         assertTrue(writes == expectedWrites, "Expected %d writes, found %d", expectedWrites, writes);
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MemoryScheduleTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MemoryScheduleTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -38,7 +38,6 @@
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.graph.iterators.NodeIterable;
 import org.graalvm.compiler.nodes.ReturnNode;
-import org.graalvm.compiler.nodes.StartNode;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
 import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult;
@@ -177,7 +176,6 @@
     @Test
     public void testLoop1() {
         ScheduleResult schedule = getFinalSchedule("testLoop1Snippet", TestMode.WITHOUT_FRAMESTATES);
-        assertDeepEquals(6, schedule.getCFG().getBlocks().length);
         assertReadWithinStartBlock(schedule, true);
         assertReadWithinAllReturnBlocks(schedule, false);
     }
@@ -202,7 +200,6 @@
     @Test
     public void testLoop2() {
         ScheduleResult schedule = getFinalSchedule("testLoop2Snippet", TestMode.WITHOUT_FRAMESTATES);
-        assertDeepEquals(6, schedule.getCFG().getBlocks().length);
         assertReadWithinStartBlock(schedule, false);
         assertReadWithinAllReturnBlocks(schedule, true);
     }
@@ -224,7 +221,6 @@
     @Test
     public void testLoop3() {
         ScheduleResult schedule = getFinalSchedule("testLoop3Snippet", TestMode.WITHOUT_FRAMESTATES);
-        assertDeepEquals(6, schedule.getCFG().getBlocks().length);
         assertReadWithinStartBlock(schedule, true);
         assertReadWithinAllReturnBlocks(schedule, false);
     }
@@ -260,7 +256,6 @@
     @Test
     public void testLoop5() {
         ScheduleResult schedule = getFinalSchedule("testLoop5Snippet", TestMode.WITHOUT_FRAMESTATES);
-        assertDeepEquals(10, schedule.getCFG().getBlocks().length);
         assertReadWithinStartBlock(schedule, false);
         assertReadWithinAllReturnBlocks(schedule, false);
     }
@@ -289,7 +284,6 @@
     @Test
     public void testLoop6() {
         ScheduleResult schedule = getFinalSchedule("testLoop6Snippet", TestMode.WITHOUT_FRAMESTATES);
-        assertDeepEquals(13, schedule.getCFG().getBlocks().length);
         assertReadWithinStartBlock(schedule, false);
         assertReadWithinAllReturnBlocks(schedule, false);
     }
@@ -322,7 +316,6 @@
     @Test
     public void testLoop7() {
         ScheduleResult schedule = getFinalSchedule("testLoop7Snippet", TestMode.WITHOUT_FRAMESTATES);
-        assertDeepEquals(18, schedule.getCFG().getBlocks().length);
         assertReadWithinStartBlock(schedule, false);
         assertReadWithinAllReturnBlocks(schedule, false);
     }
@@ -349,7 +342,6 @@
     @Test
     public void testLoop8() {
         ScheduleResult schedule = getFinalSchedule("testLoop8Snippet", TestMode.WITHOUT_FRAMESTATES);
-        assertDeepEquals(10, schedule.getCFG().getBlocks().length);
         assertReadWithinStartBlock(schedule, true);
         assertReadWithinAllReturnBlocks(schedule, false);
     }
@@ -391,7 +383,6 @@
     @Test
     public void testIfRead1() {
         ScheduleResult schedule = getFinalSchedule("testIfRead1Snippet", TestMode.WITHOUT_FRAMESTATES);
-        assertDeepEquals(3, schedule.getCFG().getBlocks().length);
         assertReadWithinStartBlock(schedule, true);
         assertReadAndWriteInSameBlock(schedule, false);
     }
@@ -412,7 +403,6 @@
     @Test
     public void testIfRead2() {
         ScheduleResult schedule = getFinalSchedule("testIfRead2Snippet", TestMode.WITHOUT_FRAMESTATES);
-        assertDeepEquals(3, schedule.getCFG().getBlocks().length);
         assertDeepEquals(1, schedule.getCFG().graph.getNodes().filter(FloatingReadNode.class).count());
         assertReadWithinStartBlock(schedule, false);
         assertReadWithinAllReturnBlocks(schedule, false);
@@ -434,7 +424,6 @@
     @Test
     public void testIfRead3() {
         ScheduleResult schedule = getFinalSchedule("testIfRead3Snippet", TestMode.WITHOUT_FRAMESTATES);
-        assertDeepEquals(4, schedule.getCFG().getBlocks().length);
         assertReadWithinStartBlock(schedule, false);
         assertReadWithinAllReturnBlocks(schedule, true);
     }
@@ -455,7 +444,6 @@
     @Test
     public void testIfRead4() {
         ScheduleResult schedule = getFinalSchedule("testIfRead4Snippet", TestMode.WITHOUT_FRAMESTATES);
-        assertDeepEquals(3, schedule.getCFG().getBlocks().length);
         assertReadWithinStartBlock(schedule, false);
         assertReadWithinAllReturnBlocks(schedule, false);
         assertReadAndWriteInSameBlock(schedule, true);
@@ -474,7 +462,6 @@
     @Test
     public void testIfRead5() {
         ScheduleResult schedule = getFinalSchedule("testIfRead5Snippet", TestMode.WITHOUT_FRAMESTATES);
-        assertDeepEquals(4, schedule.getCFG().getBlocks().length);
         assertReadWithinStartBlock(schedule, false);
         assertReadWithinAllReturnBlocks(schedule, true);
         assertReadAndWriteInSameBlock(schedule, false);
@@ -500,7 +487,6 @@
     @Test
     public void testAntiDependency() {
         ScheduleResult schedule = getFinalSchedule("testAntiDependencySnippet", TestMode.WITHOUT_FRAMESTATES);
-        assertDeepEquals(4, schedule.getCFG().getBlocks().length);
         assertReadBeforeAllWritesInStartBlock(schedule);
     }
 
@@ -527,7 +513,6 @@
         StructuredGraph graph = schedule.getCFG().graph;
         NodeIterable<WriteNode> writeNodes = graph.getNodes().filter(WriteNode.class);
 
-        assertDeepEquals(1, schedule.getCFG().getBlocks().length);
         assertDeepEquals(8, writeNodes.count());
         assertDeepEquals(1, graph.getNodes().filter(FloatingReadNode.class).count());
 
@@ -708,7 +693,7 @@
         DebugContext debug = graph.getDebug();
         try (DebugContext.Scope d = debug.scope("FloatingReadTest", graph)) {
             HighTierContext context = getDefaultHighTierContext();
-            CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+            CanonicalizerPhase canonicalizer = createCanonicalizerPhase();
             canonicalizer.apply(graph, context);
             if (mode == TestMode.INLINED_WITHOUT_FRAMESTATES) {
                 createInliningPhase(canonicalizer).apply(graph, context);
@@ -729,7 +714,6 @@
 
             SchedulePhase schedule = new SchedulePhase(schedulingStrategy);
             schedule.apply(graph);
-            assertDeepEquals(1, graph.getNodes().filter(StartNode.class).count());
             return graph.getLastSchedule();
         } catch (Throwable e) {
             throw debug.handle(e);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MergeCanonicalizerTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MergeCanonicalizerTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -30,7 +30,6 @@
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
 import org.graalvm.compiler.phases.OptimisticOptimizations;
 import org.graalvm.compiler.phases.OptimisticOptimizations.Optimization;
-import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.tiers.HighTierContext;
 import org.junit.Test;
 
@@ -70,8 +69,8 @@
 
     private void testReturnCount(String snippet, int returnCount) {
         StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
-        new CanonicalizerPhase().apply(graph, getProviders());
-        new CanonicalizerPhase().apply(graph, getProviders());
+        createCanonicalizerPhase().apply(graph, getProviders());
+        createCanonicalizerPhase().apply(graph, getProviders());
         graph.getDebug().dump(DebugContext.BASIC_LEVEL, graph, "Graph");
         assertDeepEquals(returnCount, graph.getNodes(ReturnNode.TYPE).count());
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MonitorGraphTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MonitorGraphTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2019, 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
@@ -36,7 +36,6 @@
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
 import org.graalvm.compiler.nodes.java.MonitorExitNode;
-import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
 import org.graalvm.compiler.phases.tiers.HighTierContext;
 import org.junit.Assert;
@@ -103,8 +102,8 @@
             hints.put(invoke, 1000d);
         }
         HighTierContext context = getDefaultHighTierContext();
-        createInliningPhase(hints, new CanonicalizerPhase()).apply(graph, context);
-        new CanonicalizerPhase().apply(graph, context);
+        createInliningPhase(hints, createCanonicalizerPhase()).apply(graph, context);
+        createCanonicalizerPhase().apply(graph, context);
         new DeadCodeEliminationPhase().apply(graph);
         return graph;
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/NodePropertiesTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/NodePropertiesTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -36,7 +36,7 @@
 import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.phases.BasePhase;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
-import org.graalvm.compiler.phases.common.CanonicalizerPhase.CustomCanonicalizer;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase.CustomSimplification;
 import org.graalvm.compiler.phases.contract.NodeCostUtil;
 import org.graalvm.compiler.phases.tiers.HighTierContext;
 import org.junit.Assert;
@@ -162,19 +162,21 @@
     @Test
     public void testCanonicalizationExample() {
         HighTierContext htc = getDefaultHighTierContext();
-        ImprovementSavingCanonicalizer c1 = new ImprovementSavingCanonicalizer();
+        ImprovementSavingCalculator c1 = new ImprovementSavingCalculator();
         StructuredGraph g1 = parseForCompile(getResolvedJavaMethod("test1Snippet"));
-        new CanonicalizerPhase(c1).apply(g1, htc);
-        ImprovementSavingCanonicalizer c2 = new ImprovementSavingCanonicalizer();
+        CanonicalizerPhase canonicalizer1 = this.createCanonicalizerPhase().copyWithCustomSimplification(c1);
+        canonicalizer1.apply(g1, htc);
+        ImprovementSavingCalculator c2 = new ImprovementSavingCalculator();
         StructuredGraph g2 = parseForCompile(getResolvedJavaMethod("test2Snippet"));
-        new CanonicalizerPhase(c2).apply(g2, htc);
+        CanonicalizerPhase canonicalizer2 = this.createCanonicalizerPhase().copyWithCustomSimplification(c2);
+        canonicalizer2.apply(g2, htc);
         Assert.assertEquals(0, c1.savedCycles);
         Assert.assertEquals(0, c2.savedCycles);
     }
 
-    private static void prepareGraphForLoopFrequencies(StructuredGraph g, HighTierContext htc) {
+    private void prepareGraphForLoopFrequencies(StructuredGraph g, HighTierContext htc) {
         // let canonicalizer work away branch probability nodes
-        new CanonicalizerPhase().apply(g, htc);
+        createCanonicalizerPhase().apply(g, htc);
         // recompute the loop frequencies
         ComputeLoopFrequenciesClosure.compute(g);
     }
@@ -242,8 +244,8 @@
         StructuredGraph g1 = parseForCompile(getResolvedJavaMethod("test1Snippet"));
         StructuredGraph g2 = parseForCompile(getResolvedJavaMethod("test2Snippet"));
         HighTierContext htc = getDefaultHighTierContext();
-        new CanonicalizerPhase().apply(g1, htc);
-        new CanonicalizerPhase().apply(g2, htc);
+        createCanonicalizerPhase().apply(g1, htc);
+        createCanonicalizerPhase().apply(g2, htc);
         GraphCostPhase gc1 = new GraphCostPhase();
         GraphCostPhase gc2 = new GraphCostPhase();
         gc1.apply(g1, htc);
@@ -257,7 +259,7 @@
     public void testExpectUntrusted() {
         StructuredGraph g1 = parseForCompile(getResolvedJavaMethod("untrused01"));
         HighTierContext htc = getDefaultHighTierContext();
-        new CanonicalizerPhase().apply(g1, htc);
+        createCanonicalizerPhase().apply(g1, htc);
         GraphCostPhase gc1 = new GraphCostPhase();
         gc1.apply(g1, htc);
     }
@@ -266,7 +268,7 @@
     public void testArrayLoad() {
         StructuredGraph g1 = parseForCompile(getResolvedJavaMethod("arrayLoadTest"));
         HighTierContext htc = getDefaultHighTierContext();
-        new CanonicalizerPhase().apply(g1, htc);
+        createCanonicalizerPhase().apply(g1, htc);
         GraphCostPhase gc1 = new GraphCostPhase();
         gc1.apply(g1, htc);
         Assert.assertEquals(15, gc1.finalCycles, 25);
@@ -276,7 +278,7 @@
     public void testArrayStore() {
         StructuredGraph g1 = parseForCompile(getResolvedJavaMethod("arrayStoreTest"));
         HighTierContext htc = getDefaultHighTierContext();
-        new CanonicalizerPhase().apply(g1, htc);
+        createCanonicalizerPhase().apply(g1, htc);
         GraphCostPhase gc1 = new GraphCostPhase();
         gc1.apply(g1, htc);
         Assert.assertEquals(15, gc1.finalCycles, 25);
@@ -286,7 +288,7 @@
     public void testFieldLoad() {
         StructuredGraph g1 = parseForCompile(getResolvedJavaMethod("fieldLoad"));
         HighTierContext htc = getDefaultHighTierContext();
-        new CanonicalizerPhase().apply(g1, htc);
+        createCanonicalizerPhase().apply(g1, htc);
         GraphCostPhase gc1 = new GraphCostPhase();
         gc1.apply(g1, htc);
         Assert.assertEquals(15, gc1.finalCycles, 25);
@@ -296,13 +298,13 @@
     public void testFieldStore() {
         StructuredGraph g1 = parseForCompile(getResolvedJavaMethod("fieldStore"));
         HighTierContext htc = getDefaultHighTierContext();
-        new CanonicalizerPhase().apply(g1, htc);
+        createCanonicalizerPhase().apply(g1, htc);
         GraphCostPhase gc1 = new GraphCostPhase();
         gc1.apply(g1, htc);
         Assert.assertEquals(15, gc1.finalCycles, 25);
     }
 
-    static class ImprovementSavingCanonicalizer extends CustomCanonicalizer {
+    static class ImprovementSavingCalculator implements CustomSimplification {
         private int savedCycles;
 
         @Override
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/PushNodesThroughPiTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/PushNodesThroughPiTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -104,7 +104,7 @@
     private StructuredGraph compileTestSnippet(final String snippet) {
         StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO);
         CoreProviders context = getProviders();
-        CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+        CanonicalizerPhase canonicalizer = this.createCanonicalizerPhase();
         new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
         canonicalizer.apply(graph, context);
         canonicalizer.apply(graph, context);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/PushThroughIfTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/PushThroughIfTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -29,7 +29,6 @@
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
 import org.graalvm.compiler.nodes.util.GraphUtil;
-import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.junit.Test;
 
 public class PushThroughIfTest extends GraalCompilerTest {
@@ -65,15 +64,15 @@
             fs.replaceAtUsages(null);
             GraphUtil.killWithUnusedFloatingInputs(fs);
         }
-        new CanonicalizerPhase().apply(graph, getProviders());
-        new CanonicalizerPhase().apply(graph, getProviders());
+        createCanonicalizerPhase().apply(graph, getProviders());
+        createCanonicalizerPhase().apply(graph, getProviders());
 
         StructuredGraph referenceGraph = parseEager(reference, AllowAssumptions.YES);
         for (FrameState fs : referenceGraph.getNodes(FrameState.TYPE).snapshot()) {
             fs.replaceAtUsages(null);
             GraphUtil.killWithUnusedFloatingInputs(fs);
         }
-        new CanonicalizerPhase().apply(referenceGraph, getProviders());
+        createCanonicalizerPhase().apply(referenceGraph, getProviders());
         assertEquals(referenceGraph, graph);
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ReadAfterCheckCastTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ReadAfterCheckCastTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -90,7 +90,7 @@
             // structure changes significantly
             StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
             CoreProviders context = getProviders();
-            CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+            CanonicalizerPhase canonicalizer = createCanonicalizerPhase();
             new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
             new FloatingReadPhase().apply(graph);
             canonicalizer.apply(graph, context);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ReassociateAndCanonicalTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ReassociateAndCanonicalTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -28,7 +28,6 @@
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
-import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.junit.Test;
 
 public class ReassociateAndCanonicalTest extends GraalCompilerTest {
@@ -245,9 +244,9 @@
 
     private <T extends Node & IterableNodeType> void test(String test, String ref) {
         StructuredGraph testGraph = parseEager(test, AllowAssumptions.NO);
-        new CanonicalizerPhase().apply(testGraph, getProviders());
+        createCanonicalizerPhase().apply(testGraph, getProviders());
         StructuredGraph refGraph = parseEager(ref, AllowAssumptions.NO);
-        new CanonicalizerPhase().apply(refGraph, getProviders());
+        createCanonicalizerPhase().apply(refGraph, getProviders());
         assertEquals(testGraph, refGraph);
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ScalarTypeSystemTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ScalarTypeSystemTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -28,7 +28,6 @@
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
 import org.graalvm.compiler.nodes.spi.CoreProviders;
-import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.junit.Test;
 
 /**
@@ -134,7 +133,7 @@
         StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO);
         graph.getDebug().dump(DebugContext.BASIC_LEVEL, graph, "Graph");
         CoreProviders context = getProviders();
-        new CanonicalizerPhase().apply(graph, context);
+        createCanonicalizerPhase().apply(graph, context);
         StructuredGraph referenceGraph = parseEager(referenceSnippet, AllowAssumptions.NO);
         assertEquals(referenceGraph, graph);
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SchedulingTest2.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SchedulingTest2.java	Thu Oct 31 16:54:16 2019 -0700
@@ -44,7 +44,6 @@
 import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.nodes.spi.LoweringTool;
 import org.graalvm.compiler.phases.OptimisticOptimizations;
-import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.common.FrameStateAssignmentPhase;
 import org.graalvm.compiler.phases.common.GuardLoweringPhase;
 import org.graalvm.compiler.phases.common.LoweringPhase;
@@ -99,8 +98,8 @@
         }
 
         CoreProviders context = getProviders();
-        new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
-        new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.MID_TIER).apply(graph, context);
+        new LoweringPhase(createCanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
+        new LoweringPhase(createCanonicalizerPhase(), LoweringTool.StandardLoweringStage.MID_TIER).apply(graph, context);
         MidTierContext midContext = new MidTierContext(getProviders(), getTargetProvider(), OptimisticOptimizations.ALL, graph.getProfilingInfo());
 
         new GuardLoweringPhase().apply(graph, midContext);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StampCanonicalizerTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StampCanonicalizerTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -27,7 +27,6 @@
 import org.graalvm.compiler.core.common.type.IntegerStamp;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
-import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
 import org.junit.Test;
 
@@ -111,7 +110,7 @@
 
     private void testZeroReturn(String methodName) {
         StructuredGraph graph = parseEager(methodName, AllowAssumptions.YES);
-        new CanonicalizerPhase().apply(graph, getProviders());
+        createCanonicalizerPhase().apply(graph, getProviders());
         new DeadCodeEliminationPhase().apply(graph);
         assertConstantReturn(graph, 0);
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StraighteningTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StraighteningTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -27,7 +27,6 @@
 import org.graalvm.compiler.debug.DebugContext;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
-import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.junit.Test;
 
 public class StraighteningTest extends GraalCompilerTest {
@@ -90,7 +89,7 @@
         StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
         DebugContext debug = graph.getDebug();
         debug.dump(DebugContext.BASIC_LEVEL, graph, "Graph");
-        new CanonicalizerPhase().apply(graph, getProviders());
+        createCanonicalizerPhase().apply(graph, getProviders());
         StructuredGraph referenceGraph = parseEager(REFERENCE_SNIPPET, AllowAssumptions.YES);
         assertEquals(referenceGraph, graph);
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SwitchCanonicalizerTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SwitchCanonicalizerTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -26,7 +26,6 @@
 
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.extended.IntegerSwitchNode;
-import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.junit.Test;
 
 public class SwitchCanonicalizerTest extends GraalCompilerTest {
@@ -119,7 +118,7 @@
 
     private void shouldFoldSwitch(String methodName) {
         StructuredGraph graph = parseForCompile(getResolvedJavaMethod(methodName));
-        new CanonicalizerPhase().apply(graph, getDefaultHighTierContext());
+        createCanonicalizerPhase().apply(graph, getDefaultHighTierContext());
         assertTrue(graph.getNodes().filter(IntegerSwitchNode.class).isEmpty());
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SwitchDyingLoopTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SwitchDyingLoopTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -70,7 +70,7 @@
 
     @Test
     public void test() {
-        CanonicalizerPhase canonicalizerPhase = new CanonicalizerPhase();
+        CanonicalizerPhase canonicalizerPhase = createCanonicalizerPhase();
         HighTierContext highTierContext = getDefaultHighTierContext();
         StructuredGraph graph = parseEager("snippet", StructuredGraph.AllowAssumptions.YES);
         // there should be 1 loop and 1 switch
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SwitchFoldingTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SwitchFoldingTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -27,7 +27,6 @@
 
 import org.graalvm.compiler.debug.DebugContext;
 import org.graalvm.compiler.nodes.StructuredGraph;
-import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.junit.Test;
 
 public class SwitchFoldingTest extends GraalCompilerTest {
@@ -484,7 +483,7 @@
         StructuredGraph graph = parseEager(snippet, StructuredGraph.AllowAssumptions.YES);
         DebugContext debug = graph.getDebug();
         debug.dump(DebugContext.BASIC_LEVEL, graph, "Graph");
-        new CanonicalizerPhase().apply(graph, getProviders());
+        createCanonicalizerPhase().apply(graph, getProviders());
         StructuredGraph referenceGraph = parseEager(ref, StructuredGraph.AllowAssumptions.YES);
         assertEquals(referenceGraph, graph);
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/TypeSystemTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/TypeSystemTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -41,7 +41,6 @@
 import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult;
 import org.graalvm.compiler.nodes.cfg.Block;
 import org.graalvm.compiler.nodes.java.InstanceOfNode;
-import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.common.ConditionalEliminationPhase;
 import org.graalvm.compiler.phases.schedule.SchedulePhase;
 import org.junit.Assert;
@@ -188,13 +187,13 @@
          * reference graph.
          */
         new ConditionalEliminationPhase(false).apply(graph, getProviders());
-        new CanonicalizerPhase().apply(graph, getProviders());
+        createCanonicalizerPhase().apply(graph, getProviders());
         // a second canonicalizer is needed to process nested MaterializeNodes
-        new CanonicalizerPhase().apply(graph, getProviders());
+        createCanonicalizerPhase().apply(graph, getProviders());
         StructuredGraph referenceGraph = parseEager(referenceSnippet, AllowAssumptions.NO);
         new ConditionalEliminationPhase(false).apply(referenceGraph, getProviders());
-        new CanonicalizerPhase().apply(referenceGraph, getProviders());
-        new CanonicalizerPhase().apply(referenceGraph, getProviders());
+        this.createCanonicalizerPhase().apply(referenceGraph, getProviders());
+        this.createCanonicalizerPhase().apply(referenceGraph, getProviders());
         assertEquals(referenceGraph, graph);
     }
 
@@ -244,8 +243,8 @@
 
     private <T extends Node> void testHelper(String snippet, Class<T> clazz) {
         StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO);
-        new CanonicalizerPhase().apply(graph, getProviders());
-        new CanonicalizerPhase().apply(graph, getProviders());
+        createCanonicalizerPhase().apply(graph, getProviders());
+        createCanonicalizerPhase().apply(graph, getProviders());
         DebugContext debug = graph.getDebug();
         debug.dump(DebugContext.BASIC_LEVEL, graph, "Graph " + snippet);
         Assert.assertFalse("shouldn't have nodes of type " + clazz, graph.getNodes().filter(clazz).iterator().hasNext());
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnsafeReadEliminationTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnsafeReadEliminationTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -119,7 +119,7 @@
 
     public void testEarlyReadElimination(StructuredGraph graph, int reads, int writes) {
         CoreProviders context = getDefaultHighTierContext();
-        CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+        CanonicalizerPhase canonicalizer = createCanonicalizerPhase();
         canonicalizer.apply(graph, context);
         new EarlyReadEliminationPhase(canonicalizer).apply(graph, context);
         Assert.assertEquals(3, graph.getNodes().filter(UnsafeAccessNode.class).count());
@@ -134,7 +134,7 @@
     public void testPartialEscapeReadElimination(StructuredGraph graph, int reads, int writes) {
         OptionValues options = graph.getOptions();
         CoreProviders context = getDefaultHighTierContext();
-        CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+        CanonicalizerPhase canonicalizer = createCanonicalizerPhase();
         canonicalizer.apply(graph, context);
         new PartialEscapePhase(true, true, canonicalizer, null, options).apply(graph, context);
         Assert.assertEquals(3, graph.getNodes().filter(UnsafeAccessNode.class).count());
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnsafeVirtualizationTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnsafeVirtualizationTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -147,7 +147,7 @@
         StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO);
         OptionValues options = graph.getOptions();
         CoreProviders context = getDefaultHighTierContext();
-        CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+        CanonicalizerPhase canonicalizer = createCanonicalizerPhase();
         if (canonicalizeBefore) {
             canonicalizer.apply(graph, context);
         }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnusedArray.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnusedArray.java	Thu Oct 31 16:54:16 2019 -0700
@@ -30,7 +30,6 @@
 import org.graalvm.compiler.graph.iterators.NodeIterable;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.java.NewArrayNode;
-import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.junit.Test;
 
 public class UnusedArray extends GraalCompilerTest {
@@ -66,7 +65,7 @@
 
     public void test(String method) {
         StructuredGraph graph = parseEager(method, StructuredGraph.AllowAssumptions.YES);
-        new CanonicalizerPhase().apply(graph, getProviders());
+        createCanonicalizerPhase().apply(graph, getProviders());
         NodeIterable<NewArrayNode> newArrayNodes = graph.getNodes().filter(NewArrayNode.class);
         assertThat(newArrayNodes, isEmpty());
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/deopt/CompiledMethodTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/deopt/CompiledMethodTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -29,7 +29,6 @@
 import org.graalvm.compiler.nodes.ConstantNode;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
-import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
 import org.junit.Assert;
 import org.junit.Test;
@@ -62,7 +61,7 @@
     public void test1() {
         final ResolvedJavaMethod javaMethod = getResolvedJavaMethod("testMethod");
         final StructuredGraph graph = parseEager(javaMethod, AllowAssumptions.NO);
-        new CanonicalizerPhase().apply(graph, getProviders());
+        createCanonicalizerPhase().apply(graph, getProviders());
         new DeadCodeEliminationPhase().apply(graph);
 
         for (ConstantNode node : ConstantNode.getConstantNodes(graph)) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/EATestBase.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/EATestBase.java	Thu Oct 31 16:54:16 2019 -0700
@@ -37,7 +37,6 @@
 import org.graalvm.compiler.nodes.java.NewInstanceNode;
 import org.graalvm.compiler.nodes.virtual.AllocatedObjectNode;
 import org.graalvm.compiler.nodes.virtual.CommitAllocationNode;
-import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
 import org.graalvm.compiler.phases.tiers.HighTierContext;
 import org.graalvm.compiler.virtual.phases.ea.PartialEscapePhase;
@@ -173,7 +172,7 @@
             createInliningPhase().apply(graph, context);
             new DeadCodeEliminationPhase().apply(graph);
             canonicalizeGraph();
-            new PartialEscapePhase(iterativeEscapeAnalysis, false, new CanonicalizerPhase(), null, graph.getOptions()).apply(graph, context);
+            new PartialEscapePhase(iterativeEscapeAnalysis, false, createCanonicalizerPhase(), null, graph.getOptions()).apply(graph, context);
             postEACanonicalizeGraph();
             returnNodes = graph.getNodes(ReturnNode.TYPE).snapshot();
         } catch (Throwable e) {
@@ -185,6 +184,6 @@
     }
 
     protected void canonicalizeGraph() {
-        new CanonicalizerPhase().apply(graph, context);
+        this.createCanonicalizerPhase().apply(graph, context);
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/EarlyReadEliminationTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/EarlyReadEliminationTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2019, 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
@@ -27,6 +27,9 @@
 import java.util.List;
 
 import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.IfNode;
+import org.graalvm.compiler.nodes.LogicConstantNode;
 import org.graalvm.compiler.nodes.ProxyNode;
 import org.graalvm.compiler.nodes.ReturnNode;
 import org.graalvm.compiler.nodes.StructuredGraph;
@@ -37,7 +40,6 @@
 import org.graalvm.compiler.nodes.java.StoreFieldNode;
 import org.graalvm.compiler.nodes.memory.ReadNode;
 import org.graalvm.compiler.nodes.spi.LoweringTool;
-import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.common.LoweringPhase;
 import org.graalvm.compiler.phases.tiers.HighTierContext;
 import org.graalvm.compiler.virtual.phases.ea.EarlyReadEliminationPhase;
@@ -47,6 +49,50 @@
 
     public static Object staticField;
 
+    static void cfgSnippet() {
+        if (staticField != null) {
+            staticField = 12;
+            if (staticField != null) {
+                staticField = 12;
+            }
+            if (staticField != null) {
+                staticField = 12;
+            }
+            if (staticField != null) {
+                staticField = 12;
+            }
+            if (staticField != null) {
+                staticField = 12;
+            }
+        } else {
+            if (staticField != null) {
+                staticField = 12;
+            } else {
+                if (staticField != null) {
+                    staticField = 12;
+                }
+            }
+        }
+    }
+
+    @Test
+    public void testDeadBranches() {
+        StructuredGraph graph = parseEager(getResolvedJavaMethod("cfgSnippet"), AllowAssumptions.NO);
+        HighTierContext context = getDefaultHighTierContext();
+        int index = 0;
+        boolean[] conditions = new boolean[]{true, false, false, true, true, true, false};
+        /*
+         * Create a graph with "dead" branches in the beginning.
+         */
+        for (Node n : graph.getNodes()) {
+            if (n instanceof IfNode) {
+                IfNode ifNode = (IfNode) n;
+                ifNode.setCondition(LogicConstantNode.forBoolean(conditions[index++], graph));
+            }
+        }
+        new EarlyReadEliminationPhase(createCanonicalizerPhase()).apply(graph, context);
+    }
+
     public static class TestObject {
 
         public int x;
@@ -264,9 +310,9 @@
         HighTierContext context = getDefaultHighTierContext();
         createInliningPhase().apply(graph, context);
         if (doLowering) {
-            new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
+            new LoweringPhase(createCanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
         }
-        new EarlyReadEliminationPhase(new CanonicalizerPhase()).apply(graph, context);
+        new EarlyReadEliminationPhase(createCanonicalizerPhase()).apply(graph, context);
         return graph;
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/EscapeAnalysisTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/EscapeAnalysisTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -38,7 +38,6 @@
 import org.graalvm.compiler.nodes.java.LoadFieldNode;
 import org.graalvm.compiler.nodes.virtual.AllocatedObjectNode;
 import org.graalvm.compiler.nodes.virtual.CommitAllocationNode;
-import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.schedule.SchedulePhase;
 import org.graalvm.compiler.test.SubprocessUtil;
 import org.graalvm.compiler.virtual.phases.ea.PartialEscapePhase;
@@ -327,7 +326,7 @@
         Assert.assertEquals(1, graph.getNodes().filter(BoxNode.class).count());
         List<Node> nodes = graph.getNodes().snapshot();
         // verify that an additional run doesn't add or remove nodes
-        new PartialEscapePhase(false, false, new CanonicalizerPhase(), null, graph.getOptions()).apply(graph, context);
+        new PartialEscapePhase(false, false, createCanonicalizerPhase(), null, graph.getOptions()).apply(graph, context);
         Assert.assertEquals(nodes.size(), graph.getNodeCount());
         for (Node node : nodes) {
             Assert.assertTrue(node.isAlive());
@@ -362,9 +361,9 @@
         Assert.assertEquals(2, graph.getNodes().filter(CommitAllocationNode.class).count());
         // create the situation by removing the if
         graph.replaceFixedWithFloating(graph.getNodes().filter(LoadFieldNode.class).first(), graph.unique(ConstantNode.forInt(0)));
-        new CanonicalizerPhase().apply(graph, context);
+        createCanonicalizerPhase().apply(graph, context);
         // verify that an additional run removes all allocations
-        new PartialEscapePhase(false, false, new CanonicalizerPhase(), null, graph.getOptions()).apply(graph, context);
+        new PartialEscapePhase(false, false, createCanonicalizerPhase(), null, graph.getOptions()).apply(graph, context);
         Assert.assertEquals(0, graph.getNodes().filter(CommitAllocationNode.class).count());
     }
 
@@ -440,8 +439,8 @@
     @Test
     public void testFullyUnrolledLoop() {
         prepareGraph("testFullyUnrolledLoopSnippet", false);
-        new LoopFullUnrollPhase(new CanonicalizerPhase(), new DefaultLoopPolicies()).apply(graph, context);
-        new PartialEscapePhase(false, new CanonicalizerPhase(), graph.getOptions()).apply(graph, context);
+        new LoopFullUnrollPhase(createCanonicalizerPhase(), new DefaultLoopPolicies()).apply(graph, context);
+        new PartialEscapePhase(false, createCanonicalizerPhase(), graph.getOptions()).apply(graph, context);
         Assert.assertEquals(1, returnNodes.size());
         Assert.assertTrue(returnNodes.get(0).result() instanceof AllocatedObjectNode);
         CommitAllocationNode commit = ((AllocatedObjectNode) returnNodes.get(0).result()).getCommit();
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PEAReadEliminationTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PEAReadEliminationTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2019, 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
@@ -30,7 +30,6 @@
 import org.graalvm.compiler.nodes.extended.RawLoadNode;
 import org.graalvm.compiler.nodes.java.LoadIndexedNode;
 import org.graalvm.compiler.nodes.java.StoreIndexedNode;
-import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.tiers.HighTierContext;
 import org.graalvm.compiler.virtual.phases.ea.PartialEscapePhase;
 import org.junit.Test;
@@ -181,7 +180,7 @@
         StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO);
         HighTierContext context = getDefaultHighTierContext();
         createInliningPhase().apply(graph, context);
-        new PartialEscapePhase(false, true, new CanonicalizerPhase(), null, graph.getOptions()).apply(graph, context);
+        new PartialEscapePhase(false, true, createCanonicalizerPhase(), null, graph.getOptions()).apply(graph, context);
         return graph;
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PartialEscapeAnalysisIterationTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PartialEscapeAnalysisIterationTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2019, 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
@@ -31,7 +31,6 @@
 import org.graalvm.compiler.nodes.extended.UnboxNode;
 import org.graalvm.compiler.nodes.java.StoreFieldNode;
 import org.graalvm.compiler.nodes.virtual.CommitAllocationNode;
-import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.virtual.phases.ea.PartialEscapePhase;
 import org.junit.Assert;
 import org.junit.Test;
@@ -147,7 +146,7 @@
         for (String name : new String[]{"noLoopIterationEmpty", "noLoopIteration"}) {
             prepareGraph(name, false);
             List<CommitAllocationNode> allocations = graph.getNodes().filter(CommitAllocationNode.class).snapshot();
-            new PartialEscapePhase(true, false, new CanonicalizerPhase(), null, graph.getOptions()).apply(graph, context);
+            new PartialEscapePhase(true, false, createCanonicalizerPhase(), null, graph.getOptions()).apply(graph, context);
             Assert.assertEquals(1, allocations.size());
             Assert.assertTrue(allocations.get(0).isAlive());
         }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PartialEscapeAnalysisTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PartialEscapeAnalysisTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2019, 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
@@ -44,7 +44,6 @@
 import org.graalvm.compiler.nodes.java.NewInstanceNode;
 import org.graalvm.compiler.nodes.java.StoreFieldNode;
 import org.graalvm.compiler.nodes.virtual.CommitAllocationNode;
-import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
 
 /**
@@ -287,7 +286,7 @@
             merge.setStateAfter(null);
         }
         new DeadCodeEliminationPhase().apply(graph);
-        new CanonicalizerPhase().apply(graph, context);
+        createCanonicalizerPhase().apply(graph, context);
         try {
             Assert.assertTrue("partial escape analysis should have removed all NewInstanceNode allocations", graph.getNodes().filter(NewInstanceNode.class).isEmpty());
             Assert.assertTrue("partial escape analysis should have removed all NewArrayNode allocations", graph.getNodes().filter(NewArrayNode.class).isEmpty());
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PartialEscapeAnalysisTreesTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PartialEscapeAnalysisTreesTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2019, 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
@@ -30,7 +30,6 @@
 import org.graalvm.compiler.core.test.GraalCompilerTest;
 import org.graalvm.compiler.debug.DebugContext;
 import org.graalvm.compiler.nodes.debug.BlackholeNode;
-import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
 import org.junit.Assert;
 import org.junit.Test;
@@ -118,7 +117,7 @@
                 graph.removeFixed(node);
             }
             new DeadCodeEliminationPhase().apply(graph);
-            new CanonicalizerPhase().apply(graph, context);
+            createCanonicalizerPhase().apply(graph, context);
 
             InstalledCode code = getCode(method, graph, true);
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PoorMansEATest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PoorMansEATest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -35,7 +35,6 @@
 import org.graalvm.compiler.nodes.java.NewInstanceNode;
 import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.nodes.spi.LoweringTool;
-import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.common.LoweringPhase;
 import org.graalvm.compiler.phases.tiers.HighTierContext;
 import org.junit.Test;
@@ -68,7 +67,7 @@
             HighTierContext highTierContext = getDefaultHighTierContext();
             createInliningPhase().apply(graph, highTierContext);
             CoreProviders context = getProviders();
-            new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
+            new LoweringPhase(createCanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
 
             // remove framestates in order to trigger the simplification.
             cleanup: for (FrameState fs : graph.getNodes(FrameState.TYPE).snapshot()) {
@@ -80,7 +79,7 @@
                     }
                 }
             }
-            new CanonicalizerPhase().apply(graph, context);
+            createCanonicalizerPhase().apply(graph, context);
         } catch (Throwable e) {
             throw debug.handle(e);
         }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/TrufflePEATest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/TrufflePEATest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2019, 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
@@ -32,7 +32,6 @@
 import org.graalvm.compiler.nodes.extended.RawLoadNode;
 import org.graalvm.compiler.nodes.extended.RawStoreNode;
 import org.graalvm.compiler.nodes.virtual.CommitAllocationNode;
-import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.tiers.HighTierContext;
 import org.graalvm.compiler.virtual.phases.ea.PartialEscapePhase;
 import org.junit.Test;
@@ -123,7 +122,7 @@
         StructuredGraph graph = parseEager(snippet, StructuredGraph.AllowAssumptions.NO);
         HighTierContext context = getDefaultHighTierContext();
         createInliningPhase().apply(graph, context);
-        new PartialEscapePhase(true, true, new CanonicalizerPhase(), null, graph.getOptions()).apply(graph, context);
+        new PartialEscapePhase(true, true, createCanonicalizerPhase(), null, graph.getOptions()).apply(graph, context);
         return graph;
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/UnsafeEATest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/UnsafeEATest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2019, 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
@@ -37,7 +37,6 @@
 import org.graalvm.compiler.nodes.extended.RawStoreNode;
 import org.graalvm.compiler.nodes.extended.UnsafeAccessNode;
 import org.graalvm.compiler.nodes.java.LoadFieldNode;
-import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -123,7 +122,7 @@
         for (UnpackEndianHalfNode node : graph.getNodes().filter(UnpackEndianHalfNode.class)) {
             node.lower(getTarget().arch.getByteOrder());
         }
-        new CanonicalizerPhase().applyIncremental(graph, context, mark);
+        createCanonicalizerPhase().applyIncremental(graph, context, mark);
     }
 
     private boolean testingUnsafe;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/inlining/InliningTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/inlining/InliningTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2019, 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
@@ -41,7 +41,6 @@
 import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.phases.OptimisticOptimizations;
 import org.graalvm.compiler.phases.PhaseSuite;
-import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
 import org.graalvm.compiler.phases.tiers.HighTierContext;
 import org.junit.Assert;
@@ -291,10 +290,10 @@
                                 : getDefaultGraphBuilderSuite();
                 HighTierContext context = new HighTierContext(getProviders(), graphBuilderSuite, OptimisticOptimizations.ALL);
                 debug.dump(DebugContext.BASIC_LEVEL, graph, "Graph");
-                new CanonicalizerPhase().apply(graph, context);
+                createCanonicalizerPhase().apply(graph, context);
                 createInliningPhase().apply(graph, context);
                 debug.dump(DebugContext.BASIC_LEVEL, graph, "Graph");
-                new CanonicalizerPhase().apply(graph, context);
+                createCanonicalizerPhase().apply(graph, context);
                 new DeadCodeEliminationPhase().apply(graph);
                 return graph;
             }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/inlining/NestedLoopEffectsPhaseComplexityTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/inlining/NestedLoopEffectsPhaseComplexityTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -112,8 +112,8 @@
             StructuredGraph g1 = prepareGraph(snippet, i);
             StructuredGraph g2 = (StructuredGraph) g1.copy(g1.getDebug());
             ResolvedJavaMethod method = g1.method();
-            long elapsedRE = runAndTimePhase(g1, new EarlyReadEliminationPhase(new CanonicalizerPhase()));
-            long elapsedPEA = runAndTimePhase(g2, new PartialEscapePhase(true, new CanonicalizerPhase(), g1.getOptions()));
+            long elapsedRE = runAndTimePhase(g1, new EarlyReadEliminationPhase(createCanonicalizerPhase()));
+            long elapsedPEA = runAndTimePhase(g2, new PartialEscapePhase(true, createCanonicalizerPhase(), g1.getOptions()));
             if (LOG_PHASE_TIMINGS) {
                 TTY.printf("Needed %dms to run early partial escape analysis on a graph with %d nested loops compiling method %s\n", elapsedPEA, i, method);
             }
@@ -138,7 +138,7 @@
         StructuredGraph callerGraph = parseEager(callerMethod, AllowAssumptions.YES);
         PhaseSuite<HighTierContext> graphBuilderSuite = getDefaultGraphBuilderSuite();
         HighTierContext context = new HighTierContext(getProviders(), graphBuilderSuite, OptimisticOptimizations.ALL);
-        CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+        CanonicalizerPhase canonicalizer = createCanonicalizerPhase();
         Invoke next = callerGraph.getNodes(MethodCallTargetNode.TYPE).first().invoke();
         StructuredGraph calleeGraph = parseBytecodes(next.callTarget().targetMethod(), context, canonicalizer);
         ResolvedJavaMethod calleeMethod = next.callTarget().targetMethod();
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/NodeMatchRules.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/NodeMatchRules.java	Thu Oct 31 16:54:16 2019 -0700
@@ -63,6 +63,7 @@
 import org.graalvm.compiler.nodes.java.ValueCompareAndSwapNode;
 import org.graalvm.compiler.nodes.memory.FloatingReadNode;
 import org.graalvm.compiler.nodes.memory.ReadNode;
+import org.graalvm.compiler.nodes.memory.VolatileReadNode;
 import org.graalvm.compiler.nodes.memory.WriteNode;
 
 import jdk.vm.ci.meta.Value;
@@ -75,6 +76,7 @@
 @MatchableNode(nodeClass = LeftShiftNode.class, inputs = {"x", "y"}, ignoresSideEffects = true)
 @MatchableNode(nodeClass = NarrowNode.class, inputs = {"value"}, ignoresSideEffects = true)
 @MatchableNode(nodeClass = ReadNode.class, inputs = {"address"})
+@MatchableNode(nodeClass = VolatileReadNode.class, inputs = {"address"})
 @MatchableNode(nodeClass = ReinterpretNode.class, inputs = {"value"}, ignoresSideEffects = true)
 @MatchableNode(nodeClass = SignExtendNode.class, inputs = {"value"}, ignoresSideEffects = true)
 @MatchableNode(nodeClass = UnsignedRightShiftNode.class, inputs = {"x", "y"}, ignoresSideEffects = true)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/BaseTier.java	Thu Oct 31 16:54:16 2019 -0700
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2019, 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.phases;
+
+import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode;
+
+import org.graalvm.compiler.loop.DefaultLoopPolicies;
+import org.graalvm.compiler.loop.LoopPolicies;
+import org.graalvm.compiler.options.OptionValues;
+import org.graalvm.compiler.phases.PhaseSuite;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+
+public class BaseTier<C> extends PhaseSuite<C> {
+
+    public LoopPolicies createLoopPolicies() {
+        return new DefaultLoopPolicies();
+    }
+
+    public CanonicalizerPhase createCanonicalizerPhase(OptionValues options) {
+        CanonicalizerPhase canonicalizer = null;
+        if (ImmutableCode.getValue(options)) {
+            canonicalizer = CanonicalizerPhase.createWithoutReadCanonicalization();
+        } else {
+            canonicalizer = CanonicalizerPhase.create();
+        }
+        return canonicalizer;
+    }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/EconomyHighTier.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/EconomyHighTier.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, 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
@@ -24,23 +24,16 @@
 
 package org.graalvm.compiler.core.phases;
 
-import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode;
-
 import org.graalvm.compiler.nodes.spi.LoweringTool;
 import org.graalvm.compiler.options.OptionValues;
-import org.graalvm.compiler.phases.PhaseSuite;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.common.LoweringPhase;
 import org.graalvm.compiler.phases.tiers.HighTierContext;
 
-public class EconomyHighTier extends PhaseSuite<HighTierContext> {
+public class EconomyHighTier extends BaseTier<HighTierContext> {
 
     public EconomyHighTier(OptionValues options) {
-        CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
-        if (ImmutableCode.getValue(options)) {
-            canonicalizer.disableReadCanonicalization();
-        }
-
+        CanonicalizerPhase canonicalizer = this.createCanonicalizerPhase(options);
         appendPhase(canonicalizer);
         appendPhase(new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER));
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/EconomyLowTier.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/EconomyLowTier.java	Thu Oct 31 16:54:16 2019 -0700
@@ -24,29 +24,20 @@
 
 package org.graalvm.compiler.core.phases;
 
-import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode;
-
 import org.graalvm.compiler.nodes.spi.LoweringTool;
 import org.graalvm.compiler.options.OptionValues;
-import org.graalvm.compiler.phases.PhaseSuite;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.common.ExpandLogicPhase;
 import org.graalvm.compiler.phases.common.LoweringPhase;
 import org.graalvm.compiler.phases.schedule.SchedulePhase;
 import org.graalvm.compiler.phases.tiers.LowTierContext;
 
-public class EconomyLowTier extends PhaseSuite<LowTierContext> {
+public class EconomyLowTier extends BaseTier<LowTierContext> {
 
     public EconomyLowTier(OptionValues options) {
-        CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
-        if (ImmutableCode.getValue(options)) {
-            canonicalizer.disableReadCanonicalization();
-        }
-
+        CanonicalizerPhase canonicalizer = this.createCanonicalizerPhase(options);
         appendPhase(new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.LOW_TIER));
-
         appendPhase(new ExpandLogicPhase());
-
         appendPhase(new SchedulePhase(SchedulePhase.SchedulingStrategy.LATEST_OUT_OF_LOOPS));
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/EconomyMidTier.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/EconomyMidTier.java	Thu Oct 31 16:54:16 2019 -0700
@@ -24,11 +24,8 @@
 
 package org.graalvm.compiler.core.phases;
 
-import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode;
-
 import org.graalvm.compiler.nodes.spi.LoweringTool;
 import org.graalvm.compiler.options.OptionValues;
-import org.graalvm.compiler.phases.PhaseSuite;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.common.FrameStateAssignmentPhase;
 import org.graalvm.compiler.phases.common.GuardLoweringPhase;
@@ -38,23 +35,15 @@
 import org.graalvm.compiler.phases.common.WriteBarrierAdditionPhase;
 import org.graalvm.compiler.phases.tiers.MidTierContext;
 
-public class EconomyMidTier extends PhaseSuite<MidTierContext> {
+public class EconomyMidTier extends BaseTier<MidTierContext> {
 
     public EconomyMidTier(OptionValues options) {
-        CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
-        if (ImmutableCode.getValue(options)) {
-            canonicalizer.disableReadCanonicalization();
-        }
+        CanonicalizerPhase canonicalizer = this.createCanonicalizerPhase(options);
         appendPhase(new RemoveValueProxyPhase());
-
         appendPhase(new LoopSafepointInsertionPhase());
-
         appendPhase(new GuardLoweringPhase());
-
         appendPhase(new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.MID_TIER));
-
         appendPhase(new FrameStateAssignmentPhase());
-
         appendPhase(new WriteBarrierAdditionPhase());
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/HighTier.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/HighTier.java	Thu Oct 31 16:54:16 2019 -0700
@@ -25,17 +25,16 @@
 package org.graalvm.compiler.core.phases;
 
 import static org.graalvm.compiler.core.common.GraalOptions.ConditionalElimination;
-import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode;
 import static org.graalvm.compiler.core.common.GraalOptions.LoopPeeling;
 import static org.graalvm.compiler.core.common.GraalOptions.LoopUnswitch;
 import static org.graalvm.compiler.core.common.GraalOptions.OptConvertDeoptsToGuards;
-import static org.graalvm.compiler.core.common.GraalOptions.OptLoopTransform;
 import static org.graalvm.compiler.core.common.GraalOptions.OptReadElimination;
 import static org.graalvm.compiler.core.common.GraalOptions.PartialEscapeAnalysis;
 import static org.graalvm.compiler.phases.common.DeadCodeEliminationPhase.Optionality.Optional;
 
 import org.graalvm.compiler.loop.DefaultLoopPolicies;
 import org.graalvm.compiler.loop.LoopPolicies;
+import org.graalvm.compiler.loop.phases.ConvertDeoptimizeToGuardPhase;
 import org.graalvm.compiler.loop.phases.LoopFullUnrollPhase;
 import org.graalvm.compiler.loop.phases.LoopPeelingPhase;
 import org.graalvm.compiler.loop.phases.LoopUnswitchingPhase;
@@ -44,22 +43,19 @@
 import org.graalvm.compiler.options.OptionKey;
 import org.graalvm.compiler.options.OptionType;
 import org.graalvm.compiler.options.OptionValues;
-import org.graalvm.compiler.phases.PhaseSuite;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
-import org.graalvm.compiler.loop.phases.ConvertDeoptimizeToGuardPhase;
 import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
 import org.graalvm.compiler.phases.common.IncrementalCanonicalizerPhase;
 import org.graalvm.compiler.phases.common.IterativeConditionalEliminationPhase;
 import org.graalvm.compiler.phases.common.LoweringPhase;
 import org.graalvm.compiler.phases.common.NodeCounterPhase;
-import org.graalvm.compiler.phases.common.RemoveValueProxyPhase;
 import org.graalvm.compiler.phases.common.inlining.InliningPhase;
 import org.graalvm.compiler.phases.common.inlining.policy.GreedyInliningPolicy;
 import org.graalvm.compiler.phases.tiers.HighTierContext;
 import org.graalvm.compiler.virtual.phases.ea.EarlyReadEliminationPhase;
 import org.graalvm.compiler.virtual.phases.ea.PartialEscapePhase;
 
-public class HighTier extends PhaseSuite<HighTierContext> {
+public class HighTier extends BaseTier<HighTierContext> {
 
     public static class Options {
 
@@ -70,11 +66,7 @@
     }
 
     public HighTier(OptionValues options) {
-        CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
-        if (ImmutableCode.getValue(options)) {
-            canonicalizer.disableReadCanonicalization();
-        }
-
+        CanonicalizerPhase canonicalizer = createCanonicalizerPhase(options);
         appendPhase(canonicalizer);
 
         if (NodeCounterPhase.Options.NodeCounters.getValue(options)) {
@@ -101,13 +93,12 @@
         LoopPolicies loopPolicies = createLoopPolicies();
         appendPhase(new LoopFullUnrollPhase(canonicalizer, loopPolicies));
 
-        if (OptLoopTransform.getValue(options)) {
-            if (LoopPeeling.getValue(options)) {
-                appendPhase(new IncrementalCanonicalizerPhase<>(canonicalizer, new LoopPeelingPhase(loopPolicies)));
-            }
-            if (LoopUnswitch.getValue(options)) {
-                appendPhase(new IncrementalCanonicalizerPhase<>(canonicalizer, new LoopUnswitchingPhase(loopPolicies)));
-            }
+        if (LoopPeeling.getValue(options)) {
+            appendPhase(new IncrementalCanonicalizerPhase<>(canonicalizer, new LoopPeelingPhase(loopPolicies)));
+        }
+
+        if (LoopUnswitch.getValue(options)) {
+            appendPhase(new IncrementalCanonicalizerPhase<>(canonicalizer, new LoopUnswitchingPhase(loopPolicies)));
         }
 
         if (PartialEscapeAnalysis.getValue(options)) {
@@ -118,8 +109,6 @@
             appendPhase(new EarlyReadEliminationPhase(canonicalizer));
         }
 
-        appendPhase(new RemoveValueProxyPhase());
-
         if (NodeCounterPhase.Options.NodeCounters.getValue(options)) {
             appendPhase(new NodeCounterPhase(NodeCounterPhase.Stage.LATE));
         }
@@ -127,6 +116,7 @@
         appendPhase(new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER));
     }
 
+    @Override
     public LoopPolicies createLoopPolicies() {
         return new DefaultLoopPolicies();
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/LowTier.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/LowTier.java	Thu Oct 31 16:54:16 2019 -0700
@@ -24,7 +24,7 @@
 
 package org.graalvm.compiler.core.phases;
 
-import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode;
+import static org.graalvm.compiler.core.common.GraalOptions.LateMembars;
 import static org.graalvm.compiler.phases.common.DeadCodeEliminationPhase.Optionality.Required;
 
 import org.graalvm.compiler.core.common.GraalOptions;
@@ -33,11 +33,11 @@
 import org.graalvm.compiler.options.OptionKey;
 import org.graalvm.compiler.options.OptionType;
 import org.graalvm.compiler.options.OptionValues;
-import org.graalvm.compiler.phases.PhaseSuite;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
 import org.graalvm.compiler.phases.common.ExpandLogicPhase;
 import org.graalvm.compiler.phases.common.FixReadsPhase;
+import org.graalvm.compiler.phases.common.InsertMembarsPhase;
 import org.graalvm.compiler.phases.common.LoweringPhase;
 import org.graalvm.compiler.phases.common.ProfileCompiledMethodsPhase;
 import org.graalvm.compiler.phases.common.PropagateDeoptimizeProbabilityPhase;
@@ -46,7 +46,7 @@
 import org.graalvm.compiler.phases.schedule.SchedulePhase.SchedulingStrategy;
 import org.graalvm.compiler.phases.tiers.LowTierContext;
 
-public class LowTier extends PhaseSuite<LowTierContext> {
+public class LowTier extends BaseTier<LowTierContext> {
 
     static class Options {
 
@@ -58,13 +58,8 @@
     }
 
     public LowTier(OptionValues options) {
-        CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
-        CanonicalizerPhase canonicalizerWithoutGVN = new CanonicalizerPhase();
-        canonicalizerWithoutGVN.disableGVN();
-        if (ImmutableCode.getValue(options)) {
-            canonicalizer.disableReadCanonicalization();
-            canonicalizerWithoutGVN.disableReadCanonicalization();
-        }
+        CanonicalizerPhase canonicalizer = createCanonicalizerPhase(options);
+        CanonicalizerPhase canonicalizerWithoutGVN = canonicalizer.copyWithoutGVN();
 
         if (Options.ProfileCompiledMethods.getValue(options)) {
             appendPhase(new ProfileCompiledMethodsPhase());
@@ -85,6 +80,9 @@
 
         appendPhase(new PropagateDeoptimizeProbabilityPhase());
 
+        if (LateMembars.getValue(options)) {
+            appendPhase(new InsertMembarsPhase());
+        }
         appendPhase(new SchedulePhase(SchedulePhase.SchedulingStrategy.LATEST_OUT_OF_LOOPS));
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/MidTier.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/MidTier.java	Thu Oct 31 16:54:16 2019 -0700
@@ -25,10 +25,8 @@
 package org.graalvm.compiler.core.phases;
 
 import static org.graalvm.compiler.core.common.GraalOptions.ConditionalElimination;
-import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode;
 import static org.graalvm.compiler.core.common.GraalOptions.OptDeoptimizationGrouping;
 import static org.graalvm.compiler.core.common.GraalOptions.OptFloatingReads;
-import static org.graalvm.compiler.core.common.GraalOptions.OptLoopTransform;
 import static org.graalvm.compiler.core.common.GraalOptions.PartialUnroll;
 import static org.graalvm.compiler.core.common.GraalOptions.ReassociateInvariants;
 import static org.graalvm.compiler.core.common.GraalOptions.VerifyHeapAtReturn;
@@ -43,7 +41,6 @@
 import org.graalvm.compiler.loop.phases.ReassociateInvariantPhase;
 import org.graalvm.compiler.nodes.spi.LoweringTool;
 import org.graalvm.compiler.options.OptionValues;
-import org.graalvm.compiler.phases.PhaseSuite;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.common.DeoptimizationGroupingPhase;
 import org.graalvm.compiler.phases.common.FloatingReadPhase;
@@ -56,17 +53,15 @@
 import org.graalvm.compiler.phases.common.LoopSafepointInsertionPhase;
 import org.graalvm.compiler.phases.common.LoweringPhase;
 import org.graalvm.compiler.phases.common.OptimizeDivPhase;
+import org.graalvm.compiler.phases.common.RemoveValueProxyPhase;
 import org.graalvm.compiler.phases.common.VerifyHeapAtReturnPhase;
 import org.graalvm.compiler.phases.common.WriteBarrierAdditionPhase;
 import org.graalvm.compiler.phases.tiers.MidTierContext;
 
-public class MidTier extends PhaseSuite<MidTierContext> {
+public class MidTier extends BaseTier<MidTierContext> {
 
     public MidTier(OptionValues options) {
-        CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
-        if (ImmutableCode.getValue(options)) {
-            canonicalizer.disableReadCanonicalization();
-        }
+        CanonicalizerPhase canonicalizer = createCanonicalizerPhase(options);
 
         appendPhase(new LockEliminationPhase());
 
@@ -80,8 +75,6 @@
 
         appendPhase(new LoopSafepointEliminationPhase());
 
-        appendPhase(new LoopSafepointInsertionPhase());
-
         appendPhase(new GuardLoweringPhase());
 
         if (MitigateSpeculativeExecutionAttacks.getValue(options) == GuardTargets || MitigateSpeculativeExecutionAttacks.getValue(options) == NonDeoptGuardTargets) {
@@ -92,18 +85,21 @@
             appendPhase(new VerifyHeapAtReturnPhase());
         }
 
+        appendPhase(new IncrementalCanonicalizerPhase<>(canonicalizer, new RemoveValueProxyPhase()));
+
+        appendPhase(new LoopSafepointInsertionPhase());
+
         appendPhase(new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.MID_TIER));
 
         appendPhase(new OptimizeDivPhase());
 
         appendPhase(new FrameStateAssignmentPhase());
 
-        LoopPolicies loopPolicies = createLoopPolicies();
-        if (OptLoopTransform.getValue(options)) {
-            if (PartialUnroll.getValue(options)) {
-                appendPhase(new LoopPartialUnrollPhase(loopPolicies, canonicalizer));
-            }
+        if (PartialUnroll.getValue(options)) {
+            LoopPolicies loopPolicies = createLoopPolicies();
+            appendPhase(new LoopPartialUnrollPhase(loopPolicies, canonicalizer));
         }
+
         if (ReassociateInvariants.getValue(options)) {
             appendPhase(new ReassociateInvariantPhase());
         }
@@ -117,6 +113,7 @@
         appendPhase(new WriteBarrierAdditionPhase());
     }
 
+    @Override
     public LoopPolicies createLoopPolicies() {
         return new DefaultLoopPolicies();
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackendFactory.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackendFactory.java	Thu Oct 31 16:54:16 2019 -0700
@@ -100,6 +100,7 @@
     public HotSpotBackend createBackend(HotSpotGraalRuntimeProvider graalRuntime, CompilerConfiguration compilerConfiguration, HotSpotJVMCIRuntime jvmciRuntime, HotSpotBackend host) {
         assert host == null;
 
+        OptionValues options = graalRuntime.getOptions();
         JVMCIBackend jvmci = jvmciRuntime.getHostJVMCIBackend();
         GraalHotSpotVMConfig config = graalRuntime.getVMConfig();
         HotSpotProviders providers;
@@ -156,7 +157,7 @@
             }
             try (InitTimer rt = timer("create GraphBuilderPhase plugins")) {
                 plugins = createGraphBuilderPlugins(graalRuntime, compilerConfiguration, config, constantReflection, foreignCalls, metaAccess, snippetReflection, replacements, wordTypes,
-                                graalRuntime.getOptions());
+                                graalRuntime.getOptions(), target);
                 replacements.setGraphBuilderPlugins(plugins);
             }
             try (InitTimer rt = timer("create Suites provider")) {
@@ -165,6 +166,7 @@
             providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, replacements, suites, registers,
                             snippetReflection, wordTypes, plugins, gc);
             replacements.setProviders(providers);
+            replacements.maybeInitializeEncoder(options);
         }
         try (InitTimer rt = timer("instantiate backend")) {
             return createBackend(config, graalRuntime, providers);
@@ -180,7 +182,8 @@
                     HotSpotSnippetReflectionProvider snippetReflection,
                     HotSpotReplacementsImpl replacements,
                     HotSpotWordTypes wordTypes,
-                    OptionValues options) {
+                    OptionValues options,
+                    TargetDescription target) {
         Plugins plugins = HotSpotGraphBuilderPlugins.create(graalRuntime,
                         compilerConfiguration,
                         config,
@@ -190,8 +193,9 @@
                         snippetReflection,
                         foreignCalls,
                         replacements,
-                        options);
-        AArch64GraphBuilderPlugins.register(plugins, replacements.getDefaultReplacementBytecodeProvider(), false,
+                        options,
+                        target);
+        AArch64GraphBuilderPlugins.register(plugins, replacements, false, //
                         /* registerMathPlugins */true, /* emitJDK9StringSubstitutions */true, config.useFMAIntrinsics);
         return plugins;
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackendFactory.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackendFactory.java	Thu Oct 31 16:54:16 2019 -0700
@@ -158,6 +158,7 @@
             providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, replacements, suites, registers,
                             snippetReflection, wordTypes, plugins, gc);
             replacements.setProviders(providers);
+            replacements.maybeInitializeEncoder(options);
         }
         try (InitTimer rt = timer("instantiate backend")) {
             return createBackend(config, graalRuntime, providers);
@@ -185,8 +186,9 @@
                         snippetReflection,
                         foreignCalls,
                         replacements,
-                        options);
-        AMD64GraphBuilderPlugins.register(plugins, replacements.getDefaultReplacementBytecodeProvider(), (AMD64) target.arch, false, JavaVersionUtil.JAVA_SPEC >= 9, config.useFMAIntrinsics);
+                        options,
+                        target);
+        AMD64GraphBuilderPlugins.register(plugins, replacements, (AMD64) target.arch, false, JavaVersionUtil.JAVA_SPEC >= 9, config.useFMAIntrinsics);
         return plugins;
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotBackendFactory.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotBackendFactory.java	Thu Oct 31 16:54:16 2019 -0700
@@ -87,6 +87,7 @@
     public HotSpotBackend createBackend(HotSpotGraalRuntimeProvider runtime, CompilerConfiguration compilerConfiguration, HotSpotJVMCIRuntime jvmciRuntime, HotSpotBackend host) {
         assert host == null;
 
+        OptionValues options = runtime.getOptions();
         GraalHotSpotVMConfig config = runtime.getVMConfig();
         JVMCIBackend jvmci = jvmciRuntime.getHostJVMCIBackend();
         HotSpotRegistersProvider registers = createRegisters();
@@ -106,12 +107,13 @@
         BytecodeProvider bytecodeProvider = createBytecodeProvider(metaAccess, snippetReflection);
         HotSpotReplacementsImpl replacements = createReplacements(target, p, snippetReflection, bytecodeProvider);
         Plugins plugins = createGraphBuilderPlugins(runtime, compilerConfiguration, config, metaAccess, constantReflection, foreignCalls, snippetReflection, replacements, wordTypes,
-                        runtime.getOptions());
+                        runtime.getOptions(), target);
         replacements.setGraphBuilderPlugins(plugins);
         HotSpotSuitesProvider suites = createSuites(config, runtime, compilerConfiguration, plugins, replacements);
         HotSpotProviders providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, replacements, suites, registers,
                         snippetReflection, wordTypes, plugins, gc);
         replacements.setProviders(providers);
+        replacements.maybeInitializeEncoder(options);
 
         return createBackend(config, runtime, providers);
     }
@@ -125,7 +127,8 @@
                     HotSpotSnippetReflectionProvider snippetReflection,
                     HotSpotReplacementsImpl replacements,
                     HotSpotWordTypes wordTypes,
-                    OptionValues options) {
+                    OptionValues options,
+                    TargetDescription target) {
         Plugins plugins = HotSpotGraphBuilderPlugins.create(
                         graalRuntime,
                         compilerConfiguration,
@@ -136,8 +139,9 @@
                         snippetReflection,
                         foreignCalls,
                         replacements,
-                        options);
-        SPARCGraphBuilderPlugins.register(plugins, replacements.getDefaultReplacementBytecodeProvider(), false);
+                        options,
+                        target);
+        SPARCGraphBuilderPlugins.register(plugins, replacements, false);
         return plugins;
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CheckGraalIntrinsics.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CheckGraalIntrinsics.java	Thu Oct 31 16:54:16 2019 -0700
@@ -24,9 +24,6 @@
 
 package org.graalvm.compiler.hotspot.test;
 
-import static org.graalvm.compiler.hotspot.meta.HotSpotGraphBuilderPlugins.aesDecryptName;
-import static org.graalvm.compiler.hotspot.meta.HotSpotGraphBuilderPlugins.aesEncryptName;
-
 import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -368,10 +365,6 @@
                 add(ignore,
                                 "com/sun/crypto/provider/GHASH.processBlocks([BII[J[J)V");
             }
-            if (!(config.useSHA1Intrinsics() || config.useSHA256Intrinsics() || config.useSHA512Intrinsics())) {
-                add(ignore,
-                                "sun/security/provider/DigestBase.implCompressMultiBlock0([BII)I");
-            }
             if (!config.useFMAIntrinsics) {
                 add(ignore,
                                 "java/lang/Math.fma(DDD)D",
@@ -516,15 +509,16 @@
                             "java/util/zip/CRC32C.updateDirectByteBuffer(IJII)I");
         }
 
-        boolean implNames = HotSpotGraphBuilderPlugins.cbcUsesImplNames(config);
-        String cbcEncryptName = implNames ? "implEncrypt" : "encrypt";
-        String cbcDecryptName = implNames ? "implDecrypt" : "decrypt";
+        String cbcEncryptName = HotSpotGraphBuilderPlugins.lookupIntrinsicName(config, "com/sun/crypto/provider/CipherBlockChaining", "implEncrypt", "encrypt");
+        String cbcDecryptName = HotSpotGraphBuilderPlugins.lookupIntrinsicName(config, "com/sun/crypto/provider/CipherBlockChaining", "implDecrypt", "decrypt");
+        String aesEncryptName = HotSpotGraphBuilderPlugins.lookupIntrinsicName(config, "com/sun/crypto/provider/AESCrypt", "implEncryptBlock", "encryptBlock");
+        String aesDecryptName = HotSpotGraphBuilderPlugins.lookupIntrinsicName(config, "com/sun/crypto/provider/AESCrypt", "implDecryptBlock", "decryptBlock");
 
         // AES intrinsics
         if (!config.useAESIntrinsics) {
             add(ignore,
+                            "com/sun/crypto/provider/AESCrypt." + aesEncryptName + "([BI[BI)V",
                             "com/sun/crypto/provider/AESCrypt." + aesDecryptName + "([BI[BI)V",
-                            "com/sun/crypto/provider/AESCrypt." + aesEncryptName + "([BI[BI)V",
                             "com/sun/crypto/provider/CipherBlockChaining." + cbcDecryptName + "([BII[BI)I",
                             "com/sun/crypto/provider/CipherBlockChaining." + cbcEncryptName + "([BII[BI)I");
         }
@@ -549,28 +543,21 @@
         if (!config.useSquareToLenIntrinsic()) {
             add(ignore, "java/math/BigInteger.implSquareToLen([II[II)[I");
         }
-
+        // DigestBase intrinsics
+        if (HotSpotGraphBuilderPlugins.isIntrinsicName(config, "sun/security/provider/DigestBase", "implCompressMultiBlock0") &&
+                        !(config.useSHA1Intrinsics() || config.useSHA256Intrinsics() || config.useSHA512Intrinsics())) {
+            add(ignore, "sun/security/provider/DigestBase.implCompressMultiBlock0([BII)I");
+        }
         // SHA intrinsics
+        String shaCompressName = HotSpotGraphBuilderPlugins.lookupIntrinsicName(config, "sun/security/provider/SHA", "implCompress0", "implCompress");
         if (!config.useSHA1Intrinsics()) {
-            if (isJDK9OrHigher()) {
-                add(ignore, "sun/security/provider/SHA.implCompress0([BI)V");
-            } else {
-                add(ignore, "sun/security/provider/SHA.implCompress([BI)V");
-            }
+            add(ignore, "sun/security/provider/SHA." + shaCompressName + "([BI)V");
         }
         if (!config.useSHA256Intrinsics()) {
-            if (isJDK9OrHigher()) {
-                add(ignore, "sun/security/provider/SHA2.implCompress0([BI)V");
-            } else {
-                add(ignore, "sun/security/provider/SHA2.implCompress([BI)V");
-            }
+            add(ignore, "sun/security/provider/SHA2." + shaCompressName + "([BI)V");
         }
         if (!config.useSHA512Intrinsics()) {
-            if (isJDK9OrHigher()) {
-                add(ignore, "sun/security/provider/SHA5.implCompress0([BI)V");
-            } else {
-                add(ignore, "sun/security/provider/SHA5.implCompress([BI)V");
-            }
+            add(ignore, "sun/security/provider/SHA5." + shaCompressName + "([BI)V");
         }
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorld.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorld.java	Thu Oct 31 16:54:16 2019 -0700
@@ -101,10 +101,10 @@
 import org.graalvm.compiler.options.OptionsParser;
 import org.graalvm.compiler.serviceprovider.GraalUnsafeAccess;
 import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
-import org.graalvm.compiler.test.ModuleSupport;
+import org.graalvm.compiler.api.test.ModuleSupport;
 import jdk.internal.vm.compiler.libgraal.LibGraal;
 import jdk.internal.vm.compiler.libgraal.LibGraalScope;
-import jdk.internal.vm.compiler.libgraal.OptionsEncoder;
+import org.graalvm.util.OptionsEncoder;
 
 import jdk.vm.ci.hotspot.HotSpotCodeCacheProvider;
 import jdk.vm.ci.hotspot.HotSpotCompilationRequest;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ConstantPoolSubstitutionsTests.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ConstantPoolSubstitutionsTests.java	Thu Oct 31 16:54:16 2019 -0700
@@ -34,7 +34,7 @@
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
 import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
-import org.graalvm.compiler.test.ModuleSupport;
+import org.graalvm.compiler.api.test.ModuleSupport;
 import org.junit.BeforeClass;
 import org.junit.Test;
 import org.objectweb.asm.ClassWriter;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/DeferredBarrierAdditionTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/DeferredBarrierAdditionTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -38,7 +38,6 @@
 import org.graalvm.compiler.nodes.spi.LoweringTool;
 import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.phases.OptimisticOptimizations;
-import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.common.GuardLoweringPhase;
 import org.graalvm.compiler.phases.common.LoweringPhase;
 import org.graalvm.compiler.phases.common.WriteBarrierAdditionPhase;
@@ -83,12 +82,12 @@
             StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO, debug);
             HighTierContext highContext = getDefaultHighTierContext();
             MidTierContext midContext = new MidTierContext(getProviders(), getTargetProvider(), OptimisticOptimizations.ALL, graph.getProfilingInfo());
-            new InliningPhase(new InlineEverythingPolicy(), new CanonicalizerPhase()).apply(graph, highContext);
-            new CanonicalizerPhase().apply(graph, highContext);
-            new PartialEscapePhase(false, new CanonicalizerPhase(), debug.getOptions()).apply(graph, highContext);
-            new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, highContext);
+            new InliningPhase(new InlineEverythingPolicy(), createCanonicalizerPhase()).apply(graph, highContext);
+            this.createCanonicalizerPhase().apply(graph, highContext);
+            new PartialEscapePhase(false, createCanonicalizerPhase(), debug.getOptions()).apply(graph, highContext);
+            new LoweringPhase(createCanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, highContext);
             new GuardLoweringPhase().apply(graph, midContext);
-            new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.MID_TIER).apply(graph, midContext);
+            new LoweringPhase(createCanonicalizerPhase(), LoweringTool.StandardLoweringStage.MID_TIER).apply(graph, midContext);
             new WriteBarrierAdditionPhase().apply(graph, midContext);
             debug.dump(DebugContext.BASIC_LEVEL, graph, "After Write Barrier Addition");
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotCryptoSubstitutionTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotCryptoSubstitutionTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -80,7 +80,9 @@
 
     @Test
     public void testAESCryptIntrinsics() throws Exception {
-        if (compileAndInstall("com.sun.crypto.provider.AESCrypt", HotSpotGraphBuilderPlugins.aesEncryptName, HotSpotGraphBuilderPlugins.aesDecryptName)) {
+        String aesEncryptName = HotSpotGraphBuilderPlugins.lookupIntrinsicName(runtime().getVMConfig(), "com/sun/crypto/provider/AESCrypt", "implEncryptBlock", "encryptBlock");
+        String aesDecryptName = HotSpotGraphBuilderPlugins.lookupIntrinsicName(runtime().getVMConfig(), "com/sun/crypto/provider/AESCrypt", "implDecryptBlock", "decryptBlock");
+        if (compileAndInstall("com.sun.crypto.provider.AESCrypt", aesEncryptName, aesDecryptName)) {
             ByteArrayOutputStream actual = new ByteArrayOutputStream();
             actual.write(runEncryptDecrypt(aesKey, "AES/CBC/NoPadding"));
             actual.write(runEncryptDecrypt(aesKey, "AES/CBC/PKCS5Padding"));
@@ -90,9 +92,8 @@
 
     @Test
     public void testCipherBlockChainingIntrinsics() throws Exception {
-        boolean implNames = HotSpotGraphBuilderPlugins.cbcUsesImplNames(runtime().getVMConfig());
-        String cbcEncryptName = implNames ? "implEncrypt" : "encrypt";
-        String cbcDecryptName = implNames ? "implDecrypt" : "decrypt";
+        String cbcEncryptName = HotSpotGraphBuilderPlugins.lookupIntrinsicName(runtime().getVMConfig(), "com/sun/crypto/provider/CipherBlockChaining", "implEncrypt", "encrypt");
+        String cbcDecryptName = HotSpotGraphBuilderPlugins.lookupIntrinsicName(runtime().getVMConfig(), "com/sun/crypto/provider/CipherBlockChaining", "implDecrypt", "decrypt");
         if (compileAndInstall("com.sun.crypto.provider.CipherBlockChaining", cbcEncryptName, cbcDecryptName)) {
             ByteArrayOutputStream actual = new ByteArrayOutputStream();
             actual.write(runEncryptDecrypt(aesKey, "AES/CBC/NoPadding"));
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotInvokeDynamicPluginTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotInvokeDynamicPluginTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -93,7 +93,7 @@
         StructuredGraph graph = parseEager(name, AllowAssumptions.NO, new OptionValues(getInitialOptions(), GraalOptions.GeneratePIC, true));
         MidTierContext midTierContext = new MidTierContext(getProviders(), getTargetProvider(), OptimisticOptimizations.ALL, graph.getProfilingInfo());
 
-        CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+        CanonicalizerPhase canonicalizer = createCanonicalizerPhase();
         Assert.assertEquals(expectedResolves, graph.getNodes().filter(ResolveDynamicConstantNode.class).count());
         Assert.assertEquals(0, graph.getNodes().filter(ResolveDynamicStubCall.class).count());
         CoreProviders context = getProviders();
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ReplaceConstantNodesPhaseTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ReplaceConstantNodesPhaseTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -117,7 +117,7 @@
     private void test(String name, int expectedInits, int expectedResolves, int expectedLoads) {
         StructuredGraph graph = parseEager(name, AllowAssumptions.NO, new OptionValues(getInitialOptions(), GraalOptions.GeneratePIC, true));
         HighTierContext highTierContext = getDefaultHighTierContext();
-        CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+        CanonicalizerPhase canonicalizer = createCanonicalizerPhase();
         new EliminateRedundantInitializationPhase().apply(graph, highTierContext);
         new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, highTierContext);
         new LoadJavaMirrorWithKlassPhase(config).apply(graph, highTierContext);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/TestSHASubstitutions.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/TestSHASubstitutions.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2019, 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
@@ -34,9 +34,7 @@
 import org.graalvm.compiler.api.test.Graal;
 import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
 import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
-import org.graalvm.compiler.hotspot.replacements.SHA2Substitutions;
-import org.graalvm.compiler.hotspot.replacements.SHA5Substitutions;
-import org.graalvm.compiler.hotspot.replacements.SHASubstitutions;
+import org.graalvm.compiler.hotspot.meta.HotSpotGraphBuilderPlugins;
 import org.graalvm.compiler.runtime.RuntimeProvider;
 
 import jdk.vm.ci.code.InstalledCode;
@@ -74,7 +72,8 @@
     @Test
     public void testSha1() {
         if (getConfig().useSHA1Intrinsics()) {
-            testWithInstalledIntrinsic("sun.security.provider.SHA", SHASubstitutions.implCompressName, "testDigest", "SHA-1", getData());
+            String implCompressName = HotSpotGraphBuilderPlugins.lookupIntrinsicName(getConfig(), "sun/security/provider/SHA", "implCompress0", "implCompress");
+            testWithInstalledIntrinsic("sun.security.provider.SHA", implCompressName, "testDigest", "SHA-1", getData());
         }
     }
 
@@ -107,14 +106,16 @@
     @Test
     public void testSha256() {
         if (getConfig().useSHA256Intrinsics()) {
-            testWithInstalledIntrinsic("sun.security.provider.SHA2", SHA2Substitutions.implCompressName, "testDigest", "SHA-256", getData());
+            String implCompressName = HotSpotGraphBuilderPlugins.lookupIntrinsicName(getConfig(), "sun/security/provider/SHA", "implCompress0", "implCompress");
+            testWithInstalledIntrinsic("sun.security.provider.SHA2", implCompressName, "testDigest", "SHA-256", getData());
         }
     }
 
     @Test
     public void testSha512() {
         if (getConfig().useSHA512Intrinsics()) {
-            testWithInstalledIntrinsic("sun.security.provider.SHA5", SHA5Substitutions.implCompressName, "testDigest", "SHA-512", getData());
+            String implCompressName = HotSpotGraphBuilderPlugins.lookupIntrinsicName(getConfig(), "sun/security/provider/SHA", "implCompress0", "implCompress");
+            testWithInstalledIntrinsic("sun.security.provider.SHA5", implCompressName, "testDigest", "SHA-512", getData());
         }
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/WriteBarrierAdditionTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/WriteBarrierAdditionTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -44,7 +44,6 @@
 import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
 import org.graalvm.compiler.nodes.spi.LoweringTool;
 import org.graalvm.compiler.phases.OptimisticOptimizations;
-import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.common.GuardLoweringPhase;
 import org.graalvm.compiler.phases.common.LoweringPhase;
 import org.graalvm.compiler.phases.common.WriteBarrierAdditionPhase;
@@ -263,11 +262,11 @@
             StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO, debug);
             HighTierContext highContext = getDefaultHighTierContext();
             MidTierContext midContext = new MidTierContext(getProviders(), getTargetProvider(), OptimisticOptimizations.ALL, graph.getProfilingInfo());
-            new InliningPhase(new InlineEverythingPolicy(), new CanonicalizerPhase()).apply(graph, highContext);
-            new CanonicalizerPhase().apply(graph, highContext);
-            new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, highContext);
+            new InliningPhase(new InlineEverythingPolicy(), createCanonicalizerPhase()).apply(graph, highContext);
+            this.createCanonicalizerPhase().apply(graph, highContext);
+            new LoweringPhase(this.createCanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, highContext);
             new GuardLoweringPhase().apply(graph, midContext);
-            new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.MID_TIER).apply(graph, midContext);
+            new LoweringPhase(this.createCanonicalizerPhase(), LoweringTool.StandardLoweringStage.MID_TIER).apply(graph, midContext);
             new WriteBarrierAdditionPhase().apply(graph, midContext);
             debug.dump(DebugContext.BASIC_LEVEL, graph, "After Write Barrier Addition");
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotReplacementsImpl.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotReplacementsImpl.java	Thu Oct 31 16:54:16 2019 -0700
@@ -72,26 +72,40 @@
                         replacements.getDefaultReplacementBytecodeProvider(), replacements.target);
     }
 
+    public void maybeInitializeEncoder(OptionValues options) {
+        if (IS_BUILDING_NATIVE_IMAGE || UseEncodedGraphs.getValue(options)) {
+            synchronized (HotSpotReplacementsImpl.class) {
+                if (snippetEncoder == null) {
+                    snippetEncoder = new SymbolicSnippetEncoder(this);
+                }
+            }
+        }
+    }
+
     @Override
     public Class<? extends GraphBuilderPlugin> getIntrinsifyingPlugin(ResolvedJavaMethod method) {
         return method.getAnnotation(HotSpotOperation.class) != null ? HotSpotWordOperationPlugin.class : super.getIntrinsifyingPlugin(method);
     }
 
     @Override
-    public void registerMethodSubstitution(MethodSubstitutionPlugin plugin, ResolvedJavaMethod original, IntrinsicContext.CompilationContext context, OptionValues options) {
-        if (!IS_IN_NATIVE_IMAGE) {
-            if (IS_BUILDING_NATIVE_IMAGE || UseEncodedGraphs.getValue(options)) {
-                synchronized (HotSpotReplacementsImpl.class) {
-                    if (snippetEncoder == null) {
-                        snippetEncoder = new SymbolicSnippetEncoder(this);
-                    }
-                    snippetEncoder.registerMethodSubstitution(plugin, original, context, options);
-                }
-            }
+    public void registerMethodSubstitution(MethodSubstitutionPlugin plugin) {
+        if (snippetEncoder != null) {
+            snippetEncoder.registerMethodSubstitution(plugin);
         }
     }
 
     @Override
+    public void registerConditionalPlugin(InvocationPlugin plugin) {
+        if (snippetEncoder != null) {
+            snippetEncoder.registerConditionalPlugin(plugin);
+        }
+    }
+
+    public void checkRegistered(MethodSubstitutionPlugin plugin) {
+        snippetEncoder.checkRegistered(plugin);
+    }
+
+    @Override
     public StructuredGraph getIntrinsicGraph(ResolvedJavaMethod method, CompilationIdentifier compilationId, DebugContext debug, Cancellable cancellable) {
         boolean useEncodedGraphs = UseEncodedGraphs.getValue(debug.getOptions());
         if (IS_IN_NATIVE_IMAGE || useEncodedGraphs) {
@@ -99,8 +113,9 @@
             InvocationPlugin plugin = replacements.getGraphBuilderPlugins().getInvocationPlugins().lookupInvocation(method);
             if (plugin instanceof MethodSubstitutionPlugin) {
                 MethodSubstitutionPlugin msp = (MethodSubstitutionPlugin) plugin;
-                if (useEncodedGraphs) {
-                    replacements.registerMethodSubstitution(msp, method, ROOT_COMPILATION, debug.getOptions());
+                if (!IS_IN_NATIVE_IMAGE && useEncodedGraphs) {
+                    replacements.maybeInitializeEncoder(debug.getOptions());
+                    replacements.registerMethodSubstitution(msp);
                 }
                 StructuredGraph methodSubstitution = replacements.getMethodSubstitution(msp, method, ROOT_COMPILATION, StructuredGraph.AllowAssumptions.YES, cancellable, debug.getOptions());
                 methodSubstitution.resetDebug(debug);
@@ -119,7 +134,8 @@
             if (plugin instanceof MethodSubstitutionPlugin && (!plugin.inlineOnly() || invokeBci >= 0)) {
                 MethodSubstitutionPlugin msPlugin = (MethodSubstitutionPlugin) plugin;
                 if (!IS_IN_NATIVE_IMAGE && useEncodedGraphs) {
-                    registerMethodSubstitution(msPlugin, targetMethod, INLINE_AFTER_PARSING, options);
+                    maybeInitializeEncoder(options);
+                    registerMethodSubstitution(msPlugin);
                 }
                 // This assumes the normal path creates the graph using
                 // GraphBuilderConfiguration.getSnippetDefault with omits exception edges
@@ -155,9 +171,6 @@
             assert registeredSnippets.add(method) : "Cannot register snippet twice: " + method.format("%H.%n(%p)");
             if (IS_BUILDING_NATIVE_IMAGE || UseEncodedGraphs.getValue(options)) {
                 synchronized (HotSpotReplacementsImpl.class) {
-                    if (snippetEncoder == null) {
-                        snippetEncoder = new SymbolicSnippetEncoder(this);
-                    }
                     snippetEncoder.registerSnippet(method, original, receiver, trackNodeSourcePosition, options);
                 }
             }
@@ -169,7 +182,10 @@
         snippetRegistrationClosed = true;
     }
 
-    private static SymbolicSnippetEncoder.EncodedSnippets getEncodedSnippets() {
+    private static SymbolicSnippetEncoder.EncodedSnippets getEncodedSnippets(OptionValues options) {
+        if (!IS_IN_NATIVE_IMAGE && snippetEncoder != null) {
+            snippetEncoder.encode(options);
+        }
         return encodedSnippets;
     }
 
@@ -210,20 +226,15 @@
 
     @SuppressWarnings("try")
     private StructuredGraph getEncodedSnippet(ResolvedJavaMethod method, Object[] args, StructuredGraph.AllowAssumptions allowAssumptions, OptionValues options) {
-        boolean useEncodedGraphs = UseEncodedGraphs.getValue(options);
-        if (IS_IN_NATIVE_IMAGE || useEncodedGraphs) {
+        if (IS_IN_NATIVE_IMAGE || UseEncodedGraphs.getValue(options)) {
             synchronized (HotSpotReplacementsImpl.class) {
-                if (!IS_IN_NATIVE_IMAGE) {
-                    snippetEncoder.encode(options);
-                }
-
-                if (getEncodedSnippets() == null) {
+                if (getEncodedSnippets(options) == null) {
                     throw GraalError.shouldNotReachHere("encoded snippets not found");
                 }
                 // Snippets graphs can contain foreign object reference and
                 // outlive a single compilation.
                 try (CompilationContext scope = HotSpotGraalServices.enterGlobalCompilationContext()) {
-                    StructuredGraph graph = getEncodedSnippets().getEncodedSnippet(method, this, args, allowAssumptions, options);
+                    StructuredGraph graph = getEncodedSnippets(options).getEncodedSnippet(method, this, args, allowAssumptions, options);
                     if (graph == null) {
                         throw GraalError.shouldNotReachHere("snippet not found: " + method.format("%H.%n(%p)"));
                     }
@@ -239,16 +250,11 @@
     @Override
     public StructuredGraph getMethodSubstitution(MethodSubstitutionPlugin plugin, ResolvedJavaMethod original, IntrinsicContext.CompilationContext context,
                     StructuredGraph.AllowAssumptions allowAssumptions, Cancellable cancellable, OptionValues options) {
-        boolean useEncodedGraphs = UseEncodedGraphs.getValue(options);
-        if (IS_IN_NATIVE_IMAGE || useEncodedGraphs) {
-            if (!IS_IN_NATIVE_IMAGE) {
-                snippetEncoder.encode(options);
-            }
-
-            if (getEncodedSnippets() == null) {
+        if (IS_IN_NATIVE_IMAGE || UseEncodedGraphs.getValue(options)) {
+            if (getEncodedSnippets(options) == null) {
                 throw GraalError.shouldNotReachHere("encoded snippets not found");
             }
-            return getEncodedSnippets().getMethodSubstitutionGraph(plugin, original, this, context, allowAssumptions, cancellable, options);
+            return getEncodedSnippets(options).getMethodSubstitutionGraph(plugin, original, this, context, allowAssumptions, cancellable, options);
         }
         return null;
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/SymbolicSnippetEncoder.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/SymbolicSnippetEncoder.java	Thu Oct 31 16:54:16 2019 -0700
@@ -30,6 +30,7 @@
 import static org.graalvm.compiler.core.common.GraalOptions.UseEncodedGraphs;
 import static org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin.InlineInfo.createIntrinsicInlineInfo;
 import static org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.INLINE_AFTER_PARSING;
+import static org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.ROOT_COMPILATION;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -156,6 +157,12 @@
      */
     private Map<String, StructuredGraph> preparedSnippetGraphs = new HashMap<>();
 
+    private Set<MethodSubstitutionPlugin> knownPlugins = new HashSet<>();
+
+    private Set<InvocationPlugin> conditionalPlugins = new HashSet<>();
+
+    private int preparedPlugins = 0;
+
     /**
      * The invocation plugins which were delayed during graph preparation.
      */
@@ -239,7 +246,7 @@
      * for lookup.
      */
     private static String methodKey(ResolvedJavaMethod method) {
-        return method.format("%f %H.%n(%P)");
+        return method.format("%H.%n(%P)");
     }
 
     SymbolicSnippetEncoder(HotSpotReplacementsImpl replacements) {
@@ -255,15 +262,30 @@
         this.snippetReplacements.setGraphBuilderPlugins(copy);
     }
 
+    synchronized void registerMethodSubstitution(MethodSubstitutionPlugin plugin) {
+        knownPlugins.add(plugin);
+    }
+
+    void registerConditionalPlugin(InvocationPlugin plugin) {
+        conditionalPlugins.add(plugin);
+    }
+
+    synchronized void checkRegistered(MethodSubstitutionPlugin plugin) {
+        if (!knownPlugins.contains(plugin)) {
+            throw new GraalError("missing plugin should have been registered during construction");
+        }
+    }
+
     /**
      * Compiles the snippet and stores the graph.
      */
-    synchronized void registerMethodSubstitution(MethodSubstitutionPlugin plugin, ResolvedJavaMethod original, IntrinsicContext.CompilationContext context, OptionValues options) {
+    private synchronized void registerMethodSubstitution(MethodSubstitutionPlugin plugin, ResolvedJavaMethod original, IntrinsicContext.CompilationContext context, OptionValues options) {
         ResolvedJavaMethod method = plugin.getSubstitute(snippetReplacements.getProviders().getMetaAccess());
         assert method.getAnnotation(MethodSubstitution.class) != null : "MethodSubstitution must be annotated with @" + MethodSubstitution.class.getSimpleName();
-        StructuredGraph subst = buildGraph(method, original, null, true, false, context, options);
+        String originalMethodString = plugin.originalMethodAsString();
+        StructuredGraph subst = buildGraph(method, original, originalMethodString, null, true, false, context, options);
         snippetMethods.add(method);
-        originalMethods.put(methodKey(method), methodKey(original));
+        originalMethods.put(methodKey(method), originalMethodString);
         preparedSnippetGraphs.put(plugin.toString() + context, subst);
     }
 
@@ -370,7 +392,7 @@
         }
     }
 
-    private StructuredGraph buildGraph(ResolvedJavaMethod method, ResolvedJavaMethod original, Object receiver, boolean requireInlining, boolean trackNodeSourcePosition,
+    private StructuredGraph buildGraph(ResolvedJavaMethod method, ResolvedJavaMethod original, String originalMethodString, Object receiver, boolean requireInlining, boolean trackNodeSourcePosition,
                     IntrinsicContext.CompilationContext context, OptionValues options) {
         assert method.hasBytecodes() : "Snippet must not be abstract or native";
         Object[] args = null;
@@ -378,7 +400,13 @@
             args = new Object[method.getSignature().getParameterCount(true)];
             args[0] = receiver;
         }
-        try (DebugContext debug = openDebugContext("Snippet_", method, options)) {
+        // To get dumping out from this context during image building, it's necessary to pass the
+        // dumping options directly to the VM, otherwise they aren't available during initialization
+        // of the backend. Use this:
+        //
+        // -J-Dgraal.Dump=SymbolicSnippetEncoder_:2 -J-Dgraal.PrintGraph=File
+        // -J-Dgraal.DebugStubsAndSnippets=true
+        try (DebugContext debug = openDebugContext("SymbolicSnippetEncoder_", method, options)) {
             StructuredGraph graph = snippetReplacements.makeGraph(debug, snippetReplacements.getDefaultReplacementBytecodeProvider(), method, args, original, trackNodeSourcePosition, null, context);
 
             // Check if all methods which should be inlined are really inlined.
@@ -388,7 +416,7 @@
                     throw GraalError.shouldNotReachHere("method " + callee.format("%H.%n") + " not inlined in snippet " + method.getName() + " (maybe not final?)");
                 }
             }
-            assert verifySnippetEncodeDecode(method, original, trackNodeSourcePosition, graph);
+            assert verifySnippetEncodeDecode(debug, method, original, originalMethodString, trackNodeSourcePosition, graph);
             debug.dump(DebugContext.VERBOSE_LEVEL, graph, "After buildGraph");
             return graph;
         }
@@ -426,46 +454,45 @@
     }
 
     @SuppressWarnings("try")
-    private boolean verifySnippetEncodeDecode(ResolvedJavaMethod method, ResolvedJavaMethod original, boolean trackNodeSourcePosition, StructuredGraph graph) {
+    private boolean verifySnippetEncodeDecode(DebugContext debug, ResolvedJavaMethod method, ResolvedJavaMethod original, String originalMethodString, boolean trackNodeSourcePosition,
+                    StructuredGraph graph) {
         // Verify the encoding and decoding process
         EncodedGraph encodedGraph = GraphEncoder.encodeSingleGraph(graph, HotSpotJVMCIRuntime.runtime().getHostJVMCIBackend().getTarget().arch);
 
-        try (DebugContext debug = snippetReplacements.openDebugContext("VerifySnippetEncodeDecode_", method, graph.getOptions())) {
-            HotSpotProviders originalProvider = (HotSpotProviders) snippetReplacements.getProviders();
+        HotSpotProviders originalProvider = (HotSpotProviders) snippetReplacements.getProviders();
 
-            SnippetReflectionProvider snippetReflection = originalProvider.getSnippetReflection();
-            SymbolicSnippetEncoder.HotSpotSubstrateConstantReflectionProvider constantReflection = new SymbolicSnippetEncoder.HotSpotSubstrateConstantReflectionProvider(
-                            originalProvider.getConstantReflection());
-            HotSpotProviders newProviders = new HotSpotProviders(originalProvider.getMetaAccess(), originalProvider.getCodeCache(), constantReflection,
-                            originalProvider.getConstantFieldProvider(), originalProvider.getForeignCalls(), originalProvider.getLowerer(), null, originalProvider.getSuites(),
-                            originalProvider.getRegisters(), snippetReflection, originalProvider.getWordTypes(), originalProvider.getGraphBuilderPlugins(), originalProvider.getGC());
-            HotSpotSnippetReplacementsImpl filteringReplacements = new HotSpotSnippetReplacementsImpl(newProviders, snippetReflection,
-                            originalProvider.getReplacements().getDefaultReplacementBytecodeProvider(), originalProvider.getCodeCache().getTarget());
-            filteringReplacements.setGraphBuilderPlugins(originalProvider.getReplacements().getGraphBuilderPlugins());
-            try (DebugContext.Scope scaope = debug.scope("VerifySnippetEncodeDecode", graph)) {
-                for (int i = 0; i < encodedGraph.getNumObjects(); i++) {
-                    filterSnippetObject(encodedGraph.getObject(i));
-                }
-                StructuredGraph snippet = filteringReplacements.makeGraph(debug, filteringReplacements.getDefaultReplacementBytecodeProvider(), method, null, original,
-                                trackNodeSourcePosition, null);
-                SymbolicEncodedGraph symbolicGraph = new SymbolicEncodedGraph(encodedGraph, method.getDeclaringClass(), original != null ? methodKey(original) : null);
-                StructuredGraph decodedSnippet = decodeSnippetGraph(symbolicGraph, original != null ? original : method, originalReplacements, null,
-                                StructuredGraph.AllowAssumptions.ifNonNull(graph.getAssumptions()), graph.getOptions());
-                String snippetString = getCanonicalGraphString(snippet, true, false);
-                String decodedSnippetString = getCanonicalGraphString(decodedSnippet, true, false);
-                if (snippetString.equals(decodedSnippetString)) {
-                    debug.log("Snippet decode for %s produces exactly same graph", method);
-                    debug.dump(DebugContext.VERBOSE_LEVEL, decodedSnippet, "Decoded snippet graph for %s", method);
-                } else {
-                    debug.log("Snippet decode for %s produces different graph", method);
-                    debug.log("%s", compareGraphStrings(snippet, snippetString, decodedSnippet, decodedSnippetString));
-                    debug.dump(DebugContext.VERBOSE_LEVEL, snippet, "Snippet graph for %s", method);
-                    debug.dump(DebugContext.VERBOSE_LEVEL, graph, "Encoded snippet graph for %s", method);
-                    debug.dump(DebugContext.VERBOSE_LEVEL, decodedSnippet, "Decoded snippet graph for %s", method);
-                }
-            } catch (Throwable t) {
-                throw debug.handle(t);
+        SnippetReflectionProvider snippetReflection = originalProvider.getSnippetReflection();
+        SymbolicSnippetEncoder.HotSpotSubstrateConstantReflectionProvider constantReflection = new SymbolicSnippetEncoder.HotSpotSubstrateConstantReflectionProvider(
+                        originalProvider.getConstantReflection());
+        HotSpotProviders newProviders = new HotSpotProviders(originalProvider.getMetaAccess(), originalProvider.getCodeCache(), constantReflection,
+                        originalProvider.getConstantFieldProvider(), originalProvider.getForeignCalls(), originalProvider.getLowerer(), null, originalProvider.getSuites(),
+                        originalProvider.getRegisters(), snippetReflection, originalProvider.getWordTypes(), originalProvider.getGraphBuilderPlugins(), originalProvider.getGC());
+        HotSpotSnippetReplacementsImpl filteringReplacements = new HotSpotSnippetReplacementsImpl(newProviders, snippetReflection,
+                        originalProvider.getReplacements().getDefaultReplacementBytecodeProvider(), originalProvider.getCodeCache().getTarget());
+        filteringReplacements.setGraphBuilderPlugins(originalProvider.getReplacements().getGraphBuilderPlugins());
+        try (DebugContext.Scope scaope = debug.scope("VerifySnippetEncodeDecode", graph)) {
+            for (int i = 0; i < encodedGraph.getNumObjects(); i++) {
+                filterSnippetObject(encodedGraph.getObject(i));
             }
+            StructuredGraph snippet = filteringReplacements.makeGraph(debug, filteringReplacements.getDefaultReplacementBytecodeProvider(), method, null, original,
+                            trackNodeSourcePosition, null);
+            SymbolicEncodedGraph symbolicGraph = new SymbolicEncodedGraph(encodedGraph, method.getDeclaringClass(), originalMethodString);
+            StructuredGraph decodedSnippet = decodeSnippetGraph(symbolicGraph, original != null ? original : method, originalReplacements, null,
+                            StructuredGraph.AllowAssumptions.ifNonNull(graph.getAssumptions()), graph.getOptions());
+            String snippetString = getCanonicalGraphString(snippet, true, false);
+            String decodedSnippetString = getCanonicalGraphString(decodedSnippet, true, false);
+            if (snippetString.equals(decodedSnippetString)) {
+                debug.log("Snippet decode for %s produces exactly same graph", method);
+                debug.dump(DebugContext.VERBOSE_LEVEL, decodedSnippet, "Decoded snippet graph for %s", method);
+            } else {
+                debug.log("Snippet decode for %s produces different graph", method);
+                debug.log("%s", compareGraphStrings(snippet, snippetString, decodedSnippet, decodedSnippetString));
+                debug.dump(DebugContext.VERBOSE_LEVEL, snippet, "Snippet graph for %s", method);
+                debug.dump(DebugContext.VERBOSE_LEVEL, graph, "Encoded snippet graph for %s", method);
+                debug.dump(DebugContext.VERBOSE_LEVEL, decodedSnippet, "Decoded snippet graph for %s", method);
+            }
+        } catch (Throwable t) {
+            throw debug.handle(t);
         }
         return true;
     }
@@ -475,6 +502,17 @@
      */
     @SuppressWarnings("try")
     private synchronized EncodedSnippets maybeEncodeSnippets(OptionValues options) {
+        Set<MethodSubstitutionPlugin> plugins = this.knownPlugins;
+        if (preparedPlugins != plugins.size()) {
+            for (MethodSubstitutionPlugin plugin : plugins) {
+                ResolvedJavaMethod original = plugin.getOriginalMethod(originalReplacements.getProviders().getMetaAccess());
+                registerMethodSubstitution(plugin, original, INLINE_AFTER_PARSING, options);
+                if (!original.isNative()) {
+                    registerMethodSubstitution(plugin, original, ROOT_COMPILATION, options);
+                }
+            }
+            preparedPlugins = plugins.size();
+        }
         Map<String, StructuredGraph> graphs = this.preparedSnippetGraphs;
         if (encodedGraphs != graphs.size()) {
             DebugContext debug = openDebugContext("SnippetEncoder", null, options);
@@ -499,7 +537,7 @@
                 if (original != null) {
                     originalMethods.put(key, methodKey(original));
                 }
-                StructuredGraph snippet = buildGraph(method, original, receiver, true, trackNodeSourcePosition, INLINE_AFTER_PARSING, options);
+                StructuredGraph snippet = buildGraph(method, original, null, receiver, true, trackNodeSourcePosition, INLINE_AFTER_PARSING, options);
                 snippetMethods.add(method);
                 preparedSnippetGraphs.put(key, snippet);
             }
@@ -1001,7 +1039,7 @@
      * This horror show of classes exists solely get {@link HotSpotSnippetBytecodeParser} to be used
      * as the parser for these snippets.
      */
-    static class HotSpotSnippetReplacementsImpl extends HotSpotReplacementsImpl {
+    class HotSpotSnippetReplacementsImpl extends HotSpotReplacementsImpl {
         HotSpotSnippetReplacementsImpl(HotSpotReplacementsImpl replacements, Providers providers) {
             super(replacements, providers);
         }
@@ -1016,7 +1054,7 @@
         }
     }
 
-    static class SnippetGraphMaker extends ReplacementsImpl.GraphMaker {
+    class SnippetGraphMaker extends ReplacementsImpl.GraphMaker {
         SnippetGraphMaker(ReplacementsImpl replacements, ResolvedJavaMethod substitute, ResolvedJavaMethod substitutedMethod) {
             super(replacements, substitute, substitutedMethod);
         }
@@ -1028,7 +1066,7 @@
         }
     }
 
-    static class HotSpotSnippetGraphBuilderPhase extends GraphBuilderPhase.Instance {
+    class HotSpotSnippetGraphBuilderPhase extends GraphBuilderPhase.Instance {
         HotSpotSnippetGraphBuilderPhase(Providers theProviders, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, IntrinsicContext initialIntrinsicContext) {
             super(theProviders, graphBuilderConfig, optimisticOpts, initialIntrinsicContext);
         }
@@ -1039,7 +1077,7 @@
         }
     }
 
-    static class HotSpotSnippetBytecodeParser extends BytecodeParser {
+    class HotSpotSnippetBytecodeParser extends BytecodeParser {
         HotSpotSnippetBytecodeParser(GraphBuilderPhase.Instance graphBuilderInstance, StructuredGraph graph, BytecodeParser parent, ResolvedJavaMethod method, int entryBCI,
                         IntrinsicContext intrinsicContext) {
             super(graphBuilderInstance, graph, parent, method, entryBCI, intrinsicContext);
@@ -1066,6 +1104,13 @@
                 // Always defer Fold until decode time but NodeIntrinsics may fold if they are able.
                 return false;
             }
+            InvocationPlugin plugin = graphBuilderConfig.getPlugins().getInvocationPlugins().lookupInvocation(targetMethod);
+            if (conditionalPlugins.contains(plugin)) {
+                // Because supporting arbitrary plugins in the context of encoded graphs is complex
+                // we disallow it. This limitation can be worked around through the use of method
+                // substitutions.
+                throw new GraalError("conditional plugins are unsupported in snippets and method substitutions: " + targetMethod + " " + plugin);
+            }
             return super.tryInvocationPlugin(invokeKind, args, targetMethod, resultType);
         }
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java	Thu Oct 31 16:54:16 2019 -0700
@@ -646,7 +646,7 @@
 
                 // write the displaced mark to the correct stack slot
                 AddressNode addressDisplacedMark = createOffsetAddress(graph, beginLockScope, runtime.getVMConfig().basicLockDisplacedHeaderOffset);
-                WriteNode writeStackSlot = graph.add(new WriteNode(addressDisplacedMark, DISPLACED_MARK_WORD_LOCATION, loadDisplacedHeader, BarrierType.NONE));
+                WriteNode writeStackSlot = graph.add(new WriteNode(addressDisplacedMark, DISPLACED_MARK_WORD_LOCATION, loadDisplacedHeader, BarrierType.NONE, false));
                 graph.addBeforeFixed(migrationEnd, writeStackSlot);
 
                 // load the lock object from the osr buffer
@@ -776,7 +776,7 @@
         }
 
         AddressNode address = createOffsetAddress(graph, object, runtime.getVMConfig().hubOffset);
-        return graph.add(new WriteNode(address, HUB_WRITE_LOCATION, writeValue, BarrierType.NONE));
+        return graph.add(new WriteNode(address, HUB_WRITE_LOCATION, writeValue, BarrierType.NONE, false));
     }
 
     @Override
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java	Thu Oct 31 16:54:16 2019 -0700
@@ -39,7 +39,6 @@
 import java.util.zip.CRC32;
 
 import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
-import org.graalvm.compiler.bytecode.BytecodeProvider;
 import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
 import org.graalvm.compiler.core.common.type.ObjectStamp;
 import org.graalvm.compiler.core.common.type.StampFactory;
@@ -92,6 +91,7 @@
 import org.graalvm.compiler.nodes.memory.ReadNode;
 import org.graalvm.compiler.nodes.memory.address.AddressNode;
 import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
+import org.graalvm.compiler.nodes.spi.Replacements;
 import org.graalvm.compiler.nodes.util.GraphUtil;
 import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.phases.tiers.CompilerConfiguration;
@@ -108,6 +108,7 @@
 import jdk.internal.vm.compiler.word.LocationIdentity;
 
 import jdk.vm.ci.code.CodeUtil;
+import jdk.vm.ci.code.TargetDescription;
 import jdk.vm.ci.hotspot.VMIntrinsicMethod;
 import jdk.vm.ci.meta.ConstantReflectionProvider;
 import jdk.vm.ci.meta.DeoptimizationAction;
@@ -128,6 +129,7 @@
      * @param snippetReflection
      * @param foreignCalls
      * @param options
+     * @param target
      */
     public static Plugins create(HotSpotGraalRuntimeProvider graalRuntime,
                     CompilerConfiguration compilerConfiguration,
@@ -138,11 +140,11 @@
                     SnippetReflectionProvider snippetReflection,
                     ForeignCallsProvider foreignCalls,
                     ReplacementsImpl replacements,
-                    OptionValues options) {
+                    OptionValues options, TargetDescription target) {
         InvocationPlugins invocationPlugins = new HotSpotInvocationPlugins(graalRuntime, config, compilerConfiguration);
 
         Plugins plugins = new Plugins(invocationPlugins);
-        NodeIntrinsificationProvider nodeIntrinsificationProvider = new NodeIntrinsificationProvider(metaAccess, snippetReflection, foreignCalls, wordTypes);
+        NodeIntrinsificationProvider nodeIntrinsificationProvider = new NodeIntrinsificationProvider(metaAccess, snippetReflection, foreignCalls, wordTypes, target);
         HotSpotWordOperationPlugin wordOperationPlugin = new HotSpotWordOperationPlugin(snippetReflection, wordTypes);
         HotSpotNodePlugin nodePlugin = new HotSpotNodePlugin(wordOperationPlugin, config, wordTypes);
 
@@ -171,29 +173,28 @@
 
             @Override
             public void run() {
-                BytecodeProvider replacementBytecodeProvider = replacements.getDefaultReplacementBytecodeProvider();
-                registerObjectPlugins(invocationPlugins, options, config, replacementBytecodeProvider);
-                registerClassPlugins(plugins, config, replacementBytecodeProvider);
+                registerObjectPlugins(invocationPlugins, options, config, replacements);
+                registerClassPlugins(plugins, config, replacements);
                 registerSystemPlugins(invocationPlugins, foreignCalls);
-                registerThreadPlugins(invocationPlugins, metaAccess, wordTypes, config, replacementBytecodeProvider);
+                registerThreadPlugins(invocationPlugins, metaAccess, wordTypes, config, replacements);
                 if (!GeneratePIC.getValue(options)) {
                     registerCallSitePlugins(invocationPlugins);
                 }
-                registerReflectionPlugins(invocationPlugins, replacementBytecodeProvider);
-                registerConstantPoolPlugins(invocationPlugins, wordTypes, config, replacementBytecodeProvider);
-                registerAESPlugins(invocationPlugins, config, replacementBytecodeProvider);
-                registerCRC32Plugins(invocationPlugins, config, replacementBytecodeProvider);
-                registerCRC32CPlugins(invocationPlugins, config, replacementBytecodeProvider);
-                registerBigIntegerPlugins(invocationPlugins, config, replacementBytecodeProvider);
-                registerSHAPlugins(invocationPlugins, config, replacementBytecodeProvider);
+                registerReflectionPlugins(invocationPlugins, replacements);
+                registerConstantPoolPlugins(invocationPlugins, wordTypes, config, replacements);
+                registerAESPlugins(invocationPlugins, config, replacements);
+                registerCRC32Plugins(invocationPlugins, config, replacements);
+                registerCRC32CPlugins(invocationPlugins, config, replacements);
+                registerBigIntegerPlugins(invocationPlugins, config, replacements);
+                registerSHAPlugins(invocationPlugins, config, replacements);
                 registerGHASHPlugins(invocationPlugins, config, metaAccess, foreignCalls);
-                registerCounterModePlugins(invocationPlugins, config, replacementBytecodeProvider);
+                registerCounterModePlugins(invocationPlugins, config, replacements);
                 registerBase64Plugins(invocationPlugins, config, metaAccess, foreignCalls);
-                registerUnsafePlugins(invocationPlugins, config, replacementBytecodeProvider);
-                StandardGraphBuilderPlugins.registerInvocationPlugins(metaAccess, snippetReflection, invocationPlugins, replacementBytecodeProvider, true, false);
-                registerArrayPlugins(invocationPlugins, replacementBytecodeProvider);
-                registerStringPlugins(invocationPlugins, replacementBytecodeProvider);
-                registerArraysSupportPlugins(invocationPlugins, config, replacementBytecodeProvider);
+                registerUnsafePlugins(invocationPlugins, config, replacements);
+                StandardGraphBuilderPlugins.registerInvocationPlugins(metaAccess, snippetReflection, invocationPlugins, replacements, true, false);
+                registerArrayPlugins(invocationPlugins, replacements);
+                registerStringPlugins(invocationPlugins, replacements);
+                registerArraysSupportPlugins(invocationPlugins, config, replacements);
 
                 for (NodeIntrinsicPluginFactory factory : GraalServices.load(NodeIntrinsicPluginFactory.class)) {
                     factory.registerPlugins(invocationPlugins, nodeIntrinsificationProvider);
@@ -203,8 +204,8 @@
         return plugins;
     }
 
-    private static void registerObjectPlugins(InvocationPlugins plugins, OptionValues options, GraalHotSpotVMConfig config, BytecodeProvider bytecodeProvider) {
-        Registration r = new Registration(plugins, Object.class, bytecodeProvider);
+    private static void registerObjectPlugins(InvocationPlugins plugins, OptionValues options, GraalHotSpotVMConfig config, Replacements replacements) {
+        Registration r = new Registration(plugins, Object.class, replacements);
         if (!GeneratePIC.getValue(options)) {
             // FIXME: clone() requires speculation and requires a fix in here (to check that
             // b.getAssumptions() != null), and in ReplacementImpl.getSubstitution() where there is
@@ -235,8 +236,8 @@
         }
     }
 
-    private static void registerClassPlugins(Plugins plugins, GraalHotSpotVMConfig config, BytecodeProvider bytecodeProvider) {
-        Registration r = new Registration(plugins.getInvocationPlugins(), Class.class, bytecodeProvider);
+    private static void registerClassPlugins(Plugins plugins, GraalHotSpotVMConfig config, Replacements replacements) {
+        Registration r = new Registration(plugins.getInvocationPlugins(), Class.class, replacements);
 
         r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "getModifiers", Receiver.class);
         r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "isInterface", Receiver.class);
@@ -273,8 +274,8 @@
         plugins.register(plugin, VolatileCallSite.class, "getTarget", Receiver.class);
     }
 
-    private static void registerReflectionPlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider) {
-        Registration r = new Registration(plugins, reflectionClass, bytecodeProvider);
+    private static void registerReflectionPlugins(InvocationPlugins plugins, Replacements replacements) {
+        Registration r = new Registration(plugins, reflectionClass, replacements);
         r.register0("getCallerClass", new InvocationPlugin() {
             @Override
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
@@ -290,12 +291,12 @@
         r.registerMethodSubstitution(ReflectionSubstitutions.class, "getClassAccessFlags", Class.class);
     }
 
-    private static void registerUnsafePlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, BytecodeProvider replacementBytecodeProvider) {
+    private static void registerUnsafePlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, Replacements replacements) {
         Registration r;
         if (JavaVersionUtil.JAVA_SPEC <= 8) {
-            r = new Registration(plugins, Unsafe.class, replacementBytecodeProvider);
+            r = new Registration(plugins, Unsafe.class, replacements);
         } else {
-            r = new Registration(plugins, "jdk.internal.misc.Unsafe", replacementBytecodeProvider);
+            r = new Registration(plugins, "jdk.internal.misc.Unsafe", replacements);
         }
         String substituteMethodName = config.doingUnsafeAccessOffset != Integer.MAX_VALUE ? "copyMemoryGuarded" : "copyMemory";
         r.registerMethodSubstitution(HotSpotUnsafeSubstitutions.class, HotSpotUnsafeSubstitutions.copyMemoryName, substituteMethodName, Receiver.class, Object.class, long.class, Object.class,
@@ -340,8 +341,8 @@
         return true;
     }
 
-    private static void registerConstantPoolPlugins(InvocationPlugins plugins, WordTypes wordTypes, GraalHotSpotVMConfig config, BytecodeProvider bytecodeProvider) {
-        Registration r = new Registration(plugins, constantPoolClass, bytecodeProvider);
+    private static void registerConstantPoolPlugins(InvocationPlugins plugins, WordTypes wordTypes, GraalHotSpotVMConfig config, Replacements replacements) {
+        Registration r = new Registration(plugins, constantPoolClass, replacements);
 
         r.register2("getSize0", Receiver.class, Object.class, new InvocationPlugin() {
             @Override
@@ -411,22 +412,22 @@
         });
     }
 
-    private static void registerArrayPlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider) {
-        Registration r = new Registration(plugins, Array.class, bytecodeProvider);
+    private static void registerArrayPlugins(InvocationPlugins plugins, Replacements replacements) {
+        Registration r = new Registration(plugins, Array.class, replacements);
         r.setAllowOverwrite(true);
         r.registerMethodSubstitution(HotSpotArraySubstitutions.class, "newInstance", Class.class, int.class);
     }
 
-    private static void registerStringPlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider) {
+    private static void registerStringPlugins(InvocationPlugins plugins, Replacements replacements) {
         if (JavaVersionUtil.JAVA_SPEC > 8) {
-            final Registration utf16r = new Registration(plugins, "java.lang.StringUTF16", bytecodeProvider);
+            final Registration utf16r = new Registration(plugins, "java.lang.StringUTF16", replacements);
             utf16r.registerMethodSubstitution(StringUTF16Substitutions.class, "toBytes", char[].class, int.class, int.class);
             utf16r.registerMethodSubstitution(StringUTF16Substitutions.class, "getChars", byte[].class, int.class, int.class, char[].class, int.class);
         }
     }
 
-    private static void registerThreadPlugins(InvocationPlugins plugins, MetaAccessProvider metaAccess, WordTypes wordTypes, GraalHotSpotVMConfig config, BytecodeProvider bytecodeProvider) {
-        Registration r = new Registration(plugins, Thread.class, bytecodeProvider);
+    private static void registerThreadPlugins(InvocationPlugins plugins, MetaAccessProvider metaAccess, WordTypes wordTypes, GraalHotSpotVMConfig config, Replacements replacements) {
+        Registration r = new Registration(plugins, Thread.class, replacements);
         r.register0("currentThread", new InvocationPlugin() {
             @Override
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
@@ -443,40 +444,51 @@
         r.registerMethodSubstitution(ThreadSubstitutions.class, "isInterrupted", Receiver.class, boolean.class);
     }
 
-    public static final String aesEncryptName;
-    public static final String aesDecryptName;
-
     public static final String reflectionClass;
     public static final String constantPoolClass;
 
     static {
         if (JavaVersionUtil.JAVA_SPEC <= 8) {
-            aesEncryptName = "encryptBlock";
-            aesDecryptName = "decryptBlock";
             reflectionClass = "sun.reflect.Reflection";
             constantPoolClass = "sun.reflect.ConstantPool";
         } else {
-            aesEncryptName = "implEncryptBlock";
-            aesDecryptName = "implDecryptBlock";
             reflectionClass = "jdk.internal.reflect.Reflection";
             constantPoolClass = "jdk.internal.reflect.ConstantPool";
         }
     }
 
-    public static boolean cbcUsesImplNames(GraalHotSpotVMConfig config) {
+    public static String lookupIntrinsicName(GraalHotSpotVMConfig config, String className, String name1, String name2) {
+        boolean foundName1 = false;
+        boolean foundName2 = false;
+        String name = name1;
         for (VMIntrinsicMethod intrinsic : config.getStore().getIntrinsics()) {
-            if ("com/sun/crypto/provider/CipherBlockChaining".equals(intrinsic.declaringClass)) {
-                if ("encrypt".equals(intrinsic.name)) {
-                    return false;
-                } else if ("implEncrypt".equals(intrinsic.name)) {
+            if (className.equals(intrinsic.declaringClass)) {
+                if (name1.equals(intrinsic.name)) {
+                    foundName1 = true;
+                } else if (name2.equals(intrinsic.name)) {
+                    foundName2 = true;
+                    name = name2;
+                }
+            }
+        }
+        if (foundName1 != foundName2) {
+            return name;
+        }
+        throw GraalError.shouldNotReachHere();
+    }
+
+    public static boolean isIntrinsicName(GraalHotSpotVMConfig config, String className, String name) {
+        for (VMIntrinsicMethod intrinsic : config.getStore().getIntrinsics()) {
+            if (className.equals(intrinsic.declaringClass)) {
+                if (name.equals(intrinsic.name)) {
                     return true;
                 }
             }
         }
-        throw GraalError.shouldNotReachHere();
+        return false;
     }
 
-    private static void registerAESPlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, BytecodeProvider bytecodeProvider) {
+    private static void registerAESPlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, Replacements replacements) {
         if (config.useAESIntrinsics) {
             assert config.aescryptEncryptBlockStub != 0L;
             assert config.aescryptDecryptBlockStub != 0L;
@@ -484,72 +496,66 @@
             assert config.cipherBlockChainingDecryptAESCryptStub != 0L;
             String arch = config.osArch;
             String decryptSuffix = arch.equals("sparc") ? "WithOriginalKey" : "";
-            Registration r = new Registration(plugins, "com.sun.crypto.provider.CipherBlockChaining", bytecodeProvider);
 
-            boolean implNames = cbcUsesImplNames(config);
-            String cbcEncryptName = implNames ? "implEncrypt" : "encrypt";
-            String cbcDecryptName = implNames ? "implDecrypt" : "decrypt";
-
+            String cbcEncryptName = lookupIntrinsicName(config, "com/sun/crypto/provider/CipherBlockChaining", "implEncrypt", "encrypt");
+            String cbcDecryptName = lookupIntrinsicName(config, "com/sun/crypto/provider/CipherBlockChaining", "implDecrypt", "decrypt");
+            Registration r = new Registration(plugins, "com.sun.crypto.provider.CipherBlockChaining", replacements);
             r.registerMethodSubstitution(CipherBlockChainingSubstitutions.class, cbcEncryptName, Receiver.class, byte[].class, int.class, int.class, byte[].class, int.class);
             r.registerMethodSubstitution(CipherBlockChainingSubstitutions.class, cbcDecryptName, cbcDecryptName + decryptSuffix, Receiver.class, byte[].class, int.class, int.class, byte[].class,
                             int.class);
 
-            r = new Registration(plugins, "com.sun.crypto.provider.AESCrypt", bytecodeProvider);
+            String aesEncryptName = lookupIntrinsicName(config, "com/sun/crypto/provider/AESCrypt", "implEncryptBlock", "encryptBlock");
+            String aesDecryptName = lookupIntrinsicName(config, "com/sun/crypto/provider/AESCrypt", "implDecryptBlock", "decryptBlock");
+
+            r = new Registration(plugins, "com.sun.crypto.provider.AESCrypt", replacements);
             r.registerMethodSubstitution(AESCryptSubstitutions.class, aesEncryptName, Receiver.class, byte[].class, int.class, byte[].class, int.class);
             r.registerMethodSubstitution(AESCryptSubstitutions.class, aesDecryptName, aesDecryptName + decryptSuffix, Receiver.class, byte[].class, int.class, byte[].class, int.class);
         }
     }
 
-    private static void registerBigIntegerPlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, BytecodeProvider bytecodeProvider) {
-        Registration r = new Registration(plugins, BigInteger.class, bytecodeProvider);
-        if (config.useMultiplyToLenIntrinsic()) {
-            assert config.multiplyToLen != 0L;
-            if (JavaVersionUtil.JAVA_SPEC <= 8) {
-                r.registerMethodSubstitution(BigIntegerSubstitutions.class, "multiplyToLen", "multiplyToLenStatic", int[].class, int.class, int[].class, int.class,
-                                int[].class);
-            } else {
-                r.registerMethodSubstitution(BigIntegerSubstitutions.class, "implMultiplyToLen", "multiplyToLenStatic", int[].class, int.class, int[].class, int.class,
-                                int[].class);
-            }
+    private static void registerBigIntegerPlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, Replacements replacements) {
+        Registration r = new Registration(plugins, BigInteger.class, replacements);
+        assert !config.useMultiplyToLenIntrinsic() || config.multiplyToLen != 0L;
+        if (JavaVersionUtil.JAVA_SPEC <= 8) {
+            r.registerConditionalMethodSubstitution(config.useMultiplyToLenIntrinsic(), BigIntegerSubstitutions.class, "multiplyToLen", "multiplyToLenStatic", int[].class, int.class, int[].class,
+                            int.class, int[].class);
+        } else {
+            r.registerConditionalMethodSubstitution(config.useMultiplyToLenIntrinsic(), BigIntegerSubstitutions.class, "implMultiplyToLen", "multiplyToLenStatic", int[].class, int.class, int[].class,
+                            int.class, int[].class);
         }
-        if (config.useMulAddIntrinsic()) {
-            r.registerMethodSubstitution(BigIntegerSubstitutions.class, "implMulAdd", int[].class, int[].class, int.class, int.class, int.class);
-        }
-        if (config.useMontgomeryMultiplyIntrinsic()) {
-            r.registerMethodSubstitution(BigIntegerSubstitutions.class, "implMontgomeryMultiply", int[].class, int[].class, int[].class, int.class, long.class, int[].class);
-        }
-        if (config.useMontgomerySquareIntrinsic()) {
-            r.registerMethodSubstitution(BigIntegerSubstitutions.class, "implMontgomerySquare", int[].class, int[].class, int.class, long.class, int[].class);
-        }
-        if (config.useSquareToLenIntrinsic()) {
-            r.registerMethodSubstitution(BigIntegerSubstitutions.class, "implSquareToLen", int[].class, int.class, int[].class, int.class);
-        }
+        r.registerConditionalMethodSubstitution(config.useMulAddIntrinsic(), BigIntegerSubstitutions.class, "implMulAdd", int[].class, int[].class, int.class, int.class, int.class);
+        r.registerConditionalMethodSubstitution(config.useMontgomeryMultiplyIntrinsic(), BigIntegerSubstitutions.class, "implMontgomeryMultiply", int[].class, int[].class, int[].class, int.class,
+                        long.class, int[].class);
+        r.registerConditionalMethodSubstitution(config.useMontgomerySquareIntrinsic(), BigIntegerSubstitutions.class, "implMontgomerySquare", int[].class, int[].class, int.class, long.class,
+                        int[].class);
+        r.registerConditionalMethodSubstitution(config.useSquareToLenIntrinsic(), BigIntegerSubstitutions.class, "implSquareToLen", int[].class, int.class, int[].class, int.class);
     }
 
-    private static void registerSHAPlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, BytecodeProvider bytecodeProvider) {
+    private static void registerSHAPlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, Replacements replacements) {
         boolean useSha1 = config.useSHA1Intrinsics();
         boolean useSha256 = config.useSHA256Intrinsics();
         boolean useSha512 = config.useSHA512Intrinsics();
 
-        if (JavaVersionUtil.JAVA_SPEC > 8 && (useSha1 || useSha256 || useSha512)) {
-            Registration r = new Registration(plugins, "sun.security.provider.DigestBase", bytecodeProvider);
+        if (isIntrinsicName(config, "sun/security/provider/DigestBase", "implCompressMultiBlock0") && (useSha1 || useSha256 || useSha512)) {
+            Registration r = new Registration(plugins, "sun.security.provider.DigestBase", replacements);
             r.registerMethodSubstitution(DigestBaseSubstitutions.class, "implCompressMultiBlock0", Receiver.class, byte[].class, int.class, int.class);
         }
 
+        String implCompressName = lookupIntrinsicName(config, "sun/security/provider/SHA", "implCompress", "implCompress0");
         if (useSha1) {
             assert config.sha1ImplCompress != 0L;
-            Registration r = new Registration(plugins, "sun.security.provider.SHA", bytecodeProvider);
-            r.registerMethodSubstitution(SHASubstitutions.class, SHASubstitutions.implCompressName, "implCompress0", Receiver.class, byte[].class, int.class);
+            Registration r = new Registration(plugins, "sun.security.provider.SHA", replacements);
+            r.registerMethodSubstitution(SHASubstitutions.class, implCompressName, "implCompress0", Receiver.class, byte[].class, int.class);
         }
         if (useSha256) {
             assert config.sha256ImplCompress != 0L;
-            Registration r = new Registration(plugins, "sun.security.provider.SHA2", bytecodeProvider);
-            r.registerMethodSubstitution(SHA2Substitutions.class, SHA2Substitutions.implCompressName, "implCompress0", Receiver.class, byte[].class, int.class);
+            Registration r = new Registration(plugins, "sun.security.provider.SHA2", replacements);
+            r.registerMethodSubstitution(SHA2Substitutions.class, implCompressName, "implCompress0", Receiver.class, byte[].class, int.class);
         }
         if (useSha512) {
             assert config.sha512ImplCompress != 0L;
-            Registration r = new Registration(plugins, "sun.security.provider.SHA5", bytecodeProvider);
-            r.registerMethodSubstitution(SHA5Substitutions.class, SHA5Substitutions.implCompressName, "implCompress0", Receiver.class, byte[].class, int.class);
+            Registration r = new Registration(plugins, "sun.security.provider.SHA5", replacements);
+            r.registerMethodSubstitution(SHA5Substitutions.class, implCompressName, "implCompress0", Receiver.class, byte[].class, int.class);
         }
     }
 
@@ -586,11 +592,12 @@
         }
     }
 
-    private static void registerCounterModePlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, BytecodeProvider bytecodeProvider) {
-        if (config.useAESCTRIntrinsics) {
-            assert config.counterModeAESCrypt != 0L;
-            Registration r = new Registration(plugins, "com.sun.crypto.provider.CounterMode", bytecodeProvider);
-            r.registerMethodSubstitution(CounterModeSubstitutions.class, "implCrypt", Receiver.class, byte[].class, int.class, int.class, byte[].class, int.class);
+    private static void registerCounterModePlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, Replacements replacements) {
+        if (JavaVersionUtil.JAVA_SPEC > 8) {
+            assert !config.useAESCTRIntrinsics || config.counterModeAESCrypt != 0L;
+            Registration r = new Registration(plugins, "com.sun.crypto.provider.CounterMode", replacements);
+            r.registerConditionalMethodSubstitution(config.useAESCTRIntrinsics, CounterModeSubstitutions.class, "implCrypt", Receiver.class, byte[].class, int.class, int.class, byte[].class,
+                            int.class);
         }
     }
 
@@ -626,32 +633,31 @@
         }
     }
 
-    private static void registerCRC32Plugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, BytecodeProvider bytecodeProvider) {
-        if (config.useCRC32Intrinsics) {
-            Registration r = new Registration(plugins, CRC32.class, bytecodeProvider);
-            r.registerMethodSubstitution(CRC32Substitutions.class, "update", int.class, int.class);
-            if (JavaVersionUtil.JAVA_SPEC <= 8) {
-                r.registerMethodSubstitution(CRC32Substitutions.class, "updateBytes", int.class, byte[].class, int.class, int.class);
-                r.registerMethodSubstitution(CRC32Substitutions.class, "updateByteBuffer", int.class, long.class, int.class, int.class);
-            } else {
-                r.registerMethodSubstitution(CRC32Substitutions.class, "updateBytes0", int.class, byte[].class, int.class, int.class);
-                r.registerMethodSubstitution(CRC32Substitutions.class, "updateByteBuffer0", int.class, long.class, int.class, int.class);
-            }
+    private static void registerCRC32Plugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, Replacements replacements) {
+        Registration r = new Registration(plugins, CRC32.class, replacements);
+        r.registerConditionalMethodSubstitution(config.useCRC32Intrinsics, CRC32Substitutions.class, "update", int.class, int.class);
+        if (JavaVersionUtil.JAVA_SPEC <= 8) {
+            r.registerConditionalMethodSubstitution(config.useCRC32Intrinsics, CRC32Substitutions.class, "updateBytes", int.class, byte[].class, int.class, int.class);
+            r.registerConditionalMethodSubstitution(config.useCRC32Intrinsics, CRC32Substitutions.class, "updateByteBuffer", int.class, long.class, int.class, int.class);
+        } else {
+            r.registerConditionalMethodSubstitution(config.useCRC32Intrinsics, CRC32Substitutions.class, "updateBytes0", int.class, byte[].class, int.class, int.class);
+            r.registerConditionalMethodSubstitution(config.useCRC32Intrinsics, CRC32Substitutions.class, "updateByteBuffer0", int.class, long.class, int.class, int.class);
         }
     }
 
-    private static void registerCRC32CPlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, BytecodeProvider bytecodeProvider) {
-        if (config.useCRC32CIntrinsics) {
-            Registration r = new Registration(plugins, "java.util.zip.CRC32C", bytecodeProvider);
-            r.registerMethodSubstitution(CRC32CSubstitutions.class, "updateBytes", int.class, byte[].class, int.class, int.class);
-            r.registerMethodSubstitution(CRC32CSubstitutions.class, "updateDirectByteBuffer", int.class, long.class, int.class, int.class);
+    private static void registerCRC32CPlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, Replacements replacements) {
+        if (JavaVersionUtil.JAVA_SPEC > 8) {
+            Registration r = new Registration(plugins, "java.util.zip.CRC32C", replacements);
+            r.registerConditionalMethodSubstitution(config.useCRC32CIntrinsics, CRC32CSubstitutions.class, "updateBytes", int.class, byte[].class, int.class, int.class);
+            r.registerConditionalMethodSubstitution(config.useCRC32CIntrinsics, CRC32CSubstitutions.class, "updateDirectByteBuffer", int.class, long.class, int.class, int.class);
         }
     }
 
-    private static void registerArraysSupportPlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, BytecodeProvider bytecodeProvider) {
-        if (config.useVectorizedMismatchIntrinsic) {
-            Registration r = new Registration(plugins, "jdk.internal.util.ArraysSupport", bytecodeProvider);
-            r.registerMethodSubstitution(ArraysSupportSubstitutions.class, "vectorizedMismatch", Object.class, long.class, Object.class, long.class, int.class, int.class);
+    private static void registerArraysSupportPlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, Replacements replacements) {
+        if (JavaVersionUtil.JAVA_SPEC > 8) {
+            Registration r = new Registration(plugins, "jdk.internal.util.ArraysSupport", replacements);
+            r.registerConditionalMethodSubstitution(config.useVectorizedMismatchIntrinsic, ArraysSupportSubstitutions.class, "vectorizedMismatch", Object.class, long.class, Object.class, long.class,
+                            int.class, int.class);
         }
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java	Thu Oct 31 16:54:16 2019 -0700
@@ -339,8 +339,8 @@
         linkForeignCall(options, providers, REGISTER_FINALIZER, c.registerFinalizerAddress, PREPEND_THREAD, SAFEPOINT, NOT_REEXECUTABLE, any());
         linkForeignCall(options, providers, MONITORENTER, c.monitorenterAddress, PREPEND_THREAD, SAFEPOINT, NOT_REEXECUTABLE, any());
         linkForeignCall(options, providers, MONITOREXIT, c.monitorexitAddress, PREPEND_THREAD, STACK_INSPECTABLE_LEAF, NOT_REEXECUTABLE, any());
-        linkForeignCall(options, providers, NOTIFY, c.notifyAddress, PREPEND_THREAD, SAFEPOINT, NOT_REEXECUTABLE, any());
-        linkForeignCall(options, providers, NOTIFY_ALL, c.notifyAllAddress, PREPEND_THREAD, SAFEPOINT, NOT_REEXECUTABLE, any());
+        linkForeignCall(options, providers, NOTIFY, c.notifyAddress, PREPEND_THREAD, LEAF_NO_VZERO, NOT_REEXECUTABLE, any());
+        linkForeignCall(options, providers, NOTIFY_ALL, c.notifyAllAddress, PREPEND_THREAD, LEAF_NO_VZERO, NOT_REEXECUTABLE, any());
         linkForeignCall(options, providers, LOG_PRINTF, c.logPrintfAddress, PREPEND_THREAD, LEAF, REEXECUTABLE, NO_LOCATIONS);
         linkForeignCall(options, providers, LOG_OBJECT, c.logObjectAddress, PREPEND_THREAD, LEAF, REEXECUTABLE, NO_LOCATIONS);
         linkForeignCall(options, providers, LOG_PRIMITIVE, c.logPrimitiveAddress, PREPEND_THREAD, LEAF, REEXECUTABLE, NO_LOCATIONS);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotSuitesProvider.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotSuitesProvider.java	Thu Oct 31 16:54:16 2019 -0700
@@ -168,7 +168,7 @@
         if (profileInstructions != null) {
             suites.getPostAllocationOptimizationStage().appendPhase(new HotSpotInstructionProfiling(profileInstructions));
         }
-        if (Assertions.detailedAssertionsEnabled(options)) {
+        if (Assertions.assertionsEnabled()) {
             suites.getPostAllocationOptimizationStage().appendPhase(new VerifyMaxRegisterSizePhase(config.maxVectorSize));
         }
         return suites;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/BeginLockScopeNode.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/BeginLockScopeNode.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2019, 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
@@ -73,7 +73,7 @@
     }
 
     @Override
-    public LocationIdentity getLocationIdentity() {
+    public LocationIdentity getKilledLocationIdentity() {
         return LocationIdentity.any();
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/EndLockScopeNode.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/EndLockScopeNode.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2019, 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
@@ -56,7 +56,7 @@
     }
 
     @Override
-    public LocationIdentity getLocationIdentity() {
+    public LocationIdentity getKilledLocationIdentity() {
         return LocationIdentity.any();
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/StubForeignCallNode.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/StubForeignCallNode.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2019, 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
@@ -72,7 +72,7 @@
     }
 
     @Override
-    public LocationIdentity[] getLocationIdentities() {
+    public LocationIdentity[] getKilledLocationIdentities() {
         LocationIdentity[] killedLocations = foreignCalls.getKilledLocations(descriptor);
         killedLocations = Arrays.copyOf(killedLocations, killedLocations.length + 1);
         killedLocations[killedLocations.length - 1] = HotSpotReplacementsUtil.PENDING_EXCEPTION_LOCATION;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/InitializeKlassNode.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/InitializeKlassNode.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2019, 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
@@ -64,7 +64,7 @@
     }
 
     @Override
-    public LocationIdentity getLocationIdentity() {
+    public LocationIdentity getKilledLocationIdentity() {
         return LocationIdentity.any();
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/InitializeKlassStubCall.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/InitializeKlassStubCall.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2019, 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
@@ -98,7 +98,7 @@
     }
 
     @Override
-    public LocationIdentity getLocationIdentity() {
+    public LocationIdentity getKilledLocationIdentity() {
         return LocationIdentity.any();
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveDynamicConstantNode.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveDynamicConstantNode.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2019, 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
@@ -64,7 +64,7 @@
     }
 
     @Override
-    public LocationIdentity getLocationIdentity() {
+    public LocationIdentity getKilledLocationIdentity() {
         return LocationIdentity.any();
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveDynamicStubCall.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveDynamicStubCall.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2019, 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
@@ -93,7 +93,7 @@
     }
 
     @Override
-    public LocationIdentity getLocationIdentity() {
+    public LocationIdentity getKilledLocationIdentity() {
         return LocationIdentity.any();
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/AheadOfTimeVerificationPhase.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/AheadOfTimeVerificationPhase.java	Thu Oct 31 16:54:16 2019 -0700
@@ -70,10 +70,22 @@
     }
 
     private static boolean isDirectMethodHandle(ConstantNode node) {
+        String typeName = StampTool.typeOrNull(node).getName();
         if (!isObject(node)) {
             return false;
         }
-        return "Ljava/lang/invoke/DirectMethodHandle;".equals(StampTool.typeOrNull(node).getName());
+
+        switch (typeName) {
+            case "Ljava/lang/invoke/DirectMethodHandle;":
+            case "Ljava/lang/invoke/DirectMethodHandle$StaticAccessor;":
+            case "Ljava/lang/invoke/DirectMethodHandle$Accessor;":
+            case "Ljava/lang/invoke/DirectMethodHandle$Constructor;":
+            case "Ljava/lang/invoke/DirectMethodHandle$Special;":
+            case "Ljava/lang/invoke/DirectMethodHandle$Interface;":
+                return true;
+            default:
+                return false;
+        }
     }
 
     private static boolean isBoundMethodHandle(ConstantNode node) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/IdentityHashCodeNode.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/IdentityHashCodeNode.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2019, 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
@@ -61,7 +61,7 @@
     }
 
     @Override
-    public LocationIdentity getLocationIdentity() {
+    public LocationIdentity getKilledLocationIdentity() {
         return HotSpotReplacementsUtil.MARK_WORD_LOCATION;
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/SHA2Substitutions.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/SHA2Substitutions.java	Thu Oct 31 16:54:16 2019 -0700
@@ -36,7 +36,6 @@
 import org.graalvm.compiler.nodes.extended.RawLoadNode;
 import org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext;
 import org.graalvm.compiler.replacements.ReplacementsUtil;
-import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
 import org.graalvm.compiler.word.Word;
 import jdk.internal.vm.compiler.word.LocationIdentity;
 import jdk.internal.vm.compiler.word.WordFactory;
@@ -46,8 +45,6 @@
 @ClassSubstitution(className = "sun.security.provider.SHA2", optional = true)
 public class SHA2Substitutions {
 
-    public static final String implCompressName = JavaVersionUtil.JAVA_SPEC <= 8 ? "implCompress" : "implCompress0";
-
     @MethodSubstitution(isStatic = false)
     static void implCompress0(Object receiver, byte[] buf, int ofs) {
         Object realReceiver = PiNode.piCastNonNull(receiver, HotSpotReplacementsUtil.methodHolderClass(INJECTED_INTRINSIC_CONTEXT));
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/SHA5Substitutions.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/SHA5Substitutions.java	Thu Oct 31 16:54:16 2019 -0700
@@ -37,7 +37,6 @@
 import org.graalvm.compiler.nodes.extended.RawLoadNode;
 import org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext;
 import org.graalvm.compiler.replacements.ReplacementsUtil;
-import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
 import org.graalvm.compiler.word.Word;
 import jdk.internal.vm.compiler.word.LocationIdentity;
 import jdk.internal.vm.compiler.word.WordFactory;
@@ -47,8 +46,6 @@
 @ClassSubstitution(className = "sun.security.provider.SHA5", optional = true)
 public class SHA5Substitutions {
 
-    public static final String implCompressName = JavaVersionUtil.JAVA_SPEC <= 8 ? "implCompress" : "implCompress0";
-
     @MethodSubstitution(isStatic = false)
     static void implCompress0(Object receiver, byte[] buf, int ofs) {
         Object realReceiver = PiNode.piCastNonNull(receiver, HotSpotReplacementsUtil.methodHolderClass(INJECTED_INTRINSIC_CONTEXT));
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/SHASubstitutions.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/SHASubstitutions.java	Thu Oct 31 16:54:16 2019 -0700
@@ -37,7 +37,6 @@
 import org.graalvm.compiler.nodes.extended.RawLoadNode;
 import org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext;
 import org.graalvm.compiler.replacements.ReplacementsUtil;
-import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
 import org.graalvm.compiler.word.Word;
 import jdk.internal.vm.compiler.word.LocationIdentity;
 import jdk.internal.vm.compiler.word.WordFactory;
@@ -47,8 +46,6 @@
 @ClassSubstitution(className = "sun.security.provider.SHA", optional = true)
 public class SHASubstitutions {
 
-    public static final String implCompressName = JavaVersionUtil.JAVA_SPEC <= 8 ? "implCompress" : "implCompress0";
-
     @MethodSubstitution(isStatic = false)
     static void implCompress0(Object receiver, byte[] buf, int ofs) {
         Object realReceiver = PiNode.piCastNonNull(receiver, HotSpotReplacementsUtil.methodHolderClass(INJECTED_INTRINSIC_CONTEXT));
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/ForeignCallStub.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/ForeignCallStub.java	Thu Oct 31 16:54:16 2019 -0700
@@ -56,7 +56,6 @@
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.options.OptionValues;
-import org.graalvm.compiler.phases.common.RemoveValueProxyPhase;
 import org.graalvm.compiler.replacements.GraphKit;
 import org.graalvm.compiler.replacements.nodes.ReadRegisterNode;
 import org.graalvm.compiler.word.Word;
@@ -258,7 +257,6 @@
             debug.dump(DebugContext.VERBOSE_LEVEL, graph, "Initial stub graph");
 
             kit.inlineInvokes("Foreign call stub.", "Backend");
-            new RemoveValueProxyPhase().apply(graph);
 
             debug.dump(DebugContext.VERBOSE_LEVEL, graph, "Stub graph before compilation");
             return graph;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/SnippetStub.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/SnippetStub.java	Thu Oct 31 16:54:16 2019 -0700
@@ -41,7 +41,6 @@
 import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.common.LoweringPhase;
-import org.graalvm.compiler.phases.common.RemoveValueProxyPhase;
 import org.graalvm.compiler.replacements.SnippetTemplate;
 import org.graalvm.compiler.replacements.Snippets;
 
@@ -100,9 +99,8 @@
                 }
             }
 
-            new RemoveValueProxyPhase().apply(graph);
             graph.setGuardsStage(GuardsStage.FLOATING_GUARDS);
-            CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+            CanonicalizerPhase canonicalizer = CanonicalizerPhase.create();
             canonicalizer.apply(graph, providers);
             new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, providers);
         } catch (Throwable e) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java	Thu Oct 31 16:54:16 2019 -0700
@@ -3221,7 +3221,7 @@
             lastInstr = loopBegin;
 
             // Create phi functions for all local variables and operand stack slots.
-            frameState.insertLoopPhis(liveness, block.loopId, loopBegin, forceLoopPhis(), stampFromValueForForcedPhis());
+            frameState.insertLoopPhis(liveness, block.loopId, loopBegin, forceLoopPhis() || this.graphBuilderConfig.replaceLocalsWithConstants(), stampFromValueForForcedPhis());
             loopBegin.setStateAfter(createFrameState(block.startBci, loopBegin));
 
             /*
@@ -3545,8 +3545,9 @@
                      * will never see that the branch is taken. This can lead to deopt loops or OSR
                      * failure.
                      */
+                    double calculatedProbability = negated ? BranchProbabilityNode.DEOPT_PROBABILITY : 1.0 - BranchProbabilityNode.DEOPT_PROBABILITY;
                     FixedNode deoptSuccessor = BeginNode.begin(deopt);
-                    ValueNode ifNode = genIfNode(condition, negated ? deoptSuccessor : noDeoptSuccessor, negated ? noDeoptSuccessor : deoptSuccessor, negated ? 1 - probability : probability);
+                    ValueNode ifNode = genIfNode(condition, negated ? deoptSuccessor : noDeoptSuccessor, negated ? noDeoptSuccessor : deoptSuccessor, calculatedProbability);
                     postProcessIfNode(ifNode);
                     append(ifNode);
                 }
@@ -3569,8 +3570,28 @@
             }
 
             this.controlFlowSplit = true;
-            FixedNode trueSuccessor = createTarget(trueBlock, frameState, false, false);
-            FixedNode falseSuccessor = createTarget(falseBlock, frameState, false, true);
+            FixedNode falseSuccessor = createTarget(falseBlock, frameState, false, false);
+            FixedNode trueSuccessor = createTarget(trueBlock, frameState, false, true);
+
+            if (this.graphBuilderConfig.replaceLocalsWithConstants() && condition instanceof CompareNode) {
+                CompareNode compareNode = (CompareNode) condition;
+                if (compareNode.condition() == CanonicalCondition.EQ) {
+                    ValueNode constantNode = null;
+                    ValueNode nonConstantNode = null;
+                    if (compareNode.getX() instanceof ConstantNode) {
+                        constantNode = compareNode.getX();
+                        nonConstantNode = compareNode.getY();
+                    } else if (compareNode.getY() instanceof ConstantNode) {
+                        constantNode = compareNode.getY();
+                        nonConstantNode = compareNode.getX();
+                    }
+
+                    if (constantNode != null && nonConstantNode != null) {
+                        this.getEntryState(trueBlock).replaceValue(nonConstantNode, constantNode);
+                    }
+                }
+            }
+
             ValueNode ifNode = genIfNode(condition, trueSuccessor, falseSuccessor, probability);
             postProcessIfNode(ifNode);
             append(ifNode);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/FrameStateBuilder.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/FrameStateBuilder.java	Thu Oct 31 16:54:16 2019 -0700
@@ -328,8 +328,7 @@
             outerFrameState = parent.getFrameStateBuilder().create(parent.bci(), parent.getNonIntrinsicAncestor(), true, null, null);
         }
         if (bci == BytecodeFrame.AFTER_EXCEPTION_BCI && parent != null) {
-            FrameState newFrameState = outerFrameState.duplicateModified(outerFrameState.bci, true, false, JavaKind.Void, new JavaKind[]{JavaKind.Object}, new ValueNode[]{stack[0]});
-            return newFrameState;
+            return outerFrameState.duplicateModified(graph, outerFrameState.bci, true, false, JavaKind.Void, new JavaKind[]{JavaKind.Object}, new ValueNode[]{stack[0]});
         }
         if (bci == BytecodeFrame.INVALID_FRAMESTATE_BCI) {
             throw shouldNotReachHere();
@@ -527,21 +526,21 @@
             ValueNode value = locals[i];
             if (value != null && value != TWO_SLOT_MARKER && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) {
                 debug.log(" inserting proxy for %s", value);
-                locals[i] = ProxyNode.forValue(value, loopExit, graph);
+                locals[i] = ProxyNode.forValue(value, loopExit);
             }
         }
         for (int i = 0; i < stackSize(); i++) {
             ValueNode value = stack[i];
             if (value != null && value != TWO_SLOT_MARKER && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) {
                 debug.log(" inserting proxy for %s", value);
-                stack[i] = ProxyNode.forValue(value, loopExit, graph);
+                stack[i] = ProxyNode.forValue(value, loopExit);
             }
         }
         for (int i = 0; i < lockedObjects.length; i++) {
             ValueNode value = lockedObjects[i];
             if (value != null && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) {
                 debug.log(" inserting proxy for %s", value);
-                lockedObjects[i] = ProxyNode.forValue(value, loopExit, graph);
+                lockedObjects[i] = ProxyNode.forValue(value, loopExit);
             }
         }
     }
@@ -1028,4 +1027,17 @@
         }
         sideEffects.add(sideEffect);
     }
+
+    public void replaceValue(ValueNode oldValue, ValueNode newValue) {
+        for (int i = 0; i < locals.length; ++i) {
+            if (locals[i] == oldValue) {
+                locals[i] = newValue;
+            }
+        }
+        for (int i = 0; i < stack.length; ++i) {
+            if (stack[i] == oldValue) {
+                stack[i] = newValue;
+            }
+        }
+    }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/backend/LargeConstantSectionTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/backend/LargeConstantSectionTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, 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
@@ -38,7 +38,7 @@
 
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.jtt.JTTTest;
-import org.graalvm.compiler.test.ExportingClassLoader;
+import org.graalvm.compiler.api.test.ExportingClassLoader;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/UntrustedInterfaces.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/except/UntrustedInterfaces.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2019, 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
@@ -25,7 +25,7 @@
 package org.graalvm.compiler.jtt.except;
 
 import org.graalvm.compiler.jtt.JTTTest;
-import org.graalvm.compiler.test.ExportingClassLoader;
+import org.graalvm.compiler.api.test.ExportingClassLoader;
 import org.junit.BeforeClass;
 import org.junit.Test;
 import org.objectweb.asm.ClassWriter;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/NestedLoop_EA.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/NestedLoop_EA.java	Thu Oct 31 16:54:16 2019 -0700
@@ -44,7 +44,7 @@
     protected Suites createSuites(OptionValues options) {
         Suites suites = super.createSuites(options);
         ListIterator<BasePhase<? super HighTierContext>> position = suites.getHighTier().findPhase(PartialEscapePhase.class);
-        CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+        CanonicalizerPhase canonicalizer = this.createCanonicalizerPhase();
         // incremental canonicalizer of PEA is missing some important canonicalization (TODO?)
         position.add(canonicalizer);
         position.add(new PartialEscapePhase(true, canonicalizer, options));
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/TrichotomyTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/TrichotomyTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2019, 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
@@ -2527,7 +2527,7 @@
         // test folding
         StructuredGraph graph = self.parseForCompile(self.getResolvedJavaMethod(name));
         HighTierContext context = self.getDefaultHighTierContext();
-        CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+        CanonicalizerPhase canonicalizer = self.createCanonicalizerPhase();
         canonicalizer.apply(graph, context);
         Assert.assertTrue("Too many ConditionalNodes after canonicalization", graph.getNodes().filter(ConditionalNode.class).count() <= 1);
         Assert.assertTrue("Unexpected IfNodes after canonicalization", graph.getNodes().filter(IfNode.class).isEmpty());
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ArithmeticOp.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ArithmeticOp.java	Thu Oct 31 16:54:16 2019 -0700
@@ -58,6 +58,13 @@
     DIV,
     SMULH,
     UMULH,
+    SMULL,
+    SMNEGL,
+    MADD,
+    MSUB,
+    FMADD,
+    SMADDL,
+    SMSUBL,
     REM,
     UDIV,
     UREM,
@@ -279,6 +286,12 @@
                 case MNEG:
                     masm.mneg(size, dst, src1, src2);
                     break;
+                case SMULL:
+                    masm.smull(size, dst, src1, src2);
+                    break;
+                case SMNEGL:
+                    masm.smnegl(size, dst, src1, src2);
+                    break;
                 case DIV:
                     masm.sdiv(size, dst, src1, src2);
                     break;
@@ -477,11 +490,10 @@
         @Use(REG) protected AllocatableValue src3;
 
         /**
-         * Computes <code>result = src3 <op> src1 * src2</code>.
+         * Computes <code>result = src3 +/- src1 * src2</code>.
          */
         public MultiplyAddSubOp(AArch64ArithmeticOp op, AllocatableValue result, AllocatableValue src1, AllocatableValue src2, AllocatableValue src3) {
             super(TYPE);
-            assert op == ADD || op == SUB || op == FADD;
             this.op = op;
             this.result = result;
             this.src1 = src1;
@@ -493,15 +505,23 @@
         public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
             int size = result.getPlatformKind().getSizeInBytes() * Byte.SIZE;
             switch (op) {
-                case ADD:
+                case MADD:
                     masm.madd(size, asRegister(result), asRegister(src1), asRegister(src2), asRegister(src3));
                     break;
-                case SUB:
+                case MSUB:
                     masm.msub(size, asRegister(result), asRegister(src1), asRegister(src2), asRegister(src3));
                     break;
-                case FADD:
+                case FMADD:
                     masm.fmadd(size, asRegister(result), asRegister(src1), asRegister(src2), asRegister(src3));
                     break;
+                case SMADDL:
+                    assert size == 64;
+                    masm.smaddl(size, asRegister(result), asRegister(src1), asRegister(src2), asRegister(src3));
+                    break;
+                case SMSUBL:
+                    assert size == 64;
+                    masm.smsubl(size, asRegister(result), asRegister(src1), asRegister(src2), asRegister(src3));
+                    break;
                 default:
                     throw GraalError.shouldNotReachHere();
             }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64Move.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64Move.java	Thu Oct 31 16:54:16 2019 -0700
@@ -96,7 +96,7 @@
     public static final class MoveToRegOp extends AbstractMoveOp {
         public static final LIRInstructionClass<MoveToRegOp> TYPE = LIRInstructionClass.create(MoveToRegOp.class);
 
-        @Def({REG, HINT}) protected AllocatableValue result;
+        @Def({REG, STACK, HINT}) protected AllocatableValue result;
         @Use({REG, STACK}) protected AllocatableValue input;
 
         public MoveToRegOp(AMD64Kind moveKind, AllocatableValue result, AllocatableValue input) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64StringLatin1InflateOp.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64StringLatin1InflateOp.java	Thu Oct 31 16:54:16 2019 -0700
@@ -32,6 +32,8 @@
 import static jdk.vm.ci.code.ValueUtil.asRegister;
 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
 
+import java.util.EnumSet;
+
 import org.graalvm.compiler.asm.Label;
 import org.graalvm.compiler.asm.amd64.AMD64Address;
 import org.graalvm.compiler.asm.amd64.AMD64Assembler;
@@ -43,8 +45,10 @@
 import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
 
 import jdk.vm.ci.amd64.AMD64;
+import jdk.vm.ci.amd64.AMD64.CPUFeature;
 import jdk.vm.ci.amd64.AMD64Kind;
 import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.TargetDescription;
 import jdk.vm.ci.meta.Value;
 
 @Opcode("AMD64_STRING_INFLATE")
@@ -73,7 +77,7 @@
         rdstTemp = rdst = dst;
         rlenTemp = rlen = len;
 
-        vtmp1 = tool.newVariable(LIRKind.value(AMD64Kind.V512_BYTE));
+        vtmp1 = useAVX512ForStringInflateCompress(tool.target()) ? tool.newVariable(LIRKind.value(AMD64Kind.V512_BYTE)) : tool.newVariable(LIRKind.value(AMD64Kind.V128_BYTE));
         rtmp2 = tool.newVariable(LIRKind.value(AMD64Kind.DWORD));
     }
 
@@ -89,6 +93,13 @@
         byteArrayInflate(masm, src, dst, len, tmp1, tmp2);
     }
 
+    public static boolean useAVX512ForStringInflateCompress(TargetDescription target) {
+        EnumSet<CPUFeature> features = ((AMD64) target.arch).getFeatures();
+        return features.contains(AMD64.CPUFeature.AVX512BW) &&
+                        features.contains(AMD64.CPUFeature.AVX512VL) &&
+                        features.contains(AMD64.CPUFeature.BMI2);
+    }
+
     /**
      * Inflate a Latin1 string using a byte[] array representation into a UTF16 string using a
      * char[] array representation.
@@ -110,10 +121,7 @@
         assert dst.number != len.number && dst.number != tmp.number;
         assert len.number != tmp.number;
 
-        if (masm.supports(AMD64.CPUFeature.AVX512BW) &&
-                        masm.supports(AMD64.CPUFeature.AVX512VL) &&
-                        masm.supports(AMD64.CPUFeature.BMI2)) {
-
+        if (useAVX512ForStringInflateCompress(masm.target)) {
             // If the length of the string is less than 16, we chose not to use the
             // AVX512 instructions.
             masm.testl(len, -16);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64StringUTF16CompressOp.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64StringUTF16CompressOp.java	Thu Oct 31 16:54:16 2019 -0700
@@ -34,6 +34,7 @@
 import static jdk.vm.ci.amd64.AMD64.rsp;
 import static jdk.vm.ci.code.ValueUtil.asRegister;
 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+import static org.graalvm.compiler.lir.amd64.AMD64StringLatin1InflateOp.useAVX512ForStringInflateCompress;
 
 import org.graalvm.compiler.asm.Label;
 import org.graalvm.compiler.asm.amd64.AMD64Address;
@@ -82,7 +83,7 @@
         rdstTemp = rdst = dst;
         rlenTemp = rlen = len;
 
-        LIRKind vkind = LIRKind.value(AMD64Kind.V512_BYTE);
+        LIRKind vkind = useAVX512ForStringInflateCompress(tool.target()) ? LIRKind.value(AMD64Kind.V512_BYTE) : LIRKind.value(AMD64Kind.V128_BYTE);
 
         vtmp1 = tool.newVariable(vkind);
         vtmp2 = tool.newVariable(vkind);
@@ -139,10 +140,7 @@
 
         masm.push(len);      // Save length for return.
 
-        if (masm.supports(AMD64.CPUFeature.AVX512BW) &&
-                        masm.supports(AMD64.CPUFeature.AVX512VL) &&
-                        masm.supports(AMD64.CPUFeature.BMI2)) {
-
+        if (useAVX512ForStringInflateCompress(masm.target)) {
             Label labelRestoreK1ReturnZero = new Label();
             Label labelAvxPostAlignment = new Label();
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/vector/AMD64VectorMove.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/vector/AMD64VectorMove.java	Thu Oct 31 16:54:16 2019 -0700
@@ -74,7 +74,7 @@
     public static final class MoveToRegOp extends AMD64LIRInstruction implements ValueMoveOp {
         public static final LIRInstructionClass<MoveToRegOp> TYPE = LIRInstructionClass.create(MoveToRegOp.class);
 
-        @Def({REG, HINT}) protected AllocatableValue result;
+        @Def({REG, STACK, HINT}) protected AllocatableValue result;
         @Use({REG, STACK}) protected AllocatableValue input;
 
         public MoveToRegOp(AllocatableValue result, AllocatableValue input) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/LIRIntrospection.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/LIRIntrospection.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2019, 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
@@ -214,6 +214,23 @@
         }
     }
 
+    private static boolean verifyAssignment(LIRInstruction inst, Value newValue, EnumSet<OperandFlag> flags) {
+        Class<?> type = newValue.getClass();
+        if (!flags.contains(REG)) {
+            assert !type.isAssignableFrom(REGISTER_VALUE_CLASS) && !type.isAssignableFrom(VARIABLE_CLASS) : "Cannot assign RegisterValue / Variable to field without REG flag: " + inst + " newValue=" +
+                            newValue;
+        }
+        if (!flags.contains(STACK)) {
+            assert !type.isAssignableFrom(STACK_SLOT_CLASS) : "Cannot assign StackSlot to field without STACK flag: " + inst + " newValue=" +
+                            newValue;
+        }
+        if (!flags.contains(CONST)) {
+            assert !type.isAssignableFrom(CONSTANT_VALUE_CLASS) : "Cannot assign Constant to field without CONST flag: " + inst + " newValue=" +
+                            newValue;
+        }
+        return true;
+    }
+
     protected static void forEach(LIRInstruction inst, Values values, OperandMode mode, InstructionValueProcedure proc) {
         for (int i = 0; i < values.getCount(); i++) {
             assert LIRInstruction.ALLOWED_FLAGS.get(mode).containsAll(values.getFlags(i));
@@ -228,6 +245,9 @@
                     newValue = proc.doValue(inst, value, mode, values.getFlags(i));
                 }
                 if (!value.identityEquals(newValue)) {
+                    if (!(value instanceof CompositeValue)) {
+                        assert verifyAssignment(inst, newValue, values.getFlags(i));
+                    }
                     values.setValue(inst, i, newValue);
                 }
             } else {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanLifetimeAnalysisPhase.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanLifetimeAnalysisPhase.java	Thu Oct 31 16:54:16 2019 -0700
@@ -881,7 +881,12 @@
                     }
                 }
             }
-            return move.getConstant();
+            Constant constant = move.getConstant();
+            if (!(constant instanceof JavaConstant)) {
+                // Other kinds of constants might not be supported by the generic move operation.
+                return null;
+            }
+            return constant;
         }
         return null;
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/ConvertDeoptimizeToGuardPhase.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/ConvertDeoptimizeToGuardPhase.java	Thu Oct 31 16:54:16 2019 -0700
@@ -217,7 +217,7 @@
 
                             Node newGuard = guard;
                             if (survivingSuccessor instanceof LoopExitNode) {
-                                newGuard = ProxyNode.forGuard(guard, (LoopExitNode) survivingSuccessor, graph);
+                                newGuard = ProxyNode.forGuard(guard, (LoopExitNode) survivingSuccessor);
                             }
                             survivingSuccessor.replaceAtUsages(InputType.Guard, newGuard);
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopPeelingPhase.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopPeelingPhase.java	Thu Oct 31 16:54:16 2019 -0700
@@ -24,6 +24,7 @@
 
 package org.graalvm.compiler.loop.phases;
 
+import org.graalvm.compiler.debug.CounterKey;
 import org.graalvm.compiler.debug.DebugContext;
 import org.graalvm.compiler.loop.LoopEx;
 import org.graalvm.compiler.loop.LoopPolicies;
@@ -33,6 +34,8 @@
 
 public class LoopPeelingPhase extends LoopPhase<LoopPolicies> {
 
+    public static final CounterKey PEELED = DebugContext.counter("Peeled");
+
     public LoopPeelingPhase(LoopPolicies policies) {
         super(policies);
     }
@@ -45,10 +48,13 @@
             LoopsData data = new LoopsData(graph);
             try (DebugContext.Scope s = debug.scope("peeling", data.getCFG())) {
                 for (LoopEx loop : data.outerFirst()) {
-                    if (getPolicies().shouldPeel(loop, data.getCFG(), context.getMetaAccess())) {
-                        debug.log("Peeling %s", loop);
-                        LoopTransformations.peel(loop);
-                        debug.dump(DebugContext.DETAILED_LEVEL, graph, "Peeling %s", loop);
+                    if (loop.canDuplicateLoop() && loop.loopBegin().getLoopEndCount() > 0) {
+                        if (LoopPolicies.Options.PeelALot.getValue(graph.getOptions()) || getPolicies().shouldPeel(loop, data.getCFG(), context.getMetaAccess())) {
+                            debug.log("Peeling %s", loop);
+                            PEELED.add(debug, 1);
+                            LoopTransformations.peel(loop);
+                            debug.dump(DebugContext.DETAILED_LEVEL, graph, "Peeling %s", loop);
+                        }
                     }
                 }
                 data.deleteUnusedNodes();
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopTransformations.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopTransformations.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2019, 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
@@ -35,9 +35,13 @@
 import org.graalvm.compiler.core.common.calc.CanonicalCondition;
 import org.graalvm.compiler.debug.DebugContext;
 import org.graalvm.compiler.graph.Graph.Mark;
+import org.graalvm.compiler.graph.Graph.NodeEventScope;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.graph.Position;
+import org.graalvm.compiler.graph.spi.Simplifiable;
+import org.graalvm.compiler.graph.spi.SimplifierTool;
 import org.graalvm.compiler.loop.CountedLoopInfo;
+import org.graalvm.compiler.loop.DefaultLoopPolicies;
 import org.graalvm.compiler.loop.InductionVariable.Direction;
 import org.graalvm.compiler.loop.LoopEx;
 import org.graalvm.compiler.loop.LoopFragmentInside;
@@ -49,6 +53,7 @@
 import org.graalvm.compiler.nodes.BeginNode;
 import org.graalvm.compiler.nodes.ControlSplitNode;
 import org.graalvm.compiler.nodes.EndNode;
+import org.graalvm.compiler.nodes.FixedGuardNode;
 import org.graalvm.compiler.nodes.FixedNode;
 import org.graalvm.compiler.nodes.FixedWithNextNode;
 import org.graalvm.compiler.nodes.IfNode;
@@ -65,8 +70,10 @@
 import org.graalvm.compiler.nodes.extended.OpaqueNode;
 import org.graalvm.compiler.nodes.extended.SwitchNode;
 import org.graalvm.compiler.nodes.spi.CoreProviders;
+import org.graalvm.compiler.nodes.util.GraphUtil;
 import org.graalvm.compiler.nodes.util.IntegerHelper;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.util.EconomicSetNodeEventListener;
 
 public abstract class LoopTransformations {
 
@@ -75,24 +82,63 @@
     }
 
     public static void peel(LoopEx loop) {
+        loop.detectCounted();
         loop.inside().duplicate().insertBefore(loop);
-        loop.loopBegin().setLoopFrequency(Math.max(0.0, loop.loopBegin().loopFrequency() - 1));
+        if (loop.isCounted()) {
+            // For counted loops we assume that we have an effect on the loop frequency.
+            loop.loopBegin().setLoopFrequency(Math.max(1.0, loop.loopBegin().loopFrequency() - 1));
+        }
     }
 
+    @SuppressWarnings("try")
     public static void fullUnroll(LoopEx loop, CoreProviders context, CanonicalizerPhase canonicalizer) {
         // assert loop.isCounted(); //TODO (gd) strengthen : counted with known trip count
         LoopBeginNode loopBegin = loop.loopBegin();
         StructuredGraph graph = loopBegin.graph();
         int initialNodeCount = graph.getNodeCount();
-        while (!loopBegin.isDeleted()) {
-            Mark mark = graph.getMark();
-            peel(loop);
-            canonicalizer.applyIncremental(graph, context, mark);
-            loop.invalidateFragments();
-            if (graph.getNodeCount() > initialNodeCount + MaximumDesiredSize.getValue(graph.getOptions()) * 2) {
-                throw new RetryableBailoutException("FullUnroll : Graph seems to grow out of proportion");
+        SimplifierTool defaultSimplifier = GraphUtil.getDefaultSimplifier(context.getMetaAccess(), context.getConstantReflection(), context.getConstantFieldProvider(),
+                        canonicalizer.getCanonicalizeReads(), graph.getAssumptions(), graph.getOptions());
+        /*
+         * IMPORTANT: Canonicalizations inside the body of the remaining loop can introduce new
+         * control flow that is not automatically picked up by the control flow graph computation of
+         * the original LoopEx data structure, thus we disable simplification and manually simplify
+         * conditions in the peeled iteration to simplify the exit path.
+         */
+        CanonicalizerPhase c = canonicalizer.copyWithoutSimplification();
+        EconomicSetNodeEventListener l = new EconomicSetNodeEventListener();
+        int peelings = 0;
+        try (NodeEventScope ev = graph.trackNodeEvents(l)) {
+            while (!loopBegin.isDeleted()) {
+                Mark newNodes = graph.getMark();
+                /*
+                 * Mark is not enough for the canonicalization of the floating nodes in the unrolled
+                 * code since pre-existing constants are not new nodes. Therefore, we canonicalize
+                 * (without simplification) all floating nodes changed during peeling but only
+                 * simplify new (in the peeled iteration) ones.
+                 */
+                EconomicSetNodeEventListener peeledListener = new EconomicSetNodeEventListener();
+                try (NodeEventScope peeledScope = graph.trackNodeEvents(peeledListener)) {
+                    LoopTransformations.peel(loop);
+                }
+                graph.getDebug().dump(DebugContext.VERY_DETAILED_LEVEL, graph, "After peeling loop %s", loop);
+                c.applyIncremental(graph, context, peeledListener.getNodes());
+                loop.invalidateFragments();
+                for (Node n : graph.getNewNodes(newNodes)) {
+                    if (n.isAlive() && (n instanceof IfNode || n instanceof SwitchNode || n instanceof FixedGuardNode || n instanceof BeginNode)) {
+                        Simplifiable s = (Simplifiable) n;
+                        s.simplify(defaultSimplifier);
+                        graph.getDebug().dump(DebugContext.VERY_DETAILED_LEVEL, graph, "After simplifying if %s", s);
+                    }
+                }
+                if (graph.getNodeCount() > initialNodeCount + MaximumDesiredSize.getValue(graph.getOptions()) * 2 ||
+                                peelings > DefaultLoopPolicies.Options.FullUnrollMaxIterations.getValue(graph.getOptions())) {
+                    throw new RetryableBailoutException("FullUnroll : Graph seems to grow out of proportion");
+                }
+                peelings++;
             }
         }
+        // Canonicalize with the original canonicalizer to capture all simplifications
+        canonicalizer.applyIncremental(graph, context, l.getNodes());
     }
 
     public static void unswitch(LoopEx loop, List<ControlSplitNode> controlSplitNodeSet) {
@@ -280,9 +326,9 @@
 
         // Change the preLoop to execute one iteration for now
         updatePreLoopLimit(preCounted);
-        preLoopBegin.setLoopFrequency(1);
-        mainLoopBegin.setLoopFrequency(Math.max(0.0, mainLoopBegin.loopFrequency() - 2));
-        postLoopBegin.setLoopFrequency(Math.max(0.0, postLoopBegin.loopFrequency() - 1));
+        preLoopBegin.setLoopFrequency(1.0);
+        mainLoopBegin.setLoopFrequency(Math.max(1.0, mainLoopBegin.loopFrequency() - 2));
+        postLoopBegin.setLoopFrequency(Math.max(1.0, postLoopBegin.loopFrequency() - 1));
 
         // The pre and post loops don't require safepoints at all
         for (SafepointNode safepoint : preLoop.nodes().filter(SafepointNode.class)) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.test/src/org/graalvm/compiler/loop/test/LoopPartialUnrollTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.test/src/org/graalvm/compiler/loop/test/LoopPartialUnrollTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2019, 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
@@ -302,7 +302,7 @@
         try (DebugContext.Scope buildScope = graph.getDebug().scope(name, method, graph)) {
             MidTierContext context = new MidTierContext(getProviders(), getTargetProvider(), OptimisticOptimizations.ALL, null);
 
-            CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+            CanonicalizerPhase canonicalizer = this.createCanonicalizerPhase();
             canonicalizer.apply(graph, context);
             new RemoveValueProxyPhase().apply(graph);
             new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
@@ -338,7 +338,7 @@
 
         StructuredGraph referenceGraph = buildGraph(reference, false);
         StructuredGraph testGraph = buildGraph(test, true);
-        CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+        CanonicalizerPhase canonicalizer = createCanonicalizerPhase();
         canonicalizer.apply(testGraph, getDefaultMidTierContext());
         canonicalizer.apply(referenceGraph, getDefaultMidTierContext());
         assertEquals(referenceGraph, testGraph);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/CountedLoopInfo.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/CountedLoopInfo.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2019, 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
@@ -122,18 +122,18 @@
         }
         ValueNode range = sub(max, min);
 
-        ConstantNode one = ConstantNode.forIntegerStamp(stamp, 1);
+        ConstantNode one = ConstantNode.forIntegerStamp(stamp, 1, graph);
         if (oneOff) {
             range = add(range, one);
         }
         // round-away-from-zero divison: (range + stride -/+ 1) / stride
-        ValueNode denominator = add(range, sub(absStride, one));
+        ValueNode denominator = add(graph, range, sub(absStride, one), NodeView.DEFAULT);
         ValueNode div = unsignedDivBefore(graph, loop.entryPoint(), denominator, absStride, null);
 
         if (assumeLoopEntered) {
             return graph.addOrUniqueWithInputs(div);
         }
-        ConstantNode zero = ConstantNode.forIntegerStamp(stamp, 0);
+        ConstantNode zero = ConstantNode.forIntegerStamp(stamp, 0, graph);
         // This check is "wide": it looks like min <= max
         // That's OK even if the loop is strict (`!isLimitIncluded()`)
         // because in this case, `div` will be zero when min == max
@@ -142,6 +142,40 @@
     }
 
     /**
+     * Determine if the loop might be entered. Returns {@code false} if we can tell statically that
+     * the loop cannot be entered; returns {@code true} if the loop might possibly be entered,
+     * including in the case where we cannot be sure statically.
+     *
+     * @return false if the loop can definitely not be entered, true otherwise
+     */
+    public boolean loopMightBeEntered() {
+        Stamp stamp = iv.valueNode().stamp(NodeView.DEFAULT);
+
+        ValueNode max;
+        ValueNode min;
+        if (iv.direction() == Direction.Up) {
+            max = end;
+            min = iv.initNode();
+        } else {
+            assert iv.direction() == Direction.Down;
+            max = iv.initNode();
+            min = end;
+        }
+        if (oneOff) {
+            max = add(max, ConstantNode.forIntegerStamp(stamp, 1));
+        }
+
+        LogicNode entryCheck = getCounterIntegerHelper().createCompareNode(min, max, NodeView.DEFAULT);
+        if (entryCheck.isContradiction()) {
+            // We can definitely not enter this loop.
+            return false;
+        } else {
+            // We don't know for sure that the loop can't be entered, so assume it can.
+            return true;
+        }
+    }
+
+    /**
      * @return true if the loop has constant bounds.
      */
     public boolean isConstantMaxTripCount() {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/DefaultLoopPolicies.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/DefaultLoopPolicies.java	Thu Oct 31 16:54:16 2019 -0700
@@ -26,7 +26,7 @@
 
 import static org.graalvm.compiler.core.common.GraalOptions.LoopMaxUnswitch;
 import static org.graalvm.compiler.core.common.GraalOptions.MaximumDesiredSize;
-import static org.graalvm.compiler.core.common.GraalOptions.MinimumPeelProbability;
+import static org.graalvm.compiler.core.common.GraalOptions.MinimumPeelFrequency;
 
 import java.util.List;
 
@@ -38,9 +38,6 @@
 import org.graalvm.compiler.graph.NodeBitMap;
 import org.graalvm.compiler.nodes.AbstractBeginNode;
 import org.graalvm.compiler.nodes.ControlSplitNode;
-import org.graalvm.compiler.nodes.DeoptimizeNode;
-import org.graalvm.compiler.nodes.FixedNode;
-import org.graalvm.compiler.nodes.FixedWithNextNode;
 import org.graalvm.compiler.nodes.InvokeNode;
 import org.graalvm.compiler.nodes.LoopBeginNode;
 import org.graalvm.compiler.nodes.MergeNode;
@@ -51,7 +48,6 @@
 import org.graalvm.compiler.nodes.cfg.Block;
 import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
 import org.graalvm.compiler.nodes.debug.ControlFlowAnchorNode;
-import org.graalvm.compiler.nodes.java.TypeSwitchNode;
 import org.graalvm.compiler.options.Option;
 import org.graalvm.compiler.options.OptionKey;
 import org.graalvm.compiler.options.OptionType;
@@ -79,13 +75,32 @@
     public boolean shouldPeel(LoopEx loop, ControlFlowGraph cfg, MetaAccessProvider metaAccess) {
         LoopBeginNode loopBegin = loop.loopBegin();
         double entryProbability = cfg.blockFor(loopBegin.forwardEnd()).getRelativeFrequency();
-        OptionValues options = cfg.graph.getOptions();
-        if (entryProbability > MinimumPeelProbability.getValue(options) && loop.size() + loopBegin.graph().getNodeCount() < MaximumDesiredSize.getValue(options)) {
-            // check whether we're allowed to peel this loop
-            return loop.canDuplicateLoop();
-        } else {
+        StructuredGraph graph = cfg.graph;
+        OptionValues options = graph.getOptions();
+
+        if (entryProbability < MinimumPeelFrequency.getValue(options)) {
             return false;
         }
+
+        if (loop.parent() != null) {
+            if (loop.size() > loop.parent().size() >> 1) {
+                // This loops make up more than half of the parent loop in terms of number of nodes.
+                // There is a risk that this loop unproportionally increases parent loop body size.
+                return false;
+            }
+        }
+
+        if (loop.loop().getChildren().size() > 0) {
+            // This loop has child loops. Loop peeling could explode graph size.
+            return false;
+        }
+
+        if (loop.size() + graph.getNodeCount() > MaximumDesiredSize.getValue(options)) {
+            // We are out of budget for peeling.
+            return false;
+        }
+
+        return true;
     }
 
     @Override
@@ -189,7 +204,7 @@
             return false;
         }
         OptionValues options = loop.entryPoint().getOptions();
-        return loopBegin.unswitches() <= LoopMaxUnswitch.getValue(options);
+        return loopBegin.unswitches() < LoopMaxUnswitch.getValue(options);
     }
 
     private static final class CountingClosure implements VirtualClosure {
@@ -238,19 +253,9 @@
         int loopTotal = loop.size() - loop.loopBegin().phis().count() - stateNodesCount.count - 1;
         int actualDiff = (loopTotal - inBranchTotal);
         ControlSplitNode firstSplit = controlSplits.get(0);
-        if (firstSplit instanceof TypeSwitchNode) {
-            int copies = firstSplit.successors().count() - 1;
-            for (Node succ : firstSplit.successors()) {
-                FixedNode current = (FixedNode) succ;
-                while (current instanceof FixedWithNextNode) {
-                    current = ((FixedWithNextNode) current).next();
-                }
-                if (current instanceof DeoptimizeNode) {
-                    copies--;
-                }
-            }
-            actualDiff = actualDiff * copies;
-        }
+
+        int copies = firstSplit.successors().count() - 1;
+        actualDiff = actualDiff * copies;
 
         debug.log("shouldUnswitch(%s, %s) : delta=%d (%.2f%% inside of branches), max=%d, f=%.2f, phis=%d -> %b", loop, controlSplits, actualDiff, (double) (inBranchTotal) / loopTotal * 100, maxDiff,
                         loopFrequency, phis, actualDiff <= maxDiff);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopEx.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopEx.java	Thu Oct 31 16:54:16 2019 -0700
@@ -81,6 +81,7 @@
     private LoopsData data;
     private EconomicMap<Node, InductionVariable> ivs;
     private boolean countedLoopChecked;
+    private int size = -1;
 
     LoopEx(Loop<Block> loop, LoopsData data) {
         this.loop = loop;
@@ -156,7 +157,10 @@
     }
 
     public int size() {
-        return whole().nodes().count();
+        if (size == -1) {
+            size = whole().nodes().count();
+        }
+        return size;
     }
 
     @Override
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragment.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragment.java	Thu Oct 31 16:54:16 2019 -0700
@@ -349,12 +349,11 @@
                         TriState isAnchorInLoop = isLoopNode(anchor, loopNodes, nonLoopNodes);
                         if (isAnchorInLoop != TriState.FALSE) {
                             if (!(anchor instanceof LoopExitNode && ((LoopExitNode) anchor).loopBegin() == loopBeginNode)) {
-                                /*
-                                 * (gd) this is wrong in general, it's completely avoidable while we
-                                 * are doing loop transforms using ValueProxies. If it happens after
-                                 * it could still cause problem.
-                                 */
-                                assert !((GuardNode) current).graph().hasValueProxies();
+                                // It is undecidable whether the node is in the loop or not. This is
+                                // not an issue for getting counted loop information,
+                                // but causes issues when using the information for actual loop
+                                // transformations. This is why a loop transformation must
+                                // not happen while guards are floating.
                                 isLoopNode = true;
                             }
                         } else if (AbstractControlFlowGraph.strictlyDominates(cfg.blockFor(anchor), cfg.blockFor(loopBeginNode))) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragmentInside.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragmentInside.java	Thu Oct 31 16:54:16 2019 -0700
@@ -233,7 +233,7 @@
             }
         }
         mainLoopBegin.setUnrollFactor(mainLoopBegin.getUnrollFactor() * 2);
-        mainLoopBegin.setLoopFrequency(mainLoopBegin.loopFrequency() / 2);
+        mainLoopBegin.setLoopFrequency(Math.max(1.0, mainLoopBegin.loopFrequency() / 2));
         graph.getDebug().dump(DebugContext.DETAILED_LEVEL, graph, "LoopPartialUnroll %s", loop);
 
         mainLoopBegin.getDebug().dump(DebugContext.VERBOSE_LEVEL, mainLoopBegin.graph(), "After insertWithinAfter %s", mainLoopBegin);
@@ -438,7 +438,7 @@
             for (int i = 0; i < phi.valueCount(); i++) {
                 ValueNode v = phi.valueAt(i);
                 if (loopBegin.isPhiAtMerge(v)) {
-                    PhiNode newV = peel.getDuplicatedNode((ValuePhiNode) v);
+                    PhiNode newV = peel.getDuplicatedNode((PhiNode) v);
                     if (newV != null) {
                         phi.setValueAt(i, newV);
                     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopPolicies.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopPolicies.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, 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
@@ -28,10 +28,18 @@
 
 import org.graalvm.compiler.nodes.ControlSplitNode;
 import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionKey;
+import org.graalvm.compiler.options.OptionType;
 
 import jdk.vm.ci.meta.MetaAccessProvider;
 
 public interface LoopPolicies {
+
+    class Options {
+        @Option(help = "", type = OptionType.Expert) public static final OptionKey<Boolean> PeelALot = new OptionKey<>(false);
+    }
+
     boolean shouldPeel(LoopEx loop, ControlFlowGraph cfg, MetaAccessProvider metaAccess);
 
     boolean shouldFullUnroll(LoopEx loop);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/MathUtil.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/MathUtil.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, 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
@@ -94,7 +94,9 @@
             if (before.predecessor() instanceof FixedBinaryNode) {
                 FixedBinaryNode binaryPredecessor = (FixedBinaryNode) before.predecessor();
                 if (fixedDiv.dataFlowEquals(binaryPredecessor)) {
-                    fixedDiv.safeDelete();
+                    if (fixedDiv.isAlive()) {
+                        fixedDiv.safeDelete();
+                    }
                     return binaryPredecessor;
                 }
             }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/GraalBenchmark.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/GraalBenchmark.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, 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
@@ -28,6 +28,8 @@
 import static org.graalvm.compiler.microbenchmarks.graal.GraalBenchmark.Defaults.MEASUREMENT_ITERATIONS;
 import static org.graalvm.compiler.microbenchmarks.graal.GraalBenchmark.Defaults.WARMUP_ITERATIONS;
 
+import org.graalvm.compiler.api.test.ModuleSupport;
+
 import org.openjdk.jmh.annotations.Fork;
 import org.openjdk.jmh.annotations.Measurement;
 import org.openjdk.jmh.annotations.Warmup;
@@ -41,6 +43,9 @@
 @Measurement(iterations = MEASUREMENT_ITERATIONS)
 @Fork(FORKS)
 public class GraalBenchmark {
+    static {
+        ModuleSupport.exportAndOpenAllPackagesToUnnamed("jdk.internal.vm.compiler");
+    }
 
     public static class Defaults {
         public static final int MEASUREMENT_ITERATIONS = 5;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/TestJMHWhitebox.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/TestJMHWhitebox.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, 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
@@ -36,7 +36,7 @@
 /**
  * This dummy class is used to verify that the JMH microbenchmarking environment is set up properly.
  */
-public class TestJMHWhitebox {
+public class TestJMHWhitebox extends GraalBenchmark {
 
     @Benchmark
     public void testJMH(@SuppressWarnings("unused") GraalState s) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/IfNodeCanonicalizationTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/IfNodeCanonicalizationTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -67,19 +67,19 @@
                     for (byte d : testValues) {
                         values[3] = d;
                         value = 2;
-                        super.test("testSnippet1", values, true);
-                        super.test("testSnippet1", values, false);
+                        super.test("testSnippet1", values);
                     }
                 }
             }
         }
     }
 
-    public int testSnippet1(byte[] values, boolean test) {
+    public int testSnippet1(byte[] values) {
         int v = values[0] - values[1];
-        if (test) {
-            v = values[2] - values[3];
+        if (v < 0) {
+            value = 2;
         }
+        v = values[3] - values[2];
         if (v < 0) {
             value = 1;
         }
@@ -156,13 +156,12 @@
         StructuredGraph graph = parseEager(name, AllowAssumptions.YES);
 
         CoreProviders context = getProviders();
-        CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+        CanonicalizerPhase canonicalizer = createCanonicalizerPhase();
         new ConvertDeoptimizeToGuardPhase().apply(graph, context);
         graph.clearAllStateAfter();
         graph.setGuardsStage(StructuredGraph.GuardsStage.AFTER_FSA);
         canonicalizer.apply(graph, context);
 
-        // new DominatorConditionalEliminationPhase(true).apply(graph, context);
         new IterativeConditionalEliminationPhase(canonicalizer, true).apply(graph, context);
         canonicalizer.apply(graph, context);
         canonicalizer.apply(graph, context);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/LoopPhiCanonicalizerTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/LoopPhiCanonicalizerTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -31,7 +31,6 @@
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
 import org.graalvm.compiler.nodes.spi.CoreProviders;
-import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.junit.Assert;
 import org.junit.BeforeClass;
 import org.junit.Test;
@@ -67,7 +66,7 @@
 
         CoreProviders context = getProviders();
         Assert.assertEquals(5, graph.getNodes().filter(loopPhis).count());
-        new CanonicalizerPhase().apply(graph, context);
+        createCanonicalizerPhase().apply(graph, context);
         Assert.assertEquals(2, graph.getNodes().filter(loopPhis).count());
 
         test("loopSnippet");
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/ShortCircuitOrNodeTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/ShortCircuitOrNodeTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -378,7 +378,7 @@
             String snippet = "testCascadeSnippet" + i;
             StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
             CoreProviders context = getProviders();
-            CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+            CanonicalizerPhase canonicalizer = createCanonicalizerPhase();
             canonicalizer.apply(graph, context);
             new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
             new IncrementalCanonicalizerPhase<>(canonicalizer, new FloatingReadPhase()).apply(graph, context);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FrameState.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FrameState.java	Thu Oct 31 16:54:16 2019 -0700
@@ -306,15 +306,8 @@
     /**
      * Gets a copy of this frame state.
      */
-    public FrameState duplicate(int newBci) {
-        return graph().add(new FrameState(outerFrameState(), code, newBci, values, localsSize, stackSize, rethrowException, duringCall, monitorIds, virtualObjectMappings));
-    }
-
-    /**
-     * Gets a copy of this frame state.
-     */
     public FrameState duplicate() {
-        return duplicate(bci);
+        return graph().add(new FrameState(outerFrameState(), code, bci, values, localsSize, stackSize, rethrowException, duringCall, monitorIds, virtualObjectMappings));
     }
 
     /**
@@ -350,20 +343,6 @@
     }
 
     /**
-     * Creates a copy of this frame state with one stack element of type {@code popKind} popped from
-     * the stack and the values in {@code pushedValues} pushed on the stack. The
-     * {@code pushedValues} will be formatted correctly in slot encoding: a long or double will be
-     * followed by a null slot.
-     */
-    public FrameState duplicateModified(int newBci, boolean newRethrowException, JavaKind popKind, JavaKind[] pushedSlotKinds, ValueNode[] pushedValues) {
-        return duplicateModified(graph(), newBci, newRethrowException, duringCall, popKind, pushedSlotKinds, pushedValues);
-    }
-
-    public FrameState duplicateModified(int newBci, boolean newRethrowException, boolean newDuringCall, JavaKind popKind, JavaKind[] pushedSlotKinds, ValueNode[] pushedValues) {
-        return duplicateModified(graph(), newBci, newRethrowException, newDuringCall, popKind, pushedSlotKinds, pushedValues);
-    }
-
-    /**
      * Creates a copy of this frame state with the top of stack replaced with with
      * {@code pushedValue} which must be of type {@code popKind}.
      */
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphDecoder.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphDecoder.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, 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
@@ -1748,7 +1748,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, graph);
+                ValueProxyNode proxy = ProxyNode.forValue(proxyPlaceholder.value, loopExit);
                 proxyPlaceholder.setValue(proxy);
                 newValues.add(proxy);
             }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GuardProxyNode.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GuardProxyNode.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2019, 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
@@ -25,19 +25,13 @@
 package org.graalvm.compiler.nodes;
 
 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.Canonicalizable;
-import org.graalvm.compiler.graph.spi.CanonicalizerTool;
 import org.graalvm.compiler.nodeinfo.InputType;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
 import org.graalvm.compiler.nodes.extended.GuardingNode;
-import org.graalvm.compiler.nodes.spi.LIRLowerable;
-import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
-import org.graalvm.compiler.nodes.spi.Proxy;
 
-@NodeInfo(allowedUsageTypes = {InputType.Guard}, nameTemplate = "Proxy({i#value})")
-public final class GuardProxyNode extends ProxyNode implements GuardingNode, Proxy, LIRLowerable, Canonicalizable {
+@NodeInfo(allowedUsageTypes = {InputType.Guard}, nameTemplate = "GuardProxy({i#value})")
+public final class GuardProxyNode extends ProxyNode implements GuardingNode {
 
     public static final NodeClass<GuardProxyNode> TYPE = NodeClass.create(GuardProxyNode.class);
     @OptionalInput(InputType.Guard) GuardingNode value;
@@ -47,10 +41,6 @@
         this.value = value;
     }
 
-    @Override
-    public void generate(NodeLIRBuilderTool generator) {
-    }
-
     public void setValue(GuardingNode newValue) {
         this.updateUsages(value.asNode(), newValue.asNode());
         this.value = newValue;
@@ -65,17 +55,4 @@
     public PhiNode createPhi(AbstractMergeNode merge) {
         return graph().addWithoutUnique(new GuardPhiNode(merge));
     }
-
-    @Override
-    public Node getOriginalNode() {
-        return (value == null ? null : value.asNode());
-    }
-
-    @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (value == null) {
-            return null;
-        }
-        return this;
-    }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/IfNode.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/IfNode.java	Thu Oct 31 16:54:16 2019 -0700
@@ -54,7 +54,6 @@
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.graph.NodeSourcePosition;
 import org.graalvm.compiler.graph.iterators.NodeIterable;
-import org.graalvm.compiler.graph.spi.Canonicalizable;
 import org.graalvm.compiler.graph.spi.Simplifiable;
 import org.graalvm.compiler.graph.spi.SimplifierTool;
 import org.graalvm.compiler.nodeinfo.InputType;
@@ -95,9 +94,6 @@
 public final class IfNode extends ControlSplitNode implements Simplifiable, LIRLowerable, IterableNodeType, SwitchFoldable {
     public static final NodeClass<IfNode> TYPE = NodeClass.create(IfNode.class);
 
-    private static final int MAX_USAGE_COLOR_SET_SIZE = 64;
-    private static final int MAX_FRAMESTATE_SEARCH_DEPTH = 4;
-
     private static final CounterKey CORRECTED_PROBABILITIES = DebugContext.counter("CorrectedProbabilities");
 
     @Successor AbstractBeginNode trueSuccessor;
@@ -297,10 +293,6 @@
             return;
         }
 
-        if (splitIfAtPhi(tool)) {
-            return;
-        }
-
         if (conditionalNodeOptimization(tool)) {
             return;
         }
@@ -1185,400 +1177,6 @@
     }
 
     /**
-     * Take an if that is immediately dominated by a merge with a single phi and split off any paths
-     * where the test would be statically decidable creating a new merge below the appropriate side
-     * of the IfNode. Any undecidable tests will continue to use the original IfNode.
-     *
-     * @param tool
-     */
-    @SuppressWarnings("try")
-    private boolean splitIfAtPhi(SimplifierTool tool) {
-        if (!(predecessor() instanceof MergeNode)) {
-            return false;
-        }
-        MergeNode merge = (MergeNode) predecessor();
-        if (merge.forwardEndCount() == 1) {
-            // Don't bother.
-            return false;
-        }
-        if (merge.getUsageCount() != 1 || merge.phis().count() != 1) {
-            // Don't trigger with multiple phis. Would require more rewiring.
-            // Most of the time the additional phis are memory phis that are removed after
-            // fixed read phase.
-            return false;
-        }
-        if (graph().getGuardsStage().areFrameStatesAtSideEffects() && merge.stateAfter() == null) {
-            return false;
-        }
-
-        PhiNode generalPhi = merge.phis().first();
-        if (!(generalPhi instanceof ValuePhiNode)) {
-            return false;
-        }
-
-        if (trueSuccessor().isUsedAsGuardInput() || falseSuccessor().isUsedAsGuardInput()) {
-            return false;
-        }
-
-        ValuePhiNode phi = (ValuePhiNode) generalPhi;
-
-        EconomicMap<Node, NodeColor> coloredNodes = EconomicMap.create(Equivalence.IDENTITY, 8);
-
-        /*
-         * Check that the condition uses the phi and that there is only one user of the condition
-         * expression.
-         */
-        if (!conditionUses(condition(), phi, coloredNodes)) {
-            return false;
-        }
-
-        if (!mayRemoveSplit(merge)) {
-            return false;
-        }
-
-        LogicNode[] results = new LogicNode[merge.forwardEndCount()];
-        boolean success = false;
-        for (int i = 0; i < results.length; ++i) {
-            ValueNode value = phi.valueAt(i);
-            LogicNode curResult = computeCondition(tool, condition, phi, value);
-            if (curResult != condition) {
-                for (Node n : curResult.inputs()) {
-                    if (n instanceof ConstantNode || n instanceof ParameterNode || n instanceof FixedNode) {
-                        // Constant inputs or parameters or fixed nodes are OK.
-                    } else if (n == value) {
-                        // References to the value itself are also OK.
-                    } else {
-                        // Input may cause scheduling issues.
-                        curResult = condition;
-                        break;
-                    }
-                }
-                success = true;
-            }
-            results[i] = curResult;
-        }
-
-        if (!success) {
-            return false;
-        }
-
-        for (Node usage : phi.usages()) {
-            if (usage == merge.stateAfter()) {
-                // This usage can be ignored, because it is directly in the state after.
-            } else {
-                NodeColor color = colorUsage(coloredNodes, usage, merge, this.trueSuccessor(), this.falseSuccessor());
-                if (color == NodeColor.MIXED) {
-                    return false;
-                }
-            }
-        }
-
-        /*
-         * We could additionally filter for the case that at least some of the Phi inputs or one of
-         * the condition inputs are constants but there are cases where a non-constant is
-         * simplifiable, usually where the stamp allows the question to be answered.
-         */
-
-        /* Each successor of the if gets a new merge if needed. */
-        MergeNode trueMerge = null;
-        MergeNode falseMerge = null;
-        int i = 0;
-        for (EndNode end : merge.forwardEnds().snapshot()) {
-            ValueNode value = phi.valueAt(end);
-            LogicNode result = results[i++];
-            if (result instanceof LogicConstantNode) {
-                if (((LogicConstantNode) result).getValue()) {
-                    if (trueMerge == null) {
-                        trueMerge = insertMerge(trueSuccessor(), phi, merge.stateAfter(), tool);
-                        replaceNodesInBranch(coloredNodes, NodeColor.TRUE_BRANCH, phi, trueMerge.phis().first());
-                    }
-                    trueMerge.phis().first().addInput(value);
-                    trueMerge.addForwardEnd(end);
-                } else {
-                    if (falseMerge == null) {
-                        falseMerge = insertMerge(falseSuccessor(), phi, merge.stateAfter(), tool);
-                        replaceNodesInBranch(coloredNodes, NodeColor.FALSE_BRANCH, phi, falseMerge.phis().first());
-                    }
-                    falseMerge.phis().first().addInput(value);
-                    falseMerge.addForwardEnd(end);
-                }
-                merge.removeEnd(end);
-            } else if (result != condition) {
-                // Build a new IfNode using the new condition
-                BeginNode trueBegin = graph().add(new BeginNode());
-                trueBegin.setNodeSourcePosition(trueSuccessor().getNodeSourcePosition());
-                BeginNode falseBegin = graph().add(new BeginNode());
-                falseBegin.setNodeSourcePosition(falseSuccessor().getNodeSourcePosition());
-
-                if (result.graph() == null) {
-                    result = graph().addOrUniqueWithInputs(result);
-                    result.setNodeSourcePosition(condition.getNodeSourcePosition());
-                }
-                IfNode newIfNode = graph().add(new IfNode(result, trueBegin, falseBegin, trueSuccessorProbability));
-                newIfNode.setNodeSourcePosition(getNodeSourcePosition());
-
-                if (trueMerge == null) {
-                    trueMerge = insertMerge(trueSuccessor(), phi, merge.stateAfter(), tool);
-                    replaceNodesInBranch(coloredNodes, NodeColor.TRUE_BRANCH, phi, trueMerge.phis().first());
-                }
-                trueMerge.phis().first().addInput(value);
-                trueBegin.setNext(graph().add(new EndNode()));
-                trueMerge.addForwardEnd((EndNode) trueBegin.next());
-
-                if (falseMerge == null) {
-                    falseMerge = insertMerge(falseSuccessor(), phi, merge.stateAfter(), tool);
-                    replaceNodesInBranch(coloredNodes, NodeColor.FALSE_BRANCH, phi, falseMerge.phis().first());
-                }
-                falseMerge.phis().first().addInput(value);
-                falseBegin.setNext(graph().add(new EndNode()));
-                falseMerge.addForwardEnd((EndNode) falseBegin.next());
-
-                merge.removeEnd(end);
-                ((FixedWithNextNode) end.predecessor()).setNext(newIfNode);
-                end.safeDelete();
-            }
-        }
-
-        cleanupMerge(merge);
-        cleanupMerge(trueMerge);
-        cleanupMerge(falseMerge);
-
-        return true;
-    }
-
-    private static void replaceNodesInBranch(EconomicMap<Node, NodeColor> coloredNodes, NodeColor branch, ValuePhiNode phi, ValueNode newValue) {
-        for (Node n : phi.usages().snapshot()) {
-            if (coloredNodes.get(n) == branch) {
-                n.replaceAllInputs(phi, newValue);
-            } else if (coloredNodes.get(n) == NodeColor.PHI_MIXED) {
-                assert n instanceof PhiNode;
-                PhiNode phiNode = (PhiNode) n;
-                AbstractMergeNode merge = phiNode.merge();
-                for (int i = 0; i < merge.forwardEndCount(); ++i) {
-                    if (phiNode.valueAt(i) == phi && coloredNodes.get(merge.forwardEndAt(i)) == branch) {
-                        phiNode.setValueAt(i, newValue);
-                    }
-                }
-            }
-        }
-    }
-
-    private NodeColor colorUsage(EconomicMap<Node, NodeColor> coloredNodes, Node node, MergeNode merge, AbstractBeginNode trueSucc, AbstractBeginNode falseSucc) {
-        NodeColor color = coloredNodes.get(node);
-        if (color == null) {
-
-            if (coloredNodes.size() >= MAX_USAGE_COLOR_SET_SIZE) {
-                return NodeColor.MIXED;
-            }
-
-            coloredNodes.put(node, NodeColor.MIXED);
-
-            if (node == merge) {
-                color = NodeColor.MIXED;
-            } else if (node == trueSucc) {
-                color = NodeColor.TRUE_BRANCH;
-            } else if (node == falseSucc) {
-                color = NodeColor.FALSE_BRANCH;
-            } else {
-                if (node instanceof AbstractMergeNode) {
-                    AbstractMergeNode mergeNode = (AbstractMergeNode) node;
-                    NodeColor combinedColor = null;
-                    for (int i = 0; i < mergeNode.forwardEndCount(); ++i) {
-                        NodeColor curColor = colorUsage(coloredNodes, mergeNode.forwardEndAt(i), merge, trueSucc, falseSucc);
-                        if (combinedColor == null) {
-                            combinedColor = curColor;
-                        } else if (combinedColor != curColor) {
-                            combinedColor = NodeColor.MIXED;
-                            break;
-                        }
-                    }
-                    color = combinedColor;
-                } else if (node instanceof StartNode) {
-                    color = NodeColor.MIXED;
-                } else if (node instanceof FixedNode) {
-                    FixedNode fixedNode = (FixedNode) node;
-                    Node predecessor = fixedNode.predecessor();
-                    assert predecessor != null : fixedNode;
-                    color = colorUsage(coloredNodes, predecessor, merge, trueSucc, falseSucc);
-                } else if (node instanceof PhiNode) {
-                    PhiNode phiNode = (PhiNode) node;
-                    AbstractMergeNode phiMerge = phiNode.merge();
-
-                    if (phiMerge instanceof LoopBeginNode) {
-                        color = colorUsage(coloredNodes, phiMerge, merge, trueSucc, falseSucc);
-                    } else {
-
-                        for (int i = 0; i < phiMerge.forwardEndCount(); ++i) {
-                            NodeColor curColor = colorUsage(coloredNodes, phiMerge.forwardEndAt(i), merge, trueSucc, falseSucc);
-                            if (curColor != NodeColor.TRUE_BRANCH && curColor != NodeColor.FALSE_BRANCH) {
-                                color = NodeColor.MIXED;
-                                break;
-                            }
-                        }
-
-                        if (color == null) {
-                            // Each of the inputs to the phi are either coming unambigously from
-                            // true or false branch.
-                            color = NodeColor.PHI_MIXED;
-                            assert node instanceof PhiNode;
-                        }
-                    }
-                } else {
-                    NodeColor combinedColor = null;
-                    for (Node n : node.usages()) {
-                        if (n != node) {
-                            NodeColor curColor = colorUsage(coloredNodes, n, merge, trueSucc, falseSucc);
-                            if (combinedColor == null) {
-                                combinedColor = curColor;
-                            } else if (combinedColor != curColor) {
-                                combinedColor = NodeColor.MIXED;
-                                break;
-                            }
-                        }
-                    }
-                    if (combinedColor == NodeColor.PHI_MIXED) {
-                        combinedColor = NodeColor.MIXED;
-                    }
-                    if (combinedColor == null) {
-                        // Floating node without usages => association unclear.
-                        combinedColor = NodeColor.MIXED;
-                    }
-                    color = combinedColor;
-                }
-            }
-
-            assert color != null : node;
-            coloredNodes.put(node, color);
-        }
-        return color;
-    }
-
-    /**
-     * @param condition
-     * @param phi
-     * @param coloredNodes
-     * @return true if the passed in {@code condition} uses {@code phi} and the condition is only
-     *         used once. Since the phi will go dead the condition using it will also have to be
-     *         dead after the optimization.
-     */
-    private static boolean conditionUses(LogicNode condition, PhiNode phi, EconomicMap<Node, NodeColor> coloredNodes) {
-        if (!condition.hasExactlyOneUsage()) {
-            return false;
-        }
-        if (condition instanceof ShortCircuitOrNode) {
-            if (condition.graph().getGuardsStage().areDeoptsFixed()) {
-                /*
-                 * It can be unsafe to simplify a ShortCircuitOr before deopts are fixed because
-                 * conversion to guards assumes that all the required conditions are being tested.
-                 * Simplfying the condition based on context before this happens may lose a
-                 * condition.
-                 */
-                ShortCircuitOrNode orNode = (ShortCircuitOrNode) condition;
-                return (conditionUses(orNode.x, phi, coloredNodes) || conditionUses(orNode.y, phi, coloredNodes));
-            }
-        } else if (condition instanceof Canonicalizable.Unary<?>) {
-            Canonicalizable.Unary<?> unary = (Canonicalizable.Unary<?>) condition;
-            if (unary.getValue() == phi) {
-                coloredNodes.put(condition, NodeColor.CONDITION_USAGE);
-                return true;
-            }
-        } else if (condition instanceof Canonicalizable.Binary<?>) {
-            Canonicalizable.Binary<?> binary = (Canonicalizable.Binary<?>) condition;
-            if (binary.getX() == phi || binary.getY() == phi) {
-                coloredNodes.put(condition, NodeColor.CONDITION_USAGE);
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Canonicalize {@code} condition using {@code value} in place of {@code phi}.
-     *
-     * @param tool
-     * @param condition
-     * @param phi
-     * @param value
-     * @return an improved LogicNode or the original condition
-     */
-    @SuppressWarnings("unchecked")
-    private static LogicNode computeCondition(SimplifierTool tool, LogicNode condition, PhiNode phi, Node value) {
-        if (condition instanceof ShortCircuitOrNode) {
-            if (condition.graph().getGuardsStage().areDeoptsFixed() && !condition.graph().isAfterExpandLogic()) {
-                ShortCircuitOrNode orNode = (ShortCircuitOrNode) condition;
-                LogicNode resultX = computeCondition(tool, orNode.x, phi, value);
-                LogicNode resultY = computeCondition(tool, orNode.y, phi, value);
-                if (resultX != orNode.x || resultY != orNode.y) {
-                    LogicNode result = orNode.canonical(tool, resultX, resultY);
-                    if (result != orNode) {
-                        return result;
-                    }
-                    /*
-                     * Create a new node to carry the optimized inputs.
-                     */
-                    ShortCircuitOrNode newOr = new ShortCircuitOrNode(resultX, orNode.xNegated, resultY,
-                                    orNode.yNegated, orNode.getShortCircuitProbability());
-                    return newOr.canonical(tool);
-                }
-                return orNode;
-            }
-        } else if (condition instanceof Canonicalizable.Binary<?>) {
-            Canonicalizable.Binary<Node> compare = (Canonicalizable.Binary<Node>) condition;
-            if (compare.getX() == phi || compare.getY() == phi) {
-                return (LogicNode) compare.canonical(tool, compare.getX() == phi ? value : compare.getX(), compare.getY() == phi ? value : compare.getY());
-            }
-        } else if (condition instanceof Canonicalizable.Unary<?>) {
-            Canonicalizable.Unary<Node> compare = (Canonicalizable.Unary<Node>) condition;
-            if (compare.getValue() == phi) {
-                return (LogicNode) compare.canonical(tool, value);
-            }
-        }
-        if (condition instanceof Canonicalizable) {
-            return (LogicNode) ((Canonicalizable) condition).canonical(tool);
-        }
-        return condition;
-    }
-
-    private void cleanupMerge(MergeNode merge) {
-        if (merge != null && merge.isAlive()) {
-            if (merge.forwardEndCount() == 0) {
-                GraphUtil.killCFG(merge);
-            } else if (merge.forwardEndCount() == 1) {
-                graph().reduceTrivialMerge(merge);
-            }
-        }
-    }
-
-    @SuppressWarnings("try")
-    private MergeNode insertMerge(AbstractBeginNode begin, ValuePhiNode oldPhi, FrameState stateAfter, SimplifierTool tool) {
-        MergeNode merge = graph().add(new MergeNode());
-
-        AbstractBeginNode newBegin;
-        try (DebugCloseable position = begin.withNodeSourcePosition()) {
-            newBegin = graph().add(new BeginNode());
-            begin.replaceAtPredecessor(newBegin);
-            newBegin.setNext(begin);
-        }
-
-        FixedNode next = newBegin.next();
-        next.replaceAtPredecessor(merge);
-        newBegin.setNext(graph().add(new EndNode()));
-        merge.addForwardEnd((EndNode) newBegin.next());
-
-        ValuePhiNode phi = begin.graph().addOrUnique(new ValuePhiNode(oldPhi.stamp(NodeView.DEFAULT), merge));
-        phi.addInput(oldPhi);
-
-        if (stateAfter != null) {
-            FrameState newState = stateAfter.duplicate();
-            newState.replaceAllInputs(oldPhi, phi);
-            merge.setStateAfter(newState);
-        }
-        merge.setNext(next);
-        tool.addToWorkList(begin);
-        return merge;
-    }
-
-    /**
      * Tries to connect code that initializes a variable directly with the successors of an if
      * construct that switches on the variable. For example, the pseudo code below:
      *
@@ -1709,7 +1307,7 @@
             return false;
         }
 
-        if (!mayRemoveSplit(merge)) {
+        if (merge.stateAfter() != null && !GraphUtil.mayRemoveSplit(this)) {
             return false;
         }
 
@@ -1771,15 +1369,6 @@
         return true;
     }
 
-    private boolean mayRemoveSplit(AbstractMergeNode merge) {
-
-        if (merge.stateAfter() != null && (!checkFrameState(trueSuccessor, MAX_FRAMESTATE_SEARCH_DEPTH) || !checkFrameState(trueSuccessor, MAX_FRAMESTATE_SEARCH_DEPTH))) {
-            return false;
-        }
-
-        return true;
-    }
-
     private static void propagateZeroProbability(FixedNode startNode) {
         Node prev = null;
         for (FixedNode node : GraphUtil.predecessorIterable(startNode)) {
@@ -1817,53 +1406,6 @@
     }
 
     /**
-     * Snippet lowerings may produce patterns without a frame state on the merge. We need to take
-     * extra care when optimizing these patterns.
-     */
-    private static boolean checkFrameState(FixedNode start, int maxDepth) {
-        if (maxDepth == 0) {
-            return false;
-        }
-        FixedNode node = start;
-        while (true) {
-            if (node instanceof AbstractMergeNode) {
-                AbstractMergeNode mergeNode = (AbstractMergeNode) node;
-                if (mergeNode.stateAfter() == null) {
-                    return false;
-                } else {
-                    return true;
-                }
-            } else if (node instanceof StateSplit) {
-                StateSplit stateSplitNode = (StateSplit) node;
-                if (stateSplitNode.stateAfter() != null) {
-                    return true;
-                }
-            }
-
-            if (node instanceof ControlSplitNode) {
-                ControlSplitNode controlSplitNode = (ControlSplitNode) node;
-                for (Node succ : controlSplitNode.cfgSuccessors()) {
-                    if (checkFrameState((FixedNode) succ, maxDepth - 1)) {
-                        return true;
-                    }
-                }
-                return false;
-            } else if (node instanceof FixedWithNextNode) {
-                FixedWithNextNode fixedWithNextNode = (FixedWithNextNode) node;
-                node = fixedWithNextNode.next();
-            } else if (node instanceof AbstractEndNode) {
-                AbstractEndNode endNode = (AbstractEndNode) node;
-                node = endNode.merge();
-            } else if (node instanceof ControlSinkNode) {
-                return true;
-            } else {
-                assert false : "unexpected node";
-                return false;
-            }
-        }
-    }
-
-    /**
      * Connects a set of ends to a given successor, inserting a merge node if there is more than one
      * end. If {@code ends} is not empty, then {@code successor} is added to {@code tool}'s
      * {@linkplain SimplifierTool#addToWorkList(org.graalvm.compiler.graph.Node) work list}.
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InvokeNode.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InvokeNode.java	Thu Oct 31 16:54:16 2019 -0700
@@ -109,7 +109,7 @@
         this.bci = invoke.bci;
         this.polymorphic = invoke.polymorphic;
         this.useForInlining = invoke.useForInlining;
-        this.identity = invoke.getLocationIdentity();
+        this.identity = invoke.getKilledLocationIdentity();
     }
 
     @Override
@@ -181,7 +181,7 @@
     }
 
     @Override
-    public LocationIdentity getLocationIdentity() {
+    public LocationIdentity getKilledLocationIdentity() {
         return identity;
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InvokeWithExceptionNode.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InvokeWithExceptionNode.java	Thu Oct 31 16:54:16 2019 -0700
@@ -159,7 +159,7 @@
     @Override
     public void setNext(FixedNode x) {
         if (x != null) {
-            this.setNext(KillingBeginNode.begin(x, getLocationIdentity()));
+            this.setNext(KillingBeginNode.begin(x, this.getKilledLocationIdentity()));
         } else {
             this.setNext(null);
         }
@@ -192,7 +192,7 @@
     }
 
     @Override
-    public LocationIdentity getLocationIdentity() {
+    public LocationIdentity getKilledLocationIdentity() {
         return LocationIdentity.any();
     }
 
@@ -290,7 +290,7 @@
      * code.
      */
     public InvokeNode replaceWithInvoke() {
-        InvokeNode newInvoke = graph().add(new InvokeNode(callTarget, bci, stamp, getLocationIdentity()));
+        InvokeNode newInvoke = graph().add(new InvokeNode(callTarget, bci, stamp, this.getKilledLocationIdentity()));
         newInvoke.setStateAfter(stateAfter);
         newInvoke.setStateDuring(stateDuring);
         AbstractBeginNode oldException = this.exceptionEdge;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/KillingBeginNode.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/KillingBeginNode.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2019, 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
@@ -58,7 +58,7 @@
     }
 
     @Override
-    public LocationIdentity getLocationIdentity() {
+    public LocationIdentity getKilledLocationIdentity() {
         return locationIdentity;
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/LoopBeginNode.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/LoopBeginNode.java	Thu Oct 31 16:54:16 2019 -0700
@@ -141,7 +141,7 @@
     }
 
     public void setLoopFrequency(double loopFrequency) {
-        assert loopFrequency >= 0;
+        assert loopFrequency >= 1.0;
         this.loopFrequency = loopFrequency;
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/MemoryProxyNode.java	Thu Oct 31 16:54:16 2019 -0700
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2019, 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.nodes;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.memory.MemoryNode;
+import org.graalvm.compiler.nodes.memory.MemoryPhiNode;
+import jdk.internal.vm.compiler.word.LocationIdentity;
+
+@NodeInfo(allowedUsageTypes = {InputType.Memory}, nameTemplate = "MemoryProxy({i#value})")
+public final class MemoryProxyNode extends ProxyNode implements MemoryNode {
+
+    public static final NodeClass<MemoryProxyNode> TYPE = NodeClass.create(MemoryProxyNode.class);
+    @OptionalInput(InputType.Memory) MemoryNode value;
+    protected final LocationIdentity locationIdentity;
+
+    public MemoryProxyNode(MemoryNode value, LoopExitNode proxyPoint, LocationIdentity locationIdentity) {
+        super(TYPE, StampFactory.forVoid(), proxyPoint);
+        this.value = value;
+        this.locationIdentity = locationIdentity;
+    }
+
+    public void setValue(MemoryNode newValue) {
+        this.updateUsages(value.asNode(), newValue.asNode());
+        this.value = newValue;
+    }
+
+    @Override
+    public ValueNode value() {
+        return (value == null ? null : value.asNode());
+    }
+
+    @Override
+    public PhiNode createPhi(AbstractMergeNode merge) {
+        return graph().addWithoutUnique(new MemoryPhiNode(merge, locationIdentity));
+    }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ProxyNode.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ProxyNode.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2019, 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
@@ -29,18 +29,24 @@
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
 
 import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.graph.Node.ValueNumberable;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
 import org.graalvm.compiler.nodes.calc.FloatingNode;
 import org.graalvm.compiler.nodes.extended.GuardingNode;
+import org.graalvm.compiler.nodes.memory.MemoryNode;
+import org.graalvm.compiler.nodes.spi.Proxy;
+import jdk.internal.vm.compiler.word.LocationIdentity;
 
 /**
  * A proxy is inserted at loop exits for any value that is created inside the loop (i.e. was not
  * live on entry to the loop) and is (potentially) used after the loop.
  */
 @NodeInfo(cycles = CYCLES_0, size = SIZE_0)
-public abstract class ProxyNode extends FloatingNode implements ValueNumberable {
+public abstract class ProxyNode extends FloatingNode implements Proxy, ValueNumberable, Canonicalizable {
 
     public static final NodeClass<ProxyNode> TYPE = NodeClass.create(ProxyNode.class);
     @Input(Association) LoopExitNode loopExit;
@@ -63,17 +69,34 @@
     }
 
     @Override
+    public ValueNode getOriginalNode() {
+        return value();
+    }
+
+    @Override
     public boolean verify() {
         assert !(value() instanceof ProxyNode) || ((ProxyNode) value()).loopExit != loopExit;
         return super.verify();
     }
 
-    public static ValueProxyNode forValue(ValueNode value, LoopExitNode exit, StructuredGraph graph) {
-        return graph.unique(new ValueProxyNode(value, exit));
+    public static ValueProxyNode forValue(ValueNode value, LoopExitNode exit) {
+        return exit.graph().unique(new ValueProxyNode(value, exit));
+    }
+
+    public static GuardProxyNode forGuard(GuardingNode value, LoopExitNode exit) {
+        return exit.graph().unique(new GuardProxyNode(value, exit));
     }
 
-    public static GuardProxyNode forGuard(GuardingNode value, LoopExitNode exit, StructuredGraph graph) {
-        return graph.unique(new GuardProxyNode(value, exit));
+    public static MemoryProxyNode forMemory(MemoryNode value, LoopExitNode exit, LocationIdentity locationIdentity) {
+        return exit.graph().unique(new MemoryProxyNode(value, exit, locationIdentity));
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        if (value() == null) {
+            return null;
+        }
+        return this;
     }
 
     public abstract PhiNode createPhi(AbstractMergeNode merge);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StartNode.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StartNode.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2019, 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
@@ -49,7 +49,7 @@
     }
 
     @Override
-    public LocationIdentity getLocationIdentity() {
+    public LocationIdentity getKilledLocationIdentity() {
         return LocationIdentity.any();
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StructuredGraph.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StructuredGraph.java	Thu Oct 31 16:54:16 2019 -0700
@@ -125,6 +125,10 @@
         public boolean areDeoptsFixed() {
             return this.ordinal() >= FIXED_DEOPTS.ordinal();
         }
+
+        public boolean requiresValueProxies() {
+            return this != AFTER_FSA;
+        }
     }
 
     /**
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ValueProxyNode.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ValueProxyNode.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2019, 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
@@ -35,7 +35,7 @@
 import org.graalvm.compiler.nodes.spi.VirtualizerTool;
 import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
 
-@NodeInfo(nameTemplate = "Proxy({i#value})")
+@NodeInfo(nameTemplate = "ValueProxy({i#value})")
 public final class ValueProxyNode extends ProxyNode implements Canonicalizable, Virtualizable, ValueProxy {
 
     public static final NodeClass<ValueProxyNode> TYPE = NodeClass.create(ValueProxyNode.class);
@@ -65,8 +65,13 @@
 
     @Override
     public Node canonical(CanonicalizerTool tool) {
+        Node result = super.canonical(tool);
+        if (result != this) {
+            return result;
+        }
+
         ValueNode curValue = value;
-        if (curValue.isConstant()) {
+        if (curValue.getNodeClass().isLeafNode()) {
             return curValue;
         }
         if (loopPhiProxy && !loopExit.loopBegin().isPhiAtMerge(curValue)) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/AndNode.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/AndNode.java	Thu Oct 31 16:54:16 2019 -0700
@@ -28,7 +28,6 @@
 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp;
 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.And;
 import org.graalvm.compiler.core.common.type.IntegerStamp;
-import org.graalvm.compiler.core.common.type.PrimitiveStamp;
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.graph.spi.Canonicalizable.BinaryCommutative;
@@ -41,7 +40,6 @@
 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
 import org.graalvm.compiler.nodes.util.GraphUtil;
 
-import jdk.vm.ci.code.CodeUtil;
 import jdk.vm.ci.meta.Constant;
 import jdk.vm.ci.meta.PrimitiveConstant;
 
@@ -61,7 +59,7 @@
         if (tryConstantFold != null) {
             return tryConstantFold;
         }
-        return canonical(null, op, stamp, x, y, view);
+        return canonical(null, op, x, y, view);
     }
 
     @Override
@@ -77,16 +75,29 @@
         }
 
         NodeView view = NodeView.from(tool);
-        return canonical(this, getOp(forX, forY), stamp(view), forX, forY, view);
+        return canonical(this, getOp(forX, forY), forX, forY, view);
     }
 
-    private static ValueNode canonical(AndNode self, BinaryOp<And> op, Stamp stamp, ValueNode forX, ValueNode forY, NodeView view) {
+    private static ValueNode canonical(AndNode self, BinaryOp<And> op, ValueNode forX, ValueNode forY, NodeView view) {
         if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) {
             return forX;
         }
         if (forX.isConstant() && !forY.isConstant()) {
             return new AndNode(forY, forX);
         }
+
+        Stamp rawXStamp = forX.stamp(view);
+        Stamp rawYStamp = forY.stamp(view);
+        if (rawXStamp instanceof IntegerStamp && rawYStamp instanceof IntegerStamp) {
+            IntegerStamp xStamp = (IntegerStamp) rawXStamp;
+            IntegerStamp yStamp = (IntegerStamp) rawYStamp;
+            if (((~xStamp.downMask()) & yStamp.upMask()) == 0) {
+                return forY;
+            } else if (((~yStamp.downMask()) & xStamp.upMask()) == 0) {
+                return forX;
+            }
+        }
+
         if (forY.isConstant()) {
             Constant c = forY.asConstant();
             if (op.isNeutral(c)) {
@@ -95,21 +106,12 @@
 
             if (c instanceof PrimitiveConstant && ((PrimitiveConstant) c).getJavaKind().isNumericInteger()) {
                 long rawY = ((PrimitiveConstant) c).asLong();
-                long mask = CodeUtil.mask(PrimitiveStamp.getBits(stamp));
-                if ((rawY & mask) == 0) {
-                    return ConstantNode.forIntegerStamp(stamp, 0);
-                }
                 if (forX instanceof SignExtendNode) {
                     SignExtendNode ext = (SignExtendNode) forX;
                     if (rawY == ((1L << ext.getInputBits()) - 1)) {
                         return new ZeroExtendNode(ext.getValue(), ext.getResultBits());
                     }
                 }
-                IntegerStamp xStamp = (IntegerStamp) forX.stamp(view);
-                if (((xStamp.upMask() | xStamp.downMask()) & ~rawY) == 0) {
-                    // No bits are set which are outside the mask, so the mask will have no effect.
-                    return forX;
-                }
             }
 
             return reassociate(self != null ? self : (AndNode) new AndNode(forX, forY).maybeCommuteInputs(), ValueNode.isConstantPredicate(), forX, forY, view);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/BinaryArithmeticNode.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/BinaryArithmeticNode.java	Thu Oct 31 16:54:16 2019 -0700
@@ -59,6 +59,10 @@
         super(c, opForStampComputation.foldStamp(x.stamp(NodeView.DEFAULT), y.stamp(NodeView.DEFAULT)), x, y);
     }
 
+    protected BinaryArithmeticNode(NodeClass<? extends BinaryArithmeticNode<OP>> c, Stamp stamp, ValueNode x, ValueNode y) {
+        super(c, stamp, x, y);
+    }
+
     public static ArithmeticOpTable getArithmeticOpTable(ValueNode forValue) {
         return ArithmeticOpTable.forStamp(forValue.stamp(NodeView.DEFAULT));
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/CompareNode.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/CompareNode.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2019, 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
@@ -33,8 +33,11 @@
 import org.graalvm.compiler.core.common.type.AbstractObjectStamp;
 import org.graalvm.compiler.core.common.type.AbstractPointerStamp;
 import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.Position;
 import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.nodeinfo.InputType;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
 import org.graalvm.compiler.nodes.BinaryOpLogicNode;
 import org.graalvm.compiler.nodes.ConstantNode;
@@ -44,6 +47,7 @@
 import org.graalvm.compiler.nodes.NodeView;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.memory.VolatileReadNode;
 import org.graalvm.compiler.options.OptionValues;
 
 import jdk.vm.ci.meta.Constant;
@@ -189,6 +193,19 @@
             } else if (nonConstant instanceof ConvertNode) {
                 ConvertNode convert = (ConvertNode) nonConstant;
                 boolean multiUsage = (convert.asNode().hasMoreThanOneUsage() && convert.getValue().hasExactlyOneUsage());
+                if (!multiUsage && convert.asNode().hasMoreThanOneUsage() && convert.getValue() instanceof VolatileReadNode) {
+                    // Only account for data usages
+                    VolatileReadNode read = (VolatileReadNode) convert.getValue();
+                    int nonMemoryEdges = 0;
+                    for (Node u : read.usages()) {
+                        for (Position pos : u.inputPositions()) {
+                            if (pos.get(u) == read && pos.getInputType() != InputType.Memory) {
+                                nonMemoryEdges++;
+                            }
+                        }
+                    }
+                    multiUsage = nonMemoryEdges == 1;
+                }
                 if (convert instanceof IntegerConvertNode && multiUsage) {
                     // Do not perform for integer convers if it could introduce
                     // new live values.
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/OrNode.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/OrNode.java	Thu Oct 31 16:54:16 2019 -0700
@@ -27,7 +27,7 @@
 import org.graalvm.compiler.core.common.type.ArithmeticOpTable;
 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp;
 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Or;
-import org.graalvm.compiler.core.common.type.PrimitiveStamp;
+import org.graalvm.compiler.core.common.type.IntegerStamp;
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.graph.spi.Canonicalizable.BinaryCommutative;
@@ -40,9 +40,7 @@
 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
 import org.graalvm.compiler.nodes.util.GraphUtil;
 
-import jdk.vm.ci.code.CodeUtil;
 import jdk.vm.ci.meta.Constant;
-import jdk.vm.ci.meta.PrimitiveConstant;
 
 @NodeInfo(shortName = "|")
 public final class OrNode extends BinaryArithmeticNode<Or> implements BinaryCommutative<ValueNode>, NarrowableArithmeticNode {
@@ -53,6 +51,18 @@
         super(TYPE, getArithmeticOpTable(x).getOr(), x, y);
     }
 
+    private OrNode(ValueNode x, ValueNode y, Stamp forcedStamp) {
+        super(TYPE, forcedStamp, x, y);
+    }
+
+    /**
+     * Create a new XorNode with a forced stamp, without eager folding. This should only be used in
+     * snippet code, where native-image may assign wrong stamps during graph generation.
+     */
+    public static ValueNode createForSnippet(ValueNode x, ValueNode y, Stamp forcedStamp) {
+        return new OrNode(x, y, forcedStamp);
+    }
+
     public static ValueNode create(ValueNode x, ValueNode y, NodeView view) {
         BinaryOp<Or> op = ArithmeticOpTable.forStamp(x.stamp(view)).getOr();
         Stamp stamp = op.foldStamp(x.stamp(view), y.stamp(view));
@@ -60,7 +70,7 @@
         if (tryConstantFold != null) {
             return tryConstantFold;
         }
-        return canonical(null, op, stamp, x, y, view);
+        return canonical(null, op, x, y, view);
     }
 
     @Override
@@ -76,34 +86,42 @@
             return ret;
         }
 
-        return canonical(this, getOp(forX, forY), stamp(view), forX, forY, view);
+        return canonical(this, getOp(forX, forY), forX, forY, view);
     }
 
-    private static ValueNode canonical(OrNode self, BinaryOp<Or> op, Stamp stamp, ValueNode forX, ValueNode forY, NodeView view) {
+    private static ValueNode canonical(OrNode self, BinaryOp<Or> op, ValueNode forX, ValueNode forY, NodeView view) {
         if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) {
             return forX;
         }
         if (forX.isConstant() && !forY.isConstant()) {
             return new OrNode(forY, forX);
         }
+
+        Stamp rawXStamp = forX.stamp(view);
+        Stamp rawYStamp = forY.stamp(view);
+        if (rawXStamp instanceof IntegerStamp && rawYStamp instanceof IntegerStamp) {
+            IntegerStamp xStamp = (IntegerStamp) rawXStamp;
+            IntegerStamp yStamp = (IntegerStamp) rawYStamp;
+            if (((~xStamp.downMask()) & yStamp.upMask()) == 0) {
+                return forX;
+            } else if (((~yStamp.downMask()) & xStamp.upMask()) == 0) {
+                return forY;
+            }
+        }
+
         if (forY.isConstant()) {
             Constant c = forY.asConstant();
             if (op.isNeutral(c)) {
                 return forX;
             }
 
-            if (c instanceof PrimitiveConstant && ((PrimitiveConstant) c).getJavaKind().isNumericInteger()) {
-                long rawY = ((PrimitiveConstant) c).asLong();
-                long mask = CodeUtil.mask(PrimitiveStamp.getBits(stamp));
-                if ((rawY & mask) == mask) {
-                    return ConstantNode.forIntegerStamp(stamp, mask);
-                }
-            }
             return reassociate(self != null ? self : (OrNode) new OrNode(forX, forY).maybeCommuteInputs(), ValueNode.isConstantPredicate(), forX, forY, view);
         }
+
         if (forX instanceof NotNode && forY instanceof NotNode) {
             return new NotNode(AndNode.create(((NotNode) forX).getValue(), ((NotNode) forY).getValue(), view));
         }
+
         return self != null ? self : new OrNode(forX, forY).maybeCommuteInputs();
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/XorNode.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/XorNode.java	Thu Oct 31 16:54:16 2019 -0700
@@ -54,6 +54,18 @@
         assert x.stamp(NodeView.DEFAULT).isCompatible(y.stamp(NodeView.DEFAULT));
     }
 
+    private XorNode(ValueNode x, ValueNode y, Stamp forcedStamp) {
+        super(TYPE, forcedStamp, x, y);
+    }
+
+    /**
+     * Create a new XorNode with a forced stamp, without eager folding. This should only be used in
+     * snippet code, where native-image may assign wrong stamps during graph generation.
+     */
+    public static ValueNode createForSnippet(ValueNode x, ValueNode y, Stamp forcedStamp) {
+        return new XorNode(x, y, forcedStamp);
+    }
+
     public static ValueNode create(ValueNode x, ValueNode y, NodeView view) {
         BinaryOp<Xor> op = ArithmeticOpTable.forStamp(x.stamp(view)).getXor();
         Stamp stamp = op.foldStamp(x.stamp(view), y.stamp(view));
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/Block.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/Block.java	Thu Oct 31 16:54:16 2019 -0700
@@ -260,10 +260,10 @@
         LocationSet result = new LocationSet();
         for (FixedNode node : this.getNodes()) {
             if (node instanceof MemoryCheckpoint.Single) {
-                LocationIdentity identity = ((MemoryCheckpoint.Single) node).getLocationIdentity();
+                LocationIdentity identity = ((MemoryCheckpoint.Single) node).getKilledLocationIdentity();
                 result.add(identity);
             } else if (node instanceof MemoryCheckpoint.Multi) {
-                for (LocationIdentity identity : ((MemoryCheckpoint.Multi) node).getLocationIdentities()) {
+                for (LocationIdentity identity : ((MemoryCheckpoint.Multi) node).getKilledLocationIdentities()) {
                     result.add(identity);
                 }
             }
@@ -365,4 +365,26 @@
     protected void setPostDominator(Block postdominator) {
         this.postdominator = postdominator;
     }
+
+    /**
+     * Checks whether {@code this} block is in the same loop or an outer loop of the block given as
+     * parameter.
+     */
+    public boolean isInSameOrOuterLoopOf(Block block) {
+
+        if (this.loop == null) {
+            // We are in no loop, so this holds true for every other block.
+            return true;
+        }
+
+        Loop<Block> l = block.loop;
+        while (l != null) {
+            if (l == this.loop) {
+                return true;
+            }
+            l = l.getParent();
+        }
+
+        return false;
+    }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/ControlFlowGraph.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/ControlFlowGraph.java	Thu Oct 31 16:54:16 2019 -0700
@@ -38,6 +38,7 @@
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.graph.NodeMap;
+import org.graalvm.compiler.graph.iterators.NodeIterable;
 import org.graalvm.compiler.nodes.AbstractBeginNode;
 import org.graalvm.compiler.nodes.AbstractEndNode;
 import org.graalvm.compiler.nodes.ControlSinkNode;
@@ -416,6 +417,15 @@
         return nodeToBlock.get(node);
     }
 
+    public Block commonDominatorFor(NodeIterable<? extends Node> nodes) {
+        Block commonDom = null;
+        for (Node n : nodes) {
+            Block b = blockFor(n);
+            commonDom = (Block) AbstractControlFlowGraph.commonDominator(commonDom, b);
+        }
+        return commonDom;
+    }
+
     @Override
     public List<Loop<Block>> getLoops() {
         return loops;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/StringToBytesNode.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/StringToBytesNode.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, 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
@@ -66,7 +66,7 @@
     }
 
     @Override
-    public LocationIdentity getLocationIdentity() {
+    public LocationIdentity getKilledLocationIdentity() {
         return NamedLocationIdentity.getArrayLocation(JavaKind.Byte);
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/BytecodeExceptionNode.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/BytecodeExceptionNode.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2019, 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
@@ -100,7 +100,7 @@
     }
 
     @Override
-    public LocationIdentity getLocationIdentity() {
+    public LocationIdentity getKilledLocationIdentity() {
         return LocationIdentity.any();
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/ForeignCallNode.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/ForeignCallNode.java	Thu Oct 31 16:54:16 2019 -0700
@@ -159,7 +159,7 @@
     }
 
     @Override
-    public LocationIdentity[] getLocationIdentities() {
+    public LocationIdentity[] getKilledLocationIdentities() {
         return foreignCalls.getKilledLocations(descriptor);
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/JavaWriteNode.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/JavaWriteNode.java	Thu Oct 31 16:54:16 2019 -0700
@@ -79,4 +79,9 @@
     public Stamp getAccessStamp() {
         return StampFactory.forKind(writeKind);
     }
+
+    @Override
+    public LocationIdentity getKilledLocationIdentity() {
+        return getLocationIdentity();
+    }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/MembarNode.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/MembarNode.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2019, 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
@@ -58,7 +58,7 @@
     }
 
     @Override
-    public LocationIdentity getLocationIdentity() {
+    public LocationIdentity getKilledLocationIdentity() {
         return location;
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawLoadNode.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawLoadNode.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2019, 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
@@ -161,7 +161,7 @@
 
     @Override
     protected ValueNode cloneAsFieldAccess(Assumptions assumptions, ResolvedJavaField field, boolean volatileAccess) {
-        return LoadFieldNode.create(assumptions, object(), field, volatileAccess);
+        return LoadFieldNode.create(assumptions, field.isStatic() ? null : object(), field, volatileAccess);
     }
 
     @Override
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawStoreNode.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawStoreNode.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2019, 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
@@ -134,7 +134,7 @@
 
     @Override
     protected ValueNode cloneAsFieldAccess(Assumptions assumptions, ResolvedJavaField field, boolean volatileAccess) {
-        return new StoreFieldNode(object(), field, value(), stateAfter(), volatileAccess);
+        return new StoreFieldNode(field.isStatic() ? null : object(), field, value(), stateAfter(), volatileAccess);
     }
 
     @Override
@@ -145,4 +145,9 @@
     public FrameState getState() {
         return stateAfter;
     }
+
+    @Override
+    public LocationIdentity getKilledLocationIdentity() {
+        return getLocationIdentity();
+    }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/SwitchNode.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/SwitchNode.java	Thu Oct 31 16:54:16 2019 -0700
@@ -290,4 +290,7 @@
         }
     }
 
+    public int[] getKeySuccessors() {
+        return keySuccessors.clone();
+    }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnsafeAccessNode.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnsafeAccessNode.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2019, 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
@@ -27,6 +27,8 @@
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
 
+import java.nio.ByteOrder;
+
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.graph.NodeClass;
@@ -40,6 +42,8 @@
 import jdk.internal.vm.compiler.word.LocationIdentity;
 
 import jdk.vm.ci.meta.Assumptions;
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.JavaConstant;
 import jdk.vm.ci.meta.JavaKind;
 import jdk.vm.ci.meta.ResolvedJavaField;
 import jdk.vm.ci.meta.ResolvedJavaType;
@@ -95,10 +99,14 @@
                 // Try to canonicalize to a field access.
                 ResolvedJavaType receiverType = StampTool.typeOrNull(object());
                 if (receiverType != null) {
-                    ResolvedJavaField field = receiverType.findInstanceFieldWithOffset(constantOffset, accessKind());
-                    // No need for checking that the receiver is non-null. The field access includes
-                    // the null check and if a field is found, the offset is so small that this is
-                    // never a valid access of an arbitrary address.
+                    ResolvedJavaField field = getStaticFieldUnsafeAccess(tool.getConstantReflection());
+                    if (field == null) {
+                        field = receiverType.findInstanceFieldWithOffset(constantOffset, accessKind());
+                    }
+
+                    // No need for checking that the receiver is non-null. The field access
+                    // includes the null check and if a field is found, the offset is so small that
+                    // this is never a valid access of an arbitrary address.
                     if (field != null && field.getJavaKind() == this.accessKind()) {
                         assert !graph().isAfterFloatingReadPhase() : "cannot add more precise memory location after floating read phase";
                         // Unsafe accesses never have volatile semantics.
@@ -128,4 +136,58 @@
     protected abstract ValueNode cloneAsFieldAccess(Assumptions assumptions, ResolvedJavaField field, boolean volatileAccess);
 
     protected abstract ValueNode cloneAsArrayAccess(ValueNode location, LocationIdentity identity);
+
+    /**
+     * In this method we check if the unsafe access is to a static field. This is the case when
+     * {@code object} is a constant of type {@link Class} (static field's declaring class) and
+     * {@code offset} is a constant (HotSpot-specific field offset from the declaring class).
+     *
+     * @return the static field, if any, that this node is reading
+     */
+    private ResolvedJavaField getStaticFieldUnsafeAccess(ConstantReflectionProvider constantReflection) {
+        if (!object().isJavaConstant() || !offset().isJavaConstant() ||
+                        object().isNullConstant() || offset().isNullConstant()) {
+            return null;
+        }
+        JavaConstant objectConstant = object().asJavaConstant();
+        JavaConstant offsetConstant = offset().asJavaConstant();
+        assert objectConstant != null && offsetConstant != null : "Verified by the check at the beginning.";
+        ResolvedJavaType staticReceiverType = constantReflection.asJavaType(objectConstant);
+        if (staticReceiverType == null) {
+            // object is not of type Class so it is not a static field
+            return null;
+        }
+        return findStaticFieldWithOffset(staticReceiverType, offsetConstant.asLong(), accessKind);
+    }
+
+    private static ResolvedJavaField findStaticFieldWithOffset(ResolvedJavaType type, long offset, JavaKind expectedEntryKind) {
+        try {
+            ResolvedJavaField[] declaredFields = type.getStaticFields();
+            return findFieldWithOffset(offset, expectedEntryKind, declaredFields);
+        } catch (UnsupportedOperationException e) {
+            return null;
+        }
+    }
+
+    /**
+     * NOTE GR-18873: this is a copy-paste implementation derived from
+     * {@code jdk.vm.ci.hotspot.HotSpotResolvedObjectTypeImpl#findStaticFieldWithOffset}.
+     */
+    private static ResolvedJavaField findFieldWithOffset(long offset, JavaKind expectedEntryKind, ResolvedJavaField[] declaredFields) {
+        for (ResolvedJavaField field : declaredFields) {
+            long resolvedFieldOffset = field.getOffset();
+            if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN &&
+                            expectedEntryKind.isPrimitive() &&
+                            !expectedEntryKind.equals(JavaKind.Void) &&
+                            field.getJavaKind().isPrimitive()) {
+                resolvedFieldOffset += field.getJavaKind().getByteCount() -
+                                Math.min(field.getJavaKind().getByteCount(), 4 + expectedEntryKind.getByteCount());
+            }
+            if (resolvedFieldOffset == offset) {
+                return field;
+            }
+        }
+        return null;
+    }
+
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnsafeMemoryStoreNode.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnsafeMemoryStoreNode.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2019, 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
@@ -77,7 +77,7 @@
     }
 
     @Override
-    public LocationIdentity getLocationIdentity() {
+    public LocationIdentity getKilledLocationIdentity() {
         return locationIdentity;
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderConfiguration.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderConfiguration.java	Thu Oct 31 16:54:16 2019 -0700
@@ -203,6 +203,7 @@
     private final boolean trackNodeSourcePosition;
     private final boolean retainLocalVariables;
     private final Plugins plugins;
+    private final boolean replaceLocalsWithConstants;
 
     public enum BytecodeExceptionMode {
         /**
@@ -231,6 +232,7 @@
                     boolean insertFullInfopoints,
                     boolean trackNodeSourcePosition,
                     boolean retainLocalVariables,
+                    boolean replaceLocalsWithConstants,
                     List<ResolvedJavaType> skippedExceptionTypes,
                     Plugins plugins) {
         this.eagerResolving = eagerResolving;
@@ -240,6 +242,7 @@
         this.insertFullInfopoints = insertFullInfopoints;
         this.trackNodeSourcePosition = trackNodeSourcePosition;
         this.retainLocalVariables = retainLocalVariables;
+        this.replaceLocalsWithConstants = replaceLocalsWithConstants;
         this.skippedExceptionTypes = skippedExceptionTypes;
         this.plugins = plugins;
     }
@@ -259,6 +262,7 @@
                         insertFullInfopoints,
                         trackNodeSourcePosition,
                         retainLocalVariables,
+                        replaceLocalsWithConstants,
                         skippedExceptionTypes,
                         newPlugins);
         return result;
@@ -279,6 +283,7 @@
                         insertFullInfopoints,
                         trackNodeSourcePosition,
                         retainLocalVariables,
+                        replaceLocalsWithConstants,
                         skippedExceptionTypes,
                         plugins);
     }
@@ -292,6 +297,7 @@
                         insertFullInfopoints,
                         trackNodeSourcePosition,
                         retainLocalVariables,
+                        replaceLocalsWithConstants,
                         skippedExceptionTypes,
                         plugins);
     }
@@ -305,6 +311,7 @@
                         insertFullInfopoints,
                         trackNodeSourcePosition,
                         retainLocalVariables,
+                        replaceLocalsWithConstants,
                         Collections.unmodifiableList(Arrays.asList(newSkippedExceptionTypes)),
                         plugins);
     }
@@ -317,6 +324,7 @@
                         insertFullInfopoints,
                         trackNodeSourcePosition,
                         retainLocalVariables,
+                        replaceLocalsWithConstants,
                         skippedExceptionTypes,
                         plugins);
     }
@@ -330,6 +338,7 @@
                         insertFullInfopoints,
                         trackNodeSourcePosition,
                         retainLocalVariables,
+                        replaceLocalsWithConstants,
                         skippedExceptionTypes,
                         plugins);
     }
@@ -343,6 +352,7 @@
                         newInsertFullInfopoints,
                         trackNodeSourcePosition,
                         retainLocalVariables,
+                        replaceLocalsWithConstants,
                         skippedExceptionTypes,
                         plugins);
     }
@@ -356,6 +366,7 @@
                         insertFullInfopoints,
                         newTrackNodeSourcePosition,
                         retainLocalVariables,
+                        replaceLocalsWithConstants,
                         skippedExceptionTypes,
                         plugins);
     }
@@ -369,6 +380,21 @@
                         insertFullInfopoints,
                         trackNodeSourcePosition,
                         newRetainLocalVariables,
+                        replaceLocalsWithConstants,
+                        skippedExceptionTypes,
+                        plugins);
+    }
+
+    public GraphBuilderConfiguration withReplaceLocalsWithConstants(boolean newReplaceLocalsWithConstants) {
+        return new GraphBuilderConfiguration(
+                        eagerResolving,
+                        unresolvedIsError,
+                        bytecodeExceptionMode,
+                        omitAssertions,
+                        insertFullInfopoints,
+                        trackNodeSourcePosition,
+                        retainLocalVariables,
+                        newReplaceLocalsWithConstants,
                         skippedExceptionTypes,
                         plugins);
     }
@@ -401,6 +427,10 @@
         return insertFullInfopoints;
     }
 
+    public boolean replaceLocalsWithConstants() {
+        return this.replaceLocalsWithConstants;
+    }
+
     public static GraphBuilderConfiguration getDefault(Plugins plugins) {
         return new GraphBuilderConfiguration(
                         /* eagerResolving: */ false,
@@ -410,6 +440,7 @@
                         /* insertFullInfopoints: */ false,
                         /* trackNodeSourcePosition: */ false,
                         /* retainLocalVariables */ false,
+                        /* replaceLocalsWithConstants */ false,
                         Collections.emptyList(),
                         plugins);
     }
@@ -423,6 +454,7 @@
                         /* insertFullInfopoints: */ false,
                         /* trackNodeSourcePosition: */ false,
                         /* retainLocalVariables */ false,
+                        /* replaceLocalsWithConstants */ false,
                         Collections.emptyList(),
                         plugins);
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InvocationPlugins.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InvocationPlugins.java	Thu Oct 31 16:54:16 2019 -0700
@@ -46,7 +46,6 @@
 import jdk.internal.vm.compiler.collections.UnmodifiableEconomicMap;
 import jdk.internal.vm.compiler.collections.UnmodifiableMapCursor;
 import org.graalvm.compiler.api.replacements.MethodSubstitution;
-import org.graalvm.compiler.api.replacements.MethodSubstitutionRegistry;
 import org.graalvm.compiler.bytecode.BytecodeProvider;
 import org.graalvm.compiler.core.common.SuppressFBWarnings;
 import org.graalvm.compiler.debug.Assertions;
@@ -55,6 +54,7 @@
 import org.graalvm.compiler.graph.iterators.NodeIterable;
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin.Receiver;
+import org.graalvm.compiler.nodes.spi.Replacements;
 
 import jdk.vm.ci.meta.MetaUtil;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
@@ -175,21 +175,25 @@
     }
 
     /**
-     * Utility for {@linkplain InvocationPlugins#register(InvocationPlugin, Class, String, Class...)
-     * registration} of invocation plugins.
+     * Utility for {@linkplain InvocationPlugins#register registration} of invocation plugins.
      */
-    public static class Registration implements MethodSubstitutionRegistry {
+    public static class Registration {
 
         private final InvocationPlugins plugins;
+
         private final Type declaringType;
-        private final BytecodeProvider methodSubstitutionBytecodeProvider;
+        private final Replacements replacements;
+        private final BytecodeProvider bytecodeProvider;
         private boolean allowOverwrite;
 
-        @Override
         public Class<?> getReceiverType() {
             return Receiver.class;
         }
 
+        public Type getDeclaringType() {
+            return declaringType;
+        }
+
         /**
          * Creates an object for registering {@link InvocationPlugin}s for methods declared by a
          * given class.
@@ -201,7 +205,8 @@
         public Registration(InvocationPlugins plugins, Type declaringType) {
             this.plugins = plugins;
             this.declaringType = declaringType;
-            this.methodSubstitutionBytecodeProvider = null;
+            this.replacements = null;
+            this.bytecodeProvider = null;
         }
 
         /**
@@ -211,13 +216,29 @@
          * @param plugins where to register the plugins
          * @param declaringType the class declaring the methods for which plugins will be registered
          *            via this object
-         * @param methodSubstitutionBytecodeProvider provider used to get the bytecodes to parse for
-         *            method substitutions
+         * @param replacements the current Replacements provider
          */
-        public Registration(InvocationPlugins plugins, Type declaringType, BytecodeProvider methodSubstitutionBytecodeProvider) {
+        public Registration(InvocationPlugins plugins, Type declaringType, Replacements replacements) {
             this.plugins = plugins;
             this.declaringType = declaringType;
-            this.methodSubstitutionBytecodeProvider = methodSubstitutionBytecodeProvider;
+            this.replacements = replacements;
+            this.bytecodeProvider = replacements != null ? replacements.getDefaultReplacementBytecodeProvider() : null;
+        }
+
+        /**
+         * Creates an object for registering {@link InvocationPlugin}s for methods declared by a
+         * given class.
+         *
+         * @param plugins where to register the plugins
+         * @param declaringType the class declaring the methods for which plugins will be registered
+         *            via this object
+         * @param replacements the current Replacements provider
+         */
+        public Registration(InvocationPlugins plugins, Type declaringType, Replacements replacements, BytecodeProvider bytecodeProvider) {
+            this.plugins = plugins;
+            this.declaringType = declaringType;
+            this.replacements = replacements;
+            this.bytecodeProvider = bytecodeProvider;
         }
 
         /**
@@ -231,7 +252,8 @@
         public Registration(InvocationPlugins plugins, String declaringClassName) {
             this.plugins = plugins;
             this.declaringType = new OptionalLazySymbol(declaringClassName);
-            this.methodSubstitutionBytecodeProvider = null;
+            this.replacements = null;
+            this.bytecodeProvider = null;
         }
 
         /**
@@ -241,13 +263,13 @@
          * @param plugins where to register the plugins
          * @param declaringClassName the name of the class class declaring the methods for which
          *            plugins will be registered via this object
-         * @param methodSubstitutionBytecodeProvider provider used to get the bytecodes to parse for
-         *            method substitutions
+         * @param replacements the current Replacements provider
          */
-        public Registration(InvocationPlugins plugins, String declaringClassName, BytecodeProvider methodSubstitutionBytecodeProvider) {
+        public Registration(InvocationPlugins plugins, String declaringClassName, Replacements replacements) {
             this.plugins = plugins;
             this.declaringType = new OptionalLazySymbol(declaringClassName);
-            this.methodSubstitutionBytecodeProvider = methodSubstitutionBytecodeProvider;
+            this.replacements = replacements;
+            this.bytecodeProvider = replacements != null ? replacements.getDefaultReplacementBytecodeProvider() : null;
         }
 
         /**
@@ -339,6 +361,118 @@
         }
 
         /**
+         * Registers a plugin for a method with no arguments that is conditionally enabled. This
+         * ensures that {@code Replacements} is aware of this plugin.
+         *
+         * @param name the name of the method
+         * @param plugin the plugin to be registered
+         */
+        public void registerConditional0(boolean isEnabled, String name, InvocationPlugin plugin) {
+            replacements.registerConditionalPlugin(plugin);
+            if (isEnabled) {
+                plugins.register(plugin, false, allowOverwrite, declaringType, name);
+            }
+        }
+
+        /**
+         * Registers a plugin for a method with 1 argument that is conditionally enabled. This
+         * ensures that {@code Replacements} is aware of this plugin.
+         *
+         * @param name the name of the method
+         * @param plugin the plugin to be registered
+         */
+        public void registerConditional1(boolean isEnabled, String name, Type arg, InvocationPlugin plugin) {
+            replacements.registerConditionalPlugin(plugin);
+            if (isEnabled) {
+                plugins.register(plugin, false, allowOverwrite, declaringType, name, arg);
+            }
+        }
+
+        /**
+         * Registers a plugin for a method with 2 arguments that is conditionally enabled. This
+         * ensures that {@code Replacements} is aware of this plugin.
+         *
+         * @param name the name of the method
+         * @param plugin the plugin to be registered
+         */
+        public void registerConditional2(boolean isEnabled, String name, Type arg1, Type arg2, InvocationPlugin plugin) {
+            replacements.registerConditionalPlugin(plugin);
+            if (isEnabled) {
+                plugins.register(plugin, false, allowOverwrite, declaringType, name, arg1, arg2);
+            }
+        }
+
+        /**
+         * Registers a plugin for a method with 3 arguments that is conditionally enabled. This
+         * ensures that {@code Replacements} is aware of this plugin.
+         *
+         * @param name the name of the method
+         * @param plugin the plugin to be registered
+         */
+        public void registerConditional3(boolean isEnabled, String name, Type arg1, Type arg2, Type arg3, InvocationPlugin plugin) {
+            replacements.registerConditionalPlugin(plugin);
+            if (isEnabled) {
+                plugins.register(plugin, false, allowOverwrite, declaringType, name, arg1, arg2, arg3);
+            }
+        }
+
+        /**
+         * Registers a plugin for a method with 4 arguments that is conditionally enabled. This
+         * ensures that {@code Replacements} is aware of this plugin.
+         *
+         * @param name the name of the method
+         * @param plugin the plugin to be registered
+         */
+        public void registerConditional4(boolean isEnabled, String name, Type arg1, Type arg2, Type arg3, Type arg4, InvocationPlugin plugin) {
+            replacements.registerConditionalPlugin(plugin);
+            if (isEnabled) {
+                plugins.register(plugin, false, allowOverwrite, declaringType, name, arg1, arg2, arg3, arg4);
+            }
+        }
+
+        /**
+         * Registers a plugin for a method with 5 arguments that is conditionally enabled. This
+         * ensures that {@code Replacements} is aware of this plugin.
+         *
+         * @param name the name of the method
+         * @param plugin the plugin to be registered
+         */
+        public void registerConditional5(boolean isEnabled, String name, Type arg1, Type arg2, Type arg3, Type arg4, Type arg5, InvocationPlugin plugin) {
+            replacements.registerConditionalPlugin(plugin);
+            if (isEnabled) {
+                plugins.register(plugin, false, allowOverwrite, declaringType, name, arg1, arg2, arg3, arg4, arg5);
+            }
+        }
+
+        /**
+         * Registers a plugin for a method with 6 arguments that is conditionally enabled. This
+         * ensures that {@code Replacements} is aware of this plugin.
+         *
+         * @param name the name of the method
+         * @param plugin the plugin to be registered
+         */
+        public void registerConditional6(boolean isEnabled, String name, Type arg1, Type arg2, Type arg3, Type arg4, Type arg5, Type arg6, InvocationPlugin plugin) {
+            replacements.registerConditionalPlugin(plugin);
+            if (isEnabled) {
+                plugins.register(plugin, false, allowOverwrite, declaringType, name, arg1, arg2, arg3, arg4, arg5, arg6);
+            }
+        }
+
+        /**
+         * Registers a plugin for a method with 7 arguments that is conditionally enabled. This
+         * ensures that {@code Replacements} is aware of this plugin.
+         *
+         * @param name the name of the method
+         * @param plugin the plugin to be registered
+         */
+        public void registerConditional7(boolean isEnabled, String name, Type arg1, Type arg2, Type arg3, Type arg4, Type arg5, Type arg6, Type arg7, InvocationPlugin plugin) {
+            replacements.registerConditionalPlugin(plugin);
+            if (isEnabled) {
+                plugins.register(plugin, false, allowOverwrite, declaringType, name, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
+            }
+        }
+
+        /**
          * Registers a plugin for an optional method with no arguments.
          *
          * @param name the name of the method
@@ -398,7 +532,6 @@
          *            is non-static. Upon returning, element 0 will have been rewritten to
          *            {@code declaringClass}
          */
-        @Override
         public void registerMethodSubstitution(Class<?> substituteDeclaringClass, String name, Type... argumentTypes) {
             registerMethodSubstitution(substituteDeclaringClass, name, name, argumentTypes);
         }
@@ -407,25 +540,63 @@
          * Registers a plugin that implements a method based on the bytecode of a substitute method.
          *
          * @param substituteDeclaringClass the class declaring the substitute method
-         * @param name the name of both the original method
+         * @param name the name of the original method
          * @param substituteName the name of the substitute method
          * @param argumentTypes the argument types of the method. Element 0 of this array must be
          *            the {@link Class} value for {@link InvocationPlugin.Receiver} iff the method
          *            is non-static. Upon returning, element 0 will have been rewritten to
          *            {@code declaringClass}
          */
-        @Override
         public void registerMethodSubstitution(Class<?> substituteDeclaringClass, String name, String substituteName, Type... argumentTypes) {
-            MethodSubstitutionPlugin plugin = createMethodSubstitution(substituteDeclaringClass, substituteName, argumentTypes);
-            plugins.register(plugin, false, allowOverwrite, declaringType, name, argumentTypes);
+            doMethodSubstitutionRegistration(false, true, substituteDeclaringClass, name, substituteName, argumentTypes);
+        }
+
+        /**
+         * Registers a plugin that implements a method based on the bytecode of a substitute method
+         * that is conditinally enabled. This ensures that {@code Replacements} is aware of this
+         * plugin.
+         *
+         * @param isEnabled whether the plugin is enabled in the current compiler
+         * @param substituteDeclaringClass the class declaring the substitute method
+         * @param name the name of both the original and substitute method
+         * @param argumentTypes the argument types of the method. Element 0 of this array must be
+         *            the {@link Class} value for {@link InvocationPlugin.Receiver} iff the method
+         *            is non-static. Upon returning, element 0 will have been rewritten to
+         *            {@code declaringClass}
+         */
+        public void registerConditionalMethodSubstitution(boolean isEnabled, Class<?> substituteDeclaringClass, String name, Type... argumentTypes) {
+            registerConditionalMethodSubstitution(isEnabled, substituteDeclaringClass, name, name, argumentTypes);
         }
 
-        public MethodSubstitutionPlugin createMethodSubstitution(Class<?> substituteDeclaringClass, String substituteName, Type... argumentTypes) {
-            assert methodSubstitutionBytecodeProvider != null : "Registration used for method substitutions requires a non-null methodSubstitutionBytecodeProvider";
-            MethodSubstitutionPlugin plugin = new MethodSubstitutionPlugin(methodSubstitutionBytecodeProvider, substituteDeclaringClass, substituteName, argumentTypes);
-            return plugin;
+        /**
+         * Registers a plugin that implements a method based on the bytecode of a substitute method
+         * that is conditinally enabled. This ensures that {@code Replacements} is aware of this
+         * plugin.
+         *
+         * @param isEnabled whether the plugin is enabled in the current compiler
+         * @param substituteDeclaringClass the class declaring the substitute method
+         * @param name the name of the original method
+         * @param substituteName the name of the substitute method
+         * @param argumentTypes the argument types of the method. Element 0 of this array must be
+         *            the {@link Class} value for {@link InvocationPlugin.Receiver} iff the method
+         *            is non-static. Upon returning, element 0 will have been rewritten to
+         *            {@code declaringClass}
+         */
+        public void registerConditionalMethodSubstitution(boolean isEnabled, Class<?> substituteDeclaringClass, String name, String substituteName, Type... argumentTypes) {
+            doMethodSubstitutionRegistration(true, isEnabled, substituteDeclaringClass, name, substituteName, argumentTypes);
         }
 
+        private void doMethodSubstitutionRegistration(boolean isConditional, boolean isEnabled, Class<?> substituteDeclaringClass, String name, String substituteName, Type[] argumentTypes) {
+            MethodSubstitutionPlugin plugin = new MethodSubstitutionPlugin(this, bytecodeProvider, name, substituteDeclaringClass, substituteName, argumentTypes);
+            replacements.registerMethodSubstitution(plugin);
+            if (isConditional) {
+                // Notify Replacements about the plugin even if it's not current enabled
+                replacements.registerConditionalPlugin(plugin);
+            }
+            if (isEnabled) {
+                plugins.register(plugin, false, allowOverwrite, declaringType, name, argumentTypes);
+            }
+        }
     }
 
     /**
@@ -519,13 +690,7 @@
             this.plugin = data;
             this.isStatic = isStatic;
             this.name = name;
-            StringBuilder buf = new StringBuilder();
-            buf.append('(');
-            for (int i = isStatic ? 0 : 1; i < argumentTypes.length; i++) {
-                buf.append(MetaUtil.toInternalName(argumentTypes[i].getTypeName()));
-            }
-            buf.append(')');
-            this.argumentsDescriptor = buf.toString();
+            this.argumentsDescriptor = toArgumentDescriptor(isStatic, argumentTypes);
             assert !name.equals("<init>") || !isStatic : this;
         }
 
@@ -546,6 +711,16 @@
         }
     }
 
+    static String toArgumentDescriptor(boolean isStatic, Type[] argumentTypes) {
+        StringBuilder buf = new StringBuilder();
+        buf.append('(');
+        for (int i = isStatic ? 0 : 1; i < argumentTypes.length; i++) {
+            buf.append(MetaUtil.toInternalName(argumentTypes[i].getTypeName()));
+        }
+        buf.append(')');
+        return buf.toString();
+    }
+
     /**
      * Plugin registrations for already resolved methods. If non-null, then {@link #registrations}
      * is null and no further registrations can be made.
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/MethodSubstitutionPlugin.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/MethodSubstitutionPlugin.java	Thu Oct 31 16:54:16 2019 -0700
@@ -42,6 +42,7 @@
 
 import jdk.vm.ci.meta.MetaAccessProvider;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
 
 /**
  * An {@link InvocationPlugin} for a method where the implementation of the method is provided by a
@@ -56,6 +57,8 @@
  */
 public final class MethodSubstitutionPlugin implements InvocationPlugin {
 
+    private InvocationPlugins.Registration registration;
+
     private ResolvedJavaMethod cachedSubstitute;
 
     /**
@@ -64,9 +67,14 @@
     private final Class<?> declaringClass;
 
     /**
-     * The name of the original and substitute method.
+     * The name of the substitute method.
      */
-    private final String name;
+    private final String substituteName;
+
+    /**
+     * The name of the original method.
+     */
+    private final String originalName;
 
     /**
      * The parameter types of the substitute method.
@@ -81,16 +89,21 @@
      * Creates a method substitution plugin.
      *
      * @param bytecodeProvider used to get the bytecodes to parse for the substitute method
+     * @param originalName the name of the original method
      * @param declaringClass the class in which the substitute method is declared
-     * @param name the name of the substitute method
+     * @param substituteName the name of the substitute method
      * @param parameters the parameter types of the substitute method. If the original method is not
      *            static, then {@code parameters[0]} must be the {@link Class} value denoting
      *            {@link InvocationPlugin.Receiver}
      */
-    public MethodSubstitutionPlugin(BytecodeProvider bytecodeProvider, Class<?> declaringClass, String name, Type... parameters) {
+    public MethodSubstitutionPlugin(InvocationPlugins.Registration registration, BytecodeProvider bytecodeProvider, String originalName, Class<?> declaringClass, String substituteName,
+                    Type... parameters) {
+        assert bytecodeProvider != null : "Requires a non-null methodSubstitutionBytecodeProvider";
+        this.registration = registration;
         this.bytecodeProvider = bytecodeProvider;
+        this.originalName = originalName;
         this.declaringClass = declaringClass;
-        this.name = name;
+        this.substituteName = substituteName;
         this.parameters = parameters;
         this.originalIsStatic = parameters.length == 0 || parameters[0] != InvocationPlugin.Receiver.class;
     }
@@ -144,7 +157,7 @@
      * Determines if a given method is the substitute method of this plugin.
      */
     private boolean isSubstitute(Method m) {
-        if (Modifier.isStatic(m.getModifiers()) && m.getName().equals(name)) {
+        if (Modifier.isStatic(m.getModifiers()) && m.getName().equals(substituteName)) {
             if (parameters.length == m.getParameterCount()) {
                 Class<?>[] mparams = m.getParameterTypes();
                 int start = 0;
@@ -189,9 +202,6 @@
     @Override
     public boolean execute(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode[] argsIncludingReceiver) {
         if (IS_IN_NATIVE_IMAGE || (UseEncodedGraphs.getValue(b.getOptions()) && !b.parsingIntrinsic())) {
-            if (!IS_IN_NATIVE_IMAGE && UseEncodedGraphs.getValue(b.getOptions())) {
-                b.getReplacements().registerMethodSubstitution(this, targetMethod, INLINE_AFTER_PARSING, b.getOptions());
-            }
             StructuredGraph subst = b.getReplacements().getMethodSubstitution(this,
                             targetMethod,
                             INLINE_AFTER_PARSING,
@@ -220,7 +230,27 @@
 
     @Override
     public String toString() {
-        return String.format("%s[%s.%s(%s)]", getClass().getSimpleName(), declaringClass.getName(), name,
+        return String.format("%s[%s.%s(%s)]", getClass().getSimpleName(), declaringClass.getName(), substituteName,
                         Arrays.asList(parameters).stream().map(c -> c.getTypeName()).collect(Collectors.joining(", ")));
     }
+
+    public String originalMethodAsString() {
+        return String.format("%s.%s(%s)", declaringClass.getName(), substituteName, Arrays.asList(parameters).stream().map(c -> c.getTypeName()).collect(Collectors.joining(", ")));
+    }
+
+    public ResolvedJavaMethod getOriginalMethod(MetaAccessProvider metaAccess) {
+        Class<?> clazz = resolveType(registration.getDeclaringType(), false);
+        if (clazz == null) {
+            throw new GraalError("Can't find original class for " + this + " with class " + registration.getDeclaringType());
+        }
+        ResolvedJavaType type = metaAccess.lookupJavaType(clazz);
+        String argumentsDescriptor = InvocationPlugins.toArgumentDescriptor(originalIsStatic, this.parameters);
+        for (ResolvedJavaMethod declared : type.getDeclaredMethods()) {
+            if (declared.getName().equals(originalName) && declared.isStatic() == originalIsStatic &&
+                            declared.getSignature().toMethodDescriptor().startsWith(argumentsDescriptor)) {
+                return declared;
+            }
+        }
+        throw new GraalError("Can't find original method for " + this + " with class " + registration.getDeclaringType());
+    }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AbstractCompareAndSwapNode.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AbstractCompareAndSwapNode.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2019, 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
@@ -93,4 +93,9 @@
     public Stamp getAccessStamp() {
         return expectedValue.stamp(NodeView.DEFAULT).meet(newValue.stamp(NodeView.DEFAULT)).unrestricted();
     }
+
+    @Override
+    public LocationIdentity getKilledLocationIdentity() {
+        return getLocationIdentity();
+    }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AbstractUnsafeCompareAndSwapNode.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AbstractUnsafeCompareAndSwapNode.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2019, 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
@@ -97,7 +97,7 @@
     }
 
     @Override
-    public LocationIdentity getLocationIdentity() {
+    public LocationIdentity getKilledLocationIdentity() {
         return locationIdentity;
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AtomicReadAndAddNode.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AtomicReadAndAddNode.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2019, 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
@@ -74,7 +74,7 @@
     }
 
     @Override
-    public LocationIdentity getLocationIdentity() {
+    public LocationIdentity getKilledLocationIdentity() {
         return locationIdentity;
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AtomicReadAndWriteNode.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AtomicReadAndWriteNode.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2019, 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
@@ -80,7 +80,7 @@
     }
 
     @Override
-    public LocationIdentity getLocationIdentity() {
+    public LocationIdentity getKilledLocationIdentity() {
         return locationIdentity;
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/ExceptionObjectNode.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/ExceptionObjectNode.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2019, 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
@@ -60,7 +60,7 @@
     }
 
     @Override
-    public LocationIdentity getLocationIdentity() {
+    public LocationIdentity getKilledLocationIdentity() {
         return LocationIdentity.any();
     }
 
@@ -80,7 +80,7 @@
              * Now the lowering to BeginNode+LoadExceptionNode can be performed, since no more
              * deopts can float in between the begin node and the load exception node.
              */
-            LocationIdentity locationsKilledByInvoke = ((InvokeWithExceptionNode) predecessor()).getLocationIdentity();
+            LocationIdentity locationsKilledByInvoke = ((InvokeWithExceptionNode) predecessor()).getKilledLocationIdentity();
             AbstractBeginNode entry = graph().add(KillingBeginNode.create(locationsKilledByInvoke));
             LoadExceptionObjectNode loadException = graph().add(new LoadExceptionObjectNode(stamp(NodeView.DEFAULT)));
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LoweredAtomicReadAndWriteNode.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LoweredAtomicReadAndWriteNode.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2019, 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
@@ -103,4 +103,9 @@
     public Stamp getAccessStamp() {
         return stamp(NodeView.DEFAULT);
     }
+
+    @Override
+    public LocationIdentity getKilledLocationIdentity() {
+        return getLocationIdentity();
+    }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/MonitorEnterNode.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/MonitorEnterNode.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2019, 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
@@ -57,7 +57,7 @@
     }
 
     @Override
-    public LocationIdentity getLocationIdentity() {
+    public LocationIdentity getKilledLocationIdentity() {
         return LocationIdentity.any();
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/MonitorExitNode.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/MonitorExitNode.java	Thu Oct 31 16:54:16 2019 -0700
@@ -70,7 +70,7 @@
     }
 
     @Override
-    public LocationIdentity getLocationIdentity() {
+    public LocationIdentity getKilledLocationIdentity() {
         return LocationIdentity.any();
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/RawMonitorEnterNode.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/RawMonitorEnterNode.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2019, 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
@@ -64,7 +64,7 @@
     }
 
     @Override
-    public LocationIdentity getLocationIdentity() {
+    public LocationIdentity getKilledLocationIdentity() {
         return LocationIdentity.any();
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/FixedAccessNode.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/FixedAccessNode.java	Thu Oct 31 16:54:16 2019 -0700
@@ -25,6 +25,7 @@
 package org.graalvm.compiler.nodes.memory;
 
 import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.IterableNodeType;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.nodeinfo.InputType;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
@@ -39,7 +40,7 @@
  * does not include a null check on the object.
  */
 @NodeInfo
-public abstract class FixedAccessNode extends DeoptimizingFixedWithNextNode implements Access {
+public abstract class FixedAccessNode extends DeoptimizingFixedWithNextNode implements Access, IterableNodeType {
     public static final NodeClass<FixedAccessNode> TYPE = NodeClass.create(FixedAccessNode.class);
 
     @OptionalInput(InputType.Guard) protected GuardingNode guard;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryCheckpoint.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryCheckpoint.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2019, 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
@@ -44,8 +44,7 @@
          *
          * @return the identity of the location killed by this node.
          */
-        LocationIdentity getLocationIdentity();
-
+        LocationIdentity getKilledLocationIdentity();
     }
 
     interface Multi extends MemoryCheckpoint {
@@ -57,7 +56,7 @@
          *
          * @return the identities of all locations killed by this node.
          */
-        LocationIdentity[] getLocationIdentities();
+        LocationIdentity[] getKilledLocationIdentities();
 
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/VolatileReadNode.java	Thu Oct 31 16:54:16 2019 -0700
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, Red Hat Inc. 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.nodes.memory;
+
+import org.graalvm.compiler.core.common.GraalOptions;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+import jdk.internal.vm.compiler.word.LocationIdentity;
+
+import static org.graalvm.compiler.nodeinfo.InputType.Memory;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+
+@NodeInfo(nameTemplate = "Read#{p#location/s}", allowedUsageTypes = Memory, cycles = CYCLES_2, size = SIZE_1)
+public class VolatileReadNode extends ReadNode implements MemoryCheckpoint.Single {
+    public static final NodeClass<VolatileReadNode> TYPE = NodeClass.create(VolatileReadNode.class);
+
+    public VolatileReadNode(AddressNode address, LocationIdentity location, Stamp stamp, BarrierType barrierType) {
+        super(TYPE, address, location, stamp, null, barrierType, false, null);
+        assert GraalOptions.LateMembars.getValue(address.getOptions());
+    }
+
+    @SuppressWarnings("try")
+    @Override
+    public FloatingAccessNode asFloatingNode() {
+        throw new RuntimeException();
+    }
+
+    @Override
+    public boolean canFloat() {
+        return false;
+    }
+
+    @Override
+    public LocationIdentity getKilledLocationIdentity() {
+        return LocationIdentity.any();
+    }
+
+    @Override
+    public boolean canNullCheck() {
+        return false;
+    }
+
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/WriteNode.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/WriteNode.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2019, 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
@@ -44,13 +44,16 @@
 public class WriteNode extends AbstractWriteNode implements LIRLowerableAccess, Canonicalizable {
 
     public static final NodeClass<WriteNode> TYPE = NodeClass.create(WriteNode.class);
+    private final boolean volatileAccess;
 
-    public WriteNode(AddressNode address, LocationIdentity location, ValueNode value, BarrierType barrierType) {
+    public WriteNode(AddressNode address, LocationIdentity location, ValueNode value, BarrierType barrierType, boolean volatileAccess) {
         super(TYPE, address, location, value, barrierType);
+        this.volatileAccess = volatileAccess;
     }
 
     protected WriteNode(NodeClass<? extends WriteNode> c, AddressNode address, LocationIdentity location, ValueNode value, BarrierType barrierType) {
         super(c, address, location, value, barrierType);
+        this.volatileAccess = false;
     }
 
     @Override
@@ -61,7 +64,7 @@
 
     @Override
     public boolean canNullCheck() {
-        return true;
+        return !isVolatile();
     }
 
     @Override
@@ -73,11 +76,23 @@
     public Node canonical(CanonicalizerTool tool) {
         if (tool.canonicalizeReads() && hasExactlyOneUsage() && next() instanceof WriteNode) {
             WriteNode write = (WriteNode) next();
-            if (write.lastLocationAccess == this && write.getAddress() == getAddress() && getAccessStamp().isCompatible(write.getAccessStamp())) {
+            if (write.lastLocationAccess == this && write.getAddress() == getAddress() && getAccessStamp().isCompatible(write.getAccessStamp()) && !isVolatile()) {
                 write.setLastLocationAccess(getLastLocationAccess());
                 return write;
             }
         }
         return this;
     }
+
+    @Override
+    public LocationIdentity getKilledLocationIdentity() {
+        if (isVolatile()) {
+            return LocationIdentity.any();
+        }
+        return getLocationIdentity();
+    }
+
+    public boolean isVolatile() {
+        return volatileAccess;
+    }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/DelegatingReplacements.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/DelegatingReplacements.java	Thu Oct 31 16:54:16 2019 -0700
@@ -34,6 +34,7 @@
 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderPlugin;
 import org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
 import org.graalvm.compiler.nodes.graphbuilderconf.MethodSubstitutionPlugin;
 import org.graalvm.compiler.options.OptionValues;
 
@@ -82,8 +83,13 @@
     }
 
     @Override
-    public void registerMethodSubstitution(MethodSubstitutionPlugin plugin, ResolvedJavaMethod original, IntrinsicContext.CompilationContext context, OptionValues options) {
-        delegate.registerMethodSubstitution(plugin, original, context, options);
+    public void registerMethodSubstitution(MethodSubstitutionPlugin plugin) {
+        delegate.registerMethodSubstitution(plugin);
+    }
+
+    @Override
+    public void registerConditionalPlugin(InvocationPlugin plugin) {
+        delegate.registerConditionalPlugin(plugin);
     }
 
     @Override
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/Replacements.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/Replacements.java	Thu Oct 31 16:54:16 2019 -0700
@@ -97,7 +97,14 @@
     /**
      * Registers a plugin as a substitution.
      */
-    void registerMethodSubstitution(MethodSubstitutionPlugin plugin, ResolvedJavaMethod original, IntrinsicContext.CompilationContext context, OptionValues options);
+    void registerMethodSubstitution(MethodSubstitutionPlugin plugin);
+
+    /**
+     * Marks a plugin as conditionally applied. In the contenxt of libgraal conditional plugins
+     * can't be used in during graph encoding for snippets and method substitutions and this is used
+     * to detect violations of this restriction.
+     */
+    void registerConditionalPlugin(InvocationPlugin plugin);
 
     /**
      * Gets a graph that is a substitution for a given method.
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/util/GraphUtil.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/util/GraphUtil.java	Thu Oct 31 16:54:16 2019 -0700
@@ -54,11 +54,13 @@
 import org.graalvm.compiler.nodes.AbstractEndNode;
 import org.graalvm.compiler.nodes.AbstractMergeNode;
 import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.ControlSinkNode;
 import org.graalvm.compiler.nodes.ControlSplitNode;
 import org.graalvm.compiler.nodes.FixedNode;
 import org.graalvm.compiler.nodes.FixedWithNextNode;
 import org.graalvm.compiler.nodes.FrameState;
 import org.graalvm.compiler.nodes.GuardNode;
+import org.graalvm.compiler.nodes.IfNode;
 import org.graalvm.compiler.nodes.LoopBeginNode;
 import org.graalvm.compiler.nodes.LoopEndNode;
 import org.graalvm.compiler.nodes.LoopExitNode;
@@ -105,6 +107,8 @@
         public static final OptionKey<Boolean> VerifyKillCFGUnusedNodes = new OptionKey<>(false);
     }
 
+    public static final int MAX_FRAMESTATE_SEARCH_DEPTH = 4;
+
     private static void killCFGInner(FixedNode node) {
         EconomicSet<Node> markedNodes = EconomicSet.create();
         EconomicMap<AbstractMergeNode, List<AbstractEndNode>> unmarkedMerges = EconomicMap.create();
@@ -1110,4 +1114,55 @@
         tool.createVirtualObject(newVirtualArray, newEntryState, Collections.<MonitorIdNode> emptyList(), false);
         tool.replaceWithVirtual(newVirtualArray);
     }
+
+    /**
+     * Snippet lowerings may produce patterns without a frame state on the merge. We need to take
+     * extra care when optimizing these patterns.
+     */
+    public static boolean checkFrameState(FixedNode start, int maxDepth) {
+        if (maxDepth == 0) {
+            return false;
+        }
+        FixedNode node = start;
+        while (true) {
+            if (node instanceof AbstractMergeNode) {
+                AbstractMergeNode mergeNode = (AbstractMergeNode) node;
+                if (mergeNode.stateAfter() == null) {
+                    return false;
+                } else {
+                    return true;
+                }
+            } else if (node instanceof StateSplit) {
+                StateSplit stateSplitNode = (StateSplit) node;
+                if (stateSplitNode.stateAfter() != null) {
+                    return true;
+                }
+            }
+
+            if (node instanceof ControlSplitNode) {
+                ControlSplitNode controlSplitNode = (ControlSplitNode) node;
+                for (Node succ : controlSplitNode.cfgSuccessors()) {
+                    if (checkFrameState((FixedNode) succ, maxDepth - 1)) {
+                        return true;
+                    }
+                }
+                return false;
+            } else if (node instanceof FixedWithNextNode) {
+                FixedWithNextNode fixedWithNextNode = (FixedWithNextNode) node;
+                node = fixedWithNextNode.next();
+            } else if (node instanceof AbstractEndNode) {
+                AbstractEndNode endNode = (AbstractEndNode) node;
+                node = endNode.merge();
+            } else if (node instanceof ControlSinkNode) {
+                return true;
+            } else {
+                assert false : "unexpected node";
+                return false;
+            }
+        }
+    }
+
+    public static boolean mayRemoveSplit(IfNode ifNode) {
+        return GraphUtil.checkFrameState(ifNode.trueSuccessor(), MAX_FRAMESTATE_SEARCH_DEPTH) && GraphUtil.checkFrameState(ifNode.falseSuccessor(), MAX_FRAMESTATE_SEARCH_DEPTH);
+    }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/AllocatedObjectNode.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/AllocatedObjectNode.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2019, 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
@@ -36,7 +36,7 @@
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.calc.FloatingNode;
 import org.graalvm.compiler.nodes.spi.ArrayLengthProvider;
-import org.graalvm.compiler.nodes.spi.Virtualizable;
+import org.graalvm.compiler.nodes.spi.VirtualizableAllocation;
 import org.graalvm.compiler.nodes.spi.VirtualizerTool;
 import org.graalvm.compiler.nodes.util.GraphUtil;
 
@@ -45,7 +45,7 @@
  * {@link VirtualObjectNode}.
  */
 @NodeInfo(cycles = CYCLES_0, size = SIZE_0)
-public final class AllocatedObjectNode extends FloatingNode implements Virtualizable, ArrayLengthProvider {
+public final class AllocatedObjectNode extends FloatingNode implements VirtualizableAllocation, ArrayLengthProvider {
 
     public static final NodeClass<AllocatedObjectNode> TYPE = NodeClass.create(AllocatedObjectNode.class);
     @Input VirtualObjectNode virtualObject;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/CommitAllocationNode.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/CommitAllocationNode.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2019, 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
@@ -121,7 +121,7 @@
     }
 
     @Override
-    public LocationIdentity getLocationIdentity() {
+    public LocationIdentity getKilledLocationIdentity() {
         return locks.isEmpty() ? LocationIdentity.init() : LocationIdentity.any();
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/CanonicalizerPhase.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/CanonicalizerPhase.java	Thu Oct 31 16:54:16 2019 -0700
@@ -24,6 +24,12 @@
 
 package org.graalvm.compiler.phases.common;
 
+import static org.graalvm.compiler.phases.common.CanonicalizerPhase.CanonicalizerFeature.CFG_SIMPLIFICATION;
+import static org.graalvm.compiler.phases.common.CanonicalizerPhase.CanonicalizerFeature.GVN;
+import static org.graalvm.compiler.phases.common.CanonicalizerPhase.CanonicalizerFeature.READ_CANONICALIZATION;
+
+import java.util.EnumSet;
+
 import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.debug.CounterKey;
@@ -66,6 +72,12 @@
 
 public class CanonicalizerPhase extends BasePhase<CoreProviders> {
 
+    public enum CanonicalizerFeature {
+        READ_CANONICALIZATION,
+        CFG_SIMPLIFICATION,
+        GVN
+    }
+
     private static final int MAX_ITERATION_PER_NODE = 10;
     private static final CounterKey COUNTER_CANONICALIZED_NODES = DebugContext.counter("CanonicalizedNodes");
     private static final CounterKey COUNTER_PROCESSED_NODES = DebugContext.counter("ProcessedNodes");
@@ -75,40 +87,79 @@
     private static final CounterKey COUNTER_SIMPLIFICATION_CONSIDERED_NODES = DebugContext.counter("SimplificationConsideredNodes");
     private static final CounterKey COUNTER_GLOBAL_VALUE_NUMBERING_HITS = DebugContext.counter("GlobalValueNumberingHits");
 
-    private boolean globalValueNumber = true;
-    private boolean canonicalizeReads = true;
-    private boolean simplify = true;
-    private final CustomCanonicalizer customCanonicalizer;
+    private final EnumSet<CanonicalizerFeature> features;
+    private final CustomCanonicalization customCanonicalization;
+    private final CustomSimplification customSimplification;
 
-    public abstract static class CustomCanonicalizer {
+    public interface CustomCanonicalization {
+        /**
+         * @param node the node to be canonicalized
+         * @return the same node if no action should be taken, {@code null} if the node should be
+         *         deleted, or a new node that should replace the given node
+         */
+        Node canonicalize(Node node);
+    }
 
-        public Node canonicalize(Node node) {
-            return node;
-        }
+    public interface CustomSimplification {
+        /**
+         * @param node the node to be simplified
+         * @param tool utility available during the simplification process
+         */
+        void simplify(Node node, SimplifierTool tool);
+    }
 
-        @SuppressWarnings("unused")
-        public void simplify(Node node, SimplifierTool tool) {
-        }
+    protected CanonicalizerPhase(EnumSet<CanonicalizerFeature> features) {
+        this(null, null, features);
+    }
+
+    protected CanonicalizerPhase() {
+        this(null, null, EnumSet.allOf(CanonicalizerFeature.class));
+    }
+
+    protected CanonicalizerPhase(CustomCanonicalization customCanonicalization, CustomSimplification customSimplification) {
+        this(customCanonicalization, customSimplification, EnumSet.allOf(CanonicalizerFeature.class));
     }
 
-    public CanonicalizerPhase() {
-        this(null);
+    protected CanonicalizerPhase(CustomCanonicalization customCanonicalization, CustomSimplification customSimplification, EnumSet<CanonicalizerFeature> features) {
+        this.customCanonicalization = customCanonicalization;
+        this.customSimplification = customSimplification;
+        this.features = features;
     }
 
-    public CanonicalizerPhase(CustomCanonicalizer customCanonicalizer) {
-        this.customCanonicalizer = customCanonicalizer;
+    public CanonicalizerPhase copyWithCustomCanonicalization(CustomCanonicalization newCanonicalization) {
+        return new CanonicalizerPhase(newCanonicalization, customSimplification, features);
+    }
+
+    public CanonicalizerPhase copyWithCustomSimplification(CustomSimplification newSimplification) {
+        return new CanonicalizerPhase(customCanonicalization, newSimplification, features);
+    }
+
+    public CanonicalizerPhase copyWithoutGVN() {
+        EnumSet<CanonicalizerFeature> newFeatures = EnumSet.copyOf(features);
+        newFeatures.remove(GVN);
+        return new CanonicalizerPhase(customCanonicalization, customSimplification, newFeatures);
     }
 
-    public void disableGVN() {
-        globalValueNumber = false;
+    public CanonicalizerPhase copyWithoutSimplification() {
+        EnumSet<CanonicalizerFeature> newFeatures = EnumSet.copyOf(features);
+        newFeatures.remove(CFG_SIMPLIFICATION);
+        return new CanonicalizerPhase(customCanonicalization, customSimplification, newFeatures);
+    }
+
+    public static CanonicalizerPhase create() {
+        return new CanonicalizerPhase(null, null, EnumSet.allOf(CanonicalizerFeature.class));
     }
 
-    public void disableReadCanonicalization() {
-        canonicalizeReads = false;
+    public static CanonicalizerPhase createWithoutReadCanonicalization() {
+        return new CanonicalizerPhase(EnumSet.complementOf(EnumSet.of(READ_CANONICALIZATION)));
     }
 
-    public void disableSimplification() {
-        simplify = false;
+    public static CanonicalizerPhase createWithoutGVN() {
+        return new CanonicalizerPhase(EnumSet.complementOf(EnumSet.of(GVN)));
+    }
+
+    public static CanonicalizerPhase createWithoutCFGSimplification() {
+        return new CanonicalizerPhase(EnumSet.complementOf(EnumSet.of(CFG_SIMPLIFICATION)));
     }
 
     @Override
@@ -274,7 +325,7 @@
             if (tryCanonicalize(node, nodeClass)) {
                 return true;
             }
-            if (globalValueNumber && tryGlobalValueNumbering(node, nodeClass)) {
+            if (features.contains(GVN) && tryGlobalValueNumbering(node, nodeClass)) {
                 return true;
             }
             if (node instanceof ValueNode) {
@@ -329,24 +380,18 @@
         @SuppressWarnings("try")
         public boolean tryCanonicalize(final Node node, NodeClass<?> nodeClass) {
             try (DebugCloseable position = node.withNodeSourcePosition(); DebugContext.Scope scope = debug.withContext(node)) {
-                if (customCanonicalizer != null) {
-                    Node canonical = customCanonicalizer.canonicalize(node);
-                    if (performReplacement(node, canonical)) {
-                        return true;
-                    } else {
-                        customCanonicalizer.simplify(node, tool);
-                        if (node.isDeleted()) {
-                            return true;
-                        }
-                    }
-                }
                 if (nodeClass.isCanonicalizable()) {
                     COUNTER_CANONICALIZATION_CONSIDERED_NODES.increment(debug);
-                    Node canonical;
+                    Node canonical = node;
                     try (AutoCloseable verify = getCanonicalizeableContractAssertion(node)) {
-                        canonical = ((Canonicalizable) node).canonical(tool);
-                        if (canonical == node && nodeClass.isCommutative()) {
-                            canonical = ((BinaryCommutative<?>) node).maybeCommuteInputs();
+                        if (customCanonicalization != null) {
+                            canonical = customCanonicalization.canonicalize(node);
+                        }
+                        if (canonical == node) {
+                            canonical = ((Canonicalizable) node).canonical(tool);
+                            if (canonical == node && nodeClass.isCommutative()) {
+                                canonical = ((BinaryCommutative<?>) node).maybeCommuteInputs();
+                            }
                         }
                     } catch (Throwable e) {
                         throw new GraalGraphError(e).addContext(node);
@@ -356,12 +401,17 @@
                     }
                 }
 
-                if (nodeClass.isSimplifiable() && simplify) {
+                if (features.contains(CFG_SIMPLIFICATION) && nodeClass.isSimplifiable()) {
                     debug.log(DebugContext.VERBOSE_LEVEL, "Canonicalizer: simplifying %s", node);
                     COUNTER_SIMPLIFICATION_CONSIDERED_NODES.increment(debug);
-                    node.simplify(tool);
-                    if (node.isDeleted()) {
-                        debug.log("Canonicalizer: simplified %s", node);
+                    if (customSimplification != null) {
+                        customSimplification.simplify(node, tool);
+                    }
+                    if (node.isAlive()) {
+                        node.simplify(tool);
+                        if (node.isDeleted()) {
+                            debug.log("Canonicalizer: simplified %s", node);
+                        }
                     }
                     return node.isDeleted();
                 }
@@ -518,7 +568,7 @@
 
             @Override
             public boolean canonicalizeReads() {
-                return canonicalizeReads;
+                return features.contains(READ_CANONICALIZATION);
             }
 
             @Override
@@ -549,7 +599,7 @@
     }
 
     public boolean getCanonicalizeReads() {
-        return canonicalizeReads;
+        return features.contains(READ_CANONICALIZATION);
     }
 
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ConditionalEliminationPhase.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ConditionalEliminationPhase.java	Thu Oct 31 16:54:16 2019 -0700
@@ -186,6 +186,8 @@
 
                 // Check if we can move guards upwards.
                 AbstractBeginNode trueSuccessor = node.trueSuccessor();
+                AbstractBeginNode falseSuccessor = node.falseSuccessor();
+
                 EconomicMap<LogicNode, GuardNode> trueGuards = EconomicMap.create(Equivalence.IDENTITY);
                 for (GuardNode guard : trueSuccessor.guards()) {
                     LogicNode condition = guard.getCondition();
@@ -195,7 +197,7 @@
                 }
 
                 if (!trueGuards.isEmpty()) {
-                    for (GuardNode guard : node.falseSuccessor().guards().snapshot()) {
+                    for (GuardNode guard : falseSuccessor.guards().snapshot()) {
                         GuardNode otherGuard = trueGuards.get(guard.getCondition());
                         if (otherGuard != null && guard.isNegated() == otherGuard.isNegated()) {
                             Speculation speculation = otherGuard.getSpeculation();
@@ -210,9 +212,17 @@
                                                 guard.getNoDeoptSuccessorPosition());
                                 GuardNode newGuard = node.graph().unique(newlyCreatedGuard);
                                 if (otherGuard.isAlive()) {
-                                    otherGuard.replaceAndDelete(newGuard);
+                                    if (trueSuccessor instanceof LoopExitNode && beginNode.graph().hasValueProxies()) {
+                                        otherGuard.replaceAndDelete(ProxyNode.forGuard(newGuard, (LoopExitNode) trueSuccessor));
+                                    } else {
+                                        otherGuard.replaceAndDelete(newGuard);
+                                    }
                                 }
-                                guard.replaceAndDelete(newGuard);
+                                if (falseSuccessor instanceof LoopExitNode && beginNode.graph().hasValueProxies()) {
+                                    guard.replaceAndDelete(ProxyNode.forGuard(newGuard, (LoopExitNode) falseSuccessor));
+                                } else {
+                                    guard.replaceAndDelete(newGuard);
+                                }
                             }
                         }
                     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/FloatingReadPhase.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/FloatingReadPhase.java	Thu Oct 31 16:54:16 2019 -0700
@@ -48,6 +48,7 @@
 import org.graalvm.compiler.nodes.LoopEndNode;
 import org.graalvm.compiler.nodes.LoopExitNode;
 import org.graalvm.compiler.nodes.PhiNode;
+import org.graalvm.compiler.nodes.ProxyNode;
 import org.graalvm.compiler.nodes.ReturnNode;
 import org.graalvm.compiler.nodes.StartNode;
 import org.graalvm.compiler.nodes.StructuredGraph;
@@ -166,9 +167,9 @@
 
     protected void processNode(FixedNode node, EconomicSet<LocationIdentity> currentState) {
         if (node instanceof MemoryCheckpoint.Single) {
-            processIdentity(currentState, ((MemoryCheckpoint.Single) node).getLocationIdentity());
+            processIdentity(currentState, ((MemoryCheckpoint.Single) node).getKilledLocationIdentity());
         } else if (node instanceof MemoryCheckpoint.Multi) {
-            for (LocationIdentity identity : ((MemoryCheckpoint.Multi) node).getLocationIdentities()) {
+            for (LocationIdentity identity : ((MemoryCheckpoint.Multi) node).getKilledLocationIdentities()) {
                 processIdentity(currentState, identity);
             }
         }
@@ -274,7 +275,7 @@
                 }
                 mergedStatesCount++;
             }
-            newState.lastMemorySnapshot.put(key, merged);
+            newState.getMap().put(key, merged);
         }
         return newState;
 
@@ -301,6 +302,16 @@
 
         @Override
         protected MemoryMapImpl processNode(FixedNode node, MemoryMapImpl state) {
+
+            if (node instanceof LoopExitNode) {
+                final LoopExitNode loopExitNode = (LoopExitNode) node;
+                final EconomicSet<LocationIdentity> modifiedInLoop = modifiedInLoops.get(loopExitNode.loopBegin());
+                final boolean anyModified = modifiedInLoop.contains(LocationIdentity.any());
+                state.getMap().replaceAll((locationIdentity, memoryNode) -> (anyModified || modifiedInLoop.contains(locationIdentity))
+                                ? ProxyNode.forMemory(memoryNode, loopExitNode, locationIdentity)
+                                : memoryNode);
+            }
+
             if (node instanceof MemoryAnchorNode) {
                 processAnchor((MemoryAnchorNode) node, state);
                 return state;
@@ -312,7 +323,8 @@
 
             if (createFloatingReads && node instanceof FloatableAccessNode) {
                 processFloatable((FloatableAccessNode) node, state);
-            } else if (node instanceof MemoryCheckpoint.Single) {
+            }
+            if (node instanceof MemoryCheckpoint.Single) {
                 processCheckpoint((MemoryCheckpoint.Single) node, state);
             } else if (node instanceof MemoryCheckpoint.Multi) {
                 processCheckpoint((MemoryCheckpoint.Multi) node, state);
@@ -320,7 +332,7 @@
             assert MemoryCheckpoint.TypeAssertion.correctType(node) : node;
 
             if (createMemoryMapNodes && node instanceof ReturnNode) {
-                ((ReturnNode) node).setMemoryMap(node.graph().unique(new MemoryMapNode(state.lastMemorySnapshot)));
+                ((ReturnNode) node).setMemoryMap(node.graph().unique(new MemoryMapNode(state.getMap())));
             }
             return state;
         }
@@ -355,21 +367,21 @@
         }
 
         private static void processCheckpoint(MemoryCheckpoint.Single checkpoint, MemoryMapImpl state) {
-            processIdentity(checkpoint.getLocationIdentity(), checkpoint, state);
+            processIdentity(checkpoint.getKilledLocationIdentity(), checkpoint, state);
         }
 
         private static void processCheckpoint(MemoryCheckpoint.Multi checkpoint, MemoryMapImpl state) {
-            for (LocationIdentity identity : checkpoint.getLocationIdentities()) {
+            for (LocationIdentity identity : checkpoint.getKilledLocationIdentities()) {
                 processIdentity(identity, checkpoint, state);
             }
         }
 
         private static void processIdentity(LocationIdentity identity, MemoryCheckpoint checkpoint, MemoryMapImpl state) {
             if (identity.isAny()) {
-                state.lastMemorySnapshot.clear();
+                state.getMap().clear();
             }
             if (identity.isMutable()) {
-                state.lastMemorySnapshot.put(identity, checkpoint);
+                state.getMap().put(identity, checkpoint);
             }
         }
 
@@ -405,7 +417,7 @@
                  * side it needs to choose by putting in the location identity on both successors.
                  */
                 InvokeWithExceptionNode invoke = (InvokeWithExceptionNode) node.predecessor();
-                result.lastMemorySnapshot.put(invoke.getLocationIdentity(), (MemoryCheckpoint) node);
+                result.getMap().put(invoke.getKilledLocationIdentity(), (MemoryCheckpoint) node);
             }
             return result;
         }
@@ -417,13 +429,13 @@
             if (modifiedLocations.contains(LocationIdentity.any())) {
                 // create phis for all locations if ANY is modified in the loop
                 modifiedLocations = EconomicSet.create(Equivalence.DEFAULT, modifiedLocations);
-                modifiedLocations.addAll(initialState.lastMemorySnapshot.getKeys());
+                modifiedLocations.addAll(initialState.getMap().getKeys());
             }
 
             for (LocationIdentity location : modifiedLocations) {
                 createMemoryPhi(loop, initialState, phis, location);
             }
-            initialState.lastMemorySnapshot.putAll(phis);
+            initialState.getMap().putAll(phis);
 
             LoopInfo<MemoryMapImpl> loopInfo = ReentrantNodeIterator.processLoop(this, loop, initialState);
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/GuardLoweringPhase.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/GuardLoweringPhase.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2019, 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
@@ -24,7 +24,6 @@
 
 package org.graalvm.compiler.phases.common;
 
-import org.graalvm.compiler.core.common.cfg.Loop;
 import org.graalvm.compiler.debug.DebugCloseable;
 import org.graalvm.compiler.debug.DebugContext;
 import org.graalvm.compiler.graph.Node;
@@ -34,8 +33,6 @@
 import org.graalvm.compiler.nodes.FixedWithNextNode;
 import org.graalvm.compiler.nodes.GuardNode;
 import org.graalvm.compiler.nodes.IfNode;
-import org.graalvm.compiler.nodes.LoopBeginNode;
-import org.graalvm.compiler.nodes.LoopExitNode;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.GuardsStage;
 import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult;
@@ -62,11 +59,9 @@
 
     private static class LowerGuards extends ScheduledNodeIterator {
 
-        private final Block block;
         private boolean useGuardIdAsDebugId;
 
-        LowerGuards(Block block, boolean useGuardIdAsDebugId) {
-            this.block = block;
+        LowerGuards(boolean useGuardIdAsDebugId) {
             this.useGuardIdAsDebugId = useGuardIdAsDebugId;
         }
 
@@ -95,7 +90,6 @@
                 AbstractBeginNode deoptBranch = BeginNode.begin(deopt);
                 AbstractBeginNode trueSuccessor;
                 AbstractBeginNode falseSuccessor;
-                insertLoopExits(deopt);
                 if (guard.isNegated()) {
                     trueSuccessor = deoptBranch;
                     falseSuccessor = fastPath;
@@ -108,16 +102,6 @@
                 insert(ifNode, fastPath);
             }
         }
-
-        private void insertLoopExits(DeoptimizeNode deopt) {
-            Loop<Block> loop = block.getLoop();
-            StructuredGraph graph = deopt.graph();
-            while (loop != null) {
-                LoopExitNode exit = graph.add(new LoopExitNode((LoopBeginNode) loop.getHeader().getBeginNode()));
-                graph.addBeforeFixed(deopt, exit);
-                loop = loop.getParent();
-            }
-        }
     }
 
     @Override
@@ -143,6 +127,6 @@
 
     private static void processBlock(Block block, ScheduleResult schedule) {
         DebugContext debug = block.getBeginNode().getDebug();
-        new LowerGuards(block, debug.isDumpEnabledForMethod() || debug.isLogEnabledForMethod()).processNodes(block, schedule);
+        new LowerGuards(debug.isDumpEnabledForMethod() || debug.isLogEnabledForMethod()).processNodes(block, schedule);
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/InsertMembarsPhase.java	Thu Oct 31 16:54:16 2019 -0700
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, Red Hat Inc. 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.phases.common;
+
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.extended.MembarNode;
+import org.graalvm.compiler.nodes.memory.FixedAccessNode;
+import org.graalvm.compiler.nodes.memory.ReadNode;
+import org.graalvm.compiler.nodes.memory.VolatileReadNode;
+import org.graalvm.compiler.nodes.memory.WriteNode;
+import org.graalvm.compiler.phases.Phase;
+
+import static jdk.vm.ci.code.MemoryBarriers.JMM_POST_VOLATILE_READ;
+import static jdk.vm.ci.code.MemoryBarriers.JMM_POST_VOLATILE_WRITE;
+import static jdk.vm.ci.code.MemoryBarriers.JMM_PRE_VOLATILE_READ;
+import static jdk.vm.ci.code.MemoryBarriers.JMM_PRE_VOLATILE_WRITE;
+
+public class InsertMembarsPhase extends Phase {
+    @Override
+    protected void run(StructuredGraph graph) {
+        for (FixedAccessNode access : graph.getNodes(FixedAccessNode.TYPE)) {
+            if (access instanceof VolatileReadNode) {
+                ReadNode read = (ReadNode) access;
+                MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_READ));
+                graph.addBeforeFixed(read, preMembar);
+                MembarNode postMembar = graph.add(new MembarNode(JMM_POST_VOLATILE_READ));
+                graph.addAfterFixed(read, postMembar);
+            } else if (access instanceof WriteNode && ((WriteNode) access).isVolatile()) {
+                WriteNode write = (WriteNode) access;
+                MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_WRITE));
+                graph.addBeforeFixed(write, preMembar);
+                MembarNode postMembar = graph.add(new MembarNode(JMM_POST_VOLATILE_WRITE));
+                graph.addAfterFixed(write, postMembar);
+            }
+        }
+    }
+
+    @Override
+    public float codeSizeIncrease() {
+        return 3f;
+    }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/LoweringPhase.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/LoweringPhase.java	Thu Oct 31 16:54:16 2019 -0700
@@ -46,6 +46,7 @@
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.graph.NodeBitMap;
 import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.NodeMap;
 import org.graalvm.compiler.graph.NodeSourcePosition;
 import org.graalvm.compiler.graph.iterators.NodeIterable;
 import org.graalvm.compiler.nodeinfo.InputType;
@@ -131,12 +132,14 @@
         private final NodeBitMap activeGuards;
         private AnchoringNode guardAnchor;
         private FixedWithNextNode lastFixedNode;
+        private NodeMap<Block> nodeMap;
 
-        LoweringToolImpl(CoreProviders context, AnchoringNode guardAnchor, NodeBitMap activeGuards, FixedWithNextNode lastFixedNode) {
+        LoweringToolImpl(CoreProviders context, AnchoringNode guardAnchor, NodeBitMap activeGuards, FixedWithNextNode lastFixedNode, NodeMap<Block> nodeMap) {
             this.context = context;
             this.guardAnchor = guardAnchor;
             this.activeGuards = activeGuards;
             this.lastFixedNode = lastFixedNode;
+            this.nodeMap = nodeMap;
         }
 
         @Override
@@ -199,7 +202,8 @@
             StructuredGraph graph = before.graph();
             if (OptEliminateGuards.getValue(graph.getOptions())) {
                 for (Node usage : condition.usages()) {
-                    if (!activeGuards.isNew(usage) && activeGuards.isMarked(usage) && ((GuardNode) usage).isNegated() == negated) {
+                    if (!activeGuards.isNew(usage) && activeGuards.isMarked(usage) && ((GuardNode) usage).isNegated() == negated &&
+                                    (!before.graph().hasValueProxies() || nodeMap.get(((GuardNode) usage).getAnchor().asNode()).isInSameOrOuterLoopOf(nodeMap.get(before)))) {
                         return (GuardNode) usage;
                     }
                 }
@@ -310,9 +314,9 @@
                  */
                 boolean isAny = false;
                 if (n instanceof MemoryCheckpoint.Single) {
-                    isAny = ((MemoryCheckpoint.Single) n).getLocationIdentity().isAny();
+                    isAny = ((MemoryCheckpoint.Single) n).getKilledLocationIdentity().isAny();
                 } else {
-                    for (LocationIdentity ident : ((MemoryCheckpoint.Multi) n).getLocationIdentities()) {
+                    for (LocationIdentity ident : ((MemoryCheckpoint.Multi) n).getKilledLocationIdentities()) {
                         if (ident.isAny()) {
                             isAny = true;
                         }
@@ -447,7 +451,7 @@
         @SuppressWarnings("try")
         private AnchoringNode process(final Block b, final NodeBitMap activeGuards, final AnchoringNode startAnchor) {
 
-            final LoweringToolImpl loweringTool = new LoweringToolImpl(context, startAnchor, activeGuards, b.getBeginNode());
+            final LoweringToolImpl loweringTool = new LoweringToolImpl(context, startAnchor, activeGuards, b.getBeginNode(), this.schedule.getNodeToBlockMap());
 
             // Lower the instructions of this block.
             List<Node> nodes = schedule.nodesFor(b);
@@ -613,69 +617,6 @@
         }
     }
 
-    public static void processBlockBounded(final Frame<?> rootFrame) {
-        ProcessBlockState state = ST_PROCESS;
-        Frame<?> f = rootFrame;
-        while (f != null) {
-            ProcessBlockState nextState;
-            if (state == ST_PROCESS || state == ST_PROCESS_ALWAYS_REACHED) {
-                f.preprocess();
-                nextState = state == ST_PROCESS_ALWAYS_REACHED ? ST_ENTER : ST_ENTER_ALWAYS_REACHED;
-            } else if (state == ST_ENTER_ALWAYS_REACHED) {
-                if (f.alwaysReachedBlock != null && f.alwaysReachedBlock.getDominator() == f.block) {
-                    Frame<?> continueRecur = f.enterAlwaysReached(f.alwaysReachedBlock);
-                    if (continueRecur == null) {
-                        // stop recursion here
-                        f.postprocess();
-                        f = f.parent;
-                        state = ST_ENTER;
-                        continue;
-                    }
-                    f = continueRecur;
-                    nextState = ST_PROCESS;
-                } else {
-                    nextState = ST_ENTER;
-                }
-            } else if (state == ST_ENTER) {
-                if (f.dominated != null) {
-                    Block n = f.dominated;
-                    f.dominated = n.getDominatedSibling();
-                    if (n == f.alwaysReachedBlock) {
-                        if (f.dominated != null) {
-                            n = f.dominated;
-                            f.dominated = n.getDominatedSibling();
-                        } else {
-                            n = null;
-                        }
-                    }
-                    if (n == null) {
-                        nextState = ST_LEAVE;
-                    } else {
-                        Frame<?> continueRecur = f.enter(n);
-                        if (continueRecur == null) {
-                            // stop recursion here
-                            f.postprocess();
-                            f = f.parent;
-                            state = ST_ENTER;
-                            continue;
-                        }
-                        f = continueRecur;
-                        nextState = ST_PROCESS;
-                    }
-                } else {
-                    nextState = ST_LEAVE;
-                }
-            } else if (state == ST_LEAVE) {
-                f.postprocess();
-                f = f.parent;
-                nextState = ST_ENTER;
-            } else {
-                throw GraalError.shouldNotReachHere();
-            }
-            state = nextState;
-        }
-    }
-
     public abstract static class Frame<T extends Frame<?>> {
         protected final Block block;
         final T parent;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/InliningUtil.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/InliningUtil.java	Thu Oct 31 16:54:16 2019 -0700
@@ -56,6 +56,7 @@
 import org.graalvm.compiler.graph.NodeMap;
 import org.graalvm.compiler.graph.NodeSourcePosition;
 import org.graalvm.compiler.graph.NodeWorkList;
+import org.graalvm.compiler.nodeinfo.InputType;
 import org.graalvm.compiler.nodeinfo.Verbosity;
 import org.graalvm.compiler.nodes.AbstractBeginNode;
 import org.graalvm.compiler.nodes.AbstractEndNode;
@@ -87,6 +88,7 @@
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.calc.IsNullNode;
 import org.graalvm.compiler.nodes.extended.ForeignCallNode;
+import org.graalvm.compiler.nodes.extended.GuardedNode;
 import org.graalvm.compiler.nodes.extended.GuardingNode;
 import org.graalvm.compiler.nodes.java.ExceptionObjectNode;
 import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
@@ -526,7 +528,17 @@
                 assert unwindNode.predecessor() != null;
                 assert invokeWithException.exceptionEdge().successors().count() == 1;
                 ExceptionObjectNode obj = (ExceptionObjectNode) invokeWithException.exceptionEdge();
-                obj.replaceAtUsages(unwindNode.exception());
+                /*
+                 * The exception object node is a begin node, i.e., it can be used as an anchor for
+                 * other nodes, thus we need to re-route them to a valid anchor, i.e. the begin node
+                 * of the unwind block.
+                 */
+                assert obj.usages().filter(x -> x instanceof GuardedNode && ((GuardedNode) x).getGuard() == obj).count() == 0 : "Must not have guards attached to an exception object node";
+                AbstractBeginNode replacementAnchor = AbstractBeginNode.prevBegin(unwindNode);
+                assert replacementAnchor != null;
+                obj.replaceAtUsages(InputType.Anchor, replacementAnchor);
+                obj.replaceAtUsages(InputType.Value, unwindNode.exception());
+
                 Node n = obj.next();
                 obj.setNext(null);
                 unwindNode.replaceAndDelete(n);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/MultiTypeGuardInlineInfo.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/MultiTypeGuardInlineInfo.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2019, 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
@@ -208,8 +208,10 @@
             FixedNode exceptionSux = exceptionEdge.next();
             graph.addBeforeFixed(exceptionSux, exceptionMerge);
             exceptionObjectPhi = graph.addWithoutUnique(new ValuePhiNode(StampFactory.forKind(JavaKind.Object), exceptionMerge));
-            exceptionMerge.setStateAfter(exceptionEdge.stateAfter().duplicateModified(invoke.stateAfter().bci, true, JavaKind.Object, new JavaKind[]{JavaKind.Object},
-                            new ValueNode[]{exceptionObjectPhi}));
+
+            assert exceptionEdge.stateAfter().bci == invoke.bci();
+            assert exceptionEdge.stateAfter().rethrowException();
+            exceptionMerge.setStateAfter(exceptionEdge.stateAfter().duplicateModified(JavaKind.Object, JavaKind.Object, exceptionObjectPhi));
         }
 
         // create one separate block for each invoked method
@@ -396,7 +398,7 @@
         JavaKind kind = invoke.asNode().getStackKind();
         if (kind != JavaKind.Void) {
             FrameState stateAfter = invoke.stateAfter();
-            stateAfter = stateAfter.duplicate(stateAfter.bci);
+            stateAfter = stateAfter.duplicate();
             stateAfter.replaceFirstInput(invoke.asNode(), result.asNode());
             result.setStateAfter(stateAfter);
         }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/MemoryScheduleVerification.java	Thu Oct 31 14:23:06 2019 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,164 +0,0 @@
-/*
- * Copyright (c) 2015, 2018, 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.phases.schedule;
-
-import java.util.List;
-
-import jdk.internal.vm.compiler.collections.EconomicSet;
-import jdk.internal.vm.compiler.collections.Equivalence;
-import org.graalvm.compiler.core.common.cfg.BlockMap;
-import org.graalvm.compiler.core.common.cfg.Loop;
-import org.graalvm.compiler.debug.DebugContext;
-import org.graalvm.compiler.graph.Node;
-import org.graalvm.compiler.nodes.AbstractBeginNode;
-import org.graalvm.compiler.nodes.AbstractMergeNode;
-import org.graalvm.compiler.nodes.LoopBeginNode;
-import org.graalvm.compiler.nodes.PhiNode;
-import org.graalvm.compiler.nodes.cfg.Block;
-import org.graalvm.compiler.nodes.cfg.HIRLoop;
-import org.graalvm.compiler.nodes.memory.FloatingReadNode;
-import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
-import org.graalvm.compiler.nodes.memory.MemoryNode;
-import org.graalvm.compiler.nodes.memory.MemoryPhiNode;
-import org.graalvm.compiler.phases.graph.ReentrantBlockIterator;
-import org.graalvm.compiler.phases.graph.ReentrantBlockIterator.BlockIteratorClosure;
-import jdk.internal.vm.compiler.word.LocationIdentity;
-
-public final class MemoryScheduleVerification extends BlockIteratorClosure<EconomicSet<FloatingReadNode>> {
-
-    private final BlockMap<List<Node>> blockToNodesMap;
-
-    public static boolean check(Block startBlock, BlockMap<List<Node>> blockToNodesMap) {
-        ReentrantBlockIterator.apply(new MemoryScheduleVerification(blockToNodesMap), startBlock);
-        return true;
-    }
-
-    private MemoryScheduleVerification(BlockMap<List<Node>> blockToNodesMap) {
-        this.blockToNodesMap = blockToNodesMap;
-    }
-
-    @Override
-    protected EconomicSet<FloatingReadNode> getInitialState() {
-        return EconomicSet.create(Equivalence.IDENTITY);
-    }
-
-    @Override
-    protected EconomicSet<FloatingReadNode> processBlock(Block block, EconomicSet<FloatingReadNode> currentState) {
-        AbstractBeginNode beginNode = block.getBeginNode();
-        if (beginNode instanceof AbstractMergeNode) {
-            AbstractMergeNode abstractMergeNode = (AbstractMergeNode) beginNode;
-            for (PhiNode phi : abstractMergeNode.phis()) {
-                if (phi instanceof MemoryPhiNode) {
-                    MemoryPhiNode memoryPhiNode = (MemoryPhiNode) phi;
-                    addFloatingReadUsages(currentState, memoryPhiNode);
-                }
-            }
-        }
-        for (Node n : blockToNodesMap.get(block)) {
-            if (n instanceof MemoryCheckpoint) {
-                if (n instanceof MemoryCheckpoint.Single) {
-                    MemoryCheckpoint.Single single = (MemoryCheckpoint.Single) n;
-                    processLocation(n, single.getLocationIdentity(), currentState);
-                } else if (n instanceof MemoryCheckpoint.Multi) {
-                    MemoryCheckpoint.Multi multi = (MemoryCheckpoint.Multi) n;
-                    for (LocationIdentity location : multi.getLocationIdentities()) {
-                        processLocation(n, location, currentState);
-                    }
-                }
-
-                addFloatingReadUsages(currentState, n);
-            } else if (n instanceof MemoryNode) {
-                addFloatingReadUsages(currentState, n);
-            } else if (n instanceof FloatingReadNode) {
-                FloatingReadNode floatingReadNode = (FloatingReadNode) n;
-                if (floatingReadNode.getLastLocationAccess() != null && floatingReadNode.getLocationIdentity().isMutable()) {
-                    if (currentState.contains(floatingReadNode)) {
-                        // Floating read was found in the state.
-                        currentState.remove(floatingReadNode);
-                    } else {
-                        throw new RuntimeException("Floating read node " + n + " was not found in the state, i.e., it was killed by a memory check point before its place in the schedule. Block=" +
-                                        block + ", block begin: " + block.getBeginNode() + " block loop: " + block.getLoop() + ", " + blockToNodesMap.get(block).get(0));
-                    }
-                }
-
-            }
-        }
-        return currentState;
-    }
-
-    private static void addFloatingReadUsages(EconomicSet<FloatingReadNode> currentState, Node n) {
-        for (FloatingReadNode read : n.usages().filter(FloatingReadNode.class)) {
-            if (read.getLastLocationAccess() == n && read.getLocationIdentity().isMutable()) {
-                currentState.add(read);
-            }
-        }
-    }
-
-    private void processLocation(Node n, LocationIdentity location, EconomicSet<FloatingReadNode> currentState) {
-        assert n != null;
-        if (location.isImmutable()) {
-            return;
-        }
-
-        for (FloatingReadNode r : cloneState(currentState)) {
-            if (r.getLocationIdentity().overlaps(location)) {
-                // This read is killed by this location.
-                r.getDebug().log(DebugContext.VERBOSE_LEVEL, "%s removing %s from state", n, r);
-                currentState.remove(r);
-            }
-        }
-    }
-
-    @Override
-    protected EconomicSet<FloatingReadNode> merge(Block merge, List<EconomicSet<FloatingReadNode>> states) {
-        EconomicSet<FloatingReadNode> result = states.get(0);
-        for (int i = 1; i < states.size(); ++i) {
-            result.retainAll(states.get(i));
-        }
-        return result;
-    }
-
-    @Override
-    protected EconomicSet<FloatingReadNode> cloneState(EconomicSet<FloatingReadNode> oldState) {
-        EconomicSet<FloatingReadNode> result = EconomicSet.create(Equivalence.IDENTITY);
-        if (oldState != null) {
-            result.addAll(oldState);
-        }
-        return result;
-    }
-
-    @Override
-    protected List<EconomicSet<FloatingReadNode>> processLoop(Loop<Block> loop, EconomicSet<FloatingReadNode> initialState) {
-        HIRLoop l = (HIRLoop) loop;
-        for (MemoryPhiNode memoryPhi : ((LoopBeginNode) l.getHeader().getBeginNode()).memoryPhis()) {
-            for (FloatingReadNode r : cloneState(initialState)) {
-                if (r.getLocationIdentity().overlaps(memoryPhi.getLocationIdentity())) {
-                    initialState.remove(r);
-                }
-            }
-        }
-        return ReentrantBlockIterator.processLoop(this, loop, initialState).exitStates;
-    }
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/SchedulePhase.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/SchedulePhase.java	Thu Oct 31 16:54:16 2019 -0700
@@ -206,7 +206,8 @@
                 sortNodesLatestWithinBlock(cfg, earliestBlockToNodesMap, latestBlockToNodesMap, currentNodeMap, watchListMap, visited);
 
                 assert verifySchedule(cfg, latestBlockToNodesMap, currentNodeMap);
-                assert (!Assertions.detailedAssertionsEnabled(graph.getOptions())) || MemoryScheduleVerification.check(cfg.getStartBlock(), latestBlockToNodesMap);
+                assert (!Assertions.detailedAssertionsEnabled(graph.getOptions())) ||
+                                ScheduleVerification.check(cfg.getStartBlock(), latestBlockToNodesMap, currentNodeMap);
 
                 this.blockToNodesMap = latestBlockToNodesMap;
 
@@ -358,7 +359,7 @@
             }
 
             if (lastBlock.getBeginNode() instanceof KillingBeginNode) {
-                LocationIdentity locationIdentity = ((KillingBeginNode) lastBlock.getBeginNode()).getLocationIdentity();
+                LocationIdentity locationIdentity = ((KillingBeginNode) lastBlock.getBeginNode()).getKilledLocationIdentity();
                 if ((locationIdentity.isAny() || locationIdentity.equals(location)) && lastBlock != earliestBlock) {
                     // The begin of this block kills the location, so we *have* to schedule the node
                     // in the dominating block.
@@ -374,13 +375,13 @@
                 for (Node n : subList) {
                     // Check if this node kills a node in the watch list.
                     if (n instanceof MemoryCheckpoint.Single) {
-                        LocationIdentity identity = ((MemoryCheckpoint.Single) n).getLocationIdentity();
+                        LocationIdentity identity = ((MemoryCheckpoint.Single) n).getKilledLocationIdentity();
                         killed.add(identity);
                         if (killed.isAny()) {
                             return;
                         }
                     } else if (n instanceof MemoryCheckpoint.Multi) {
-                        for (LocationIdentity identity : ((MemoryCheckpoint.Multi) n).getLocationIdentities()) {
+                        for (LocationIdentity identity : ((MemoryCheckpoint.Multi) n).getKilledLocationIdentities()) {
                             killed.add(identity);
                             if (killed.isAny()) {
                                 return;
@@ -471,10 +472,10 @@
             if (watchList != null && !watchList.isEmpty()) {
                 // Check if this node kills a node in the watch list.
                 if (n instanceof MemoryCheckpoint.Single) {
-                    LocationIdentity identity = ((MemoryCheckpoint.Single) n).getLocationIdentity();
+                    LocationIdentity identity = ((MemoryCheckpoint.Single) n).getKilledLocationIdentity();
                     checkWatchList(watchList, identity, b, result, nodeMap, unprocessed);
                 } else if (n instanceof MemoryCheckpoint.Multi) {
-                    for (LocationIdentity identity : ((MemoryCheckpoint.Multi) n).getLocationIdentities()) {
+                    for (LocationIdentity identity : ((MemoryCheckpoint.Multi) n).getKilledLocationIdentities()) {
                         checkWatchList(watchList, identity, b, result, nodeMap, unprocessed);
                     }
                 }
@@ -896,7 +897,7 @@
                 }
             }
 
-            assert (!Assertions.detailedAssertionsEnabled(cfg.graph.getOptions())) || MemoryScheduleVerification.check(cfg.getStartBlock(), blockToNodes);
+            assert (!Assertions.detailedAssertionsEnabled(cfg.graph.getOptions())) || ScheduleVerification.check(cfg.getStartBlock(), blockToNodes, nodeToBlock);
         }
 
         private static void processNodes(NodeBitMap visited, NodeMap<MicroBlock> entries, NodeStack stack, MicroBlock startBlock, Iterable<? extends Node> nodes) {
@@ -1183,10 +1184,10 @@
             Formatter buf = new Formatter();
             buf.format("%s", n);
             if (n instanceof MemoryCheckpoint.Single) {
-                buf.format(" // kills %s", ((MemoryCheckpoint.Single) n).getLocationIdentity());
+                buf.format(" // kills %s", ((MemoryCheckpoint.Single) n).getKilledLocationIdentity());
             } else if (n instanceof MemoryCheckpoint.Multi) {
                 buf.format(" // kills ");
-                for (LocationIdentity locid : ((MemoryCheckpoint.Multi) n).getLocationIdentities()) {
+                for (LocationIdentity locid : ((MemoryCheckpoint.Multi) n).getKilledLocationIdentities()) {
                     buf.format("%s, ", locid);
                 }
             } else if (n instanceof FloatingReadNode) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/ScheduleVerification.java	Thu Oct 31 16:54:16 2019 -0700
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2015, 2019, 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.phases.schedule;
+
+import java.util.List;
+
+import jdk.internal.vm.compiler.collections.EconomicSet;
+import jdk.internal.vm.compiler.collections.Equivalence;
+import org.graalvm.compiler.core.common.cfg.BlockMap;
+import org.graalvm.compiler.core.common.cfg.Loop;
+import org.graalvm.compiler.debug.DebugContext;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeMap;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.AbstractMergeNode;
+import org.graalvm.compiler.nodes.LoopBeginNode;
+import org.graalvm.compiler.nodes.LoopExitNode;
+import org.graalvm.compiler.nodes.MemoryProxyNode;
+import org.graalvm.compiler.nodes.PhiNode;
+import org.graalvm.compiler.nodes.ProxyNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.VirtualState;
+import org.graalvm.compiler.nodes.cfg.Block;
+import org.graalvm.compiler.nodes.cfg.HIRLoop;
+import org.graalvm.compiler.nodes.memory.FloatingReadNode;
+import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
+import org.graalvm.compiler.nodes.memory.MemoryNode;
+import org.graalvm.compiler.nodes.memory.MemoryPhiNode;
+import org.graalvm.compiler.phases.graph.ReentrantBlockIterator;
+import org.graalvm.compiler.phases.graph.ReentrantBlockIterator.BlockIteratorClosure;
+import jdk.internal.vm.compiler.word.LocationIdentity;
+
+/**
+ * Verifies that the schedule of the graph is correct. Checks that floating reads are not killed
+ * between definition and usage. Also checks that there are no usages spanning loop exits without a
+ * proper proxy node.
+ */
+public final class ScheduleVerification extends BlockIteratorClosure<EconomicSet<FloatingReadNode>> {
+
+    private final BlockMap<List<Node>> blockToNodesMap;
+    private final NodeMap<Block> nodeMap;
+    private final StructuredGraph graph;
+
+    public static boolean check(Block startBlock, BlockMap<List<Node>> blockToNodesMap, NodeMap<Block> nodeMap) {
+        ReentrantBlockIterator.apply(new ScheduleVerification(blockToNodesMap, nodeMap, startBlock.getBeginNode().graph()), startBlock);
+        return true;
+    }
+
+    private ScheduleVerification(BlockMap<List<Node>> blockToNodesMap, NodeMap<Block> nodeMap, StructuredGraph graph) {
+        this.blockToNodesMap = blockToNodesMap;
+        this.nodeMap = nodeMap;
+        this.graph = graph;
+    }
+
+    @Override
+    protected EconomicSet<FloatingReadNode> getInitialState() {
+        return EconomicSet.create(Equivalence.IDENTITY);
+    }
+
+    @Override
+    protected EconomicSet<FloatingReadNode> processBlock(Block block, EconomicSet<FloatingReadNode> currentState) {
+        AbstractBeginNode beginNode = block.getBeginNode();
+        if (beginNode instanceof AbstractMergeNode) {
+            AbstractMergeNode abstractMergeNode = (AbstractMergeNode) beginNode;
+            for (PhiNode phi : abstractMergeNode.phis()) {
+                if (phi instanceof MemoryPhiNode) {
+                    MemoryPhiNode memoryPhiNode = (MemoryPhiNode) phi;
+                    addFloatingReadUsages(currentState, memoryPhiNode);
+                }
+            }
+        }
+        if (beginNode instanceof LoopExitNode) {
+            LoopExitNode loopExitNode = (LoopExitNode) beginNode;
+            for (ProxyNode proxy : loopExitNode.proxies()) {
+                if (proxy instanceof MemoryProxyNode) {
+                    MemoryProxyNode memoryProxyNode = (MemoryProxyNode) proxy;
+                    addFloatingReadUsages(currentState, memoryProxyNode);
+                }
+            }
+        }
+        for (Node n : blockToNodesMap.get(block)) {
+            if (n instanceof MemoryCheckpoint) {
+                if (n instanceof MemoryCheckpoint.Single) {
+                    MemoryCheckpoint.Single single = (MemoryCheckpoint.Single) n;
+                    processLocation(n, single.getKilledLocationIdentity(), currentState);
+                } else if (n instanceof MemoryCheckpoint.Multi) {
+                    MemoryCheckpoint.Multi multi = (MemoryCheckpoint.Multi) n;
+                    for (LocationIdentity location : multi.getKilledLocationIdentities()) {
+                        processLocation(n, location, currentState);
+                    }
+                }
+
+                addFloatingReadUsages(currentState, n);
+            } else if (n instanceof MemoryNode) {
+                addFloatingReadUsages(currentState, n);
+            } else if (n instanceof FloatingReadNode) {
+                FloatingReadNode floatingReadNode = (FloatingReadNode) n;
+                if (floatingReadNode.getLastLocationAccess() != null && floatingReadNode.getLocationIdentity().isMutable()) {
+                    if (currentState.contains(floatingReadNode)) {
+                        // Floating read was found in the state.
+                        currentState.remove(floatingReadNode);
+                    } else {
+                        throw new RuntimeException("Floating read node " + n + " was not found in the state, i.e., it was killed by a memory check point before its place in the schedule. Block=" +
+                                        block + ", block begin: " + block.getBeginNode() + " block loop: " + block.getLoop() + ", " + blockToNodesMap.get(block).get(0));
+                    }
+                }
+            }
+            assert nodeMap.get(n) == block;
+            if (graph.hasValueProxies() && block.getLoop() != null && !(n instanceof VirtualState)) {
+                for (Node usage : n.usages()) {
+                    Node usageNode = usage;
+
+                    if (usageNode instanceof PhiNode) {
+                        PhiNode phiNode = (PhiNode) usage;
+                        usageNode = phiNode.merge();
+                    }
+
+                    if (usageNode instanceof LoopExitNode) {
+                        LoopExitNode loopExitNode = (LoopExitNode) usageNode;
+                        if (loopExitNode.loopBegin() == n || loopExitNode.stateAfter() == n) {
+                            continue;
+                        }
+                    }
+                    Block usageBlock = nodeMap.get(usageNode);
+
+                    Loop<Block> usageLoop = null;
+                    if (usageNode instanceof ProxyNode) {
+                        ProxyNode proxyNode = (ProxyNode) usageNode;
+                        usageLoop = nodeMap.get(proxyNode.proxyPoint().loopBegin()).getLoop();
+                    } else {
+                        if (usageBlock.getBeginNode() instanceof LoopExitNode) {
+                            // For nodes in the loop exit node block, we don't know for sure
+                            // whether they are "in the loop" or not. It depends on whether
+                            // one of their transient usages is a loop proxy node.
+                            // For now, let's just assume those nodes are OK, i.e., "in the loop".
+                            LoopExitNode loopExitNode = (LoopExitNode) usageBlock.getBeginNode();
+                            usageLoop = nodeMap.get(loopExitNode.loopBegin()).getLoop();
+                        } else {
+                            usageLoop = usageBlock.getLoop();
+                        }
+                    }
+
+                    assert usageLoop != null : n + ", " + nodeMap.get(n) + " / " + usageNode + ", " + nodeMap.get(usageNode);
+                    while (usageLoop != block.getLoop() && usageLoop != null) {
+                        usageLoop = usageLoop.getParent();
+                    }
+                    assert usageLoop != null : n + ", " + usageNode + ", " + usageBlock + ", " + usageBlock.getLoop() + ", " + block + ", " + block.getLoop();
+                }
+            }
+        }
+        return currentState;
+    }
+
+    private static void addFloatingReadUsages(EconomicSet<FloatingReadNode> currentState, Node n) {
+        for (FloatingReadNode read : n.usages().filter(FloatingReadNode.class)) {
+            if (read.getLastLocationAccess() == n && read.getLocationIdentity().isMutable()) {
+                currentState.add(read);
+            }
+        }
+    }
+
+    private void processLocation(Node n, LocationIdentity location, EconomicSet<FloatingReadNode> currentState) {
+        assert n != null;
+        if (location.isImmutable()) {
+            return;
+        }
+
+        for (FloatingReadNode r : cloneState(currentState)) {
+            if (r.getLocationIdentity().overlaps(location)) {
+                // This read is killed by this location.
+                r.getDebug().log(DebugContext.VERBOSE_LEVEL, "%s removing %s from state", n, r);
+                currentState.remove(r);
+            }
+        }
+    }
+
+    @Override
+    protected EconomicSet<FloatingReadNode> merge(Block merge, List<EconomicSet<FloatingReadNode>> states) {
+        EconomicSet<FloatingReadNode> result = states.get(0);
+        for (int i = 1; i < states.size(); ++i) {
+            result.retainAll(states.get(i));
+        }
+        return result;
+    }
+
+    @Override
+    protected EconomicSet<FloatingReadNode> cloneState(EconomicSet<FloatingReadNode> oldState) {
+        EconomicSet<FloatingReadNode> result = EconomicSet.create(Equivalence.IDENTITY);
+        if (oldState != null) {
+            result.addAll(oldState);
+        }
+        return result;
+    }
+
+    @Override
+    protected List<EconomicSet<FloatingReadNode>> processLoop(Loop<Block> loop, EconomicSet<FloatingReadNode> initialState) {
+        HIRLoop l = (HIRLoop) loop;
+        for (MemoryPhiNode memoryPhi : ((LoopBeginNode) l.getHeader().getBeginNode()).memoryPhis()) {
+            for (FloatingReadNode r : cloneState(initialState)) {
+                if (r.getLocationIdentity().overlaps(memoryPhi.getLocationIdentity())) {
+                    initialState.remove(r);
+                }
+            }
+        }
+        return ReentrantBlockIterator.processLoop(this, loop, initialState).exitStates;
+    }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64GraphBuilderPlugins.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64GraphBuilderPlugins.java	Thu Oct 31 16:54:16 2019 -0700
@@ -32,7 +32,6 @@
 import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.SIN;
 import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.TAN;
 
-import org.graalvm.compiler.bytecode.BytecodeProvider;
 import org.graalvm.compiler.lir.aarch64.AArch64ArithmeticLIRGeneratorTool.RoundingMode;
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
@@ -45,6 +44,7 @@
 import org.graalvm.compiler.nodes.java.AtomicReadAndWriteNode;
 import org.graalvm.compiler.nodes.memory.address.AddressNode;
 import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
+import org.graalvm.compiler.nodes.spi.Replacements;
 import org.graalvm.compiler.replacements.TargetGraphBuilderPlugins;
 import org.graalvm.compiler.replacements.nodes.BinaryMathIntrinsicNode;
 import org.graalvm.compiler.replacements.nodes.FusedMultiplyAddNode;
@@ -60,39 +60,39 @@
 
 public class AArch64GraphBuilderPlugins implements TargetGraphBuilderPlugins {
     @Override
-    public void register(Plugins plugins, BytecodeProvider replacementsBytecodeProvider, Architecture arch, boolean explicitUnsafeNullChecks, boolean registerMathPlugins,
+    public void register(Plugins plugins, Replacements replacements, Architecture arch, boolean explicitUnsafeNullChecks, boolean registerMathPlugins,
                     boolean emitJDK9StringSubstitutions, boolean useFMAIntrinsics) {
-        register(plugins, replacementsBytecodeProvider, explicitUnsafeNullChecks, registerMathPlugins, emitJDK9StringSubstitutions, useFMAIntrinsics);
+        register(plugins, replacements, explicitUnsafeNullChecks, registerMathPlugins, emitJDK9StringSubstitutions, useFMAIntrinsics);
     }
 
-    public static void register(Plugins plugins, BytecodeProvider bytecodeProvider, boolean explicitUnsafeNullChecks,
+    public static void register(Plugins plugins, Replacements replacements, boolean explicitUnsafeNullChecks,
                     boolean registerMathPlugins, boolean emitJDK9StringSubstitutions, boolean useFMAIntrinsics) {
         InvocationPlugins invocationPlugins = plugins.getInvocationPlugins();
         invocationPlugins.defer(new Runnable() {
             @Override
             public void run() {
-                registerIntegerLongPlugins(invocationPlugins, JavaKind.Int, bytecodeProvider);
-                registerIntegerLongPlugins(invocationPlugins, JavaKind.Long, bytecodeProvider);
+                registerIntegerLongPlugins(invocationPlugins, JavaKind.Int, replacements);
+                registerIntegerLongPlugins(invocationPlugins, JavaKind.Long, replacements);
                 if (registerMathPlugins) {
                     registerMathPlugins(invocationPlugins, useFMAIntrinsics);
                 }
                 if (emitJDK9StringSubstitutions) {
-                    registerStringLatin1Plugins(invocationPlugins, bytecodeProvider);
-                    registerStringUTF16Plugins(invocationPlugins, bytecodeProvider);
+                    registerStringLatin1Plugins(invocationPlugins, replacements);
+                    registerStringUTF16Plugins(invocationPlugins, replacements);
                 }
-                registerUnsafePlugins(invocationPlugins, bytecodeProvider);
+                registerUnsafePlugins(invocationPlugins, replacements);
                 // This is temporarily disabled until we implement correct emitting of the CAS
                 // instructions of the proper width.
-                registerPlatformSpecificUnsafePlugins(invocationPlugins, bytecodeProvider, explicitUnsafeNullChecks,
+                registerPlatformSpecificUnsafePlugins(invocationPlugins, replacements, explicitUnsafeNullChecks,
                                 new JavaKind[]{JavaKind.Int, JavaKind.Long, JavaKind.Object});
             }
         });
     }
 
-    private static void registerIntegerLongPlugins(InvocationPlugins plugins, JavaKind kind, BytecodeProvider bytecodeProvider) {
+    private static void registerIntegerLongPlugins(InvocationPlugins plugins, JavaKind kind, Replacements replacements) {
         Class<?> declaringClass = kind.toBoxedJavaClass();
         Class<?> type = kind.toJavaClass();
-        Registration r = new Registration(plugins, declaringClass, bytecodeProvider);
+        Registration r = new Registration(plugins, declaringClass, replacements);
         r.register1("numberOfLeadingZeros", type, new InvocationPlugin() {
             @Override
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
@@ -196,29 +196,29 @@
         });
     }
 
-    private static void registerStringLatin1Plugins(InvocationPlugins plugins, BytecodeProvider replacementsBytecodeProvider) {
+    private static void registerStringLatin1Plugins(InvocationPlugins plugins, Replacements replacements) {
         if (JavaVersionUtil.JAVA_SPEC >= 9) {
-            Registration r = new Registration(plugins, "java.lang.StringLatin1", replacementsBytecodeProvider);
+            Registration r = new Registration(plugins, "java.lang.StringLatin1", replacements);
             r.setAllowOverwrite(true);
             r.registerMethodSubstitution(AArch64StringLatin1Substitutions.class, "compareTo", byte[].class, byte[].class);
             r.registerMethodSubstitution(AArch64StringLatin1Substitutions.class, "compareToUTF16", byte[].class, byte[].class);
         }
     }
 
-    private static void registerStringUTF16Plugins(InvocationPlugins plugins, BytecodeProvider replacementsBytecodeProvider) {
+    private static void registerStringUTF16Plugins(InvocationPlugins plugins, Replacements replacements) {
         if (JavaVersionUtil.JAVA_SPEC >= 9) {
-            Registration r = new Registration(plugins, "java.lang.StringUTF16", replacementsBytecodeProvider);
+            Registration r = new Registration(plugins, "java.lang.StringUTF16", replacements);
             r.setAllowOverwrite(true);
             r.registerMethodSubstitution(AArch64StringUTF16Substitutions.class, "compareTo", byte[].class, byte[].class);
             r.registerMethodSubstitution(AArch64StringUTF16Substitutions.class, "compareToLatin1", byte[].class, byte[].class);
         }
     }
 
-    private static void registerUnsafePlugins(InvocationPlugins plugins, BytecodeProvider replacementsBytecodeProvider) {
+    private static void registerUnsafePlugins(InvocationPlugins plugins, Replacements replacements) {
         registerUnsafePlugins(new Registration(plugins, Unsafe.class),
                         new JavaKind[]{JavaKind.Int, JavaKind.Long, JavaKind.Object}, "Object");
         if (JavaVersionUtil.JAVA_SPEC > 8) {
-            registerUnsafePlugins(new Registration(plugins, "jdk.internal.misc.Unsafe", replacementsBytecodeProvider),
+            registerUnsafePlugins(new Registration(plugins, "jdk.internal.misc.Unsafe", replacements),
                             new JavaKind[]{JavaKind.Int, JavaKind.Long, JavaKind.Object},
                             JavaVersionUtil.JAVA_SPEC <= 11 ? "Object" : "Reference");
         }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64CountLeadingZerosNode.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64CountLeadingZerosNode.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2019, 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
@@ -90,4 +90,10 @@
     public void generate(NodeLIRBuilderTool builder, ArithmeticLIRGeneratorTool gen) {
         builder.setResult(this, ((AMD64ArithmeticLIRGeneratorTool) gen).emitCountLeadingZeros(builder.operand(getValue())));
     }
+
+    @NodeIntrinsic
+    public static native int countLeadingZeros(int i);
+
+    @NodeIntrinsic
+    public static native int countLeadingZeros(long i);
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64CountTrailingZerosNode.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64CountTrailingZerosNode.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2019, 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
@@ -90,4 +90,10 @@
     public void generate(NodeLIRBuilderTool builder, ArithmeticLIRGeneratorTool gen) {
         builder.setResult(this, ((AMD64ArithmeticLIRGeneratorTool) gen).emitCountTrailingZeros(builder.operand(getValue())));
     }
+
+    @NodeIntrinsic
+    public static native int countTrailingZeros(int i);
+
+    @NodeIntrinsic
+    public static native int countTrailingZeros(long i);
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64GraphBuilderPlugins.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64GraphBuilderPlugins.java	Thu Oct 31 16:54:16 2019 -0700
@@ -35,7 +35,6 @@
 
 import java.util.Arrays;
 
-import org.graalvm.compiler.bytecode.BytecodeProvider;
 import org.graalvm.compiler.lir.amd64.AMD64ArithmeticLIRGeneratorTool.RoundingMode;
 import org.graalvm.compiler.nodes.PauseNode;
 import org.graalvm.compiler.nodes.ValueNode;
@@ -48,9 +47,8 @@
 import org.graalvm.compiler.nodes.java.AtomicReadAndAddNode;
 import org.graalvm.compiler.nodes.java.AtomicReadAndWriteNode;
 import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
+import org.graalvm.compiler.nodes.spi.Replacements;
 import org.graalvm.compiler.replacements.ArraysSubstitutions;
-import org.graalvm.compiler.replacements.IntegerSubstitutions;
-import org.graalvm.compiler.replacements.LongSubstitutions;
 import org.graalvm.compiler.replacements.StandardGraphBuilderPlugins.UnsafeAccessPlugin;
 import org.graalvm.compiler.replacements.StandardGraphBuilderPlugins.UnsafeGetPlugin;
 import org.graalvm.compiler.replacements.StandardGraphBuilderPlugins.UnsafePutPlugin;
@@ -72,30 +70,31 @@
 
 public class AMD64GraphBuilderPlugins implements TargetGraphBuilderPlugins {
     @Override
-    public void register(Plugins plugins, BytecodeProvider replacementsBytecodeProvider, Architecture architecture, boolean explicitUnsafeNullChecks,
+    public void register(Plugins plugins, Replacements replacements, Architecture architecture, boolean explicitUnsafeNullChecks,
                     boolean registerMathPlugins, boolean emitJDK9StringSubstitutions, boolean useFMAIntrinsics) {
-        register(plugins, replacementsBytecodeProvider, (AMD64) architecture, explicitUnsafeNullChecks, emitJDK9StringSubstitutions, useFMAIntrinsics);
+        register(plugins, replacements, (AMD64) architecture, explicitUnsafeNullChecks, emitJDK9StringSubstitutions, useFMAIntrinsics);
     }
 
-    public static void register(Plugins plugins, BytecodeProvider replacementsBytecodeProvider, AMD64 arch, boolean explicitUnsafeNullChecks, boolean emitJDK9StringSubstitutions,
+    public static void register(Plugins plugins, Replacements replacements, AMD64 arch, boolean explicitUnsafeNullChecks,
+                    boolean emitJDK9StringSubstitutions,
                     boolean useFMAIntrinsics) {
         InvocationPlugins invocationPlugins = plugins.getInvocationPlugins();
         invocationPlugins.defer(new Runnable() {
             @Override
             public void run() {
                 registerThreadPlugins(invocationPlugins, arch);
-                registerIntegerLongPlugins(invocationPlugins, IntegerSubstitutions.class, JavaKind.Int, arch, replacementsBytecodeProvider);
-                registerIntegerLongPlugins(invocationPlugins, LongSubstitutions.class, JavaKind.Long, arch, replacementsBytecodeProvider);
-                registerPlatformSpecificUnsafePlugins(invocationPlugins, replacementsBytecodeProvider, explicitUnsafeNullChecks,
+                registerIntegerLongPlugins(invocationPlugins, AMD64IntegerSubstitutions.class, JavaKind.Int, arch, replacements);
+                registerIntegerLongPlugins(invocationPlugins, AMD64LongSubstitutions.class, JavaKind.Long, arch, replacements);
+                registerPlatformSpecificUnsafePlugins(invocationPlugins, replacements, explicitUnsafeNullChecks,
                                 new JavaKind[]{JavaKind.Int, JavaKind.Long, JavaKind.Object, JavaKind.Boolean, JavaKind.Byte, JavaKind.Short, JavaKind.Char, JavaKind.Float, JavaKind.Double});
-                registerUnsafePlugins(invocationPlugins, replacementsBytecodeProvider, explicitUnsafeNullChecks);
-                registerStringPlugins(invocationPlugins, replacementsBytecodeProvider);
+                registerUnsafePlugins(invocationPlugins, replacements, explicitUnsafeNullChecks);
+                registerStringPlugins(invocationPlugins, replacements);
                 if (emitJDK9StringSubstitutions) {
-                    registerStringLatin1Plugins(invocationPlugins, replacementsBytecodeProvider);
-                    registerStringUTF16Plugins(invocationPlugins, replacementsBytecodeProvider);
+                    registerStringLatin1Plugins(invocationPlugins, replacements);
+                    registerStringUTF16Plugins(invocationPlugins, replacements);
                 }
-                registerMathPlugins(invocationPlugins, useFMAIntrinsics, arch, replacementsBytecodeProvider);
-                registerArraysEqualsPlugins(invocationPlugins, replacementsBytecodeProvider);
+                registerMathPlugins(invocationPlugins, useFMAIntrinsics, arch, replacements);
+                registerArraysEqualsPlugins(invocationPlugins, replacements);
             }
         });
     }
@@ -103,72 +102,37 @@
     private static void registerThreadPlugins(InvocationPlugins plugins, AMD64 arch) {
         if (JavaVersionUtil.JAVA_SPEC > 8) {
             // Pause instruction introduced with SSE2
-            if (arch.getFeatures().contains(AMD64.CPUFeature.SSE2)) {
-                Registration r = new Registration(plugins, Thread.class);
-                r.register0("onSpinWait", new InvocationPlugin() {
-                    @Override
-                    public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
-                        b.append(new PauseNode());
-                        return true;
-                    }
-                });
-            }
-        }
-    }
-
-    private static void registerIntegerLongPlugins(InvocationPlugins plugins, Class<?> substituteDeclaringClass, JavaKind kind, AMD64 arch, BytecodeProvider bytecodeProvider) {
-        Class<?> declaringClass = kind.toBoxedJavaClass();
-        Class<?> type = kind.toJavaClass();
-        Registration r = new Registration(plugins, declaringClass, bytecodeProvider);
-        r.registerMethodSubstitution(substituteDeclaringClass, "numberOfLeadingZeros", type);
-        if (arch.getFeatures().contains(AMD64.CPUFeature.LZCNT) && arch.getFlags().contains(AMD64.Flag.UseCountLeadingZerosInstruction)) {
-            r.setAllowOverwrite(true);
-            r.register1("numberOfLeadingZeros", type, new InvocationPlugin() {
+            assert (arch.getFeatures().contains(AMD64.CPUFeature.SSE2));
+            Registration r = new Registration(plugins, Thread.class);
+            r.register0("onSpinWait", new InvocationPlugin() {
                 @Override
-                public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
-                    ValueNode folded = AMD64CountLeadingZerosNode.tryFold(value);
-                    if (folded != null) {
-                        b.addPush(JavaKind.Int, folded);
-                    } else {
-                        b.addPush(JavaKind.Int, new AMD64CountLeadingZerosNode(value));
-                    }
+                public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
+                    b.append(new PauseNode());
                     return true;
                 }
             });
         }
-
-        r.registerMethodSubstitution(substituteDeclaringClass, "numberOfTrailingZeros", type);
-        if (arch.getFeatures().contains(AMD64.CPUFeature.BMI1) && arch.getFlags().contains(AMD64.Flag.UseCountTrailingZerosInstruction)) {
-            r.setAllowOverwrite(true);
-            r.register1("numberOfTrailingZeros", type, new InvocationPlugin() {
-
-                @Override
-                public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
-                    ValueNode folded = AMD64CountTrailingZerosNode.tryFold(value);
-                    if (folded != null) {
-                        b.addPush(JavaKind.Int, folded);
-                    } else {
-                        b.addPush(JavaKind.Int, new AMD64CountTrailingZerosNode(value));
-                    }
-                    return true;
-                }
-            });
-        }
-
-        if (arch.getFeatures().contains(AMD64.CPUFeature.POPCNT)) {
-            r.register1("bitCount", type, new InvocationPlugin() {
-                @Override
-                public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
-                    b.push(JavaKind.Int, b.append(new BitCountNode(value).canonical(null)));
-                    return true;
-                }
-            });
-        }
-
     }
 
-    private static void registerMathPlugins(InvocationPlugins plugins, boolean useFMAIntrinsics, AMD64 arch, BytecodeProvider bytecodeProvider) {
-        Registration r = new Registration(plugins, Math.class, bytecodeProvider);
+    private static void registerIntegerLongPlugins(InvocationPlugins plugins, Class<?> substituteDeclaringClass, JavaKind kind, AMD64 arch, Replacements replacements) {
+        Class<?> declaringClass = kind.toBoxedJavaClass();
+        Class<?> type = kind.toJavaClass();
+        Registration r = new Registration(plugins, declaringClass, replacements);
+        r.registerMethodSubstitution(substituteDeclaringClass, "numberOfLeadingZeros", type);
+        r.registerMethodSubstitution(substituteDeclaringClass, "numberOfTrailingZeros", type);
+
+        r.registerConditional1(arch.getFeatures().contains(AMD64.CPUFeature.POPCNT),
+                        "bitCount", type, new InvocationPlugin() {
+                            @Override
+                            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
+                                b.push(JavaKind.Int, b.append(new BitCountNode(value).canonical(null)));
+                                return true;
+                            }
+                        });
+    }
+
+    private static void registerMathPlugins(InvocationPlugins plugins, boolean useFMAIntrinsics, AMD64 arch, Replacements replacements) {
+        Registration r = new Registration(plugins, Math.class, replacements);
         registerUnaryMath(r, "log", LOG);
         registerUnaryMath(r, "log10", LOG10);
         registerUnaryMath(r, "exp", EXP);
@@ -177,19 +141,18 @@
         registerUnaryMath(r, "cos", COS);
         registerUnaryMath(r, "tan", TAN);
 
-        if (arch.getFeatures().contains(CPUFeature.SSE4_1)) {
-            registerRound(r, "rint", RoundingMode.NEAREST);
-            registerRound(r, "ceil", RoundingMode.UP);
-            registerRound(r, "floor", RoundingMode.DOWN);
-        }
+        boolean roundEnabled = arch.getFeatures().contains(CPUFeature.SSE4_1);
+        registerRound(roundEnabled, r, "rint", RoundingMode.NEAREST);
+        registerRound(roundEnabled, r, "ceil", RoundingMode.UP);
+        registerRound(roundEnabled, r, "floor", RoundingMode.DOWN);
 
-        if (useFMAIntrinsics && JavaVersionUtil.JAVA_SPEC > 8 && arch.getFeatures().contains(CPUFeature.FMA)) {
-            registerFMA(r);
+        if (JavaVersionUtil.JAVA_SPEC > 8) {
+            registerFMA(r, useFMAIntrinsics && arch.getFeatures().contains(CPUFeature.FMA));
         }
     }
 
-    private static void registerFMA(Registration r) {
-        r.register3("fma",
+    private static void registerFMA(Registration r, boolean isEnabled) {
+        r.registerConditional3(isEnabled, "fma",
                         Double.TYPE,
                         Double.TYPE,
                         Double.TYPE,
@@ -205,7 +168,7 @@
                                 return true;
                             }
                         });
-        r.register3("fma",
+        r.registerConditional3(isEnabled, "fma",
                         Float.TYPE,
                         Float.TYPE,
                         Float.TYPE,
@@ -243,8 +206,8 @@
         });
     }
 
-    private static void registerRound(Registration r, String name, RoundingMode mode) {
-        r.register1(name, Double.TYPE, new InvocationPlugin() {
+    private static void registerRound(boolean isEnabled, Registration r, String name, RoundingMode mode) {
+        r.registerConditional1(isEnabled, name, Double.TYPE, new InvocationPlugin() {
             @Override
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg) {
                 b.push(JavaKind.Double, b.append(new AMD64RoundNode(arg, mode)));
@@ -253,10 +216,10 @@
         });
     }
 
-    private static void registerStringPlugins(InvocationPlugins plugins, BytecodeProvider replacementsBytecodeProvider) {
+    private static void registerStringPlugins(InvocationPlugins plugins, Replacements replacements) {
         if (JavaVersionUtil.JAVA_SPEC <= 8) {
             Registration r;
-            r = new Registration(plugins, String.class, replacementsBytecodeProvider);
+            r = new Registration(plugins, String.class, replacements);
             r.setAllowOverwrite(true);
             r.registerMethodSubstitution(AMD64StringSubstitutions.class, "indexOf", char[].class, int.class,
                             int.class, char[].class, int.class, int.class, int.class);
@@ -265,8 +228,8 @@
         }
     }
 
-    private static void registerStringLatin1Plugins(InvocationPlugins plugins, BytecodeProvider replacementsBytecodeProvider) {
-        Registration r = new Registration(plugins, "java.lang.StringLatin1", replacementsBytecodeProvider);
+    private static void registerStringLatin1Plugins(InvocationPlugins plugins, Replacements replacements) {
+        Registration r = new Registration(plugins, "java.lang.StringLatin1", replacements);
         r.setAllowOverwrite(true);
         r.registerMethodSubstitution(AMD64StringLatin1Substitutions.class, "compareTo", byte[].class, byte[].class);
         r.registerMethodSubstitution(AMD64StringLatin1Substitutions.class, "compareToUTF16", byte[].class, byte[].class);
@@ -276,8 +239,8 @@
         r.registerMethodSubstitution(AMD64StringLatin1Substitutions.class, "indexOf", byte[].class, int.class, byte[].class, int.class, int.class);
     }
 
-    private static void registerStringUTF16Plugins(InvocationPlugins plugins, BytecodeProvider replacementsBytecodeProvider) {
-        Registration r = new Registration(plugins, "java.lang.StringUTF16", replacementsBytecodeProvider);
+    private static void registerStringUTF16Plugins(InvocationPlugins plugins, Replacements replacements) {
+        Registration r = new Registration(plugins, "java.lang.StringUTF16", replacements);
         r.setAllowOverwrite(true);
         r.registerMethodSubstitution(AMD64StringUTF16Substitutions.class, "compareTo", byte[].class, byte[].class);
         r.registerMethodSubstitution(AMD64StringUTF16Substitutions.class, "compareToLatin1", byte[].class, byte[].class);
@@ -288,10 +251,10 @@
         r.registerMethodSubstitution(AMD64StringUTF16Substitutions.class, "indexOfLatin1Unsafe", byte[].class, int.class, byte[].class, int.class, int.class);
     }
 
-    private static void registerUnsafePlugins(InvocationPlugins plugins, BytecodeProvider replacementsBytecodeProvider, boolean explicitUnsafeNullChecks) {
+    private static void registerUnsafePlugins(InvocationPlugins plugins, Replacements replacements, boolean explicitUnsafeNullChecks) {
         registerUnsafePlugins(new Registration(plugins, Unsafe.class), explicitUnsafeNullChecks, new JavaKind[]{JavaKind.Int, JavaKind.Long, JavaKind.Object}, true);
         if (JavaVersionUtil.JAVA_SPEC > 8) {
-            registerUnsafePlugins(new Registration(plugins, "jdk.internal.misc.Unsafe", replacementsBytecodeProvider), explicitUnsafeNullChecks,
+            registerUnsafePlugins(new Registration(plugins, "jdk.internal.misc.Unsafe", replacements), explicitUnsafeNullChecks,
                             new JavaKind[]{JavaKind.Boolean, JavaKind.Byte, JavaKind.Char, JavaKind.Short, JavaKind.Int, JavaKind.Long, JavaKind.Object},
                             JavaVersionUtil.JAVA_SPEC <= 11);
         }
@@ -330,8 +293,8 @@
         }
     }
 
-    private static void registerArraysEqualsPlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider) {
-        Registration r = new Registration(plugins, Arrays.class, bytecodeProvider);
+    private static void registerArraysEqualsPlugins(InvocationPlugins plugins, Replacements replacements) {
+        Registration r = new Registration(plugins, Arrays.class, replacements);
         r.registerMethodSubstitution(ArraysSubstitutions.class, "equals", float[].class, float[].class);
         r.registerMethodSubstitution(ArraysSubstitutions.class, "equals", double[].class, double[].class);
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64IntegerSubstitutions.java	Thu Oct 31 16:54:16 2019 -0700
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2019, 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.replacements.amd64;
+
+import static org.graalvm.compiler.replacements.NodeIntrinsificationProvider.INJECTED_TARGET;
+
+import org.graalvm.compiler.api.replacements.ClassSubstitution;
+import org.graalvm.compiler.api.replacements.Fold;
+import org.graalvm.compiler.api.replacements.MethodSubstitution;
+import org.graalvm.compiler.core.common.SuppressFBWarnings;
+import org.graalvm.compiler.replacements.nodes.BitScanForwardNode;
+import org.graalvm.compiler.replacements.nodes.BitScanReverseNode;
+
+import jdk.vm.ci.amd64.AMD64;
+import jdk.vm.ci.code.TargetDescription;
+
+@ClassSubstitution(Integer.class)
+public class AMD64IntegerSubstitutions {
+
+    @Fold
+    static boolean lzcnt(@Fold.InjectedParameter TargetDescription target) {
+        AMD64 arch = (AMD64) target.arch;
+        return arch.getFeatures().contains(AMD64.CPUFeature.LZCNT) && arch.getFlags().contains(AMD64.Flag.UseCountLeadingZerosInstruction);
+    }
+
+    @Fold
+    static boolean tzcnt(@Fold.InjectedParameter TargetDescription target) {
+        AMD64 arch = (AMD64) target.arch;
+        return arch.getFeatures().contains(AMD64.CPUFeature.BMI1) && arch.getFlags().contains(AMD64.Flag.UseCountTrailingZerosInstruction);
+    }
+
+    @MethodSubstitution
+    @SuppressFBWarnings(value = "NP_NULL_PARAM_DEREF_NONVIRTUAL", justification = "foldable method parameters are injected")
+    public static int numberOfLeadingZeros(int i) {
+        if (lzcnt(INJECTED_TARGET)) {
+            return AMD64CountLeadingZerosNode.countLeadingZeros(i);
+        }
+        if (i == 0) {
+            return 32;
+        }
+        return 31 - BitScanReverseNode.unsafeScan(i);
+    }
+
+    @MethodSubstitution
+    @SuppressFBWarnings(value = "NP_NULL_PARAM_DEREF_NONVIRTUAL", justification = "foldable method parameters are injected")
+    public static int numberOfTrailingZeros(int i) {
+        if (tzcnt(INJECTED_TARGET)) {
+            return AMD64CountTrailingZerosNode.countTrailingZeros(i);
+        }
+        if (i == 0) {
+            return 32;
+        }
+        return BitScanForwardNode.unsafeScan(i);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64LongSubstitutions.java	Thu Oct 31 16:54:16 2019 -0700
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2019, 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.replacements.amd64;
+
+// JaCoCo Exclude
+
+import static org.graalvm.compiler.replacements.NodeIntrinsificationProvider.INJECTED_TARGET;
+
+import org.graalvm.compiler.api.replacements.ClassSubstitution;
+import org.graalvm.compiler.api.replacements.Fold;
+import org.graalvm.compiler.api.replacements.MethodSubstitution;
+import org.graalvm.compiler.core.common.SuppressFBWarnings;
+import org.graalvm.compiler.replacements.nodes.BitScanForwardNode;
+import org.graalvm.compiler.replacements.nodes.BitScanReverseNode;
+
+import jdk.vm.ci.amd64.AMD64;
+import jdk.vm.ci.code.TargetDescription;
+
+@ClassSubstitution(Long.class)
+public class AMD64LongSubstitutions {
+
+    @Fold
+    static boolean lzcnt(@Fold.InjectedParameter TargetDescription target) {
+        AMD64 arch = (AMD64) target.arch;
+        return arch.getFeatures().contains(AMD64.CPUFeature.LZCNT) && arch.getFlags().contains(AMD64.Flag.UseCountLeadingZerosInstruction);
+    }
+
+    @Fold
+    static boolean tzcnt(@Fold.InjectedParameter TargetDescription target) {
+        AMD64 arch = (AMD64) target.arch;
+        return arch.getFeatures().contains(AMD64.CPUFeature.BMI1) && arch.getFlags().contains(AMD64.Flag.UseCountTrailingZerosInstruction);
+    }
+
+    @MethodSubstitution
+    @SuppressFBWarnings(value = "NP_NULL_PARAM_DEREF_NONVIRTUAL", justification = "foldable method parameters are injected")
+    public static int numberOfLeadingZeros(long i) {
+        if (lzcnt(INJECTED_TARGET)) {
+            return AMD64CountLeadingZerosNode.countLeadingZeros(i);
+        }
+        if (i == 0) {
+            return 64;
+        }
+        return 63 - BitScanReverseNode.unsafeScan(i);
+    }
+
+    @MethodSubstitution
+    @SuppressFBWarnings(value = "NP_NULL_PARAM_DEREF_NONVIRTUAL", justification = "foldable method parameters are injected")
+    public static int numberOfTrailingZeros(long i) {
+        if (tzcnt(INJECTED_TARGET)) {
+            return AMD64CountTrailingZerosNode.countTrailingZeros(i);
+        }
+
+        if (i == 0) {
+            return 64;
+        }
+        return BitScanForwardNode.unsafeScan(i);
+    }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringLatin1InflateNode.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringLatin1InflateNode.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2019, 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
@@ -82,7 +82,7 @@
     }
 
     @Override
-    public LocationIdentity[] getLocationIdentities() {
+    public LocationIdentity[] getKilledLocationIdentities() {
         // Model write access via 'dst' using:
         return new LocationIdentity[]{NamedLocationIdentity.getArrayLocation(writeKind)};
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringUTF16CompressNode.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringUTF16CompressNode.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2019, 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
@@ -82,7 +82,7 @@
     }
 
     @Override
-    public LocationIdentity[] getLocationIdentities() {
+    public LocationIdentity[] getKilledLocationIdentities() {
         // Model write access via 'dst' using:
         return new LocationIdentity[]{NamedLocationIdentity.getArrayLocation(JavaKind.Byte)};
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.jdk9.test/src/org/graalvm/compiler/replacements/jdk9/test/VarHandleTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.jdk9.test/src/org/graalvm/compiler/replacements/jdk9/test/VarHandleTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2019, 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
@@ -162,12 +162,12 @@
                 startNodes++;
             } else if (n instanceof MemoryCheckpoint.Single) {
                 MemoryCheckpoint.Single single = (MemoryCheckpoint.Single) n;
-                if (single.getLocationIdentity().isAny()) {
+                if (single.getKilledLocationIdentity().isAny()) {
                     anyKillCount++;
                 }
             } else if (n instanceof MemoryCheckpoint.Multi) {
                 MemoryCheckpoint.Multi multi = (MemoryCheckpoint.Multi) n;
-                for (LocationIdentity loc : multi.getLocationIdentities()) {
+                for (LocationIdentity loc : multi.getKilledLocationIdentities()) {
                     if (loc.isAny()) {
                         anyKillCount++;
                         break;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.sparc/src/org/graalvm/compiler/replacements/sparc/SPARCGraphBuilderPlugins.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.sparc/src/org/graalvm/compiler/replacements/sparc/SPARCGraphBuilderPlugins.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, 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
@@ -32,13 +32,13 @@
 import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.SIN;
 import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.TAN;
 
-import org.graalvm.compiler.bytecode.BytecodeProvider;
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration;
+import org.graalvm.compiler.nodes.spi.Replacements;
 import org.graalvm.compiler.replacements.IntegerSubstitutions;
 import org.graalvm.compiler.replacements.LongSubstitutions;
 import org.graalvm.compiler.replacements.nodes.BinaryMathIntrinsicNode;
@@ -51,26 +51,26 @@
 
 public class SPARCGraphBuilderPlugins {
 
-    public static void register(Plugins plugins, BytecodeProvider bytecodeProvider, boolean explicitUnsafeNullChecks) {
+    public static void register(Plugins plugins, Replacements replacements, boolean explicitUnsafeNullChecks) {
         InvocationPlugins invocationPlugins = plugins.getInvocationPlugins();
         invocationPlugins.defer(new Runnable() {
             @Override
             public void run() {
-                registerIntegerLongPlugins(invocationPlugins, IntegerSubstitutions.class, JavaKind.Int, bytecodeProvider);
-                registerIntegerLongPlugins(invocationPlugins, LongSubstitutions.class, JavaKind.Long, bytecodeProvider);
+                registerIntegerLongPlugins(invocationPlugins, IntegerSubstitutions.class, JavaKind.Int, replacements);
+                registerIntegerLongPlugins(invocationPlugins, LongSubstitutions.class, JavaKind.Long, replacements);
                 registerMathPlugins(invocationPlugins);
                 // This is temporarily disabled until we implement correct emitting of the CAS
                 // instructions of the proper width.
-                registerPlatformSpecificUnsafePlugins(invocationPlugins, bytecodeProvider, explicitUnsafeNullChecks,
+                registerPlatformSpecificUnsafePlugins(invocationPlugins, replacements, explicitUnsafeNullChecks,
                                 new JavaKind[]{JavaKind.Int, JavaKind.Long, JavaKind.Object});
             }
         });
     }
 
-    private static void registerIntegerLongPlugins(InvocationPlugins plugins, Class<?> substituteDeclaringClass, JavaKind kind, BytecodeProvider bytecodeProvider) {
+    private static void registerIntegerLongPlugins(InvocationPlugins plugins, Class<?> substituteDeclaringClass, JavaKind kind, Replacements replacements) {
         Class<?> declaringClass = kind.toBoxedJavaClass();
         Class<?> type = kind.toJavaClass();
-        Registration r = new Registration(plugins, declaringClass, bytecodeProvider);
+        Registration r = new Registration(plugins, declaringClass, replacements);
         r.registerMethodSubstitution(substituteDeclaringClass, "numberOfLeadingZeros", type);
         r.registerMethodSubstitution(substituteDeclaringClass, "numberOfTrailingZeros", type);
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ArraysSubstitutionsTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ArraysSubstitutionsTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -31,7 +31,6 @@
 import org.graalvm.compiler.nodes.ReturnNode;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.phases.OptimisticOptimizations;
-import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.tiers.HighTierContext;
 import org.graalvm.compiler.replacements.nodes.ArrayEqualsNode;
 import org.graalvm.compiler.virtual.phases.ea.PartialEscapePhase;
@@ -132,7 +131,7 @@
         StructuredGraph graph = parseEager("testCanonicalLengthSnippet", AllowAssumptions.NO);
         HighTierContext context = new HighTierContext(getProviders(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
         createInliningPhase().apply(graph, context);
-        new CanonicalizerPhase().apply(graph, getProviders());
+        createCanonicalizerPhase().apply(graph, getProviders());
 
         Assert.assertTrue(graph.getNodes(ReturnNode.TYPE).first().result().asJavaConstant().asLong() == 0);
     }
@@ -148,7 +147,7 @@
         StructuredGraph graph = parseEager("testCanonicalEqualSnippet", AllowAssumptions.NO);
         HighTierContext context = new HighTierContext(getProviders(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
         createInliningPhase().apply(graph, context);
-        new CanonicalizerPhase().apply(graph, getProviders());
+        createCanonicalizerPhase().apply(graph, getProviders());
 
         Assert.assertTrue(graph.getNodes(ReturnNode.TYPE).first().result().asJavaConstant().asLong() == 1);
     }
@@ -162,9 +161,9 @@
         StructuredGraph graph = parseEager("testVirtualEqualSnippet", AllowAssumptions.NO);
         HighTierContext context = new HighTierContext(getProviders(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
         createInliningPhase().apply(graph, context);
-        new CanonicalizerPhase().apply(graph, getProviders());
-        new PartialEscapePhase(false, new CanonicalizerPhase(), graph.getOptions()).apply(graph, context);
-        new CanonicalizerPhase().apply(graph, getProviders());
+        createCanonicalizerPhase().apply(graph, getProviders());
+        new PartialEscapePhase(false, this.createCanonicalizerPhase(), graph.getOptions()).apply(graph, context);
+        createCanonicalizerPhase().apply(graph, getProviders());
 
         Assert.assertTrue(graph.getNodes(ReturnNode.TYPE).first().result().asJavaConstant().asLong() == 1);
     }
@@ -180,9 +179,9 @@
         StructuredGraph graph = parseEager("testVirtualNotEqualSnippet", AllowAssumptions.NO);
         HighTierContext context = getDefaultHighTierContext();
         createInliningPhase().apply(graph, context);
-        new CanonicalizerPhase().apply(graph, getProviders());
-        new PartialEscapePhase(false, new CanonicalizerPhase(), graph.getOptions()).apply(graph, context);
-        new CanonicalizerPhase().apply(graph, getProviders());
+        createCanonicalizerPhase().apply(graph, getProviders());
+        new PartialEscapePhase(false, this.createCanonicalizerPhase(), graph.getOptions()).apply(graph, context);
+        createCanonicalizerPhase().apply(graph, getProviders());
 
         Assert.assertTrue(graph.getNodes(ReturnNode.TYPE).first().result().asJavaConstant().asLong() == 0);
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/BitOpNodesTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/BitOpNodesTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2019, 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
@@ -303,7 +303,7 @@
     private ValueNode parseAndInline(String name, Class<? extends ValueNode> expectedClass) {
         StructuredGraph graph = parseEager(name, AllowAssumptions.YES);
         HighTierContext context = getDefaultHighTierContext();
-        CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+        CanonicalizerPhase canonicalizer = createCanonicalizerPhase();
         canonicalizer.apply(graph, context);
         createInliningPhase(canonicalizer).apply(graph, context);
         canonicalizer.apply(graph, context);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/DeoptimizeOnExceptionTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/DeoptimizeOnExceptionTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -35,7 +35,7 @@
 import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.phases.common.AbstractInliningPhase;
 import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
-import org.graalvm.compiler.test.ExportingClassLoader;
+import org.graalvm.compiler.api.test.ExportingClassLoader;
 import org.junit.Assert;
 import org.junit.Assume;
 import org.junit.Test;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/EdgesTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/EdgesTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2019, 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
@@ -45,7 +45,6 @@
 import org.graalvm.compiler.nodes.calc.FloatingNode;
 import org.graalvm.compiler.nodes.java.InstanceOfNode;
 import org.graalvm.compiler.options.OptionValues;
-import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.common.inlining.InliningPhase;
 import org.graalvm.compiler.phases.common.inlining.policy.InlineMethodSubstitutionsPolicy;
 import org.graalvm.compiler.phases.tiers.HighTierContext;
@@ -133,8 +132,8 @@
         ResolvedJavaMethod javaMethod = getMetaAccess().lookupJavaMethod(method);
         StructuredGraph g = parseProfiled(javaMethod, AllowAssumptions.NO);
         HighTierContext context = getDefaultHighTierContext();
-        new InliningPhase(new InlineMethodSubstitutionsPolicy(), new CanonicalizerPhase()).apply(g, context);
-        new CanonicalizerPhase().apply(g, context);
+        new InliningPhase(new InlineMethodSubstitutionsPolicy(), createCanonicalizerPhase()).apply(g, context);
+        this.createCanonicalizerPhase().apply(g, context);
         Assert.assertTrue(g.getNodes().filter(InstanceOfNode.class).isEmpty());
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/FoldTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/FoldTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -81,10 +81,10 @@
 
     @Override
     protected void registerInvocationPlugins(InvocationPlugins invocationPlugins) {
-        InjectionProvider injection = new NodeIntrinsificationProvider(getMetaAccess(), getSnippetReflection(), getProviders().getForeignCalls(), null);
+        InjectionProvider injection = new NodeIntrinsificationProvider(getMetaAccess(), getSnippetReflection(), getProviders().getForeignCalls(), null, getTarget());
         new PluginFactory_FoldTest().registerPlugins(invocationPlugins, injection);
         BytecodeProvider replacementBytecodeProvider = getSystemClassLoaderBytecodeProvider();
-        Registration r = new Registration(invocationPlugins, TestMethod.class, replacementBytecodeProvider);
+        Registration r = new Registration(invocationPlugins, TestMethod.class, getReplacements(), replacementBytecodeProvider);
         r.registerMethodSubstitution(TestMethodSubstitution.class, "test");
         super.registerInvocationPlugins(invocationPlugins);
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/IntegerExactFoldTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/IntegerExactFoldTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -94,7 +94,7 @@
         Node originalNode = graph.getNodes().filter(x -> x instanceof IntegerExactArithmeticNode).first();
         assertNotNull("original node must be in the graph", originalNode);
 
-        new CanonicalizerPhase().apply(graph, getDefaultHighTierContext());
+        createCanonicalizerPhase().apply(graph, getDefaultHighTierContext());
 
         ValueNode node = findNode(graph);
         boolean overflowExpected = node instanceof IntegerExactArithmeticNode;
@@ -109,19 +109,19 @@
 
         Node originalNode = graph.getNodes().filter(x -> x instanceof IntegerExactArithmeticNode).first();
         assertNotNull("original node must be in the graph", originalNode);
-        CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+        CanonicalizerPhase canonicalizer = createCanonicalizerPhase();
         HighTierContext highTierContext = getDefaultHighTierContext();
         new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, highTierContext);
         MidTierContext midTierContext = getDefaultMidTierContext();
         new GuardLoweringPhase().apply(graph, midTierContext);
-        new CanonicalizerPhase().apply(graph, midTierContext);
+        createCanonicalizerPhase().apply(graph, midTierContext);
 
         IntegerExactArithmeticSplitNode loweredNode = graph.getNodes().filter(IntegerExactArithmeticSplitNode.class).first();
         assertNotNull("the lowered node must be in the graph", loweredNode);
 
         loweredNode.getX().setStamp(StampFactory.forInteger(bits, lowerBoundA, upperBoundA));
         loweredNode.getY().setStamp(StampFactory.forInteger(bits, lowerBoundB, upperBoundB));
-        new CanonicalizerPhase().apply(graph, midTierContext);
+        createCanonicalizerPhase().apply(graph, midTierContext);
 
         ValueNode node = findNode(graph);
         boolean overflowExpected = node instanceof IntegerExactArithmeticSplitNode;
@@ -144,7 +144,7 @@
         String snippet = "snippetInt" + bits;
         StructuredGraph graph = parseEager(getResolvedJavaMethod(operation.getClass(), snippet), AllowAssumptions.NO);
         HighTierContext context = getDefaultHighTierContext();
-        new CanonicalizerPhase().apply(graph, context);
+        createCanonicalizerPhase().apply(graph, context);
         return graph;
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/MethodSubstitutionTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/MethodSubstitutionTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -25,6 +25,7 @@
 package org.graalvm.compiler.replacements.test;
 
 import java.lang.reflect.InvocationTargetException;
+import java.util.Arrays;
 
 import org.graalvm.compiler.api.replacements.MethodSubstitution;
 import org.graalvm.compiler.core.test.GraalCompilerTest;
@@ -35,7 +36,6 @@
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
 import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
 import org.graalvm.compiler.nodes.spi.LoweringTool;
-import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
 import org.graalvm.compiler.phases.common.LoweringPhase;
 import org.graalvm.compiler.phases.tiers.HighTierContext;
@@ -78,14 +78,14 @@
             debug.dump(DebugContext.BASIC_LEVEL, graph, "Graph");
             createInliningPhase().apply(graph, context);
             debug.dump(DebugContext.BASIC_LEVEL, graph, "Graph");
-            new CanonicalizerPhase().apply(graph, context);
+            createCanonicalizerPhase().apply(graph, context);
             new DeadCodeEliminationPhase().apply(graph);
             // Try to ensure any macro nodes are lowered to expose any resulting invokes
             if (graph.getNodes().filter(MacroNode.class).isNotEmpty()) {
-                new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
+                new LoweringPhase(this.createCanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
             }
             if (graph.getNodes().filter(MacroNode.class).isNotEmpty()) {
-                new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.MID_TIER).apply(graph, context);
+                new LoweringPhase(this.createCanonicalizerPhase(), LoweringTool.StandardLoweringStage.MID_TIER).apply(graph, context);
             }
             assertNotInGraph(graph, MacroNode.class);
             if (name != null) {
@@ -153,13 +153,20 @@
         }
     }
 
-    protected static StructuredGraph assertInGraph(StructuredGraph graph, Class<?> clazz) {
+    protected static StructuredGraph assertInGraph(StructuredGraph graph, Class<?>... clazzes) {
         for (Node node : graph.getNodes()) {
-            if (clazz.isInstance(node)) {
-                return graph;
+            for (Class<?> clazz : clazzes) {
+                if (clazz.isInstance(node)) {
+                    return graph;
+                }
             }
         }
-        fail("Graph does not contain a node of class " + clazz.getName());
+        if (clazzes.length == 1) {
+            fail("Graph does not contain a node of class " + clazzes[0].getName());
+        } else {
+            fail("Graph does not contain a node of one these classes class " + Arrays.toString(clazzes));
+
+        }
         return graph;
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ObjectAccessTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ObjectAccessTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2019, 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
@@ -130,7 +130,7 @@
         Assert.assertEquals(graph.getParameter(0), address.getBase());
         Assert.assertEquals(BytecodeFrame.AFTER_BCI, write.stateAfter().bci);
 
-        Assert.assertEquals(locationIdentity, write.getLocationIdentity());
+        Assert.assertEquals(locationIdentity, write.getKilledLocationIdentity());
 
         if (indexConvert) {
             SignExtendNode convert = (SignExtendNode) address.getOffset();
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PEGraphDecoderTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PEGraphDecoderTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -46,7 +46,6 @@
 import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
 import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.phases.OptimisticOptimizations;
-import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.replacements.CachingPEGraphDecoder;
 import jdk.internal.vm.compiler.word.LocationIdentity;
 import org.junit.Test;
@@ -146,7 +145,7 @@
             targetGraph.verify();
 
             CoreProviders context = getProviders();
-            new CanonicalizerPhase().apply(targetGraph, context);
+            createCanonicalizerPhase().apply(targetGraph, context);
             targetGraph.verify();
 
         } catch (Throwable ex) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PointerTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PointerTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2019, 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
@@ -37,7 +37,6 @@
 import org.graalvm.compiler.nodes.extended.JavaWriteNode;
 import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
 import org.graalvm.compiler.phases.OptimisticOptimizations;
-import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.tiers.HighTierContext;
 import org.graalvm.compiler.word.Word;
 import org.graalvm.compiler.word.WordCastNode;
@@ -150,7 +149,7 @@
         Assert.assertEquals(graph.getParameter(0), cast.getInput());
         Assert.assertEquals(target.wordJavaKind, cast.stamp(NodeView.DEFAULT).getStackKind());
 
-        Assert.assertEquals(locationIdentity, write.getLocationIdentity());
+        Assert.assertEquals(locationIdentity, write.getKilledLocationIdentity());
 
         if (indexConvert) {
             SignExtendNode convert = (SignExtendNode) address.getOffset();
@@ -409,7 +408,7 @@
         HighTierContext context = new HighTierContext(getProviders(), null, OptimisticOptimizations.ALL);
 
         StructuredGraph graph = parseEager(snippetName, AllowAssumptions.YES);
-        new CanonicalizerPhase().apply(graph, context);
+        this.createCanonicalizerPhase().apply(graph, context);
         Assert.assertEquals(expectedWordCasts, graph.getNodes().filter(WordCastNode.class).count());
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ReplacementsParseTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ReplacementsParseTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -318,7 +318,7 @@
     @Override
     protected void registerInvocationPlugins(InvocationPlugins invocationPlugins) {
         BytecodeProvider replacementBytecodeProvider = getSystemClassLoaderBytecodeProvider();
-        Registration r = new Registration(invocationPlugins, TestObject.class, replacementBytecodeProvider);
+        Registration r = new Registration(invocationPlugins, TestObject.class, getReplacements(), replacementBytecodeProvider);
         NodeIntrinsicPluginFactory.InjectionProvider injections = new DummyInjectionProvider();
         new PluginFactory_ReplacementsParseTest().registerPlugins(invocationPlugins, injections);
         r.registerMethodSubstitution(TestObjectSubstitutions.class, "nextAfter", double.class, double.class);
@@ -634,7 +634,7 @@
                 node.remove();
             }
             HighTierContext context = getDefaultHighTierContext();
-            CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+            CanonicalizerPhase canonicalizer = createCanonicalizerPhase();
             new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
             new FloatingReadPhase().apply(graph);
             canonicalizer.apply(graph, context);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/StandardMethodSubstitutionsTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/StandardMethodSubstitutionsTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -31,6 +31,8 @@
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.calc.AbsNode;
 import org.graalvm.compiler.nodes.calc.ReinterpretNode;
+import org.graalvm.compiler.replacements.amd64.AMD64CountLeadingZerosNode;
+import org.graalvm.compiler.replacements.amd64.AMD64CountTrailingZerosNode;
 import org.graalvm.compiler.replacements.nodes.BitCountNode;
 import org.graalvm.compiler.replacements.nodes.BitScanForwardNode;
 import org.graalvm.compiler.replacements.nodes.BitScanReverseNode;
@@ -132,7 +134,7 @@
         return Math.sqrt(value) + Math.log(value) + Math.log10(value) + Math.sin(value) + Math.cos(value) + Math.tan(value);
     }
 
-    public void testSubstitution(String testMethodName, Class<?> intrinsicClass, Class<?> holder, String methodName, boolean optional, Object... args) {
+    public void testSubstitution(String testMethodName, Class<?> holder, String methodName, boolean optional, Object[] args, Class<?>... intrinsicClasses) {
         ResolvedJavaMethod realJavaMethod = getResolvedJavaMethod(holder, methodName);
         ResolvedJavaMethod testJavaMethod = getResolvedJavaMethod(testMethodName);
         StructuredGraph graph = testGraph(testMethodName);
@@ -140,7 +142,7 @@
         // Check to see if the resulting graph contains the expected node
         StructuredGraph replacement = getReplacements().getSubstitution(realJavaMethod, -1, false, null, graph.getOptions());
         if (replacement == null && !optional) {
-            assertInGraph(graph, intrinsicClass);
+            assertInGraph(graph, intrinsicClasses);
         }
 
         for (Object l : args) {
@@ -159,7 +161,7 @@
     public void testCharSubstitutions() {
         Object[] args = new Character[]{Character.MIN_VALUE, (char) -1, (char) 0, (char) 1, Character.MAX_VALUE};
 
-        testSubstitution("charReverseBytes", ReverseBytesNode.class, Character.class, "reverseBytes", false, args);
+        testSubstitution("charReverseBytes", Character.class, "reverseBytes", false, args, ReverseBytesNode.class);
     }
 
     public static char charReverseBytes(char value) {
@@ -183,7 +185,7 @@
     public void testShortSubstitutions() {
         Object[] args = new Short[]{Short.MIN_VALUE, -1, 0, 1, Short.MAX_VALUE};
 
-        testSubstitution("shortReverseBytes", ReverseBytesNode.class, Short.class, "reverseBytes", false, args);
+        testSubstitution("shortReverseBytes", Short.class, "reverseBytes", false, args, ReverseBytesNode.class);
     }
 
     public static short shortReverseBytes(short value) {
@@ -207,10 +209,10 @@
     public void testIntegerSubstitutions() {
         Object[] args = new Object[]{Integer.MIN_VALUE, -1, 0, 1, Integer.MAX_VALUE};
 
-        testSubstitution("integerReverseBytes", ReverseBytesNode.class, Integer.class, "reverseBytes", false, args);
-        testSubstitution("integerNumberOfLeadingZeros", BitScanReverseNode.class, Integer.class, "numberOfLeadingZeros", true, args);
-        testSubstitution("integerNumberOfTrailingZeros", BitScanForwardNode.class, Integer.class, "numberOfTrailingZeros", false, args);
-        testSubstitution("integerBitCount", BitCountNode.class, Integer.class, "bitCount", true, args);
+        testSubstitution("integerReverseBytes", Integer.class, "reverseBytes", false, args, ReverseBytesNode.class);
+        testSubstitution("integerNumberOfLeadingZeros", Integer.class, "numberOfLeadingZeros", true, args, BitScanReverseNode.class, AMD64CountLeadingZerosNode.class);
+        testSubstitution("integerNumberOfTrailingZeros", Integer.class, "numberOfTrailingZeros", false, args, BitScanForwardNode.class, AMD64CountTrailingZerosNode.class);
+        testSubstitution("integerBitCount", Integer.class, "bitCount", true, args, BitCountNode.class);
     }
 
     public static int integerReverseBytes(int value) {
@@ -233,10 +235,10 @@
     public void testLongSubstitutions() {
         Object[] args = new Object[]{Long.MIN_VALUE, -1L, 0L, 1L, Long.MAX_VALUE};
 
-        testSubstitution("longReverseBytes", ReverseBytesNode.class, Long.class, "reverseBytes", false, args);
-        testSubstitution("longNumberOfLeadingZeros", BitScanReverseNode.class, Long.class, "numberOfLeadingZeros", true, args);
-        testSubstitution("longNumberOfTrailingZeros", BitScanForwardNode.class, Long.class, "numberOfTrailingZeros", false, args);
-        testSubstitution("longBitCount", BitCountNode.class, Long.class, "bitCount", true, args);
+        testSubstitution("longReverseBytes", Long.class, "reverseBytes", false, args, ReverseBytesNode.class);
+        testSubstitution("longNumberOfLeadingZeros", Long.class, "numberOfLeadingZeros", true, args, BitScanReverseNode.class, AMD64CountLeadingZerosNode.class);
+        testSubstitution("longNumberOfTrailingZeros", Long.class, "numberOfTrailingZeros", false, args, BitScanForwardNode.class, AMD64CountTrailingZerosNode.class);
+        testSubstitution("longBitCount", Long.class, "bitCount", true, args, BitCountNode.class);
     }
 
     public static long longReverseBytes(long value) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/SubstitutionNodeSourcePositionTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/SubstitutionNodeSourcePositionTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -84,7 +84,7 @@
     protected void registerInvocationPlugins(InvocationPlugins invocationPlugins) {
         new PluginFactory_SubstitutionNodeSourcePositionTest().registerPlugins(invocationPlugins, null);
         ClassfileBytecodeProvider bytecodeProvider = getSystemClassLoaderBytecodeProvider();
-        InvocationPlugins.Registration r = new InvocationPlugins.Registration(invocationPlugins, TestMethod.class, bytecodeProvider);
+        InvocationPlugins.Registration r = new InvocationPlugins.Registration(invocationPlugins, TestMethod.class, getReplacements(), bytecodeProvider);
         r.registerMethodSubstitution(TestMethodSubstitution.class, "test", int.class);
         super.registerInvocationPlugins(invocationPlugins);
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/SubstitutionsTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/SubstitutionsTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -120,7 +120,7 @@
     protected void registerInvocationPlugins(InvocationPlugins invocationPlugins) {
         new PluginFactory_SubstitutionsTest().registerPlugins(invocationPlugins, null);
         ClassfileBytecodeProvider bytecodeProvider = getSystemClassLoaderBytecodeProvider();
-        Registration r = new Registration(invocationPlugins, TestMethod.class, bytecodeProvider);
+        Registration r = new Registration(invocationPlugins, TestMethod.class, getReplacements(), bytecodeProvider);
         r.registerMethodSubstitution(TestMethodSubstitution.class, "test");
         super.registerInvocationPlugins(invocationPlugins);
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/classfile/ClassfileBytecodeProviderTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/classfile/ClassfileBytecodeProviderTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -104,7 +104,7 @@
 import org.graalvm.compiler.replacements.classfile.ClassfileBytecodeProvider;
 import org.graalvm.compiler.runtime.RuntimeProvider;
 import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
-import org.graalvm.compiler.test.ModuleSupport;
+import org.graalvm.compiler.api.test.ModuleSupport;
 import org.graalvm.compiler.test.SubprocessUtil;
 import org.junit.Assert;
 import org.junit.Assume;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/classfile/RedefineIntrinsicTest.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/classfile/RedefineIntrinsicTest.java	Thu Oct 31 16:54:16 2019 -0700
@@ -87,7 +87,7 @@
     @Override
     protected void registerInvocationPlugins(InvocationPlugins invocationPlugins) {
         BytecodeProvider replacementBytecodeProvider = getSystemClassLoaderBytecodeProvider();
-        Registration r = new Registration(invocationPlugins, Original.class, replacementBytecodeProvider);
+        Registration r = new Registration(invocationPlugins, Original.class, getReplacements(), replacementBytecodeProvider);
         r.registerMethodSubstitution(Intrinsic.class, "getValue");
         super.registerInvocationPlugins(invocationPlugins);
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/CachingPEGraphDecoder.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/CachingPEGraphDecoder.java	Thu Oct 31 16:54:16 2019 -0700
@@ -132,7 +132,7 @@
                             : null;
             GraphBuilderPhase.Instance graphBuilderPhaseInstance = createGraphBuilderPhaseInstance(initialIntrinsicContext);
             graphBuilderPhaseInstance.apply(graphToEncode);
-            new CanonicalizerPhase().apply(graphToEncode, providers);
+            CanonicalizerPhase.create().apply(graphToEncode, providers);
             if (postParsingPhase != null) {
                 postParsingPhase.apply(graphToEncode, providers);
             }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/DefaultJavaLoweringProvider.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/DefaultJavaLoweringProvider.java	Thu Oct 31 16:54:16 2019 -0700
@@ -47,6 +47,7 @@
 import org.graalvm.compiler.api.directives.GraalDirectives;
 import org.graalvm.compiler.api.replacements.Snippet;
 import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
+import org.graalvm.compiler.core.common.GraalOptions;
 import org.graalvm.compiler.core.common.LIRKind;
 import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
 import org.graalvm.compiler.core.common.type.AbstractPointerStamp;
@@ -129,6 +130,7 @@
 import org.graalvm.compiler.nodes.java.ValueCompareAndSwapNode;
 import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType;
 import org.graalvm.compiler.nodes.memory.ReadNode;
+import org.graalvm.compiler.nodes.memory.VolatileReadNode;
 import org.graalvm.compiler.nodes.memory.WriteNode;
 import org.graalvm.compiler.nodes.memory.address.AddressNode;
 import org.graalvm.compiler.nodes.memory.address.IndexAddressNode;
@@ -397,12 +399,17 @@
         AddressNode address = createFieldAddress(graph, object, field);
         assert address != null : "Field that is loaded must not be eliminated: " + field.getDeclaringClass().toJavaName(true) + "." + field.getName();
 
-        ReadNode memoryRead = graph.add(new ReadNode(address, fieldLocationIdentity(field), loadStamp, fieldLoadBarrierType(field)));
+        ReadNode memoryRead = null;
+        if (loadField.isVolatile() && GraalOptions.LateMembars.getValue(graph.getOptions())) {
+            memoryRead = graph.add(new VolatileReadNode(address, fieldLocationIdentity(field), loadStamp, fieldLoadBarrierType(field)));
+        } else {
+            memoryRead = graph.add(new ReadNode(address, fieldLocationIdentity(field), loadStamp, fieldLoadBarrierType(field)));
+        }
         ValueNode readValue = implicitLoadConvert(graph, getStorageKind(field), memoryRead);
         loadField.replaceAtUsages(readValue);
         graph.replaceFixed(loadField, memoryRead);
 
-        if (loadField.isVolatile()) {
+        if (loadField.isVolatile() && !GraalOptions.LateMembars.getValue(graph.getOptions())) {
             MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_READ));
             graph.addBeforeFixed(memoryRead, preMembar);
             MembarNode postMembar = graph.add(new MembarNode(JMM_POST_VOLATILE_READ));
@@ -419,11 +426,11 @@
         AddressNode address = createFieldAddress(graph, object, field);
         assert address != null;
 
-        WriteNode memoryWrite = graph.add(new WriteNode(address, fieldLocationIdentity(field), value, fieldStoreBarrierType(storeField.field())));
+        WriteNode memoryWrite = graph.add(new WriteNode(address, fieldLocationIdentity(field), value, fieldStoreBarrierType(storeField.field()), storeField.isVolatile()));
         memoryWrite.setStateAfter(storeField.stateAfter());
         graph.replaceFixedWithFixed(storeField, memoryWrite);
 
-        if (storeField.isVolatile()) {
+        if (storeField.isVolatile() && !GraalOptions.LateMembars.getValue(graph.getOptions())) {
             MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_WRITE));
             graph.addBeforeFixed(memoryWrite, preMembar);
             MembarNode postMembar = graph.add(new MembarNode(JMM_POST_VOLATILE_WRITE));
@@ -528,7 +535,7 @@
 
         AddressNode address = createArrayIndexAddress(graph, array, elementKind, storeIndexed.index(), boundsCheck);
         WriteNode memoryWrite = graph.add(new WriteNode(address, NamedLocationIdentity.getArrayLocation(elementKind), implicitStoreConvert(graph, elementKind, value),
-                        arrayStoreBarrierType(storeIndexed.elementKind())));
+                        arrayStoreBarrierType(storeIndexed.elementKind()), false));
         memoryWrite.setGuard(boundsCheck);
         if (condition != null) {
             tool.createGuard(storeIndexed, condition, DeoptimizationReason.ArrayStoreException, DeoptimizationAction.InvalidateReprofile);
@@ -623,7 +630,7 @@
 
         AddressNode address = graph.unique(new OffsetAddressNode(cas.object(), cas.offset()));
         BarrierType barrierType = guessStoreBarrierType(cas.object(), expectedValue);
-        LogicCompareAndSwapNode atomicNode = graph.add(new LogicCompareAndSwapNode(address, cas.getLocationIdentity(), expectedValue, newValue, barrierType));
+        LogicCompareAndSwapNode atomicNode = graph.add(new LogicCompareAndSwapNode(address, cas.getKilledLocationIdentity(), expectedValue, newValue, barrierType));
         atomicNode.setStateAfter(cas.stateAfter());
         graph.replaceFixedWithFixed(cas, atomicNode);
     }
@@ -637,7 +644,7 @@
 
         AddressNode address = graph.unique(new OffsetAddressNode(cas.object(), cas.offset()));
         BarrierType barrierType = guessStoreBarrierType(cas.object(), expectedValue);
-        ValueCompareAndSwapNode atomicNode = graph.add(new ValueCompareAndSwapNode(address, expectedValue, newValue, cas.getLocationIdentity(), barrierType));
+        ValueCompareAndSwapNode atomicNode = graph.add(new ValueCompareAndSwapNode(address, expectedValue, newValue, cas.getKilledLocationIdentity(), barrierType));
         ValueNode coercedNode = implicitLoadConvert(graph, valueKind, atomicNode, true);
         atomicNode.setStateAfter(cas.stateAfter());
         cas.replaceAtUsages(coercedNode);
@@ -653,7 +660,7 @@
         AddressNode address = graph.unique(new OffsetAddressNode(n.object(), n.offset()));
         BarrierType barrierType = guessStoreBarrierType(n.object(), n.newValue());
         LIRKind lirAccessKind = LIRKind.fromJavaKind(target.arch, valueKind);
-        LoweredAtomicReadAndWriteNode memoryRead = graph.add(new LoweredAtomicReadAndWriteNode(address, n.getLocationIdentity(), newValue, lirAccessKind, barrierType));
+        LoweredAtomicReadAndWriteNode memoryRead = graph.add(new LoweredAtomicReadAndWriteNode(address, n.getKilledLocationIdentity(), newValue, lirAccessKind, barrierType));
         memoryRead.setStateAfter(n.stateAfter());
 
         ValueNode readValue = implicitLoadConvert(graph, valueKind, memoryRead);
@@ -744,7 +751,7 @@
         JavaKind valueKind = store.accessKind();
         ValueNode value = implicitStoreConvert(graph, valueKind, store.value(), compressible);
         AddressNode address = createUnsafeAddress(graph, store.object(), store.offset());
-        WriteNode write = graph.add(new WriteNode(address, store.getLocationIdentity(), value, unsafeStoreBarrierType(store)));
+        WriteNode write = graph.add(new WriteNode(address, store.getKilledLocationIdentity(), value, unsafeStoreBarrierType(store), false));
         write.setStateAfter(store.stateAfter());
         graph.replaceFixedWithFixed(store, write);
     }
@@ -755,7 +762,7 @@
         JavaKind valueKind = store.getKind();
         ValueNode value = implicitStoreConvert(graph, valueKind, store.getValue(), false);
         AddressNode address = graph.addOrUniqueWithInputs(OffsetAddressNode.create(store.getAddress()));
-        WriteNode write = graph.add(new WriteNode(address, store.getLocationIdentity(), value, BarrierType.NONE));
+        WriteNode write = graph.add(new WriteNode(address, store.getKilledLocationIdentity(), value, BarrierType.NONE, false));
         write.setStateAfter(store.stateAfter());
         graph.replaceFixedWithFixed(store, write);
     }
@@ -782,7 +789,7 @@
     protected void lowerJavaWriteNode(JavaWriteNode write) {
         StructuredGraph graph = write.graph();
         ValueNode value = implicitStoreConvert(graph, write.getWriteKind(), write.value(), write.isCompressible());
-        WriteNode memoryWrite = graph.add(new WriteNode(write.getAddress(), write.getLocationIdentity(), value, write.getBarrierType()));
+        WriteNode memoryWrite = graph.add(new WriteNode(write.getAddress(), write.getKilledLocationIdentity(), value, write.getBarrierType(), false));
         memoryWrite.setStateAfter(write.stateAfter());
         graph.replaceFixedWithFixed(write, memoryWrite);
         memoryWrite.setGuard(write.getGuard());
@@ -842,7 +849,7 @@
                                 barrierType = arrayInitializationBarrier(entryKind);
                             }
                             if (address != null) {
-                                WriteNode write = new WriteNode(address, LocationIdentity.init(), implicitStoreConvert(graph, entryKind, value), barrierType);
+                                WriteNode write = new WriteNode(address, LocationIdentity.init(), implicitStoreConvert(graph, entryKind, value), barrierType, false);
                                 graph.addAfterFixed(newObject, graph.add(write));
                             }
                         }
@@ -875,7 +882,7 @@
                                     barrierType = arrayStoreBarrierType(virtual.entryKind(i));
                                 }
                                 if (address != null) {
-                                    WriteNode write = new WriteNode(address, LocationIdentity.init(), implicitStoreConvert(graph, JavaKind.Object, allocValue), barrierType);
+                                    WriteNode write = new WriteNode(address, LocationIdentity.init(), implicitStoreConvert(graph, JavaKind.Object, allocValue), barrierType, false);
                                     graph.addBeforeFixed(commit, graph.add(write));
                                 }
                             }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/NodeIntrinsificationProvider.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/NodeIntrinsificationProvider.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2019, 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
@@ -34,22 +34,27 @@
 import org.graalvm.compiler.replacements.arraycopy.ArrayCopyForeignCalls;
 import org.graalvm.compiler.word.WordTypes;
 
+import jdk.vm.ci.code.TargetDescription;
 import jdk.vm.ci.meta.JavaKind;
 import jdk.vm.ci.meta.MetaAccessProvider;
 import jdk.vm.ci.meta.ResolvedJavaType;
 
 public class NodeIntrinsificationProvider implements InjectionProvider {
 
+    public static final TargetDescription INJECTED_TARGET = null;
+
     private final MetaAccessProvider metaAccess;
     private final SnippetReflectionProvider snippetReflection;
     private final ForeignCallsProvider foreignCalls;
     private final WordTypes wordTypes;
+    private final TargetDescription target;
 
-    public NodeIntrinsificationProvider(MetaAccessProvider metaAccess, SnippetReflectionProvider snippetReflection, ForeignCallsProvider foreignCalls, WordTypes wordTypes) {
+    public NodeIntrinsificationProvider(MetaAccessProvider metaAccess, SnippetReflectionProvider snippetReflection, ForeignCallsProvider foreignCalls, WordTypes wordTypes, TargetDescription target) {
         this.metaAccess = metaAccess;
         this.snippetReflection = snippetReflection;
         this.foreignCalls = foreignCalls;
         this.wordTypes = wordTypes;
+        this.target = target;
     }
 
     @Override
@@ -78,6 +83,8 @@
             return type.cast(snippetReflection);
         } else if (type.equals(WordTypes.class)) {
             return type.cast(wordTypes);
+        } else if (type.equals(TargetDescription.class)) {
+            return type.cast(target);
         } else {
             throw new GraalError("Cannot handle injected argument of type %s.", type.getName());
         }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ReplacementsImpl.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ReplacementsImpl.java	Thu Oct 31 16:54:16 2019 -0700
@@ -269,11 +269,15 @@
     }
 
     @Override
-    public void registerMethodSubstitution(MethodSubstitutionPlugin plugin, ResolvedJavaMethod original, IntrinsicContext.CompilationContext context, OptionValues options) {
+    public void registerMethodSubstitution(MethodSubstitutionPlugin plugin) {
         // No initialization needed as method substitutions are parsed by the BytecodeParser.
     }
 
     @Override
+    public void registerConditionalPlugin(InvocationPlugin plugin) {
+    }
+
+    @Override
     public boolean hasSubstitution(ResolvedJavaMethod method, int invokeBci) {
         InvocationPlugin plugin = graphBuilderPlugins.getInvocationPlugins().lookupInvocation(method);
         return plugin != null && (!plugin.inlineOnly() || invokeBci >= 0);
@@ -560,7 +564,7 @@
 
                 createGraphBuilder(replacements.providers, config, OptimisticOptimizations.NONE, initialIntrinsicContext).apply(graph);
 
-                new CanonicalizerPhase().apply(graph, replacements.providers);
+                CanonicalizerPhase.create().apply(graph, replacements.providers);
             } catch (Throwable e) {
                 throw debug.handle(e);
             }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetTemplate.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetTemplate.java	Thu Oct 31 16:54:16 2019 -0700
@@ -891,7 +891,7 @@
             }
             snippetCopy.setGuardsStage(guardsStage);
             try (DebugContext.Scope s = debug.scope("LoweringSnippetTemplate", snippetCopy)) {
-                new LoweringPhase(new CanonicalizerPhase(), args.cacheKey.loweringStage).apply(snippetCopy, providers);
+                new LoweringPhase(CanonicalizerPhase.create(), args.cacheKey.loweringStage).apply(snippetCopy, providers);
             } catch (Throwable e) {
                 throw debug.handle(e);
             }
@@ -930,7 +930,10 @@
             assert checkAllVarargPlaceholdersAreDeleted(parameterCount, placeholders);
 
             new FloatingReadPhase(true, true).apply(snippetCopy);
-            new RemoveValueProxyPhase().apply(snippetCopy);
+
+            if (!guardsStage.requiresValueProxies()) {
+                new RemoveValueProxyPhase().apply(snippetCopy);
+            }
 
             MemoryAnchorNode anchor = snippetCopy.add(new MemoryAnchorNode());
             snippetCopy.start().replaceAtUsages(InputType.Memory, anchor);
@@ -1059,8 +1062,14 @@
                 if (loopBegin != null) {
                     LoopEx loop = new LoopsData(snippetCopy).loop(loopBegin);
                     Mark mark = snippetCopy.getMark();
-                    LoopTransformations.fullUnroll(loop, providers, new CanonicalizerPhase());
-                    new CanonicalizerPhase().applyIncremental(snippetCopy, providers, mark, false);
+                    CanonicalizerPhase canonicalizer = null;
+                    if (GraalOptions.ImmutableCode.getValue(snippetCopy.getOptions())) {
+                        canonicalizer = CanonicalizerPhase.createWithoutReadCanonicalization();
+                    } else {
+                        canonicalizer = CanonicalizerPhase.create();
+                    }
+                    LoopTransformations.fullUnroll(loop, providers, canonicalizer);
+                    CanonicalizerPhase.create().applyIncremental(snippetCopy, providers, mark, false);
                     loop.deleteUnusedNodes();
                 }
                 GraphUtil.removeFixedWithUnusedInputs(explodeLoop);
@@ -1278,7 +1287,7 @@
 
         if (replacee instanceof MemoryCheckpoint.Single) {
             // check if some node in snippet graph also kills the same location
-            LocationIdentity locationIdentity = ((MemoryCheckpoint.Single) replacee).getLocationIdentity();
+            LocationIdentity locationIdentity = ((MemoryCheckpoint.Single) replacee).getKilledLocationIdentity();
             if (locationIdentity.isAny()) {
                 assert !(memoryMap.getLastLocationAccess(any()) instanceof MemoryAnchorNode) : replacee + " kills ANY_LOCATION, but snippet does not";
                 // if the replacee kills ANY_LOCATION, the snippet can kill arbitrary locations
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java	Thu Oct 31 16:54:16 2019 -0700
@@ -40,7 +40,6 @@
 
 import org.graalvm.compiler.api.directives.GraalDirectives;
 import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
-import org.graalvm.compiler.bytecode.BytecodeProvider;
 import org.graalvm.compiler.core.common.calc.Condition;
 import org.graalvm.compiler.core.common.calc.Condition.CanonicalizedCondition;
 import org.graalvm.compiler.core.common.calc.UnsignedMath;
@@ -115,6 +114,7 @@
 import org.graalvm.compiler.nodes.java.UnsafeCompareAndSwapNode;
 import org.graalvm.compiler.nodes.memory.HeapAccess;
 import org.graalvm.compiler.nodes.memory.address.IndexAddressNode;
+import org.graalvm.compiler.nodes.spi.Replacements;
 import org.graalvm.compiler.nodes.type.StampTool;
 import org.graalvm.compiler.nodes.util.GraphUtil;
 import org.graalvm.compiler.nodes.virtual.EnsureVirtualizedNode;
@@ -154,30 +154,30 @@
  */
 public class StandardGraphBuilderPlugins {
 
-    public static void registerInvocationPlugins(MetaAccessProvider metaAccess, SnippetReflectionProvider snippetReflection, InvocationPlugins plugins, BytecodeProvider bytecodeProvider,
+    public static void registerInvocationPlugins(MetaAccessProvider metaAccess, SnippetReflectionProvider snippetReflection, InvocationPlugins plugins, Replacements replacements,
                     boolean allowDeoptimization, boolean explicitUnsafeNullChecks) {
         registerObjectPlugins(plugins);
         registerClassPlugins(plugins);
         registerMathPlugins(plugins, allowDeoptimization);
         registerStrictMathPlugins(plugins);
         registerUnsignedMathPlugins(plugins);
-        registerStringPlugins(plugins, bytecodeProvider, snippetReflection);
+        registerStringPlugins(plugins, replacements, snippetReflection);
         registerCharacterPlugins(plugins);
         registerShortPlugins(plugins);
         registerIntegerLongPlugins(plugins, JavaKind.Int);
         registerIntegerLongPlugins(plugins, JavaKind.Long);
         registerFloatPlugins(plugins);
         registerDoublePlugins(plugins);
-        registerArraysPlugins(plugins, bytecodeProvider);
-        registerArrayPlugins(plugins, bytecodeProvider);
-        registerUnsafePlugins(plugins, bytecodeProvider, explicitUnsafeNullChecks);
+        registerArraysPlugins(plugins, replacements);
+        registerArrayPlugins(plugins, replacements);
+        registerUnsafePlugins(plugins, replacements, explicitUnsafeNullChecks);
         registerEdgesPlugins(metaAccess, plugins);
         registerGraalDirectivesPlugins(plugins);
         registerBoxingPlugins(plugins);
-        registerJMHBlackholePlugins(plugins, bytecodeProvider);
-        registerJFRThrowablePlugins(plugins, bytecodeProvider);
-        registerMethodHandleImplPlugins(plugins, snippetReflection, bytecodeProvider);
-        registerJcovCollectPlugins(plugins, bytecodeProvider);
+        registerJMHBlackholePlugins(plugins, replacements);
+        registerJFRThrowablePlugins(plugins, replacements);
+        registerMethodHandleImplPlugins(plugins, snippetReflection, replacements);
+        registerJcovCollectPlugins(plugins, replacements);
     }
 
     private static final Field STRING_VALUE_FIELD;
@@ -196,8 +196,8 @@
         STRING_CODER_FIELD = coder;
     }
 
-    private static void registerStringPlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider, SnippetReflectionProvider snippetReflection) {
-        final Registration r = new Registration(plugins, String.class, bytecodeProvider);
+    private static void registerStringPlugins(InvocationPlugins plugins, Replacements replacements, SnippetReflectionProvider snippetReflection) {
+        final Registration r = new Registration(plugins, String.class, replacements);
         r.register1("hashCode", Receiver.class, new InvocationPlugin() {
             @Override
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
@@ -243,7 +243,7 @@
             });
         } else {
             r.registerMethodSubstitution(JDK9StringSubstitutions.class, "equals", Receiver.class, Object.class);
-            Registration utf16sub = new Registration(plugins, StringUTF16Substitutions.class, bytecodeProvider);
+            Registration utf16sub = new Registration(plugins, StringUTF16Substitutions.class, replacements);
             utf16sub.register2("getCharDirect", byte[].class, int.class, new InvocationPlugin() {
                 @Override
                 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg1, ValueNode arg2) {
@@ -261,10 +261,10 @@
                 }
             });
 
-            final Registration latin1r = new Registration(plugins, "java.lang.StringLatin1", bytecodeProvider);
+            final Registration latin1r = new Registration(plugins, "java.lang.StringLatin1", replacements);
             latin1r.register5("indexOf", byte[].class, int.class, byte[].class, int.class, int.class, new StringLatin1IndexOfConstantPlugin());
 
-            final Registration utf16r = new Registration(plugins, "java.lang.StringUTF16", bytecodeProvider);
+            final Registration utf16r = new Registration(plugins, "java.lang.StringUTF16", replacements);
             utf16r.register5("indexOfUnsafe", byte[].class, int.class, byte[].class, int.class, int.class, new StringUTF16IndexOfConstantPlugin());
             utf16r.setAllowOverwrite(true);
             utf16r.registerMethodSubstitution(StringUTF16Substitutions.class, "getChar", byte[].class, int.class);
@@ -292,8 +292,8 @@
         }
     }
 
-    private static void registerArraysPlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider) {
-        Registration r = new Registration(plugins, Arrays.class, bytecodeProvider);
+    private static void registerArraysPlugins(InvocationPlugins plugins, Replacements replacements) {
+        Registration r = new Registration(plugins, Arrays.class, replacements);
         r.registerMethodSubstitution(ArraysSubstitutions.class, "equals", boolean[].class, boolean[].class);
         r.registerMethodSubstitution(ArraysSubstitutions.class, "equals", byte[].class, byte[].class);
         r.registerMethodSubstitution(ArraysSubstitutions.class, "equals", short[].class, short[].class);
@@ -302,8 +302,8 @@
         r.registerMethodSubstitution(ArraysSubstitutions.class, "equals", long[].class, long[].class);
     }
 
-    private static void registerArrayPlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider) {
-        Registration r = new Registration(plugins, Array.class, bytecodeProvider);
+    private static void registerArrayPlugins(InvocationPlugins plugins, Replacements replacements) {
+        Registration r = new Registration(plugins, Array.class, replacements);
         r.register2("newInstance", Class.class, int.class, new InvocationPlugin() {
             @Override
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unused, ValueNode componentType, ValueNode length) {
@@ -381,10 +381,10 @@
 
     private static UnsafeCompareAndExchangePluginsRegistrar unsafeCompareAndExchangePluginsRegistrar = new UnsafeCompareAndExchangePluginsRegistrar();
 
-    public static void registerPlatformSpecificUnsafePlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider, boolean explicitUnsafeNullChecks, JavaKind[] supportedCasKinds) {
+    public static void registerPlatformSpecificUnsafePlugins(InvocationPlugins plugins, Replacements replacements, boolean explicitUnsafeNullChecks, JavaKind[] supportedCasKinds) {
         registerPlatformSpecificUnsafePlugins(supportedCasKinds, new Registration(plugins, Unsafe.class), true, explicitUnsafeNullChecks);
         if (JavaVersionUtil.JAVA_SPEC > 8) {
-            registerPlatformSpecificUnsafePlugins(supportedCasKinds, new Registration(plugins, "jdk.internal.misc.Unsafe", bytecodeProvider), false, explicitUnsafeNullChecks);
+            registerPlatformSpecificUnsafePlugins(supportedCasKinds, new Registration(plugins, "jdk.internal.misc.Unsafe", replacements), false, explicitUnsafeNullChecks);
         }
 
     }
@@ -398,10 +398,10 @@
         }
     }
 
-    private static void registerUnsafePlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider, boolean explicitUnsafeNullChecks) {
+    private static void registerUnsafePlugins(InvocationPlugins plugins, Replacements replacements, boolean explicitUnsafeNullChecks) {
         registerUnsafePlugins(new Registration(plugins, Unsafe.class), true, explicitUnsafeNullChecks);
         if (JavaVersionUtil.JAVA_SPEC > 8) {
-            registerUnsafePlugins(new Registration(plugins, "jdk.internal.misc.Unsafe", bytecodeProvider), false, explicitUnsafeNullChecks);
+            registerUnsafePlugins(new Registration(plugins, "jdk.internal.misc.Unsafe", replacements), false, explicitUnsafeNullChecks);
         }
     }
 
@@ -1300,7 +1300,7 @@
         });
     }
 
-    private static void registerJMHBlackholePlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider) {
+    private static void registerJMHBlackholePlugins(InvocationPlugins plugins, Replacements replacements) {
         InvocationPlugin blackholePlugin = new InvocationPlugin() {
             @Override
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver blackhole, ValueNode value) {
@@ -1316,7 +1316,7 @@
         };
         String[] names = {"org.openjdk.jmh.infra.Blackhole", "org.openjdk.jmh.logic.BlackHole"};
         for (String name : names) {
-            Registration r = new Registration(plugins, name, bytecodeProvider);
+            Registration r = new Registration(plugins, name, replacements);
             for (JavaKind kind : JavaKind.values()) {
                 if ((kind.isPrimitive() && kind != JavaKind.Void) || kind == JavaKind.Object) {
                     Class<?> javaClass = kind == JavaKind.Object ? Object.class : kind.toJavaClass();
@@ -1327,8 +1327,8 @@
         }
     }
 
-    private static void registerJFRThrowablePlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider) {
-        Registration r = new Registration(plugins, "oracle.jrockit.jfr.jdkevents.ThrowableTracer", bytecodeProvider);
+    private static void registerJFRThrowablePlugins(InvocationPlugins plugins, Replacements replacements) {
+        Registration r = new Registration(plugins, "oracle.jrockit.jfr.jdkevents.ThrowableTracer", replacements);
         r.register2("traceThrowable", Throwable.class, String.class, new InvocationPlugin() {
             @Override
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode throwable, ValueNode message) {
@@ -1343,8 +1343,8 @@
         });
     }
 
-    private static void registerMethodHandleImplPlugins(InvocationPlugins plugins, SnippetReflectionProvider snippetReflection, BytecodeProvider bytecodeProvider) {
-        Registration r = new Registration(plugins, "java.lang.invoke.MethodHandleImpl", bytecodeProvider);
+    private static void registerMethodHandleImplPlugins(InvocationPlugins plugins, SnippetReflectionProvider snippetReflection, Replacements replacements) {
+        Registration r = new Registration(plugins, "java.lang.invoke.MethodHandleImpl", replacements);
         // In later JDKs this no longer exists and the usage is replace by Class.cast which is
         // already an intrinsic
         r.registerOptional2("castReference", Class.class, Object.class, new InvocationPlugin() {
@@ -1408,8 +1408,8 @@
      * Registers a plugin to ignore {@code com.sun.tdk.jcov.runtime.Collect.hit} within an
      * intrinsic.
      */
-    private static void registerJcovCollectPlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider) {
-        Registration r = new Registration(plugins, "com.sun.tdk.jcov.runtime.Collect", bytecodeProvider);
+    private static void registerJcovCollectPlugins(InvocationPlugins plugins, Replacements replacements) {
+        Registration r = new Registration(plugins, "com.sun.tdk.jcov.runtime.Collect", replacements);
         r.register1("hit", int.class, new InvocationPlugin() {
             @Override
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/TargetGraphBuilderPlugins.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/TargetGraphBuilderPlugins.java	Thu Oct 31 16:54:16 2019 -0700
@@ -24,12 +24,12 @@
 
 package org.graalvm.compiler.replacements;
 
-import org.graalvm.compiler.bytecode.BytecodeProvider;
 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import org.graalvm.compiler.nodes.spi.Replacements;
 
 import jdk.vm.ci.code.Architecture;
 
 public interface TargetGraphBuilderPlugins {
-    void register(Plugins plugins, BytecodeProvider replacementsBytecodeProvider, Architecture arch, boolean explicitUnsafeNullChecks, boolean registerMathPlugins, boolean emitJDK9StringSubstitutions,
+    void register(Plugins plugins, Replacements replacements, Architecture arch, boolean explicitUnsafeNullChecks, boolean registerMathPlugins, boolean emitJDK9StringSubstitutions,
                     boolean useFMAIntrinsics);
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/arraycopy/ArrayCopyCallNode.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/arraycopy/ArrayCopyCallNode.java	Thu Oct 31 16:54:16 2019 -0700
@@ -188,6 +188,11 @@
         return locationIdentity;
     }
 
+    @Override
+    public LocationIdentity getKilledLocationIdentity() {
+        return getLocationIdentity();
+    }
+
     @NodeIntrinsic(hasSideEffect = true)
     private static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantNodeParameter JavaKind elementKind, @ConstantNodeParameter boolean aligned,
                     @ConstantNodeParameter boolean disjoint, @ConstantNodeParameter boolean uninitialized, @ConstantNodeParameter int heapWordSize);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/arraycopy/ArrayCopyNode.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/arraycopy/ArrayCopyNode.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2019, 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
@@ -57,7 +57,7 @@
     }
 
     @Override
-    public LocationIdentity getLocationIdentity() {
+    public LocationIdentity getKilledLocationIdentity() {
         if (!forceAnyLocation && elementKind == null) {
             elementKind = ArrayCopySnippets.Templates.selectComponentKind(this);
         }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/arraycopy/CheckcastArrayCopyCallNode.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/arraycopy/CheckcastArrayCopyCallNode.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2019, 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
@@ -146,7 +146,7 @@
     }
 
     @Override
-    public LocationIdentity getLocationIdentity() {
+    public LocationIdentity getKilledLocationIdentity() {
         /*
          * Because of restrictions that the memory graph of snippets matches the original node,
          * pretend that we kill any.
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/arraycopy/GenericArrayCopyCallNode.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/arraycopy/GenericArrayCopyCallNode.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2019, 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
@@ -102,7 +102,7 @@
     }
 
     @Override
-    public LocationIdentity getLocationIdentity() {
+    public LocationIdentity getKilledLocationIdentity() {
         return LocationIdentity.any();
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BasicArrayCopyNode.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BasicArrayCopyNode.java	Thu Oct 31 16:54:16 2019 -0700
@@ -128,6 +128,11 @@
     }
 
     @Override
+    public LocationIdentity getKilledLocationIdentity() {
+        return getLocationIdentity();
+    }
+
+    @Override
     public MemoryNode getLastLocationAccess() {
         return lastLocationAccess;
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroNode.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroNode.java	Thu Oct 31 16:54:16 2019 -0700
@@ -173,7 +173,7 @@
         }
         DebugContext debug = replacementGraph.getDebug();
         try (DebugContext.Scope s = debug.scope("LoweringSnippetTemplate", replacementGraph)) {
-            new LoweringPhase(new CanonicalizerPhase(), tool.getLoweringStage()).apply(replacementGraph, c);
+            new LoweringPhase(CanonicalizerPhase.create(), tool.getLoweringStage()).apply(replacementGraph, c);
         } catch (Throwable e) {
             throw debug.handle(e);
         }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroStateSplitNode.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroStateSplitNode.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2019, 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
@@ -75,7 +75,7 @@
     }
 
     @Override
-    public LocationIdentity getLocationIdentity() {
+    public LocationIdentity getKilledLocationIdentity() {
         return LocationIdentity.any();
     }
 
@@ -87,7 +87,7 @@
             }
             assert invoke.stateAfter().bci == BytecodeFrame.AFTER_BCI;
             // Here we need to fix the bci of the invoke
-            InvokeNode newInvoke = snippetGraph.add(new InvokeNode(invoke.callTarget(), bci(), invoke.getLocationIdentity()));
+            InvokeNode newInvoke = snippetGraph.add(new InvokeNode(invoke.callTarget(), bci(), invoke.getKilledLocationIdentity()));
             newInvoke.setStateAfter(invoke.stateAfter());
             snippetGraph.replaceFixedWithFixed((InvokeNode) invoke.asNode(), newInvoke);
         }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/ExportingClassLoader.java	Thu Oct 31 14:23:06 2019 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,40 +0,0 @@
-/*
- * Copyright (c) 2016, 2019, 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.test;
-
-/**
- * A class loader that exports all packages in the module defining the class loader to all classes
- * in the unnamed module associated with the loader.
- */
-public class ExportingClassLoader extends ClassLoader {
-    public ExportingClassLoader() {
-        ModuleSupport.exportAllPackagesTo(getClass(), this);
-    }
-
-    public ExportingClassLoader(ClassLoader parent) {
-        super(parent);
-        ModuleSupport.exportAllPackagesTo(getClass(), this);
-    }
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/ModuleSupport.java	Thu Oct 31 14:23:06 2019 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,129 +0,0 @@
-/*
- * Copyright (c) 2019, 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.test;
-
-import java.io.IOException;
-import java.lang.module.ModuleDescriptor.Requires;
-import java.net.URI;
-import java.nio.file.FileSystem;
-import java.nio.file.FileSystems;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import org.graalvm.compiler.debug.DebugOptions;
-
-import jdk.internal.module.Modules;
-
-public class ModuleSupport {
-
-    public static void exportPackageTo(Class<?> moduleMember, String packageName, Class<?> requestor) {
-        Module moduleToExport = moduleMember.getModule();
-        Module requestorModule = requestor.getModule();
-        if (moduleToExport != requestorModule) {
-            Modules.addExports(moduleToExport, packageName, requestorModule);
-        }
-    }
-
-    public static void exportAllPackagesTo(Class<?> moduleMember, Class<?> requestor) {
-        Module moduleToExport = moduleMember.getModule();
-        Module requestorModule = requestor.getModule();
-        if (moduleToExport != requestorModule) {
-            for (String packageName : moduleToExport.getPackages()) {
-                Modules.addExports(moduleToExport, packageName, requestorModule);
-            }
-        }
-    }
-
-    public static void exportAllPackagesTo(Class<?> moduleMember, ClassLoader cl) {
-        Module moduleToExport = moduleMember.getModule();
-        Module unnamedModule = cl.getUnnamedModule();
-        for (String packageName : moduleToExport.getPackages()) {
-            Modules.addExports(moduleToExport, packageName, unnamedModule);
-        }
-    }
-
-    @SuppressWarnings("unused")
-    public static void exportAndOpenAllPackagesToUnnamed(String name) {
-        Module module = ModuleLayer.boot().findModule(name).orElseThrow();
-        Set<String> packages = module.getPackages();
-        for (String pkg : packages) {
-            Modules.addExportsToAllUnnamed(module, pkg);
-            Modules.addOpensToAllUnnamed(module, pkg);
-        }
-    }
-
-    public static List<String> getJRTGraalClassNames() throws IOException {
-        List<String> classNames = new ArrayList<>();
-        FileSystem fs = FileSystems.newFileSystem(URI.create("jrt:/"), Collections.emptyMap());
-        Module graalModule = DebugOptions.class.getModule();
-        Set<String> graalModuleSet = new HashSet<>();
-        graalModuleSet.add(graalModule.getName());
-        for (Module module : graalModule.getLayer().modules()) {
-            if (requires(module, graalModule)) {
-                graalModuleSet.add(module.getName());
-            }
-        }
-
-        Path top = fs.getPath("/modules/");
-        Files.find(top, Integer.MAX_VALUE,
-                        (path, attrs) -> attrs.isRegularFile()).forEach(p -> {
-                            int nameCount = p.getNameCount();
-                            if (nameCount > 2) {
-                                String base = p.getName(nameCount - 1).toString();
-                                if (base.endsWith(".class") && !base.equals("module-info.class")) {
-                                    String module = p.getName(1).toString();
-                                    if (graalModuleSet.contains(module)) {
-                                        // Strip module prefix and convert to dotted
-                                        // form
-                                        String className = p.subpath(2, nameCount).toString().replace('/', '.');
-                                        // Strip ".class" suffix
-                                        className = className.replace('/', '.').substring(0, className.length() - ".class".length());
-                                        classNames.add(className);
-                                    }
-                                }
-                            }
-                        });
-        return classNames;
-    }
-
-    private static boolean requires(Module module, Module graalModule) {
-        ModuleLayer graalLayer = graalModule.getLayer();
-        for (Requires r : module.getDescriptor().requires()) {
-            if (r.name().equals(graalModule.getName())) {
-                return true;
-            }
-            Module dep = graalLayer.findModule(r.name()).get();
-            if (requires(dep, graalModule)) {
-                return true;
-            }
-        }
-        return false;
-    }
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationClosure.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationClosure.java	Thu Oct 31 16:54:16 2019 -0700
@@ -121,11 +121,11 @@
             return processUnsafeStore((RawStoreNode) node, state, effects);
         } else if (node instanceof MemoryCheckpoint.Single) {
             COUNTER_MEMORYCHECKPOINT.increment(node.getDebug());
-            LocationIdentity identity = ((MemoryCheckpoint.Single) node).getLocationIdentity();
+            LocationIdentity identity = ((MemoryCheckpoint.Single) node).getKilledLocationIdentity();
             processIdentity(state, identity);
         } else if (node instanceof MemoryCheckpoint.Multi) {
             COUNTER_MEMORYCHECKPOINT.increment(node.getDebug());
-            for (LocationIdentity identity : ((MemoryCheckpoint.Multi) node).getLocationIdentities()) {
+            for (LocationIdentity identity : ((MemoryCheckpoint.Multi) node).getKilledLocationIdentities()) {
                 processIdentity(state, identity);
             }
         }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/ReadEliminationBlockState.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/ReadEliminationBlockState.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2019, 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
@@ -152,6 +152,7 @@
     }
 
     public ReadEliminationBlockState(ReadEliminationBlockState other) {
+        super(other);
         readCache = EconomicMap.create(Equivalence.DEFAULT, other.readCache);
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/ReadEliminationClosure.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/ReadEliminationClosure.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2019, 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
@@ -135,9 +135,9 @@
             }
         } else if (node instanceof WriteNode) {
             WriteNode write = (WriteNode) node;
-            if (write.getLocationIdentity().isSingle()) {
+            if (write.getKilledLocationIdentity().isSingle()) {
                 ValueNode object = GraphUtil.unproxify(write.getAddress());
-                LoadCacheEntry identifier = new LoadCacheEntry(object, write.getLocationIdentity());
+                LoadCacheEntry identifier = new LoadCacheEntry(object, write.getKilledLocationIdentity());
                 ValueNode cachedValue = state.getCacheEntry(identifier);
 
                 ValueNode value = getScalarAlias(write.value());
@@ -145,10 +145,10 @@
                     effects.deleteNode(write);
                     deleted = true;
                 }
-                processIdentity(state, write.getLocationIdentity());
+                processIdentity(state, write.getKilledLocationIdentity());
                 state.addCacheEntry(identifier, value);
             } else {
-                processIdentity(state, write.getLocationIdentity());
+                processIdentity(state, write.getKilledLocationIdentity());
             }
         } else if (node instanceof UnsafeAccessNode) {
             ResolvedJavaType type = StampTool.typeOrNull(((UnsafeAccessNode) node).object());
@@ -170,9 +170,9 @@
                 } else {
                     assert node instanceof RawStoreNode;
                     RawStoreNode write = (RawStoreNode) node;
-                    if (write.getLocationIdentity().isSingle()) {
+                    if (write.getKilledLocationIdentity().isSingle()) {
                         ValueNode object = GraphUtil.unproxify(write.object());
-                        UnsafeLoadCacheEntry identifier = new UnsafeLoadCacheEntry(object, write.offset(), write.getLocationIdentity());
+                        UnsafeLoadCacheEntry identifier = new UnsafeLoadCacheEntry(object, write.offset(), write.getKilledLocationIdentity());
                         ValueNode cachedValue = state.getCacheEntry(identifier);
 
                         ValueNode value = getScalarAlias(write.value());
@@ -180,18 +180,18 @@
                             effects.deleteNode(write);
                             deleted = true;
                         }
-                        processIdentity(state, write.getLocationIdentity());
+                        processIdentity(state, write.getKilledLocationIdentity());
                         state.addCacheEntry(identifier, value);
                     } else {
-                        processIdentity(state, write.getLocationIdentity());
+                        processIdentity(state, write.getKilledLocationIdentity());
                     }
                 }
             }
         } else if (node instanceof MemoryCheckpoint.Single) {
-            LocationIdentity identity = ((MemoryCheckpoint.Single) node).getLocationIdentity();
+            LocationIdentity identity = ((MemoryCheckpoint.Single) node).getKilledLocationIdentity();
             processIdentity(state, identity);
         } else if (node instanceof MemoryCheckpoint.Multi) {
-            for (LocationIdentity identity : ((MemoryCheckpoint.Multi) node).getLocationIdentities()) {
+            for (LocationIdentity identity : ((MemoryCheckpoint.Multi) node).getKilledLocationIdentities()) {
                 processIdentity(state, identity);
             }
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/OptionsEncoder.java	Thu Oct 31 16:54:16 2019 -0700
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2018, 2019, 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.util;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * Facilities for encoding/decoding a set of options to/from a byte array.
+ */
+public final class OptionsEncoder {
+
+    private OptionsEncoder() {
+    }
+
+    /**
+     * Determines if {@code value} is supported by {@link #encode(Map)}.
+     */
+    public static boolean isValueSupported(Object value) {
+        return TypedDataOutputStream.isValueSupported(value);
+    }
+
+    /**
+     * Encodes {@code options} into a byte array.
+     *
+     * @throws IllegalArgumentException if any value in {@code options} is not
+     *             {@linkplain #isValueSupported(Object) supported}
+     */
+    public static byte[] encode(final Map<String, Object> options) {
+        try (ByteArrayOutputStream baout = new ByteArrayOutputStream()) {
+            try (TypedDataOutputStream out = new TypedDataOutputStream(baout)) {
+                out.writeInt(options.size());
+                for (Map.Entry<String, Object> e : options.entrySet()) {
+                    out.writeUTF(e.getKey());
+                    try {
+                        out.writeTypedValue(e.getValue());
+                    } catch (IllegalArgumentException iae) {
+                        throw new IllegalArgumentException(String.format("Key: %s, Value: %s, Value type: %s",
+                                        e.getKey(), e.getValue(), e.getValue().getClass()), iae);
+                    }
+                }
+            }
+            return baout.toByteArray();
+        } catch (IOException ioe) {
+            throw new IllegalArgumentException(ioe);
+        }
+    }
+
+    /**
+     * Decodes {@code input} into a name/value map.
+     *
+     * @throws IllegalArgumentException if {@code input} cannot be decoded
+     */
+    public static Map<String, Object> decode(byte[] input) {
+        Map<String, Object> res = new LinkedHashMap<>();
+        try (TypedDataInputStream in = new TypedDataInputStream(new ByteArrayInputStream(input))) {
+            final int size = in.readInt();
+            for (int i = 0; i < size; i++) {
+                final String key = in.readUTF();
+                final Object value = in.readTypedValue();
+                res.put(key, value);
+            }
+            if (in.available() != 0) {
+                throw new IllegalArgumentException(in.available() + " undecoded bytes");
+            }
+        } catch (IOException ioe) {
+            throw new IllegalArgumentException(ioe);
+        }
+        return res;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/TypedDataInputStream.java	Thu Oct 31 16:54:16 2019 -0700
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2019, 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.util;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * A stream that can read (trivial) values using their in-band data type information, intended for
+ * use with {@link TypedDataOutputStream}.
+ */
+public class TypedDataInputStream extends DataInputStream {
+    public TypedDataInputStream(InputStream in) {
+        super(in);
+    }
+
+    /**
+     * Reads a single value, using the data type encoded in the stream.
+     *
+     * @return The read value, such as a boxed primitive or a {@link String}.
+     * @exception IOException in case of an I/O error.
+     */
+    public Object readTypedValue() throws IOException {
+        Object value;
+        final byte type = readByte();
+        switch (type) {
+            case 'Z':
+                value = readBoolean();
+                break;
+            case 'B':
+                value = readByte();
+                break;
+            case 'S':
+                value = readShort();
+                break;
+            case 'C':
+                value = readChar();
+                break;
+            case 'I':
+                value = readInt();
+                break;
+            case 'J':
+                value = readLong();
+                break;
+            case 'F':
+                value = readFloat();
+                break;
+            case 'D':
+                value = readDouble();
+                break;
+            case 'U':
+                value = readUTF();
+                break;
+            default:
+                throw new IOException("Unsupported type: " + Integer.toHexString(type));
+        }
+        return value;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/TypedDataOutputStream.java	Thu Oct 31 16:54:16 2019 -0700
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2019, 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.util;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * A stream that can write (trivial) values together with their data type, for use with
+ * {@link TypedDataInputStream}.
+ */
+public class TypedDataOutputStream extends DataOutputStream {
+    /** Determines if {@code value} is supported by {@link #writeTypedValue(Object)}. */
+    public static boolean isValueSupported(Object value) {
+        if (value == null) {
+            return false;
+        }
+        Class<?> valueClass = value.getClass();
+        return valueClass == Boolean.class ||
+                        valueClass == Byte.class ||
+                        valueClass == Short.class ||
+                        valueClass == Character.class ||
+                        valueClass == Integer.class ||
+                        valueClass == Long.class ||
+                        valueClass == Float.class ||
+                        valueClass == Double.class ||
+                        valueClass == String.class ||
+                        value.getClass().isEnum();
+    }
+
+    public TypedDataOutputStream(OutputStream out) {
+        super(out);
+    }
+
+    /**
+     * Writes the value that is represented by the given non-null object, together with information
+     * on the value's data type.
+     *
+     * @param value A value of a {@linkplain #isValueSupported supported type}.
+     * @exception IllegalArgumentException when the provided type is not supported.
+     * @exception IOException in case of an I/O error.
+     */
+    public void writeTypedValue(Object value) throws IOException {
+        Class<?> valueClz = value.getClass();
+        if (valueClz == Boolean.class) {
+            this.writeByte('Z');
+            this.writeBoolean((Boolean) value);
+        } else if (valueClz == Byte.class) {
+            this.writeByte('B');
+            this.writeByte((Byte) value);
+        } else if (valueClz == Short.class) {
+            this.writeByte('S');
+            this.writeShort((Short) value);
+        } else if (valueClz == Character.class) {
+            this.writeByte('C');
+            this.writeChar((Character) value);
+        } else if (valueClz == Integer.class) {
+            this.writeByte('I');
+            this.writeInt((Integer) value);
+        } else if (valueClz == Long.class) {
+            this.writeByte('J');
+            this.writeLong((Long) value);
+        } else if (valueClz == Float.class) {
+            this.writeByte('F');
+            this.writeFloat((Float) value);
+        } else if (valueClz == Double.class) {
+            this.writeByte('D');
+            this.writeDouble((Double) value);
+        } else if (valueClz == String.class) {
+            this.writeByte('U');
+            this.writeUTF((String) value);
+        } else if (valueClz.isEnum()) {
+            this.writeByte('U');
+            this.writeUTF(((Enum<?>) value).name());
+        } else {
+            throw new IllegalArgumentException(String.format("Unsupported type: Value: %s, Value type: %s", value, valueClz));
+        }
+    }
+}