changeset 54328:37648a9c4a6a

8221341: Update Graal Reviewed-by: kvn
author jwilhelm
date Thu, 28 Mar 2019 19:39:14 +0100
parents a4d19817609c
children ddd60ad787d4
files src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/DataPatchProcessor.java src/jdk.internal.vm.ci/share/classes/module-info.java src/jdk.internal.vm.compiler.management/share/classes/org.graalvm.compiler.hotspot.management/src/org/graalvm/compiler/hotspot/management/HotSpotGraalRuntimeMBean.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.asm/src/org/graalvm/compiler/asm/Assembler.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/AArch64LIRGenerator.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64.test/src/org/graalvm/compiler/core/amd64/test/AMD64MatchRuleTest.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64ArithmeticLIRGenerator.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/Fields.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/FieldsScanner.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/UnsafeAccess.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/UnsafeAccess.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/UnsafeArrayTypeReader.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/UnsafeArrayTypeWriter.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.match.processor/src/org/graalvm/compiler/core/match/processor/MatchProcessor.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/FinalizableSubclassTest.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/NewInstanceTest.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SwitchTest.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnbalancedMonitorsTest.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyBailoutUsage.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyCallerSensitiveMethods.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyDebugUsage.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyFoldableMethods.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyGetOptionsUsage.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyGraphAddUsage.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyInstanceOfUsage.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifySystemPropertyUsage.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyUnsafeAccess.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyUpdateUsages.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyUsageWithEquals.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyVirtualizableUsage.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/tutorial/StaticAnalysis.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/tutorial/StaticAnalysisTests.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/LIRGenerationPhase.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/NodeLIRBuilder.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/match/MatchContext.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchPattern.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchStatement.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchableNode.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugContext.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/LogStream.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/MemUseTrackerKey.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/Versions.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Edges.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Node.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeClass.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeSourcePosition.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/UnsafeAccess.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.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotLIRGenerator.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64IndirectCallOp.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64ArrayCompareToStub.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64ArrayEqualsStub.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotForeignCallsProvider.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRGenerator.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/NodeCostDumpUtil.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/StringInternConstantTest.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/BootstrapWatchDog.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationStatistics.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationTask.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationWatchDog.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfigBase.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompiler.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompilerFactory.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotTTYStreamProvider.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/IsGraalPredicate.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/IsGraalPredicateBase.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/JVMCIVersionCheck.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/NodeCostDumpUtil.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/debug/BenchmarkCounters.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotNodePlugin.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotObjdumpDisassemblerProvider.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/phases/AheadOfTimeVerificationPhase.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.java/src/org/graalvm/compiler/java/GraphBuilderPhase.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ArithmeticLIRGeneratorTool.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64Call.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64Compare.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ControlFlow.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64MathIntrinsicBinaryOp.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64Move.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ArrayIndexOfOp.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64Binary.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64BinaryConsumer.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/LIRGenerator.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/LIRGeneratorTool.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/hashing/HashFunction.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/hashing/Hasher.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/SimplifyingGraphDecoder.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/graphbuilderconf/GraphBuilderConfiguration.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderTool.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/NodePlugin.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/AbstractWriteNode.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/CoreProviders.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/CoreProvidersImpl.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/LoweringTool.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/NodeLIRBuilderTool.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionsParser.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/ProfileCompiledMethodsPhase.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/InliningData.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/VerifyPhase.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/tiers/PhaseContext.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/util/Providers.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/CFGPrinterObserver.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraphPrinterDumpHandler.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/src/org/graalvm/compiler/replacements/CachingPEGraphDecoder.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ConstantStringIndexOfSnippets.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/GraphKit.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/InlineDuringParsingPlugin.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/IntrinsicGraphBuilder.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.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/SnippetCounterNode.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/UnsafeAccess.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileBytecodeProvider.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ArrayCompareToNode.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ArrayEqualsNode.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ArrayRegionEqualsNode.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.serviceprovider/src/org/graalvm/compiler/serviceprovider/GraalUnsafeAccess.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/JavaVersionUtil.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsClosure.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PartialEscapeClosure.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/UnsafeAccess.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/Word.java
diffstat 141 files changed, 3271 insertions(+), 1342 deletions(-) [+]
line wrap: on
line diff
--- a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/DataPatchProcessor.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/DataPatchProcessor.java	Thu Mar 28 19:39:14 2019 +0100
@@ -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
@@ -47,6 +47,7 @@
 import jdk.vm.ci.hotspot.HotSpotObjectConstant;
 import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
 import jdk.vm.ci.hotspot.HotSpotSentinelConstant;
+import jdk.vm.ci.meta.JavaConstant;
 import jdk.vm.ci.meta.VMConstant;
 
 final class DataPatchProcessor {
@@ -95,21 +96,24 @@
                 gotName = "got." + targetSymbol;
                 binaryContainer.addCountersSymbol(targetSymbol);
             }
-        } else if (constant instanceof HotSpotObjectConstant) {
-            HotSpotObjectConstant oopConstant = (HotSpotObjectConstant) constant;
-            if (oopConstant instanceof HotSpotConstantPoolObject) {
-                HotSpotConstantPoolObject cpo = (HotSpotConstantPoolObject) oopConstant;
+        } else if (constant instanceof JavaConstant) {
+            JavaConstant jConstant = (JavaConstant) constant;
+            if (jConstant instanceof HotSpotConstantPoolObject) {
+                HotSpotConstantPoolObject cpo = (HotSpotConstantPoolObject) jConstant;
                 // Even if two locations use the same object, resolve separately
-                targetSymbol = "ldc." + cpo.getCpType().getName() + cpo.getCpi();
-            } else {
+                targetSymbol = "ldc." + cpo.toValueString();
+                Integer offset = binaryContainer.addOopSymbol(targetSymbol);
+                gotName = "got.ldc." + offset;
+            } else if (jConstant instanceof HotSpotObjectConstant) {
+                HotSpotObjectConstant oopConstant = (HotSpotObjectConstant) jConstant;
                 // String constant.
                 targetSymbol = "ldc." + oopConstant.toValueString();
+                Integer offset = binaryContainer.addOopSymbol(targetSymbol);
+                gotName = "got.ldc." + offset;
+            } else if (jConstant instanceof HotSpotSentinelConstant) {
+                targetSymbol = "state.M" + methodInfo.getCodeId();
+                gotName = "got." + targetSymbol;
             }
-            Integer offset = binaryContainer.addOopSymbol(targetSymbol);
-            gotName = "got.ldc." + offset;
-        } else if (constant instanceof HotSpotSentinelConstant) {
-            targetSymbol = "state.M" + methodInfo.getCodeId();
-            gotName = "got." + targetSymbol;
         }
 
         assert gotName != null : "Unknown constant type: " + constant;
--- a/src/jdk.internal.vm.ci/share/classes/module-info.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.ci/share/classes/module-info.java	Thu Mar 28 19:39:14 2019 +0100
@@ -24,7 +24,9 @@
  */
 
 module jdk.internal.vm.ci {
-    exports jdk.vm.ci.services to jdk.internal.vm.compiler;
+    exports jdk.vm.ci.services to
+        jdk.internal.vm.compiler,
+        jdk.internal.vm.compiler.management;
     exports jdk.vm.ci.runtime to
         jdk.internal.vm.compiler,
         jdk.internal.vm.compiler.management;
--- a/src/jdk.internal.vm.compiler.management/share/classes/org.graalvm.compiler.hotspot.management/src/org/graalvm/compiler/hotspot/management/HotSpotGraalRuntimeMBean.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler.management/share/classes/org.graalvm.compiler.hotspot.management/src/org/graalvm/compiler/hotspot/management/HotSpotGraalRuntimeMBean.java	Thu Mar 28 19:39:14 2019 +0100
@@ -52,6 +52,8 @@
 import org.graalvm.compiler.options.OptionsParser;
 import org.graalvm.compiler.serviceprovider.GraalServices;
 
+import jdk.vm.ci.services.Services;
+
 /**
  * MBean used to access properties and operations of a {@link HotSpotGraalRuntime} instance.
  */
@@ -84,7 +86,7 @@
 
     private static boolean initDebug() {
         try {
-            return Boolean.getBoolean(HotSpotGraalRuntimeMBean.class.getSimpleName() + ".debug");
+            return Boolean.parseBoolean(Services.getSavedProperties().get(HotSpotGraalRuntimeMBean.class.getSimpleName() + ".debug"));
         } catch (SecurityException e) {
             // Swallow the exception
             return false;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64Assembler.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64Assembler.java	Thu Mar 28 19:39:14 2019 +0100
@@ -40,6 +40,7 @@
 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.BR;
 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.BRK;
 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.CAS;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.CCMP;
 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.CLREX;
 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.CLS;
 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.CLZ;
@@ -86,6 +87,7 @@
 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.MOVK;
 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.MOVN;
 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.MOVZ;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.MRS;
 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.MSUB;
 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.ORN;
 import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.ORR;
@@ -436,6 +438,7 @@
     private static final int FpImmOffset = 13;
 
     private static final int FpCmpOp = 0x1E202000;
+    private static final int FpCmpeOp = 0x1E202010;
 
     private static final int PcRelImmHiOffset = 5;
     private static final int PcRelImmLoOffset = 29;
@@ -532,6 +535,8 @@
         SUB(0x40000000),
         SUBS(SUB.encoding | AddSubSetFlag),
 
+        CCMP(0x7A400000),
+
         NOT(0x00200000),
         AND(0x00000000),
         BIC(AND.encoding | NOT.encoding),
@@ -618,6 +623,9 @@
         HINT(0xD503201F),
         DMB(0x000000A0),
 
+        MRS(0xD5300000),
+        MSR(0xD5100000),
+
         BLR_NATIVE(0xc0000000);
 
         public final int encoding;
@@ -628,6 +636,29 @@
 
     }
 
+    public enum SystemRegister {
+        FPCR(0b11, 0b011, 0b0100, 0b0100, 0b000),
+        FPSR(0b11, 0b011, 0b0100, 0b0100, 0b001);
+
+        SystemRegister(int op0, int op1, int crn, int crm, int op2) {
+            this.op0 = op0;
+            this.op1 = op1;
+            this.crn = crn;
+            this.crm = crm;
+            this.op2 = op2;
+        }
+
+        public int encoding() {
+            return op0 << 19 | op1 << 16 | crn << 12 | crm << 8 | op2 << 5;
+        }
+
+        private final int op0;
+        private final int op1;
+        private final int crn;
+        private final int crm;
+        private final int op2;
+    }
+
     public enum ShiftType {
         LSL(0),
         LSR(1),
@@ -971,8 +1002,10 @@
         int imm = (imm28 & NumUtil.getNbitNumberInt(28)) >> 2;
         int instrEncoding = instr.encoding | UnconditionalBranchImmOp;
         if (pos == -1) {
+            annotatePatchingImmediate(position(), instr, 26, 0, 2);
             emitInt(instrEncoding | imm);
         } else {
+            annotatePatchingImmediate(pos, instr, 26, 0, 2);
             emitInt(instrEncoding | imm, pos);
         }
     }
@@ -1011,6 +1044,7 @@
         assert !reg.equals(zr);
         assert !reg.equals(sp);
         emitInt(instr.encoding | UnconditionalBranchRegOp | rs1(reg));
+
     }
 
     /* Load-Store Single Register (5.3.1) */
@@ -1161,9 +1195,11 @@
         int memop = instr.encoding | transferSizeEncoding | is32Bit | isFloat | rt(reg);
         switch (address.getAddressingMode()) {
             case IMMEDIATE_SCALED:
+                annotatePatchingImmediate(position(), instr, 12, LoadStoreScaledImmOffset, log2TransferSize);
                 emitInt(memop | LoadStoreScaledOp | address.getImmediate() << LoadStoreScaledImmOffset | rs1(address.getBase()));
                 break;
             case IMMEDIATE_UNSCALED:
+                annotatePatchingImmediate(position(), instr, 9, LoadStoreUnscaledImmOffset, 0);
                 emitInt(memop | LoadStoreUnscaledOp | address.getImmediate() << LoadStoreUnscaledImmOffset | rs1(address.getBase()));
                 break;
             case BASE_REGISTER_ONLY:
@@ -1178,12 +1214,15 @@
             case PC_LITERAL:
                 assert log2TransferSize >= 2 : "PC literal loads only works for load/stores of 32-bit and larger";
                 transferSizeEncoding = (log2TransferSize - 2) << LoadStoreTransferSizeOffset;
+                annotatePatchingImmediate(position(), instr, 21, LoadLiteralImmeOffset, 2);
                 emitInt(transferSizeEncoding | isFloat | LoadLiteralOp | rd(reg) | address.getImmediate() << LoadLiteralImmeOffset);
                 break;
             case IMMEDIATE_POST_INDEXED:
+                annotatePatchingImmediate(position(), instr, 9, LoadStoreIndexedImmOffset, 0);
                 emitInt(memop | LoadStorePostIndexedOp | rs1(address.getBase()) | address.getImmediate() << LoadStoreIndexedImmOffset);
                 break;
             case IMMEDIATE_PRE_INDEXED:
+                annotatePatchingImmediate(position(), instr, 9, LoadStoreIndexedImmOffset, 0);
                 emitInt(memop | LoadStorePreIndexedOp | rs1(address.getBase()) | address.getImmediate() << LoadStoreIndexedImmOffset);
                 break;
             default:
@@ -1529,6 +1568,10 @@
         emitInt(type.encoding | instr.encoding | AddSubImmOp | encodeAimm(aimm) | rd(dst) | rs1(src));
     }
 
+    public void ccmp(int size, Register x, Register y, int aimm, ConditionFlag condition) {
+        emitInt(generalFromSize(size).encoding | CCMP.encoding | rs1(x) | rs2(y) | encodeAimm(aimm) | condition.encoding << ConditionalConditionOffset);
+    }
+
     /**
      * Encodes arithmetic immediate.
      *
@@ -2414,7 +2457,8 @@
             return false;
         }
         // bits[62] and bits[61] are opposites.
-        return ((bits ^ (bits << 1)) & (1L << 62)) != 0;
+        boolean result = ((bits ^ (bits << 1)) & (1L << 62)) != 0;
+        return result;
     }
 
     private static int getFloatImmediate(float imm) {
@@ -2694,6 +2738,20 @@
     }
 
     /**
+     * Signalling compares src1 to src2.
+     *
+     * @param size register size.
+     * @param src1 floating point register. May not be null.
+     * @param src2 floating point register. May not be null.
+     */
+    public void fcmpe(int size, Register src1, Register src2) {
+        assert src1.getRegisterCategory().equals(SIMD);
+        assert src2.getRegisterCategory().equals(SIMD);
+        InstructionType type = floatFromSize(size);
+        emitInt(type.encoding | FCMP.encoding | FpCmpeOp | rs1(src1) | rs2(src2));
+    }
+
+    /**
      * Conditional compare. NZCV = fcmp(src1, src2) if condition else uimm4.
      *
      * @param size register size.
@@ -2722,6 +2780,18 @@
         emitInt(type.encoding | FCMPZERO.encoding | FpCmpOp | rs1(src));
     }
 
+    /**
+     * Signalling compare register to 0.0 .
+     *
+     * @param size register size.
+     * @param src floating point register. May not be null.
+     */
+    public void fcmpeZero(int size, Register src) {
+        assert src.getRegisterCategory().equals(SIMD);
+        InstructionType type = floatFromSize(size);
+        emitInt(type.encoding | FCMPZERO.encoding | FpCmpeOp | rs1(src));
+    }
+
     /* Floating-point Conditional Select (5.7.11) */
 
     /**
@@ -2833,4 +2903,58 @@
         emitInt(DMB.encoding | BarrierOp | barrierKind.encoding << BarrierKindOffset);
     }
 
+    public void mrs(Register dst, SystemRegister systemRegister) {
+        emitInt(MRS.encoding | systemRegister.encoding() | rt(dst));
+    }
+
+    public void msr(SystemRegister systemRegister, Register src) {
+        emitInt(MRS.encoding | systemRegister.encoding() | rt(src));
+    }
+
+    public void annotatePatchingImmediate(int pos, Instruction instruction, int operandSizeBits, int offsetBits, int shift) {
+        if (codePatchingAnnotationConsumer != null) {
+            codePatchingAnnotationConsumer.accept(new OperandDataAnnotation(pos, instruction, operandSizeBits, offsetBits, shift));
+        }
+    }
+
+    void annotatePatchingImmediateNativeAddress(int pos, int operandSizeBits, int numInstrs) {
+        if (codePatchingAnnotationConsumer != null) {
+            codePatchingAnnotationConsumer.accept(new MovSequenceAnnotation(pos, operandSizeBits, numInstrs));
+        }
+    }
+
+    public static class OperandDataAnnotation extends CodeAnnotation {
+
+        /**
+         * The size of the operand, in bytes.
+         */
+        public final int operandSizeBits;
+        public final int offsetBits;
+        public final Instruction instruction;
+        public final int shift;
+
+        OperandDataAnnotation(int instructionPosition, Instruction instruction, int operandSizeBits, int offsetBits, int shift) {
+            super(instructionPosition);
+            this.operandSizeBits = operandSizeBits;
+            this.offsetBits = offsetBits;
+            this.shift = shift;
+            this.instruction = instruction;
+        }
+    }
+
+    public static class MovSequenceAnnotation extends CodeAnnotation {
+
+        /**
+         * The size of the operand, in bytes.
+         */
+        public final int operandSizeBits;
+        public final int numInstrs;
+
+        MovSequenceAnnotation(int instructionPosition, int operandSizeBits, int numInstrs) {
+            super(instructionPosition);
+            this.operandSizeBits = operandSizeBits;
+            this.numInstrs = numInstrs;
+        }
+    }
+
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64MacroAssembler.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64MacroAssembler.java	Thu Mar 28 19:39:14 2019 +0100
@@ -266,7 +266,8 @@
      * @return AArch64Address pointing to memory at {@code base + displacement}.
      */
     public AArch64Address makeAddress(Register base, long displacement, int transferSize) {
-        return makeAddress(base, displacement, zr, /* signExtend */false, transferSize, zr, /* allowOverwrite */false);
+        return makeAddress(base, displacement, zr, /* signExtend */false, //
+                        transferSize, zr, /* allowOverwrite */false);
     }
 
     /**
@@ -365,7 +366,19 @@
      * @param imm immediate loaded into register.
      */
     public void mov(Register dst, long imm) {
+        mov(dst, imm, false);
+    }
+
+    /**
+     * Loads immediate into register.
+     *
+     * @param dst general purpose register. May not be null, zero-register or stackpointer.
+     * @param imm immediate loaded into register.
+     * @param annotateImm Flag to signal of the immediate value should be annotated.
+     */
+    public void mov(Register dst, long imm, boolean annotateImm) {
         assert dst.getRegisterCategory().equals(CPU);
+        int pos = position();
         if (imm == 0L) {
             movx(dst, zr);
         } else if (LogicalImmediateTable.isRepresentable(true, imm) != LogicalImmediateTable.Representable.NO) {
@@ -379,6 +392,9 @@
             sxt(64, 32, dst, dst);
         } else {
             mov64(dst, imm);
+            if (annotateImm) {
+                annotatePatchingImmediateNativeAddress(pos, 64, 4);
+            }
         }
     }
 
@@ -403,9 +419,25 @@
      * @param imm
      */
     public void movNativeAddress(Register dst, long imm) {
+        movNativeAddress(dst, imm, false);
+    }
+
+    /**
+     * Generates a 48-bit immediate move code sequence. The immediate may later be updated by
+     * HotSpot.
+     *
+     * In AArch64 mode the virtual address space is 48-bits in size, so we only need three
+     * instructions to create a patchable instruction sequence that can reach anywhere.
+     *
+     * @param dst general purpose register. May not be null, stackpointer or zero-register.
+     * @param imm The immediate address
+     * @param annotateImm Flag to signal of the immediate value should be annotated.
+     */
+    public void movNativeAddress(Register dst, long imm, boolean annotateImm) {
         assert (imm & 0xFFFF_0000_0000_0000L) == 0;
         // We have to move all non zero parts of the immediate in 16-bit chunks
         boolean firstMove = true;
+        int pos = position();
         for (int offset = 0; offset < 48; offset += 16) {
             int chunk = (int) (imm >> offset) & NumUtil.getNbitNumberInt(16);
             if (firstMove) {
@@ -415,6 +447,9 @@
                 movk(64, dst, chunk, offset);
             }
         }
+        if (annotateImm) {
+            annotatePatchingImmediateNativeAddress(pos, 48, 3);
+        }
         assert !firstMove;
     }
 
@@ -1597,7 +1632,7 @@
     }
 
     public void pause() {
-        throw GraalError.unimplemented();
+        super.hint(SystemHint.YIELD);
     }
 
     /**
@@ -1721,7 +1756,8 @@
      */
     @Override
     public AArch64Address makeAddress(Register base, int displacement) {
-        return makeAddress(base, displacement, zr, /* signExtend */false, /* transferSize */0, zr, /* allowOverwrite */false);
+        return makeAddress(base, displacement, zr, /* signExtend */false, /* transferSize */0, //
+                        zr, /* allowOverwrite */false);
     }
 
     @Override
@@ -1730,7 +1766,9 @@
     }
 
     public void addressOf(Register dst) {
-        // This will be fixed up later.
+        if (codePatchingAnnotationConsumer != null) {
+            codePatchingAnnotationConsumer.accept(new AdrpAddMacroInstruction(position()));
+        }
         super.adrp(dst);
         super.add(64, dst, dst, 0);
     }
@@ -1744,4 +1782,51 @@
     public void lea(Register d, AArch64Address a) {
         a.lea(this, d);
     }
+
+    public interface MacroInstruction {
+        void patch(int codePos, int relative, byte[] code);
+    }
+
+    /**
+     * Emits elf patchable adrp add sequence.
+     */
+    public void adrAddRel(int srcSize, Register result, AArch64Address a) {
+        if (codePatchingAnnotationConsumer != null) {
+            codePatchingAnnotationConsumer.accept(new ADRADDPRELMacroInstruction(position()));
+        }
+        super.adrp(a.getBase());
+        this.ldr(srcSize, result, a);
+    }
+
+    public static class ADRADDPRELMacroInstruction extends CodeAnnotation implements MacroInstruction {
+        public ADRADDPRELMacroInstruction(int position) {
+            super(position);
+        }
+
+        @Override
+        public String toString() {
+            return "ADR_PREL_PG";
+        }
+
+        @Override
+        public void patch(int codePos, int relative, byte[] code) {
+            throw GraalError.unimplemented();
+        }
+    }
+
+    public static class AdrpAddMacroInstruction extends CodeAnnotation implements MacroInstruction {
+        public AdrpAddMacroInstruction(int position) {
+            super(position);
+        }
+
+        @Override
+        public String toString() {
+            return "ADRP_ADD";
+        }
+
+        @Override
+        public void patch(int codePos, int relative, byte[] code) {
+            throw GraalError.unimplemented();
+        }
+    }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm/src/org/graalvm/compiler/asm/Assembler.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm/src/org/graalvm/compiler/asm/Assembler.java	Thu Mar 28 19:39:14 2019 +0100
@@ -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
@@ -123,7 +123,7 @@
         return codeBuffer.getInt(pos);
     }
 
-    private static final String NEWLINE = System.getProperty("line.separator");
+    private static final String NEWLINE = System.lineSeparator();
 
     /**
      * Some GPU architectures have a text based encoding.
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64ArithmeticLIRGenerator.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64ArithmeticLIRGenerator.java	Thu Mar 28 19:39:14 2019 +0100
@@ -62,11 +62,26 @@
 
 public class AArch64ArithmeticLIRGenerator extends ArithmeticLIRGenerator implements AArch64ArithmeticLIRGeneratorTool {
 
+    public AArch64ArithmeticLIRGenerator(AllocatableValue nullRegisterValue) {
+        this.nullRegisterValue = nullRegisterValue;
+    }
+
+    private final AllocatableValue nullRegisterValue;
+
     @Override
     public AArch64LIRGenerator getLIRGen() {
         return (AArch64LIRGenerator) super.getLIRGen();
     }
 
+    public boolean mustReplaceNullWithNullRegister(JavaConstant nullConstant) {
+        /* Uncompressed null pointers only */
+        return nullRegisterValue != null && JavaConstant.NULL_POINTER.equals(nullConstant);
+    }
+
+    public AllocatableValue getNullRegisterValue() {
+        return nullRegisterValue;
+    }
+
     @Override
     protected boolean isNumericInteger(PlatformKind kind) {
         return ((AArch64Kind) kind).isInteger();
@@ -485,11 +500,6 @@
     }
 
     @Override
-    public void emitCompareOp(AArch64Kind cmpKind, Variable left, Value right) {
-        throw GraalError.unimplemented();
-    }
-
-    @Override
     public Value emitRound(Value value, RoundingMode mode) {
         AArch64ArithmeticOp op;
         switch (mode) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64LIRGenerator.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64LIRGenerator.java	Thu Mar 28 19:39:14 2019 +0100
@@ -164,7 +164,7 @@
     public Variable emitValueCompareAndSwap(LIRKind accessKind, Value address, Value expectedValue, Value newValue) {
         Variable result = newVariable(newValue.getValueKind());
         Variable scratch = newVariable(LIRKind.value(AArch64Kind.WORD));
-        append(new CompareAndSwapOp(result, loadNonCompareConst(expectedValue), loadReg(newValue), asAllocatable(address), scratch));
+        append(new CompareAndSwapOp(result, loadReg(expectedValue), loadReg(newValue), asAllocatable(address), scratch));
         return result;
     }
 
@@ -238,8 +238,13 @@
      *         null.
      */
     @Override
-    public Variable emitConditionalMove(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, Value trueValue, Value falseValue) {
-        boolean mirrored = emitCompare(cmpKind, left, right, cond, unorderedIsTrue);
+    public Variable emitConditionalMove(PlatformKind cmpKind, Value left, final Value right, Condition cond, boolean unorderedIsTrue, Value trueValue, Value falseValue) {
+        AArch64ArithmeticLIRGenerator arithLir = ((AArch64ArithmeticLIRGenerator) arithmeticLIRGen);
+        Value actualRight = right;
+        if (isJavaConstant(actualRight) && arithLir.mustReplaceNullWithNullRegister((asJavaConstant(actualRight)))) {
+            actualRight = arithLir.getNullRegisterValue();
+        }
+        boolean mirrored = emitCompare(cmpKind, left, actualRight, cond, unorderedIsTrue);
         Condition finalCondition = mirrored ? cond.mirror() : cond;
         boolean finalUnorderedIsTrue = mirrored ? !unorderedIsTrue : unorderedIsTrue;
         ConditionFlag cmpCondition = toConditionFlag(((AArch64Kind) cmpKind).isInteger(), finalCondition, finalUnorderedIsTrue);
@@ -256,30 +261,38 @@
     }
 
     @Override
-    public void emitCompareBranch(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination,
+    public void emitCompareBranch(PlatformKind cmpKind, Value left, final Value right, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination,
                     double trueDestinationProbability) {
+        Value actualRight = right;
         if (cond == Condition.EQ) {
             // emit cbz instruction for IsNullNode.
             assert !LIRValueUtil.isNullConstant(left) : "emitNullCheckBranch()'s null input should be in right.";
-            if (LIRValueUtil.isNullConstant(right)) {
-                append(new CompareBranchZeroOp(asAllocatable(left), trueDestination, falseDestination, trueDestinationProbability));
-                return;
+            AArch64ArithmeticLIRGenerator arithLir = ((AArch64ArithmeticLIRGenerator) arithmeticLIRGen);
+            if (LIRValueUtil.isNullConstant(actualRight)) {
+                JavaConstant rightConstant = asJavaConstant(actualRight);
+                if (arithLir.mustReplaceNullWithNullRegister(rightConstant)) {
+                    actualRight = arithLir.getNullRegisterValue();
+                } else {
+                    append(new CompareBranchZeroOp(asAllocatable(left), trueDestination, falseDestination,
+                                    trueDestinationProbability));
+                    return;
+                }
             }
 
             // emit cbz instruction for IntegerEquals when any of the inputs is zero.
             AArch64Kind kind = (AArch64Kind) cmpKind;
             if (kind.isInteger()) {
                 if (isIntConstant(left, 0)) {
-                    append(new CompareBranchZeroOp(asAllocatable(right), trueDestination, falseDestination, trueDestinationProbability));
+                    append(new CompareBranchZeroOp(asAllocatable(actualRight), trueDestination, falseDestination, trueDestinationProbability));
                     return;
-                } else if (isIntConstant(right, 0)) {
+                } else if (isIntConstant(actualRight, 0)) {
                     append(new CompareBranchZeroOp(asAllocatable(left), trueDestination, falseDestination, trueDestinationProbability));
                     return;
                 }
             }
         }
 
-        boolean mirrored = emitCompare(cmpKind, left, right, cond, unorderedIsTrue);
+        boolean mirrored = emitCompare(cmpKind, left, actualRight, cond, unorderedIsTrue);
         Condition finalCondition = mirrored ? cond.mirror() : cond;
         boolean finalUnorderedIsTrue = mirrored ? !unorderedIsTrue : unorderedIsTrue;
         ConditionFlag cmpCondition = toConditionFlag(((AArch64Kind) cmpKind).isInteger(), finalCondition, finalUnorderedIsTrue);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64.test/src/org/graalvm/compiler/core/amd64/test/AMD64MatchRuleTest.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64.test/src/org/graalvm/compiler/core/amd64/test/AMD64MatchRuleTest.java	Thu Mar 28 19:39:14 2019 +0100
@@ -26,14 +26,19 @@
 
 import static org.junit.Assume.assumeTrue;
 
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
 import org.graalvm.compiler.core.test.MatchRuleTest;
 import org.graalvm.compiler.lir.LIR;
 import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.amd64.AMD64Binary;
 import org.graalvm.compiler.lir.amd64.AMD64BinaryConsumer.MemoryConstOp;
+import org.graalvm.compiler.lir.amd64.AMD64BinaryConsumer.ConstOp;
+import org.graalvm.compiler.lir.amd64.AMD64Unary;
 import org.junit.Before;
 import org.junit.Test;
 
 import jdk.vm.ci.amd64.AMD64;
+import jdk.vm.ci.amd64.AMD64Kind;
 
 public class AMD64MatchRuleTest extends MatchRuleTest {
     @Before
@@ -77,4 +82,182 @@
             this.x = x;
         }
     }
+
+    static volatile short shortValue;
+
+    public static long testVolatileExtensionSnippet() {
+        return shortValue;
+    }
+
+    @Test
+    public void testVolatileExtension() {
+        compile(getResolvedJavaMethod("testVolatileExtensionSnippet"), null);
+        LIR lir = getLIR();
+        boolean found = false;
+        for (LIRInstruction ins : lir.getLIRforBlock(lir.codeEmittingOrder()[0])) {
+            if (ins instanceof AMD64Unary.MemoryOp) {
+                ins.visitEachOutput((value, mode, flags) -> assertTrue(value.getPlatformKind().toString(), value.getPlatformKind().equals(AMD64Kind.QWORD)));
+                assertFalse("MemoryOp expected only once in first block", found);
+                found = true;
+            }
+        }
+        assertTrue("sign extending load must be in the LIR", found);
+    }
+
+    static int intValue;
+    static volatile int volatileIntValue;
+
+    /**
+     * Can't match test and load of input because of volatile store in between.
+     */
+    public static short testLoadTestNoMatchSnippet() {
+        int v = intValue;
+        volatileIntValue = 42;
+        if (v == 42) {
+            return shortValue;
+        }
+        return 0;
+    }
+
+    @Test
+    public void testLoadTestNoMatch() {
+        compile(getResolvedJavaMethod("testLoadTestNoMatchSnippet"), null);
+        LIR lir = getLIR();
+        boolean found = false;
+        for (LIRInstruction ins : lir.getLIRforBlock(lir.codeEmittingOrder()[0])) {
+            if (ins instanceof ConstOp && ((ConstOp) ins).getOpcode().toString().equals("CMP")) {
+                assertFalse("CMP expected only once in first block", found);
+                found = true;
+            }
+        }
+        assertTrue("CMP must be in the LIR", found);
+    }
+
+    /**
+     * Should match as an add with a memory operand.
+     */
+    public static int testAddLoadSnippet() {
+        int v1 = volatileIntValue;
+        int v2 = intValue;
+        return v2 + (2 * v1);
+    }
+
+    @Test
+    public void testAddLoad() {
+        compile(getResolvedJavaMethod("testAddLoadSnippet"), null);
+        LIR lir = getLIR();
+        boolean found = false;
+        for (LIRInstruction ins : lir.getLIRforBlock(lir.codeEmittingOrder()[0])) {
+            if (ins instanceof AMD64Binary.MemoryTwoOp && ((AMD64Binary.MemoryTwoOp) ins).getOpcode().toString().equals("ADD")) {
+                assertFalse("MemoryTwoOp expected only once in first block", found);
+                found = true;
+            }
+        }
+        assertTrue("ADD with memory argument must be in the LIR", found);
+    }
+
+    /**
+     * Can't match as an add with a memory operand because the other add input is too late.
+     */
+    public static int testAddLoadNoMatchSnippet() {
+        int v1 = volatileIntValue;
+        int v2 = intValue;
+        return v1 + (2 * v2);
+    }
+
+    @Test
+    public void testAddLoadNoMatch() {
+        compile(getResolvedJavaMethod("testAddLoadNoMatchSnippet"), null);
+        LIR lir = getLIR();
+        boolean found = false;
+        for (LIRInstruction ins : lir.getLIRforBlock(lir.codeEmittingOrder()[0])) {
+            if (ins instanceof AMD64Binary.CommutativeTwoOp && ((AMD64Binary.CommutativeTwoOp) ins).getOpcode().toString().equals("ADD")) {
+                assertFalse("CommutativeTwoOp expected only once in first block", found);
+                found = true;
+            }
+        }
+        assertTrue("ADD with memory argument must not be in the LIR", found);
+    }
+
+    /**
+     * sign extension and load are in different blocks but can still be matched as a single
+     * instruction.
+     */
+    public static long testVolatileExtensionDifferentBlocksSnippet(boolean flag) {
+        short v = shortValue;
+        if (flag) {
+            return v;
+        }
+        return 0;
+    }
+
+    @Test
+    public void testVolatileExtensionDifferentBlocks() {
+        compile(getResolvedJavaMethod("testVolatileExtensionDifferentBlocksSnippet"), null);
+        LIR lir = getLIR();
+        boolean found = false;
+        for (LIRInstruction ins : lir.getLIRforBlock(lir.codeEmittingOrder()[0])) {
+            if (ins instanceof AMD64Unary.MemoryOp) {
+                ins.visitEachOutput((value, mode, flags) -> assertTrue(value.getPlatformKind().toString(), value.getPlatformKind().equals(AMD64Kind.QWORD)));
+                assertFalse("MemoryOp expected only once in first block", found);
+                found = true;
+            }
+        }
+        assertTrue("sign extending load must be in the LIR", found);
+    }
+
+    /**
+     * Add and load are not in the same block and one input is too late: can't match.
+     */
+    public static int testAddLoadDifferentBlocksNoMatchSnippet(boolean flag) {
+        int v1 = volatileIntValue;
+        if (flag) {
+            int v2 = intValue;
+            return v1 + (2 * v2);
+        }
+        return 0;
+    }
+
+    @Test
+    public void testAddLoadDifferentBlocksNoMatch() {
+        compile(getResolvedJavaMethod("testAddLoadDifferentBlocksNoMatchSnippet"), null);
+        LIR lir = getLIR();
+        boolean found = false;
+        for (AbstractBlockBase<?> b : lir.codeEmittingOrder()) {
+            for (LIRInstruction ins : lir.getLIRforBlock(b)) {
+                if (ins instanceof AMD64Binary.CommutativeTwoOp && ((AMD64Binary.CommutativeTwoOp) ins).getOpcode().toString().equals("ADD")) {
+                    assertFalse("CommutativeTwoOp expected only once in first block", found);
+                    found = true;
+                }
+            }
+        }
+        assertTrue("ADD with memory argument must not be in the LIR", found);
+    }
+
+    /**
+     * Add and load are in different blocks but can still match.
+     */
+    public static int testAddLoadDifferentBlocksSnippet(boolean flag) {
+        int v2 = intValue;
+        int v1 = volatileIntValue;
+        if (flag) {
+            return v1 + v2;
+        }
+        return 0;
+    }
+
+    @Test
+    public void testAddLoadDifferentBlocks() {
+        compile(getResolvedJavaMethod("testAddLoadDifferentBlocksSnippet"), null);
+        LIR lir = getLIR();
+        boolean found = false;
+        for (LIRInstruction ins : lir.getLIRforBlock(lir.codeEmittingOrder()[0])) {
+            if (ins instanceof AMD64Binary.MemoryTwoOp && ((AMD64Binary.MemoryTwoOp) ins).getOpcode().toString().equals("ADD")) {
+                assertFalse("MemoryTwoOp expected only once in first block", found);
+                found = true;
+            }
+        }
+        assertTrue("ADD with memory argument must be in the LIR", found);
+    }
+
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64ArithmeticLIRGenerator.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64ArithmeticLIRGenerator.java	Thu Mar 28 19:39:14 2019 +0100
@@ -689,10 +689,9 @@
                 getLIRGen().append(new AMD64Unary.MOp(op.m1Op, size, result, input));
             } else {
                 /*
-                 * c is implicitly masked to 5 or 6 bits by the CPU, so casting it to (int) is
-                 * always correct, even without the NumUtil.is32bit() test.
+                 * c needs to be masked here, because shifts with immediate expect a byte.
                  */
-                getLIRGen().append(new AMD64Binary.ConstOp(op.miOp, size, result, input, (int) c.asLong()));
+                getLIRGen().append(new AMD64Binary.ConstOp(op.miOp, size, result, input, (byte) c.asLong()));
             }
         } else {
             getLIRGen().emitMove(RCX_I, b);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/Fields.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/Fields.java	Thu Mar 28 19:39:14 2019 +0100
@@ -24,7 +24,7 @@
 
 package org.graalvm.compiler.core.common;
 
-import static org.graalvm.compiler.core.common.UnsafeAccess.UNSAFE;
+import static org.graalvm.compiler.serviceprovider.GraalUnsafeAccess.getUnsafe;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -38,6 +38,8 @@
  */
 public class Fields {
 
+    private static final Unsafe UNSAFE = getUnsafe();
+
     /**
      * Offsets used with {@link Unsafe} to access the fields.
      */
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/FieldsScanner.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/FieldsScanner.java	Thu Mar 28 19:39:14 2019 +0100
@@ -24,7 +24,7 @@
 
 package org.graalvm.compiler.core.common;
 
-import static org.graalvm.compiler.core.common.UnsafeAccess.UNSAFE;
+import static org.graalvm.compiler.serviceprovider.GraalUnsafeAccess.getUnsafe;
 
 import java.lang.reflect.Field;
 import java.lang.reflect.Modifier;
@@ -50,6 +50,8 @@
      */
     public static class DefaultCalcOffset implements CalcOffset {
 
+        private static final Unsafe UNSAFE = getUnsafe();
+
         @Override
         public long getOffset(Field field) {
             return UNSAFE.objectFieldOffset(field);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/GraalOptions.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/GraalOptions.java	Thu Mar 28 19:39:14 2019 +0100
@@ -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
@@ -278,4 +278,8 @@
 
     @Option(help = "Enable inlining decision tracing in stubs and snippets.", type = OptionType.Debug)
     public static final OptionKey<Boolean> TraceInliningForStubsAndSnippets = new OptionKey<>(false);
+
+    @Option(help = "Use Graal-generated stubs for complicated LIR operations instead of embedding all the emitted code.")
+    public static final OptionKey<Boolean> UseGraalStubs = new OptionKey<>(true);
+
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/UnsafeAccess.java	Thu Mar 28 11:06:00 2019 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-/*
- * Copyright (c) 2012, 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.core.common;
-
-import java.lang.reflect.Field;
-
-import sun.misc.Unsafe;
-
-/**
- * Package private access to the {@link Unsafe} capability.
- */
-class UnsafeAccess {
-
-    static final Unsafe UNSAFE = initUnsafe();
-
-    private static Unsafe initUnsafe() {
-        try {
-            // Fast path when we are trusted.
-            return Unsafe.getUnsafe();
-        } catch (SecurityException se) {
-            // Slow path when we are not trusted.
-            try {
-                Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
-                theUnsafe.setAccessible(true);
-                return (Unsafe) theUnsafe.get(Unsafe.class);
-            } catch (Exception e) {
-                throw new RuntimeException("exception while trying to get Unsafe", e);
-            }
-        }
-    }
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/UnsafeAccess.java	Thu Mar 28 11:06:00 2019 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-/*
- * Copyright (c) 2012, 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.core.common.util;
-
-import java.lang.reflect.Field;
-
-import sun.misc.Unsafe;
-
-/**
- * Package private access to the {@link Unsafe} capability.
- */
-class UnsafeAccess {
-
-    static final Unsafe UNSAFE = initUnsafe();
-
-    private static Unsafe initUnsafe() {
-        try {
-            // Fast path when we are trusted.
-            return Unsafe.getUnsafe();
-        } catch (SecurityException se) {
-            // Slow path when we are not trusted.
-            try {
-                Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
-                theUnsafe.setAccessible(true);
-                return (Unsafe) theUnsafe.get(Unsafe.class);
-            } catch (Exception e) {
-                throw new RuntimeException("exception while trying to get Unsafe", e);
-            }
-        }
-    }
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/UnsafeArrayTypeReader.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/UnsafeArrayTypeReader.java	Thu Mar 28 19:39:14 2019 +0100
@@ -24,7 +24,8 @@
 
 package org.graalvm.compiler.core.common.util;
 
-import static org.graalvm.compiler.core.common.util.UnsafeAccess.UNSAFE;
+import static org.graalvm.compiler.serviceprovider.GraalUnsafeAccess.getUnsafe;
+
 import sun.misc.Unsafe;
 
 /**
@@ -41,6 +42,8 @@
  */
 public abstract class UnsafeArrayTypeReader implements TypeReader {
 
+    private static final Unsafe UNSAFE = getUnsafe();
+
     public static int getS1(byte[] data, long byteIndex) {
         return UNSAFE.getByte(data, readOffset(data, byteIndex, Byte.BYTES));
     }
@@ -142,6 +145,8 @@
 }
 
 final class UnalignedUnsafeArrayTypeReader extends UnsafeArrayTypeReader {
+    private static final Unsafe UNSAFE = getUnsafe();
+
     protected static int getS2(byte[] data, long byteIndex) {
         return UNSAFE.getShort(data, readOffset(data, byteIndex, Short.BYTES));
     }
@@ -181,6 +186,8 @@
 }
 
 class AlignedUnsafeArrayTypeReader extends UnsafeArrayTypeReader {
+    private static final Unsafe UNSAFE = getUnsafe();
+
     protected static int getS2(byte[] data, long byteIndex) {
         long offset = readOffset(data, byteIndex, Short.BYTES);
         return ((UNSAFE.getByte(data, offset + 0) & 0xFF) << 0) | //
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/UnsafeArrayTypeWriter.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/UnsafeArrayTypeWriter.java	Thu Mar 28 19:39:14 2019 +0100
@@ -30,6 +30,8 @@
 import static org.graalvm.compiler.core.common.util.TypeConversion.asU1;
 import static org.graalvm.compiler.core.common.util.TypeConversion.asU2;
 import static org.graalvm.compiler.core.common.util.TypeConversion.asU4;
+import static org.graalvm.compiler.serviceprovider.GraalUnsafeAccess.getUnsafe;
+
 import sun.misc.Unsafe;
 
 /**
@@ -44,6 +46,7 @@
  */
 public abstract class UnsafeArrayTypeWriter implements TypeWriter {
 
+    private static final Unsafe UNSAFE = getUnsafe();
     private static final int MIN_CHUNK_LENGTH = 200;
     private static final int MAX_CHUNK_LENGTH = 16000;
 
@@ -96,13 +99,13 @@
     @Override
     public final void putS1(long value) {
         long offset = writeOffset(Byte.BYTES);
-        UnsafeAccess.UNSAFE.putByte(writeChunk.data, offset, asS1(value));
+        UNSAFE.putByte(writeChunk.data, offset, asS1(value));
     }
 
     @Override
     public final void putU1(long value) {
         long offset = writeOffset(Byte.BYTES);
-        UnsafeAccess.UNSAFE.putByte(writeChunk.data, offset, asU1(value));
+        UNSAFE.putByte(writeChunk.data, offset, asU1(value));
     }
 
     @Override
@@ -134,52 +137,56 @@
 }
 
 final class UnalignedUnsafeArrayTypeWriter extends UnsafeArrayTypeWriter {
+    private static final Unsafe UNSAFE = getUnsafe();
+
     @Override
     public void putS2(long value) {
         long offset = writeOffset(Short.BYTES);
-        UnsafeAccess.UNSAFE.putShort(writeChunk.data, offset, asS2(value));
+        UNSAFE.putShort(writeChunk.data, offset, asS2(value));
     }
 
     @Override
     public void putS4(long value) {
         long offset = writeOffset(Integer.BYTES);
-        UnsafeAccess.UNSAFE.putInt(writeChunk.data, offset, asS4(value));
+        UNSAFE.putInt(writeChunk.data, offset, asS4(value));
     }
 
     @Override
     public void putS8(long value) {
         long offset = writeOffset(Long.BYTES);
-        UnsafeAccess.UNSAFE.putLong(writeChunk.data, offset, value);
+        UNSAFE.putLong(writeChunk.data, offset, value);
     }
 }
 
 final class AlignedUnsafeArrayTypeWriter extends UnsafeArrayTypeWriter {
+    private static final Unsafe UNSAFE = getUnsafe();
+
     @Override
     public void putS2(long value) {
         long offset = writeOffset(Short.BYTES);
-        UnsafeAccess.UNSAFE.putByte(writeChunk.data, offset + 0, (byte) (value >> 0));
-        UnsafeAccess.UNSAFE.putByte(writeChunk.data, offset + 1, (byte) (value >> 8));
+        UNSAFE.putByte(writeChunk.data, offset + 0, (byte) (value >> 0));
+        UNSAFE.putByte(writeChunk.data, offset + 1, (byte) (value >> 8));
     }
 
     @Override
     public void putS4(long value) {
         long offset = writeOffset(Integer.BYTES);
-        UnsafeAccess.UNSAFE.putByte(writeChunk.data, offset + 0, (byte) (value >> 0));
-        UnsafeAccess.UNSAFE.putByte(writeChunk.data, offset + 1, (byte) (value >> 8));
-        UnsafeAccess.UNSAFE.putByte(writeChunk.data, offset + 2, (byte) (value >> 16));
-        UnsafeAccess.UNSAFE.putByte(writeChunk.data, offset + 3, (byte) (value >> 24));
+        UNSAFE.putByte(writeChunk.data, offset + 0, (byte) (value >> 0));
+        UNSAFE.putByte(writeChunk.data, offset + 1, (byte) (value >> 8));
+        UNSAFE.putByte(writeChunk.data, offset + 2, (byte) (value >> 16));
+        UNSAFE.putByte(writeChunk.data, offset + 3, (byte) (value >> 24));
     }
 
     @Override
     public void putS8(long value) {
         long offset = writeOffset(Long.BYTES);
-        UnsafeAccess.UNSAFE.putByte(writeChunk.data, offset + 0, (byte) (value >> 0));
-        UnsafeAccess.UNSAFE.putByte(writeChunk.data, offset + 1, (byte) (value >> 8));
-        UnsafeAccess.UNSAFE.putByte(writeChunk.data, offset + 2, (byte) (value >> 16));
-        UnsafeAccess.UNSAFE.putByte(writeChunk.data, offset + 3, (byte) (value >> 24));
-        UnsafeAccess.UNSAFE.putByte(writeChunk.data, offset + 4, (byte) (value >> 32));
-        UnsafeAccess.UNSAFE.putByte(writeChunk.data, offset + 5, (byte) (value >> 40));
-        UnsafeAccess.UNSAFE.putByte(writeChunk.data, offset + 6, (byte) (value >> 48));
-        UnsafeAccess.UNSAFE.putByte(writeChunk.data, offset + 7, (byte) (value >> 56));
+        UNSAFE.putByte(writeChunk.data, offset + 0, (byte) (value >> 0));
+        UNSAFE.putByte(writeChunk.data, offset + 1, (byte) (value >> 8));
+        UNSAFE.putByte(writeChunk.data, offset + 2, (byte) (value >> 16));
+        UNSAFE.putByte(writeChunk.data, offset + 3, (byte) (value >> 24));
+        UNSAFE.putByte(writeChunk.data, offset + 4, (byte) (value >> 32));
+        UNSAFE.putByte(writeChunk.data, offset + 5, (byte) (value >> 40));
+        UNSAFE.putByte(writeChunk.data, offset + 6, (byte) (value >> 48));
+        UNSAFE.putByte(writeChunk.data, offset + 7, (byte) (value >> 56));
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.match.processor/src/org/graalvm/compiler/core/match/processor/MatchProcessor.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.match.processor/src/org/graalvm/compiler/core/match/processor/MatchProcessor.java	Thu Mar 28 19:39:14 2019 +0100
@@ -348,9 +348,15 @@
          */
         final boolean shareable;
 
+        /**
+         * Can this node be subsumed into a match even if there are side effecting nodes between
+         * this node and the match.
+         */
+        final boolean ignoresSideEffects;
+
         final Set<Element> originatingElements = new HashSet<>();
 
-        TypeDescriptor(TypeMirror mirror, String shortName, String nodeClass, String nodePackage, List<String> inputs, boolean commutative, boolean shareable) {
+        TypeDescriptor(TypeMirror mirror, String shortName, String nodeClass, String nodePackage, List<String> inputs, boolean commutative, boolean shareable, boolean ignoresSideEffects) {
             this.mirror = mirror;
             this.shortName = shortName;
             this.nodeClass = nodeClass;
@@ -358,6 +364,7 @@
             this.inputs = inputs;
             this.commutative = commutative;
             this.shareable = shareable;
+            this.ignoresSideEffects = ignoresSideEffects;
             assert !commutative || inputs.size() == 2;
         }
     }
@@ -369,8 +376,9 @@
 
     private TypeDescriptor valueType;
 
-    private void declareType(TypeMirror mirror, String shortName, String nodeClass, String nodePackage, List<String> inputs, boolean commutative, boolean shareable, Element element) {
-        TypeDescriptor descriptor = new TypeDescriptor(mirror, shortName, nodeClass, nodePackage, inputs, commutative, shareable);
+    private void declareType(TypeMirror mirror, String shortName, String nodeClass, String nodePackage, List<String> inputs, boolean commutative, boolean shareable, boolean ignoresSideEffects,
+                    Element element) {
+        TypeDescriptor descriptor = new TypeDescriptor(mirror, shortName, nodeClass, nodePackage, inputs, commutative, shareable, ignoresSideEffects);
         descriptor.originatingElements.add(element);
         knownTypes.put(shortName, descriptor);
     }
@@ -453,7 +461,7 @@
 
         private String formatPrefix() {
             if (nodeType == valueType) {
-                return String.format("new MatchPattern(%s, false", name != null ? ("\"" + name + "\"") : "null");
+                return String.format("new MatchPattern(%s, false, false", name != null ? ("\"" + name + "\"") : "null");
             } else {
                 return String.format("new MatchPattern(%s.class, %s", nodeType.nodeClass, name != null ? ("\"" + name + "\"") : "null");
             }
@@ -462,13 +470,13 @@
         private String formatSuffix() {
             if (nodeType != null) {
                 if (inputs.length != nodeType.inputs.size()) {
-                    return ", true)";
+                    return ", true, " + nodeType.ignoresSideEffects + ")";
                 } else {
                     if (nodeType.inputs.size() > 0) {
-                        return ", " + nodeType.nodeClass + "_positions, " + !nodeType.shareable + ")";
+                        return ", " + nodeType.nodeClass + "_positions, " + !nodeType.shareable + ", " + nodeType.ignoresSideEffects + ")";
                     }
                     if (nodeType.shareable) {
-                        return ", false)";
+                        return ", false, " + nodeType.ignoresSideEffects + ")";
                     }
                 }
             }
@@ -721,7 +729,7 @@
             // Define a TypeDescriptor for the generic node but don't enter it into the nodeTypes
             // table since it shouldn't be mentioned in match rules.
             TypeMirror valueTypeMirror = getTypeElement(VALUE_NODE_CLASS_NAME).asType();
-            valueType = new TypeDescriptor(valueTypeMirror, "Value", "ValueNode", "org.graalvm.compiler.nodes", Collections.emptyList(), false, false);
+            valueType = new TypeDescriptor(valueTypeMirror, "Value", "ValueNode", "org.graalvm.compiler.nodes", Collections.emptyList(), false, false, false);
 
             Map<TypeElement, MatchRuleDescriptor> map = new HashMap<>();
 
@@ -831,7 +839,8 @@
 
         boolean commutative = getAnnotationValue(matchable, "commutative", Boolean.class);
         boolean shareable = getAnnotationValue(matchable, "shareable", Boolean.class);
-        declareType(nodeClassMirror, shortName, nodeClass, nodePackage, inputs, commutative, shareable, element);
+        boolean ignoresSideEffects = getAnnotationValue(matchable, "ignoresSideEffects", Boolean.class);
+        declareType(nodeClassMirror, shortName, nodeClass, nodePackage, inputs, commutative, shareable, ignoresSideEffects, element);
     }
 
     private void processMatchRules(Map<TypeElement, MatchRuleDescriptor> map, Element element, List<AnnotationMirror> matchRules) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CheckGraalInvariants.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CheckGraalInvariants.java	Thu Mar 28 19:39:14 2019 +0100
@@ -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
@@ -32,6 +32,7 @@
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.Enumeration;
 import java.util.List;
@@ -266,9 +267,11 @@
         verifiers.add(new VerifyVirtualizableUsage());
         verifiers.add(new VerifyUpdateUsages());
         verifiers.add(new VerifyBailoutUsage());
+        verifiers.add(new VerifySystemPropertyUsage());
         verifiers.add(new VerifyInstanceOfUsage());
         verifiers.add(new VerifyGraphAddUsage());
         verifiers.add(new VerifyGetOptionsUsage());
+        verifiers.add(new VerifyUnsafeAccess());
 
         VerifyFoldableMethods foldableMethodsVerifier = new VerifyFoldableMethods();
         if (tool.shouldVerifyFoldableMethods()) {
@@ -301,21 +304,29 @@
                 String className = c.getName();
                 executor.execute(() -> {
                     try {
-                        checkClass(c, metaAccess);
+                        checkClass(c, metaAccess, verifiers);
                     } catch (Throwable e) {
                         errors.add(String.format("Error while checking %s:%n%s", className, printStackTraceToString(e)));
                     }
                 });
 
-                for (Method m : c.getDeclaredMethods()) {
-                    if (Modifier.isNative(m.getModifiers()) || Modifier.isAbstract(m.getModifiers())) {
+                ResolvedJavaType type = metaAccess.lookupJavaType(c);
+                List<ResolvedJavaMethod> methods = new ArrayList<>();
+                methods.addAll(Arrays.asList(type.getDeclaredMethods()));
+                methods.addAll(Arrays.asList(type.getDeclaredConstructors()));
+                ResolvedJavaMethod clinit = type.getClassInitializer();
+                if (clinit != null) {
+                    methods.add(clinit);
+                }
+
+                for (ResolvedJavaMethod method : methods) {
+                    if (Modifier.isNative(method.getModifiers()) || Modifier.isAbstract(method.getModifiers())) {
                         // ignore
                     } else {
-                        String methodName = className + "." + m.getName();
+                        String methodName = className + "." + method.getName();
                         if (matches(filters, methodName)) {
                             executor.execute(() -> {
                                 try (DebugContext debug = DebugContext.create(options, DebugHandlersFactory.LOADER)) {
-                                    ResolvedJavaMethod method = metaAccess.lookupJavaMethod(m);
                                     boolean isSubstitution = method.getAnnotation(Snippet.class) != null || method.getAnnotation(MethodSubstitution.class) != null;
                                     StructuredGraph graph = new StructuredGraph.Builder(options, debug).method(method).setIsSubstitution(isSubstitution).build();
                                     try (DebugCloseable s = debug.disableIntercept(); DebugContext.Scope ds = debug.scope("CheckingGraph", graph, method)) {
@@ -400,14 +411,18 @@
 
     /**
      * @param metaAccess
+     * @param verifiers
      */
-    private static void checkClass(Class<?> c, MetaAccessProvider metaAccess) {
+    private static void checkClass(Class<?> c, MetaAccessProvider metaAccess, List<VerifyPhase<PhaseContext>> verifiers) {
         if (Node.class.isAssignableFrom(c)) {
             if (c.getAnnotation(NodeInfo.class) == null) {
                 throw new AssertionError(String.format("Node subclass %s requires %s annotation", c.getName(), NodeClass.class.getSimpleName()));
             }
             VerifyNodeCosts.verifyNodeClass(c);
         }
+        for (VerifyPhase<PhaseContext> verifier : verifiers) {
+            verifier.verifyClass(c, metaAccess);
+        }
     }
 
     private static void checkMethod(ResolvedJavaMethod method) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/FinalizableSubclassTest.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/FinalizableSubclassTest.java	Thu Mar 28 19:39:14 2019 +0100
@@ -77,8 +77,7 @@
         StructuredGraph graph = new StructuredGraph.Builder(options, getDebugContext(options, null, javaMethod), allowAssumptions).method(javaMethod).build();
 
         GraphBuilderConfiguration conf = GraphBuilderConfiguration.getSnippetDefault(getDefaultGraphBuilderPlugins());
-        new GraphBuilderPhase.Instance(getMetaAccess(), getProviders().getStampProvider(), getProviders().getConstantReflection(), getProviders().getConstantFieldProvider(), conf,
-                        OptimisticOptimizations.ALL, null).apply(graph);
+        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);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/NewInstanceTest.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/NewInstanceTest.java	Thu Mar 28 19:39:14 2019 +0100
@@ -76,8 +76,7 @@
         StructuredGraph graph = new StructuredGraph.Builder(options, getDebugContext(options, null, javaMethod), AllowAssumptions.YES).method(javaMethod).build();
 
         GraphBuilderConfiguration conf = GraphBuilderConfiguration.getSnippetDefault(getDefaultGraphBuilderPlugins()).withUnresolvedIsError(false);
-        new GraphBuilderPhase.Instance(getMetaAccess(), getProviders().getStampProvider(), getProviders().getConstantReflection(), getProviders().getConstantFieldProvider(), conf,
-                        OptimisticOptimizations.ALL, null).apply(graph);
+        new GraphBuilderPhase.Instance(getProviders(), conf, OptimisticOptimizations.ALL, null).apply(graph);
         return 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/SwitchTest.java	Thu Mar 28 19:39:14 2019 +0100
@@ -0,0 +1,55 @@
+/*
+ * 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.test;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import org.junit.Test;
+
+// Regression test for JDK-8220643 (GR-14583)
+public class SwitchTest extends GraalCompilerTest {
+    public static boolean test1(int arg) {
+        switch (arg) {
+            case -2139290527:
+            case -1466249004:
+            case -1063407861:
+            case 125135499:
+            case 425995464:
+            case 786490581:
+            case 1180611932:
+            case 1790655921:
+            case 1970660086:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        ResolvedJavaMethod method = getResolvedJavaMethod("test1");
+        Result compiled = executeActual(method, null, -2139290527);
+        assertEquals(new Result(true, null), compiled);
+    }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnbalancedMonitorsTest.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnbalancedMonitorsTest.java	Thu Mar 28 19:39:14 2019 +0100
@@ -94,7 +94,7 @@
             GraphBuilderConfiguration graphBuilderConfig = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true).withUnresolvedIsError(true);
             OptimisticOptimizations optimisticOpts = OptimisticOptimizations.NONE;
 
-            GraphBuilderPhase.Instance graphBuilder = new GraphBuilderPhase.Instance(getMetaAccess(), getProviders().getStampProvider(), null, null, graphBuilderConfig, optimisticOpts, null);
+            GraphBuilderPhase.Instance graphBuilder = new GraphBuilderPhase.Instance(getProviders(), graphBuilderConfig, optimisticOpts, null);
             graphBuilder.apply(graph);
         } catch (BailoutException e) {
             if (e.getMessage().contains("unbalanced monitors")) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyBailoutUsage.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyBailoutUsage.java	Thu Mar 28 19:39:14 2019 +0100
@@ -73,7 +73,7 @@
     }
 
     @Override
-    protected boolean verify(StructuredGraph graph, PhaseContext context) {
+    protected void verify(StructuredGraph graph, PhaseContext context) {
         final ResolvedJavaType bailoutType = context.getMetaAccess().lookupJavaType(BailoutException.class);
         ResolvedJavaMethod caller = graph.method();
         String holderQualified = caller.format("%H");
@@ -92,7 +92,6 @@
                 }
             }
         }
-        return true;
     }
 
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyCallerSensitiveMethods.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyCallerSensitiveMethods.java	Thu Mar 28 19:39:14 2019 +0100
@@ -67,7 +67,7 @@
     }
 
     @Override
-    protected boolean verify(StructuredGraph graph, PhaseContext context) {
+    protected void verify(StructuredGraph graph, PhaseContext context) {
         Invoke invoke = callsReflectionGetCallerClass(graph, context);
         Annotation annotation = graph.method().getAnnotation(callerSensitiveClass);
         if (invoke != null) {
@@ -79,7 +79,6 @@
         } else if (annotation != null) {
             throw new VerificationError(String.format("%s: method annotated with @CallerSensitive does not call Reflection.getCallerClass()", graph.method().format("%H.%n(%p)")));
         }
-        return true;
     }
 
     private Invoke callsReflectionGetCallerClass(StructuredGraph graph, PhaseContext context) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyDebugUsage.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyDebugUsage.java	Thu Mar 28 19:39:14 2019 +0100
@@ -78,7 +78,7 @@
     MetaAccessProvider metaAccess;
 
     @Override
-    protected boolean verify(StructuredGraph graph, PhaseContext context) {
+    protected void verify(StructuredGraph graph, PhaseContext context) {
         metaAccess = context.getMetaAccess();
         ResolvedJavaType debugType = metaAccess.lookupJavaType(DebugContext.class);
         ResolvedJavaType nodeType = metaAccess.lookupJavaType(Node.class);
@@ -108,7 +108,6 @@
                 }
             }
         }
-        return true;
     }
 
     private void verifyParameters(MethodCallTargetNode callTarget, StructuredGraph callerGraph, NodeInputList<? extends ValueNode> args, ResolvedJavaType stringType, int startArgIdx) {
@@ -167,6 +166,7 @@
                     "org.graalvm.compiler.phases.BasePhase.dumpAfter",
                     "org.graalvm.compiler.replacements.ReplacementsImpl$GraphMaker.makeGraph",
                     "org.graalvm.compiler.replacements.SnippetTemplate.instantiate",
+                    "org.graalvm.compiler.replacements.SnippetTemplate.<init>",
                     "org.graalvm.compiler.hotspot.SymbolicSnippetEncoder.verifySnippetEncodeDecode"));
 
     private void verifyParameters(StructuredGraph callerGraph, MethodCallTargetNode debugCallTarget, List<? extends ValueNode> args, ResolvedJavaType stringType, int startArgIdx,
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyFoldableMethods.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyFoldableMethods.java	Thu Mar 28 19:39:14 2019 +0100
@@ -52,7 +52,7 @@
     ResolvedJavaType generatedInvocationPluginType;
 
     @Override
-    protected boolean verify(StructuredGraph graph, PhaseContext context) {
+    protected void verify(StructuredGraph graph, PhaseContext context) {
         ResolvedJavaMethod method = graph.method();
         if (method.getAnnotation(Fold.class) != null) {
             foldables.putIfAbsent(method, false);
@@ -69,7 +69,6 @@
                 }
             }
         }
-        return true;
     }
 
     public void finish() {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyGetOptionsUsage.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyGetOptionsUsage.java	Thu Mar 28 19:39:14 2019 +0100
@@ -36,6 +36,7 @@
 
 import jdk.vm.ci.meta.MetaAccessProvider;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaMethod.Parameter;
 import jdk.vm.ci.meta.ResolvedJavaType;
 
 /**
@@ -55,15 +56,19 @@
     }
 
     @Override
-    protected boolean verify(StructuredGraph graph, PhaseContext context) {
+    protected void verify(StructuredGraph graph, PhaseContext context) {
         MetaAccessProvider metaAccess = context.getMetaAccess();
         ResolvedJavaType canonicalizerToolClass = metaAccess.lookupJavaType(CanonicalizerTool.class);
         boolean hasTool = false;
+        ResolvedJavaMethod method = graph.method();
         try {
-            for (ResolvedJavaMethod.Parameter parameter : graph.method().getParameters()) {
-                if (parameter.getType().getName().equals(canonicalizerToolClass.getName())) {
-                    hasTool = true;
-                    break;
+            Parameter[] parameters = method.getParameters();
+            if (parameters != null) {
+                for (ResolvedJavaMethod.Parameter parameter : parameters) {
+                    if (parameter.getType().getName().equals(canonicalizerToolClass.getName())) {
+                        hasTool = true;
+                        break;
+                    }
                 }
             }
         } catch (MalformedParametersException e) {
@@ -76,13 +81,11 @@
                 if (callee.equals(getOptionsMethod)) {
                     if (hasTool) {
                         throw new VerificationError("Must use CanonicalizerTool.getOptions() instead of Node.getOptions() in method '%s' of class '%s'.",
-                                        graph.method().getName(), graph.method().getDeclaringClass().getName());
+                                        method.getName(), method.getDeclaringClass().getName());
                     }
                 }
             }
         }
-
-        return true;
     }
 
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyGraphAddUsage.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyGraphAddUsage.java	Thu Mar 28 19:39:14 2019 +0100
@@ -66,7 +66,7 @@
     }
 
     @Override
-    protected boolean verify(StructuredGraph graph, PhaseContext context) {
+    protected void verify(StructuredGraph graph, PhaseContext context) {
         boolean allowed = false;
         for (Class<?> cls : ALLOWED_CLASSES) {
             ResolvedJavaType declaringClass = graph.method().getDeclaringClass();
@@ -85,8 +85,6 @@
                 }
             }
         }
-
-        return true;
     }
 
     private void checkNonFactory(StructuredGraph graph, EconomicSet<Node> seen, PhaseContext context, ValueNode node) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyInstanceOfUsage.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyInstanceOfUsage.java	Thu Mar 28 19:39:14 2019 +0100
@@ -53,7 +53,7 @@
     }
 
     @Override
-    protected boolean verify(StructuredGraph graph, PhaseContext context) {
+    protected void verify(StructuredGraph graph, PhaseContext context) {
         final ResolvedJavaType[] bailoutType = new ResolvedJavaType[FORBIDDEN_INSTANCE_OF_CHECKS.length];
         for (int i = 0; i < FORBIDDEN_INSTANCE_OF_CHECKS.length; i++) {
             bailoutType[i] = context.getMetaAccess().lookupJavaType(FORBIDDEN_INSTANCE_OF_CHECKS[i]);
@@ -77,7 +77,6 @@
                 }
             }
         }
-        return true;
     }
 
     private static boolean isTrustedInterface(ResolvedJavaType declaringClass, MetaAccessProvider metaAccess) {
--- /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/VerifySystemPropertyUsage.java	Thu Mar 28 19:39:14 2019 +0100
@@ -0,0 +1,125 @@
+/*
+ * 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.test;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
+import org.graalvm.compiler.phases.VerifyPhase;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+import jdk.vm.ci.services.Services;
+
+/**
+ * Checks against calls to {@link System#getProperty(String)},
+ * {@link System#getProperty(String, String)} and {@link System#getProperties()}. System properties
+ * can be modified by application code so {@link Services#getSavedProperties()} should be used
+ * instead.
+ */
+public class VerifySystemPropertyUsage extends VerifyPhase<PhaseContext> {
+
+    static final Class<?>[] BOXES = {Integer.class, Long.class, Boolean.class, Float.class, Double.class};
+    static final int JVMCI_VERSION_MAJOR;
+    static final int JVMCI_VERSION_MINOR;
+    static {
+        int major = -1;
+        int minor = -1;
+        String vmVersion = System.getProperty("java.vm.version");
+        if (System.getProperty("java.specification.version").compareTo("1.9") < 0) {
+            Pattern re = Pattern.compile(".*-jvmci-(\\d+)\\.(\\d+).*");
+            Matcher matcher = re.matcher(vmVersion);
+            if (matcher.matches()) {
+                major = Integer.parseInt(matcher.group(1));
+                minor = Integer.parseInt(matcher.group(2));
+            }
+        }
+        JVMCI_VERSION_MAJOR = major;
+        JVMCI_VERSION_MINOR = minor;
+    }
+
+    @Override
+    protected void verify(StructuredGraph graph, PhaseContext context) {
+        MetaAccessProvider metaAccess = context.getMetaAccess();
+        final ResolvedJavaType systemType = metaAccess.lookupJavaType(System.class);
+        final ResolvedJavaType[] boxTypes = new ResolvedJavaType[BOXES.length];
+        for (int i = 0; i < boxTypes.length; i++) {
+            boxTypes[i] = metaAccess.lookupJavaType(BOXES[i]);
+        }
+
+        ResolvedJavaMethod caller = graph.method();
+        String holderQualified = caller.format("%H");
+        String holderUnqualified = caller.format("%h");
+        String packageName = holderQualified.equals(holderUnqualified) ? "" : holderQualified.substring(0, holderQualified.length() - holderUnqualified.length() - 1);
+        if (packageName.startsWith("jdk.vm.ci")) {
+            if (JVMCI_VERSION_MAJOR >= 0 && JVMCI_VERSION_MINOR > 56) {
+                // This JVMCI version should not use non-saved system properties
+            } else {
+                // This JVMCI version still has some calls that need to be removed
+                return;
+            }
+        } else if (holderQualified.equals("org.graalvm.compiler.hotspot.JVMCIVersionCheck") && caller.getName().equals("main")) {
+            // The main method in JVMCIVersionCheck is only called from the shell
+            return;
+        } else if (packageName.startsWith("com.oracle.truffle") || packageName.startsWith("org.graalvm.polyglot")) {
+            // Truffle and Polyglot do not depend on JVMCI so cannot use
+            // Services.getSavedProperties()
+            return;
+        } else if (packageName.startsWith("com.oracle.svm")) {
+            // SVM must read system properties in:
+            // * its JDK substitutions to mimic required JDK semantics
+            // * native-image for config info
+            return;
+        }
+        for (MethodCallTargetNode t : graph.getNodes(MethodCallTargetNode.TYPE)) {
+            ResolvedJavaMethod callee = t.targetMethod();
+            if (callee.getDeclaringClass().equals(systemType)) {
+                if (callee.getName().equals("getProperty") || callee.getName().equals("getProperties")) {
+                    throw new VerificationError("Call to %s at callsite %s is prohibited. Call Services.getSavedProperties().get(String) instead.",
+                                    callee.format("%H.%n(%p)"),
+                                    caller.format("%H.%n(%p)"));
+                }
+            } else {
+                for (int i = 0; i < boxTypes.length; i++) {
+                    ResolvedJavaType boxType = boxTypes[i];
+                    if (callee.getDeclaringClass().equals(boxType)) {
+                        String simpleName = boxType.toJavaName(false);
+                        if (callee.getName().equals("get" + simpleName)) {
+                            throw new VerificationError("Call to %s at callsite %s is prohibited. Call %s.parse%s(Services.getSavedProperties().get(String)) instead.",
+                                            callee.format("%H.%n(%p)"),
+                                            caller.format("%H.%n(%p)"),
+                                            simpleName, simpleName);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+}
--- /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/VerifyUnsafeAccess.java	Thu Mar 28 19:39:14 2019 +0100
@@ -0,0 +1,116 @@
+/*
+ * 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.test;
+
+import static java.lang.reflect.Modifier.isProtected;
+import static java.lang.reflect.Modifier.isPublic;
+
+import java.lang.reflect.Field;
+
+import org.graalvm.compiler.core.common.type.TypeReference;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.java.InstanceOfNode;
+import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
+import org.graalvm.compiler.phases.VerifyPhase;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+import org.graalvm.compiler.serviceprovider.GraalUnsafeAccess;
+
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+import sun.misc.Unsafe;
+
+/**
+ * Checks that the {@link Unsafe} singleton instance is only accessed via well known classes such as
+ * {@link GraalUnsafeAccess}.
+ */
+public class VerifyUnsafeAccess extends VerifyPhase<PhaseContext> {
+
+    @Override
+    protected void verify(StructuredGraph graph, PhaseContext context) {
+        MetaAccessProvider metaAccess = context.getMetaAccess();
+        final ResolvedJavaType unsafeType = metaAccess.lookupJavaType(Unsafe.class);
+
+        ResolvedJavaMethod caller = graph.method();
+        String holderQualified = caller.format("%H");
+        String holderUnqualified = caller.format("%h");
+        String packageName = holderQualified.equals(holderUnqualified) ? "" : holderQualified.substring(0, holderQualified.length() - holderUnqualified.length() - 1);
+        if ((holderQualified.equals(GraalUnsafeAccess.class.getName()) ||
+                        holderQualified.equals("jdk.vm.ci.hotspot.UnsafeAccess")) &&
+                        caller.getName().equals("initUnsafe")) {
+            // This is the blessed way access Unsafe in Graal and JVMCI
+            return;
+        } else if (packageName.startsWith("com.oracle.truffle") || packageName.startsWith("org.graalvm.compiler.truffle.runtime")) {
+            // Truffle and GraalTruffleRuntime do not depend on Graal and so cannot use
+            // GraalUnsafeAccess
+            return;
+        }
+
+        if (caller.getSignature().getReturnType(caller.getDeclaringClass()).equals(unsafeType)) {
+            if (caller.isPublic()) {
+                if (holderQualified.equals(GraalUnsafeAccess.class.getName()) && caller.getName().equals("getUnsafe")) {
+                    // pass
+                } else {
+                    throw new VerificationError("Cannot leak Unsafe from public method %s",
+                                    caller.format("%H.%n(%p)"));
+                }
+            }
+        }
+
+        for (InstanceOfNode node : graph.getNodes().filter(InstanceOfNode.class)) {
+            TypeReference typeRef = node.type();
+            if (typeRef != null) {
+                if (unsafeType.isAssignableFrom(typeRef.getType())) {
+                    throw new VerificationError("Cast to %s in %s is prohibited as it implies accessing Unsafe.theUnsafe via reflection. Use %s.getUnsafe() instead.",
+                                    unsafeType.toJavaName(),
+                                    caller.format("%H.%n(%p)"),
+                                    GraalUnsafeAccess.class.getName());
+
+                }
+            }
+        }
+        for (MethodCallTargetNode t : graph.getNodes(MethodCallTargetNode.TYPE)) {
+            ResolvedJavaMethod callee = t.targetMethod();
+            if (callee.getDeclaringClass().equals(unsafeType)) {
+                if (callee.getName().equals("getUnsafe")) {
+                    throw new VerificationError("Call to %s at callsite %s is prohibited. Use %s.getUnsafe() instead.",
+                                    callee.format("%H.%n(%p)"),
+                                    caller.format("%H.%n(%p)"),
+                                    GraalUnsafeAccess.class.getName());
+                }
+            }
+        }
+    }
+
+    @Override
+    public void verifyClass(Class<?> c, MetaAccessProvider metaAccess) {
+        for (Field field : c.getDeclaredFields()) {
+            int modifiers = field.getModifiers();
+            if (field.getType() == Unsafe.class && (isPublic(modifiers) || isProtected(modifiers))) {
+                throw new VerificationError("Field of type %s must be private or package-private: %s", Unsafe.class.getName(), field);
+            }
+        }
+    }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyUpdateUsages.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyUpdateUsages.java	Thu Mar 28 19:39:14 2019 +0100
@@ -56,9 +56,9 @@
     }
 
     @Override
-    protected boolean verify(StructuredGraph graph, PhaseContext context) {
+    protected void verify(StructuredGraph graph, PhaseContext context) {
         if (graph.method().isConstructor()) {
-            return true;
+            return;
         }
         /*
          * There are only two acceptable patterns for methods which update Node inputs, either a
@@ -78,35 +78,51 @@
                 } else if (storeField2 == null) {
                     storeField2 = store;
                 } else {
-                    return false;
+                    throw new VerificationError("More than 2 stores to %s or %s fields found in %s",
+                                    Input.class.getSimpleName(),
+                                    OptionalInput.class.getSimpleName(),
+                                    graph.method().format("%H.%n(%p)"));
                 }
             }
         }
         if (storeField1 == null) {
-            return true;
+            return;
         }
         if (storeField2 == null) {
-            // Single input field update so just check for updateUsages or updateUsagesInterface
-            // call
-            ResolvedJavaType node = context.getMetaAccess().lookupJavaType(Node.class);
+            // Single input field update so just check for updateUsages
+            // or updateUsagesInterface call
+            ResolvedJavaType nodeType = context.getMetaAccess().lookupJavaType(Node.class);
             for (MethodCallTargetNode call : graph.getNodes().filter(MethodCallTargetNode.class)) {
                 ResolvedJavaMethod callee = call.targetMethod();
-                if (callee.getDeclaringClass().equals(node) && (callee.getName().equals("updateUsages") || callee.getName().equals("updateUsagesInterface"))) {
-                    return true;
+                if (callee.getDeclaringClass().equals(nodeType) && (callee.getName().equals("updateUsages") || callee.getName().equals("updateUsagesInterface"))) {
+                    return;
                 }
             }
+            throw new VerificationError("%s updates field '%s' without calling %s.updateUsages() or %s.updateUsagesInterface()",
+                            graph.method().format("%H.%n(%p)"),
+                            storeField1.field().getName(),
+                            Node.class.getName(),
+                            Node.class.getName());
         } else {
             if (storeField1.value() instanceof LoadFieldNode && storeField2.value() instanceof LoadFieldNode) {
                 LoadFieldNode load1 = (LoadFieldNode) storeField1.value();
                 LoadFieldNode load2 = (LoadFieldNode) storeField2.value();
                 // Check for swapping values within the same object
-                if (load1.object() == storeField1.object() && load2.object() == storeField2.object() && storeField1.object() == storeField2.object() &&
-                                load1.field().equals(storeField2.field()) && load2.field().equals(storeField1.field())) {
-                    return true;
+                if (load1.object() == storeField1.object() &&
+                                load2.object() == storeField2.object() &&
+                                storeField1.object() == storeField2.object() &&
+                                load1.field().equals(storeField2.field()) &&
+                                load2.field().equals(storeField1.field())) {
+                    return;
                 }
             }
+            throw new VerificationError("%s performs non-swap update to fields '%s' and '%s' without calling %s.updateUsages() or %s.updateUsagesInterface()",
+                            graph.method().format("%H.%n(%p)"),
+                            storeField1.field().getName(),
+                            storeField2.field().getName(),
+                            Node.class.getName(),
+                            Node.class.getName());
         }
-        return false;
     }
 
     boolean isNodeInput(ResolvedJavaField field, ResolvedJavaType declaringClass, ResolvedJavaType nodeInputList) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyUsageWithEquals.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyUsageWithEquals.java	Thu Mar 28 19:39:14 2019 +0100
@@ -143,7 +143,7 @@
     }
 
     @Override
-    protected boolean verify(StructuredGraph graph, PhaseContext context) {
+    protected void verify(StructuredGraph graph, PhaseContext context) {
         for (ObjectEqualsNode cn : graph.getNodes().filter(ObjectEqualsNode.class)) {
             // bail out if we compare an object of type klass with == or != (except null checks)
             ResolvedJavaMethod method = graph.method();
@@ -156,6 +156,5 @@
                                 " must use .equals() for object equality, not '==' or '!='");
             }
         }
-        return true;
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyVirtualizableUsage.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyVirtualizableUsage.java	Thu Mar 28 19:39:14 2019 +0100
@@ -53,7 +53,7 @@
     }
 
     @Override
-    protected boolean verify(StructuredGraph graph, PhaseContext context) {
+    protected void verify(StructuredGraph graph, PhaseContext context) {
         final ResolvedJavaType graphType = context.getMetaAccess().lookupJavaType(Graph.class);
         final ResolvedJavaType virtualizableType = context.getMetaAccess().lookupJavaType(Virtualizable.class);
         final ResolvedJavaType constantNodeType = context.getMetaAccess().lookupJavaType(ConstantNode.class);
@@ -70,7 +70,6 @@
                 }
             }
         }
-        return true;
     }
 
     private static void verifyVirtualizableEffectArguments(ResolvedJavaType constantNodeType, ResolvedJavaMethod caller, ResolvedJavaMethod callee, int bciCaller,
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/EATestBase.java	Thu Mar 28 11:06:00 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 Mar 28 19:39:14 2019 +0100
@@ -152,13 +152,17 @@
                 Assert.assertEquals(expectedConstantResult, returnNode.result().asConstant());
             }
         }
-        int newInstanceCount = graph.getNodes().filter(isA(NewInstanceNode.class).or(NewArrayNode.class).or(AllocatedObjectNode.class)).count();
+        int newInstanceCount = getAllocationCount();
         Assert.assertEquals("Expected allocation count does not match", expectedAllocationCount, newInstanceCount);
         if (expectedAllocationCount == 0) {
             Assert.assertTrue("Unexpected CommitAllocationNode", graph.getNodes().filter(CommitAllocationNode.class).isEmpty());
         }
     }
 
+    protected int getAllocationCount() {
+        return graph.getNodes().filter(isA(NewInstanceNode.class).or(NewArrayNode.class).or(AllocatedObjectNode.class)).count();
+    }
+
     @SuppressWarnings("try")
     protected void prepareGraph(String snippet, boolean iterativeEscapeAnalysis) {
         ResolvedJavaMethod method = getResolvedJavaMethod(snippet);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/tutorial/StaticAnalysis.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/tutorial/StaticAnalysis.java	Thu Mar 28 19:39:14 2019 +0100
@@ -34,8 +34,8 @@
 import java.util.Map;
 import java.util.Set;
 
+import org.graalvm.compiler.debug.DebugContext;
 import org.graalvm.compiler.debug.DebugHandlersFactory;
-import org.graalvm.compiler.debug.DebugContext;
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.graph.NodeMap;
@@ -58,7 +58,7 @@
 import org.graalvm.compiler.nodes.java.NewArrayNode;
 import org.graalvm.compiler.nodes.java.NewInstanceNode;
 import org.graalvm.compiler.nodes.java.StoreFieldNode;
-import org.graalvm.compiler.nodes.spi.StampProvider;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.nodes.util.GraphUtil;
 import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.phases.OptimisticOptimizations;
@@ -66,7 +66,6 @@
 
 import jdk.vm.ci.meta.JavaConstant;
 import jdk.vm.ci.meta.JavaKind;
-import jdk.vm.ci.meta.MetaAccessProvider;
 import jdk.vm.ci.meta.ResolvedJavaField;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 import jdk.vm.ci.meta.ResolvedJavaType;
@@ -89,18 +88,21 @@
  * {@link MethodState#formalReturn return value}.
  */
 public class StaticAnalysis {
-    /** Access to type, method, and fields using the Graal API. */
-    private final MetaAccessProvider metaAccess;
-    /** Access to platform dependent stamps. */
-    private final StampProvider stampProvider;
-    /** The results of the static analysis. */
+    /**
+     * Access to various builtin providers.
+     */
+    private final CoreProviders providers;
+    /**
+     * The results of the static analysis.
+     */
     private final Results results;
-    /** Worklist for fixpoint iteration. */
+    /**
+     * Worklist for fixpoint iteration.
+     */
     private final Deque<WorklistEntry> worklist;
 
-    public StaticAnalysis(MetaAccessProvider metaAccess, StampProvider stampProvider) {
-        this.metaAccess = metaAccess;
-        this.stampProvider = stampProvider;
+    public StaticAnalysis(CoreProviders providers) {
+        this.providers = providers;
         this.results = new Results();
         this.worklist = new ArrayDeque<>();
     }
@@ -273,7 +275,7 @@
                      */
                     OptimisticOptimizations optimisticOpts = OptimisticOptimizations.NONE;
 
-                    GraphBuilderPhase.Instance graphBuilder = new GraphBuilderPhase.Instance(metaAccess, stampProvider, null, null, graphBuilderConfig, optimisticOpts, null);
+                    GraphBuilderPhase.Instance graphBuilder = new GraphBuilderPhase.Instance(providers, graphBuilderConfig, optimisticOpts, null);
                     graphBuilder.apply(graph);
                 } catch (Throwable ex) {
                     debug.handle(ex);
@@ -304,7 +306,9 @@
             uses = new HashSet<>();
         }
 
-        /** Returns the types of this element. */
+        /**
+         * Returns the types of this element.
+         */
         public Set<ResolvedJavaType> getTypes() {
             return types;
         }
@@ -349,7 +353,7 @@
      * Adding a new callee means linking the type flow of the actual parameters with the formal
      * parameters of the callee, and linking the return value of the callee with the return value
      * state of the invocation.
-     *
+     * <p>
      * Statically bindable methods calls ({@link InvokeKind#Static static} and
      * {@link InvokeKind#Special special} calls) have only one callee, but use the same code for
      * simplicity.
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/tutorial/StaticAnalysisTests.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/tutorial/StaticAnalysisTests.java	Thu Mar 28 19:39:14 2019 +0100
@@ -29,21 +29,18 @@
 import java.util.Arrays;
 import java.util.Collection;
 
-import jdk.vm.ci.meta.MetaAccessProvider;
-import jdk.vm.ci.meta.ResolvedJavaField;
-import jdk.vm.ci.meta.ResolvedJavaMethod;
-import jdk.vm.ci.meta.ResolvedJavaType;
-
-import org.junit.Assert;
-import org.junit.Test;
-
 import org.graalvm.compiler.api.test.Graal;
 import org.graalvm.compiler.core.target.Backend;
 import org.graalvm.compiler.core.test.tutorial.StaticAnalysis.MethodState;
 import org.graalvm.compiler.core.test.tutorial.StaticAnalysis.TypeFlow;
-import org.graalvm.compiler.nodes.spi.StampProvider;
-import org.graalvm.compiler.phases.util.Providers;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.runtime.RuntimeProvider;
+import org.junit.Assert;
+import org.junit.Test;
+
+import jdk.vm.ci.meta.ResolvedJavaField;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
 
 public class StaticAnalysisTests {
 
@@ -68,14 +65,11 @@
         Object f;
     }
 
-    private final MetaAccessProvider metaAccess;
-    private final StampProvider stampProvider;
+    private final CoreProviders providers;
 
     public StaticAnalysisTests() {
         Backend backend = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend();
-        Providers providers = backend.getProviders();
-        this.metaAccess = providers.getMetaAccess();
-        this.stampProvider = providers.getStampProvider();
+        providers = backend.getProviders();
     }
 
     static void test01Entry() {
@@ -85,7 +79,7 @@
 
     @Test
     public void test01() {
-        StaticAnalysis sa = new StaticAnalysis(metaAccess, stampProvider);
+        StaticAnalysis sa = new StaticAnalysis(providers);
         sa.addMethod(findMethod(StaticAnalysisTests.class, "test01Entry"));
         sa.finish();
 
@@ -106,7 +100,7 @@
 
     @Test
     public void test02() {
-        StaticAnalysis sa = new StaticAnalysis(metaAccess, stampProvider);
+        StaticAnalysis sa = new StaticAnalysis(providers);
         sa.addMethod(findMethod(StaticAnalysisTests.class, "test02Entry"));
         sa.finish();
 
@@ -134,7 +128,7 @@
 
     @Test
     public void test03() {
-        StaticAnalysis sa = new StaticAnalysis(metaAccess, stampProvider);
+        StaticAnalysis sa = new StaticAnalysis(providers);
         sa.addMethod(findMethod(StaticAnalysisTests.class, "test03Entry"));
         sa.finish();
 
@@ -165,7 +159,7 @@
 
     @Test
     public void test04() {
-        StaticAnalysis sa = new StaticAnalysis(metaAccess, stampProvider);
+        StaticAnalysis sa = new StaticAnalysis(providers);
         sa.addMethod(findMethod(StaticAnalysisTests.class, "test04Entry"));
         sa.finish();
 
@@ -192,7 +186,7 @@
     }
 
     private ResolvedJavaType t(Class<?> clazz) {
-        return metaAccess.lookupJavaType(clazz);
+        return providers.getMetaAccess().lookupJavaType(clazz);
     }
 
     private ResolvedJavaMethod findMethod(Class<?> declaringClass, String name) {
@@ -204,7 +198,7 @@
             }
         }
         assert reflectionMethod != null : "No method with name " + name + " in class " + declaringClass.getName();
-        return metaAccess.lookupJavaMethod(reflectionMethod);
+        return providers.getMetaAccess().lookupJavaMethod(reflectionMethod);
     }
 
     private ResolvedJavaField findField(Class<?> declaringClass, String name) {
@@ -214,6 +208,6 @@
         } catch (NoSuchFieldException | SecurityException ex) {
             throw new AssertionError(ex);
         }
-        return metaAccess.lookupJavaField(reflectionField);
+        return providers.getMetaAccess().lookupJavaField(reflectionField);
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/LIRGenerationPhase.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/LIRGenerationPhase.java	Thu Mar 28 19:39:14 2019 +0100
@@ -67,7 +67,11 @@
         NodeLIRBuilderTool nodeLirBuilder = context.nodeLirBuilder;
         StructuredGraph graph = context.graph;
         ScheduleResult schedule = context.schedule;
-        for (AbstractBlockBase<?> b : lirGenRes.getLIR().getControlFlowGraph().getBlocks()) {
+        AbstractBlockBase<?>[] blocks = lirGenRes.getLIR().getControlFlowGraph().getBlocks();
+        for (AbstractBlockBase<?> b : blocks) {
+            matchBlock(nodeLirBuilder, (Block) b, graph, schedule);
+        }
+        for (AbstractBlockBase<?> b : blocks) {
             emitBlock(nodeLirBuilder, lirGenRes, (Block) b, graph, schedule.getBlockToNodesMap());
         }
         context.lirGen.beforeRegisterAllocation();
@@ -84,6 +88,10 @@
         instructionCounter.add(debug, lir.getLIRforBlock(b).size());
     }
 
+    private static void matchBlock(NodeLIRBuilderTool nodeLirGen, Block b, StructuredGraph graph, ScheduleResult schedule) {
+        nodeLirGen.matchBlock(b, graph, schedule);
+    }
+
     private static boolean verifyPredecessors(LIRGenerationResult lirGenRes, Block block) {
         for (Block pred : block.getPredecessors()) {
             if (!block.isLoopHeader() || !pred.isLoopEnd()) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/NodeLIRBuilder.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/NodeLIRBuilder.java	Thu Mar 28 19:39:14 2019 +0100
@@ -48,6 +48,7 @@
 import org.graalvm.compiler.core.match.MatchPattern;
 import org.graalvm.compiler.core.match.MatchRuleRegistry;
 import org.graalvm.compiler.core.match.MatchStatement;
+import org.graalvm.compiler.debug.DebugCloseable;
 import org.graalvm.compiler.debug.DebugContext;
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.debug.TTY;
@@ -255,7 +256,7 @@
 
             // get ValueKind for input
             final LIRKind valueKind;
-            if (value != null) {
+            if (value != null && !(value instanceof ComplexMatchValue)) {
                 valueKind = value.getValueKind(LIRKind.class);
             } else {
                 assert isPhiInputFromBackedge(phi, i) : String.format("Input %s to phi node %s is not yet available although it is not coming from a loop back edge", node, phi);
@@ -358,10 +359,6 @@
 
             List<Node> nodes = blockMap.get(block);
 
-            // Allow NodeLIRBuilder subclass to specialize code generation of any interesting groups
-            // of instructions
-            matchComplexExpressions(nodes);
-
             boolean trace = traceLIRGeneratorLevel >= 3;
             for (int i = 0; i < nodes.size(); i++) {
                 Node node = nodes.get(i);
@@ -419,11 +416,23 @@
         }
     }
 
+    @Override
     @SuppressWarnings("try")
-    protected void matchComplexExpressions(List<Node> nodes) {
+    public void matchBlock(Block block, StructuredGraph graph, StructuredGraph.ScheduleResult schedule) {
+        try (DebugCloseable matchScope = gen.getMatchScope(block)) {
+            // Allow NodeLIRBuilder subclass to specialize code generation of any interesting groups
+            // of instructions
+            matchComplexExpressions(block, schedule);
+        }
+    }
+
+    @SuppressWarnings("try")
+    protected void matchComplexExpressions(Block block, StructuredGraph.ScheduleResult schedule) {
+
         if (matchRules != null) {
             DebugContext debug = gen.getResult().getLIR().getDebug();
             try (DebugContext.Scope s = debug.scope("MatchComplexExpressions")) {
+                List<Node> nodes = schedule.getBlockToNodesMap().get(block);
                 if (LogVerbose.getValue(nodeOperands.graph().getOptions())) {
                     int i = 0;
                     for (Node node : nodes) {
@@ -441,7 +450,7 @@
                     List<MatchStatement> statements = matchRules.get(node.getClass());
                     if (statements != null) {
                         for (MatchStatement statement : statements) {
-                            if (statement.generate(this, index, node, nodes)) {
+                            if (statement.generate(this, index, node, block, schedule)) {
                                 // Found a match so skip to the next
                                 break;
                             }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/NodeMatchRules.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/NodeMatchRules.java	Thu Mar 28 19:39:14 2019 +0100
@@ -67,38 +67,38 @@
 
 import jdk.vm.ci.meta.Value;
 
-@MatchableNode(nodeClass = ConstantNode.class, shareable = true)
-@MatchableNode(nodeClass = FloatConvertNode.class, inputs = {"value"})
+@MatchableNode(nodeClass = ConstantNode.class, shareable = true, ignoresSideEffects = true)
+@MatchableNode(nodeClass = FloatConvertNode.class, inputs = {"value"}, ignoresSideEffects = true)
 @MatchableNode(nodeClass = FloatingReadNode.class, inputs = {"address"})
 @MatchableNode(nodeClass = IfNode.class, inputs = {"condition"})
-@MatchableNode(nodeClass = SubNode.class, inputs = {"x", "y"})
-@MatchableNode(nodeClass = LeftShiftNode.class, inputs = {"x", "y"})
-@MatchableNode(nodeClass = NarrowNode.class, inputs = {"value"})
+@MatchableNode(nodeClass = SubNode.class, inputs = {"x", "y"}, ignoresSideEffects = true)
+@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 = ReinterpretNode.class, inputs = {"value"})
-@MatchableNode(nodeClass = SignExtendNode.class, inputs = {"value"})
-@MatchableNode(nodeClass = UnsignedRightShiftNode.class, inputs = {"x", "y"})
+@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)
 @MatchableNode(nodeClass = WriteNode.class, inputs = {"address", "value"})
-@MatchableNode(nodeClass = ZeroExtendNode.class, inputs = {"value"})
-@MatchableNode(nodeClass = AndNode.class, inputs = {"x", "y"}, commutative = true)
-@MatchableNode(nodeClass = NegateNode.class, inputs = {"value"})
-@MatchableNode(nodeClass = NotNode.class, inputs = {"value"})
-@MatchableNode(nodeClass = FloatEqualsNode.class, inputs = {"x", "y"}, commutative = true)
-@MatchableNode(nodeClass = FloatLessThanNode.class, inputs = {"x", "y"}, commutative = true)
-@MatchableNode(nodeClass = PointerEqualsNode.class, inputs = {"x", "y"}, commutative = true)
-@MatchableNode(nodeClass = AddNode.class, inputs = {"x", "y"}, commutative = true)
-@MatchableNode(nodeClass = IntegerBelowNode.class, inputs = {"x", "y"}, commutative = true)
-@MatchableNode(nodeClass = IntegerEqualsNode.class, inputs = {"x", "y"}, commutative = true)
-@MatchableNode(nodeClass = IntegerLessThanNode.class, inputs = {"x", "y"}, commutative = true)
-@MatchableNode(nodeClass = MulNode.class, inputs = {"x", "y"}, commutative = true)
-@MatchableNode(nodeClass = IntegerTestNode.class, inputs = {"x", "y"}, commutative = true)
-@MatchableNode(nodeClass = ObjectEqualsNode.class, inputs = {"x", "y"}, commutative = true)
-@MatchableNode(nodeClass = OrNode.class, inputs = {"x", "y"}, commutative = true)
-@MatchableNode(nodeClass = XorNode.class, inputs = {"x", "y"}, commutative = true)
-@MatchableNode(nodeClass = PiNode.class, inputs = {"object"})
+@MatchableNode(nodeClass = ZeroExtendNode.class, inputs = {"value"}, ignoresSideEffects = true)
+@MatchableNode(nodeClass = AndNode.class, inputs = {"x", "y"}, commutative = true, ignoresSideEffects = true)
+@MatchableNode(nodeClass = NegateNode.class, inputs = {"value"}, ignoresSideEffects = true)
+@MatchableNode(nodeClass = NotNode.class, inputs = {"value"}, ignoresSideEffects = true)
+@MatchableNode(nodeClass = FloatEqualsNode.class, inputs = {"x", "y"}, commutative = true, ignoresSideEffects = true)
+@MatchableNode(nodeClass = FloatLessThanNode.class, inputs = {"x", "y"}, commutative = true, ignoresSideEffects = true)
+@MatchableNode(nodeClass = PointerEqualsNode.class, inputs = {"x", "y"}, commutative = true, ignoresSideEffects = true)
+@MatchableNode(nodeClass = AddNode.class, inputs = {"x", "y"}, commutative = true, ignoresSideEffects = true)
+@MatchableNode(nodeClass = IntegerBelowNode.class, inputs = {"x", "y"}, commutative = true, ignoresSideEffects = true)
+@MatchableNode(nodeClass = IntegerEqualsNode.class, inputs = {"x", "y"}, commutative = true, ignoresSideEffects = true)
+@MatchableNode(nodeClass = IntegerLessThanNode.class, inputs = {"x", "y"}, commutative = true, ignoresSideEffects = true)
+@MatchableNode(nodeClass = MulNode.class, inputs = {"x", "y"}, commutative = true, ignoresSideEffects = true)
+@MatchableNode(nodeClass = IntegerTestNode.class, inputs = {"x", "y"}, commutative = true, ignoresSideEffects = true)
+@MatchableNode(nodeClass = ObjectEqualsNode.class, inputs = {"x", "y"}, commutative = true, ignoresSideEffects = true)
+@MatchableNode(nodeClass = OrNode.class, inputs = {"x", "y"}, commutative = true, ignoresSideEffects = true)
+@MatchableNode(nodeClass = XorNode.class, inputs = {"x", "y"}, commutative = true, ignoresSideEffects = true)
+@MatchableNode(nodeClass = PiNode.class, inputs = {"object"}, ignoresSideEffects = true)
 @MatchableNode(nodeClass = LogicCompareAndSwapNode.class, inputs = {"address", "expectedValue", "newValue"})
 @MatchableNode(nodeClass = ValueCompareAndSwapNode.class, inputs = {"address", "expectedValue", "newValue"})
-@MatchableNode(nodeClass = RightShiftNode.class, inputs = {"x", "y"})
+@MatchableNode(nodeClass = RightShiftNode.class, inputs = {"x", "y"}, ignoresSideEffects = true)
 public abstract class NodeMatchRules {
 
     NodeLIRBuilder lirBuilder;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchContext.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchContext.java	Thu Mar 28 19:39:14 2019 +0100
@@ -24,40 +24,120 @@
 
 package org.graalvm.compiler.core.match;
 
+import static org.graalvm.compiler.core.common.cfg.AbstractControlFlowGraph.dominates;
+import static org.graalvm.compiler.core.common.cfg.AbstractControlFlowGraph.strictlyDominates;
 import static org.graalvm.compiler.debug.DebugOptions.LogVerbose;
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Iterator;
 import java.util.List;
 
 import jdk.internal.vm.compiler.collections.EconomicMap;
 import jdk.internal.vm.compiler.collections.Equivalence;
+import org.graalvm.compiler.core.common.cfg.BlockMap;
 import org.graalvm.compiler.core.gen.NodeLIRBuilder;
 import org.graalvm.compiler.core.match.MatchPattern.Result;
+import org.graalvm.compiler.debug.CounterKey;
 import org.graalvm.compiler.debug.DebugContext;
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeMap;
+import org.graalvm.compiler.nodes.PhiNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.calc.FloatingNode;
+import org.graalvm.compiler.nodes.cfg.Block;
 import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
 
 /**
  * Container for state captured during a match.
  */
 public class MatchContext {
+    private static final CounterKey MatchContextSuccessDifferentBlocks = DebugContext.counter("MatchContextSuccessDifferentBlocks");
 
     private final Node root;
 
-    private final List<Node> nodes;
-
     private final MatchStatement rule;
+    private final StructuredGraph.ScheduleResult schedule;
 
     private EconomicMap<String, NamedNode> namedNodes;
 
-    private ArrayList<Node> consumed;
+    /**
+     * A node consumed by a match. Keeps track of whether side effects can be ignored.
+     */
+    static final class ConsumedNode {
+        final Node node;
+        final boolean ignoresSideEffects;
 
-    private int startIndex;
+        ConsumedNode(Node node, boolean ignoresSideEffects) {
+            this.node = node;
+            this.ignoresSideEffects = ignoresSideEffects;
+        }
+    }
 
-    private int endIndex;
+    /**
+     * The collection of nodes consumed by this match.
+     */
+    static final class ConsumedNodes implements Iterable<ConsumedNode> {
+        private ArrayList<ConsumedNode> nodes;
+
+        ConsumedNodes() {
+            this.nodes = null;
+        }
+
+        public void add(Node node, boolean ignoresSideEffects) {
+            if (nodes == null) {
+                nodes = new ArrayList<>(2);
+            }
+            nodes.add(new ConsumedNode(node, ignoresSideEffects));
+        }
+
+        public boolean contains(Node node) {
+            for (ConsumedNode c : nodes) {
+                if (c.node == node) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public ConsumedNode find(Node node) {
+            for (ConsumedNode c : nodes) {
+                if (c.node == node) {
+                    return c;
+                }
+            }
+            return null;
+        }
+
+        @Override
+        public String toString() {
+            Node[] arr = new Node[nodes.size()];
+            int i = 0;
+            for (ConsumedNode c : nodes) {
+                arr[i++] = c.node;
+            }
+            return Arrays.toString(arr);
+        }
+
+        @Override
+        public Iterator<ConsumedNode> iterator() {
+            return nodes.iterator();
+        }
+    }
+
+    private ConsumedNodes consumed = new ConsumedNodes();
+
+    private Block rootBlock;
+    private int rootIndex;
+
+    /**
+     * Block and index in the block at which the match should be emitted. Differs from
+     * rootBlock/rootIndex for (ZeroExtend Read=access) for instance: match should be emitted where
+     * the Read is.
+     */
+    private int emitIndex;
+    private Block emitBlock;
 
     private final NodeLIRBuilder builder;
 
@@ -71,14 +151,15 @@
         }
     }
 
-    public MatchContext(NodeLIRBuilder builder, MatchStatement rule, int index, Node node, List<Node> nodes) {
+    public MatchContext(NodeLIRBuilder builder, MatchStatement rule, int index, Node node, Block rootBlock, StructuredGraph.ScheduleResult schedule) {
         this.builder = builder;
         this.rule = rule;
         this.root = node;
-        this.nodes = nodes;
-        assert index == nodes.indexOf(node);
+        assert index == schedule.getBlockToNodesMap().get(rootBlock).indexOf(node);
+        this.schedule = schedule;
         // The root should be the last index since all the inputs must be scheduled before it.
-        startIndex = endIndex = index;
+        this.rootBlock = rootBlock;
+        rootIndex = index;
     }
 
     public Node getRoot() {
@@ -103,28 +184,177 @@
     }
 
     public Result validate() {
-        // Ensure that there's no unsafe work in between these operations.
-        for (int i = startIndex; i <= endIndex; i++) {
+        Result result = findEarlyPosition();
+        if (result != Result.OK) {
+            return result;
+        }
+        findLatePosition();
+        assert emitIndex == rootIndex || consumed.find(root).ignoresSideEffects;
+        return verifyInputs();
+    }
+
+    private Result findEarlyPosition() {
+        int startIndexSideEffect = -1;
+        int endIndexSideEffect = -1;
+        final NodeMap<Block> nodeToBlockMap = schedule.getNodeToBlockMap();
+        final BlockMap<List<Node>> blockToNodesMap = schedule.getBlockToNodesMap();
+
+        // Nodes affected by side effects must be in the same block
+        for (ConsumedNode cn : consumed) {
+            if (!cn.ignoresSideEffects) {
+                Block b = nodeToBlockMap.get(cn.node);
+                if (emitBlock == null) {
+                    emitBlock = b;
+                    startIndexSideEffect = endIndexSideEffect = blockToNodesMap.get(b).indexOf(cn.node);
+                } else if (emitBlock == b) {
+                    int index = blockToNodesMap.get(b).indexOf(cn.node);
+                    startIndexSideEffect = Math.min(startIndexSideEffect, index);
+                    endIndexSideEffect = Math.max(endIndexSideEffect, index);
+                } else {
+                    logFailedMatch("nodes affected by side effects in different blocks %s", cn.node);
+                    return Result.notInBlock(cn.node, rule.getPattern());
+                }
+            }
+        }
+        if (emitBlock != null) {
+            // There must be no side effects between nodes that are affected by side effects
+            assert startIndexSideEffect != -1 && endIndexSideEffect != -1;
+            final List<Node> nodes = blockToNodesMap.get(emitBlock);
+            for (int i = startIndexSideEffect; i <= endIndexSideEffect; i++) {
+                Node node = nodes.get(i);
+                if (!sideEffectFree(node) && !consumed.contains(node)) {
+                    logFailedMatch("unexpected side effect %s", node);
+                    return Result.notSafe(node, rule.getPattern());
+                }
+            }
+            // early position is at the node affected by side effects the closest to the root
+            emitIndex = endIndexSideEffect;
+        } else {
+            // Nodes not affected by side effect: early position is at the root
+            emitBlock = nodeToBlockMap.get(root);
+            emitIndex = rootIndex;
+        }
+        return Result.OK;
+    }
+
+    private static boolean sideEffectFree(Node node) {
+        // The order of evaluation of these nodes controlled by data dependence so they
+        // don't interfere with this match.
+        return node instanceof VirtualObjectNode || node instanceof FloatingNode;
+    }
+
+    private void findLatePosition() {
+        // If emit position is at a node affected by side effects that's followed by side effect
+        // free nodes, the node can be emitted later. This helps when the match has inputs that are
+        // late in the block.
+        int index = rootIndex;
+        if (emitBlock != rootBlock) {
+            index = schedule.getBlockToNodesMap().get(emitBlock).size() - 1;
+        }
+        final List<Node> emitBlockNodes = schedule.getBlockToNodesMap().get(emitBlock);
+        for (int i = emitIndex + 1; i <= index; i++) {
+            Node node = emitBlockNodes.get(i);
+            ConsumedNode cn = consumed.find(node);
+            if (cn == null) {
+                if (!sideEffectFree(node)) {
+                    return;
+                }
+            } else {
+                assert cn.ignoresSideEffects;
+                emitIndex = i;
+            }
+        }
+    }
+
+    private Result verifyInputs() {
+        DebugContext debug = root.getDebug();
+        if (emitBlock != rootBlock) {
+            assert consumed.find(root).ignoresSideEffects;
+            Result result = verifyInputsDifferentBlock(root);
+            if (result == Result.OK) {
+                MatchContextSuccessDifferentBlocks.increment(debug);
+            }
+            return result;
+        }
+        // We are going to emit the match at emitIndex. We need to make sure nodes of the match
+        // between emitIndex and rootIndex don't have inputs after position emitIndex that would
+        // make emitIndex an illegal position.
+        final List<Node> nodes = schedule.getBlockToNodesMap().get(rootBlock);
+        for (int i = emitIndex + 1; i <= rootIndex; i++) {
             Node node = nodes.get(i);
-            if (node instanceof VirtualObjectNode || node instanceof FloatingNode) {
-                // The order of evaluation of these nodes controlled by data dependence so they
-                // don't interfere with this match.
-                continue;
-            } else if ((consumed == null || !consumed.contains(node)) && node != root) {
-                if (LogVerbose.getValue(root.getOptions())) {
-                    DebugContext debug = root.getDebug();
-                    debug.log("unexpected node %s", node);
-                    for (int j = startIndex; j <= endIndex; j++) {
-                        Node theNode = nodes.get(j);
-                        debug.log("%s(%s) %1s", (consumed != null && consumed.contains(theNode) || theNode == root) ? "*" : " ", theNode.getUsageCount(), theNode);
+            ConsumedNode cn = consumed.find(node);
+            if (cn != null) {
+                assert cn.ignoresSideEffects;
+                for (Node in : node.inputs()) {
+                    if (!consumed.contains(in)) {
+                        for (int j = emitIndex + 1; j < i; j++) {
+                            if (nodes.get(j) == in) {
+                                logFailedMatch("Earliest position in block is too late %s", in);
+                                assert consumed.find(root).ignoresSideEffects;
+                                assert verifyInputsDifferentBlock(root) != Result.OK;
+                                return Result.tooLate(node, rule.getPattern());
+                            }
+                        }
                     }
                 }
-                return Result.notSafe(node, rule.getPattern());
+            }
+        }
+        assert verifyInputsDifferentBlock(root) == Result.OK;
+        return Result.OK;
+    }
+
+    private Result verifyInputsDifferentBlock(Node node) {
+        // Is there an input that's not part of the match that's after the emit position?
+        for (Node in : node.inputs()) {
+            if (in instanceof PhiNode) {
+                Block b = schedule.getNodeToBlockMap().get(((PhiNode) in).merge());
+                if (dominates(b, emitBlock)) {
+                    continue;
+                }
+            } else {
+                Block b = schedule.getNodeToBlockMap().get(in);
+                if (strictlyDominates(b, emitBlock) || (b == emitBlock && schedule.getBlockToNodesMap().get(emitBlock).indexOf(in) <= emitIndex)) {
+                    continue;
+                }
+            }
+            ConsumedNode cn = consumed.find(in);
+            if (cn == null) {
+                logFailedMatch("Earliest position in block is too late %s", in);
+                return Result.tooLate(node, rule.getPattern());
+            }
+            assert cn.ignoresSideEffects;
+            Result res = verifyInputsDifferentBlock(in);
+            if (res != Result.OK) {
+                return res;
             }
         }
         return Result.OK;
     }
 
+    private void logFailedMatch(String s, Node node) {
+        if (LogVerbose.getValue(root.getOptions())) {
+            DebugContext debug = root.getDebug();
+            debug.log(s, node);
+            int startIndex = emitIndex;
+            if (emitBlock != rootBlock) {
+                int endIndex = schedule.getBlockToNodesMap().get(emitBlock).size() - 1;
+                final List<Node> emitBlockNodes = schedule.getBlockToNodesMap().get(emitBlock);
+                debug.log("%s:", emitBlock);
+                for (int j = startIndex; j <= endIndex; j++) {
+                    Node theNode = emitBlockNodes.get(j);
+                    debug.log("%s(%s) %1s", consumed.contains(theNode) ? "*" : " ", theNode.getUsageCount(), theNode);
+                }
+                startIndex = 0;
+            }
+            debug.log("%s:", rootBlock);
+            final List<Node> nodes = schedule.getBlockToNodesMap().get(rootBlock);
+            for (int j = startIndex; j <= rootIndex; j++) {
+                Node theNode = nodes.get(j);
+                debug.log("%s(%s) %1s", consumed.contains(theNode) ? "*" : " ", theNode.getUsageCount(), theNode);
+            }
+        }
+    }
+
     /**
      * Mark the interior nodes with INTERIOR_MATCH and set the Value of the root to be the result.
      * During final LIR generation it will be evaluated to produce the actual LIR value.
@@ -133,20 +363,28 @@
      */
     public void setResult(ComplexMatchResult result) {
         ComplexMatchValue value = new ComplexMatchValue(result);
+        Node emitNode = schedule.getBlockToNodesMap().get(emitBlock).get(emitIndex);
         DebugContext debug = root.getDebug();
         if (debug.isLogEnabled()) {
-            debug.log("matched %s %s", rule.getName(), rule.getPattern());
+            debug.log("matched %s %s%s", rule.getName(), rule.getPattern(), emitIndex != rootIndex ? " skipping side effects" : "");
             debug.log("with nodes %s", rule.formatMatch(root));
         }
-        if (consumed != null) {
-            for (Node node : consumed) {
-                // All the interior nodes should be skipped during the normal doRoot calls in
-                // NodeLIRBuilder so mark them as interior matches. The root of the match will get a
-                // closure which will be evaluated to produce the final LIR.
-                builder.setMatchResult(node, ComplexMatchValue.INTERIOR_MATCH);
+        for (ConsumedNode cn : consumed) {
+            if (cn.node == root || cn.node == emitNode) {
+                continue;
             }
+            // All the interior nodes should be skipped during the normal doRoot calls in
+            // NodeLIRBuilder so mark them as interior matches. The root of the match will get a
+            // closure which will be evaluated to produce the final LIR.
+            builder.setMatchResult(cn.node, ComplexMatchValue.INTERIOR_MATCH);
         }
-        builder.setMatchResult(root, value);
+        builder.setMatchResult(emitNode, value);
+        if (root != emitNode) {
+            // Match is not emitted at the position of root in the block but the uses of root needs
+            // the result of the match so add a ComplexMatchValue that will simply return the result
+            // of the actual match above.
+            builder.setMatchResult(root, new ComplexMatchValue(gen -> gen.operand(emitNode)));
+        }
     }
 
     /**
@@ -154,24 +392,18 @@
      *
      * @return Result.OK if the node can be safely consumed.
      */
-    public Result consume(Node node) {
+    public Result consume(Node node, boolean ignoresSideEffects, boolean atRoot) {
+        if (atRoot) {
+            consumed.add(node, ignoresSideEffects);
+            return Result.OK;
+        }
         assert MatchPattern.isSingleValueUser(node) : "should have already been checked";
 
-        // Check NOT_IN_BLOCK first since that usually implies ALREADY_USED
-        int index = nodes.indexOf(node);
-        if (index == -1) {
-            return Result.notInBlock(node, rule.getPattern());
-        }
-
         if (builder.hasOperand(node)) {
             return Result.alreadyUsed(node, rule.getPattern());
         }
 
-        startIndex = Math.min(startIndex, index);
-        if (consumed == null) {
-            consumed = new ArrayList<>(2);
-        }
-        consumed.add(node);
+        consumed.add(node, ignoresSideEffects);
         return Result.OK;
     }
 
@@ -194,6 +426,6 @@
 
     @Override
     public String toString() {
-        return String.format("%s %s (%d, %d) consumed %s", rule, root, startIndex, endIndex, consumed != null ? Arrays.toString(consumed.toArray()) : "");
+        return String.format("%s %s (%s/%d, %s/%d) consumed %s", rule, root, rootBlock, rootIndex, emitBlock, emitIndex, consumed);
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchPattern.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchPattern.java	Thu Mar 28 19:39:14 2019 +0100
@@ -30,6 +30,7 @@
 import org.graalvm.compiler.graph.Position;
 import org.graalvm.compiler.nodeinfo.InputType;
 import org.graalvm.compiler.nodeinfo.Verbosity;
+import org.graalvm.compiler.nodes.calc.FloatingNode;
 
 /**
  * A simple recursive pattern matcher for a DAG of nodes.
@@ -45,6 +46,7 @@
         NOT_IN_BLOCK,
         NOT_SAFE,
         ALREADY_USED,
+        TOO_LATE,
     }
 
     /**
@@ -70,6 +72,7 @@
         private static final CounterKey MatchResult_NOT_IN_BLOCK = DebugContext.counter("MatchResult_NOT_IN_BLOCK");
         private static final CounterKey MatchResult_NOT_SAFE = DebugContext.counter("MatchResult_NOT_SAFE");
         private static final CounterKey MatchResult_ALREADY_USED = DebugContext.counter("MatchResult_ALREADY_USED");
+        private static final CounterKey MatchResult_TOO_LATE = DebugContext.counter("MatchResult_TOO_LATE");
 
         static final Result OK = new Result(MatchResultCode.OK, null, null);
         private static final Result CACHED_WRONG_CLASS = new Result(MatchResultCode.WRONG_CLASS, null, null);
@@ -78,6 +81,7 @@
         private static final Result CACHED_NOT_IN_BLOCK = new Result(MatchResultCode.NOT_IN_BLOCK, null, null);
         private static final Result CACHED_NOT_SAFE = new Result(MatchResultCode.NOT_SAFE, null, null);
         private static final Result CACHED_ALREADY_USED = new Result(MatchResultCode.ALREADY_USED, null, null);
+        private static final Result CACHED_TOO_LATE = new Result(MatchResultCode.TOO_LATE, null, null);
 
         static Result wrongClass(Node node, MatchPattern matcher) {
             MatchResult_WRONG_CLASS.increment(node.getDebug());
@@ -109,6 +113,11 @@
             return node.getDebug().isLogEnabled() ? new Result(MatchResultCode.ALREADY_USED, node, matcher) : CACHED_ALREADY_USED;
         }
 
+        static Result tooLate(Node node, MatchPattern matcher) {
+            MatchResult_TOO_LATE.increment(node.getDebug());
+            return node.getDebug().isLogEnabled() ? new Result(MatchResultCode.TOO_LATE, node, matcher) : CACHED_TOO_LATE;
+        }
+
         @Override
         public String toString() {
             if (code == MatchResultCode.OK) {
@@ -149,39 +158,49 @@
      */
     private final boolean singleUser;
 
+    /**
+     * Can this node be subsumed into a match even if there are side effecting nodes between this
+     * node and the match.
+     */
+    private final boolean ignoresSideEffects;
+
     private static final MatchPattern[] EMPTY_PATTERNS = new MatchPattern[0];
 
-    public MatchPattern(String name, boolean singleUser) {
-        this(null, name, singleUser);
+    public MatchPattern(String name, boolean singleUser, boolean ignoresSideEffects) {
+        this(null, name, singleUser, ignoresSideEffects);
     }
 
-    public MatchPattern(Class<? extends Node> nodeClass, String name, boolean singleUser) {
+    public MatchPattern(Class<? extends Node> nodeClass, String name, boolean singleUser, boolean ignoresSideEffects) {
         this.nodeClass = nodeClass;
         this.name = name;
         this.singleUser = singleUser;
+        this.ignoresSideEffects = ignoresSideEffects;
         this.patterns = EMPTY_PATTERNS;
         this.inputs = null;
+        assert !ignoresSideEffects || FloatingNode.class.isAssignableFrom(nodeClass);
     }
 
-    private MatchPattern(Class<? extends Node> nodeClass, String name, boolean singleUser, MatchPattern[] patterns, Position[] inputs) {
+    private MatchPattern(Class<? extends Node> nodeClass, String name, boolean singleUser, boolean ignoresSideEffects, MatchPattern[] patterns, Position[] inputs) {
         assert inputs == null || inputs.length == patterns.length;
         this.nodeClass = nodeClass;
         this.name = name;
         this.singleUser = singleUser;
+        this.ignoresSideEffects = ignoresSideEffects;
         this.patterns = patterns;
         this.inputs = inputs;
+        assert !ignoresSideEffects || FloatingNode.class.isAssignableFrom(nodeClass);
     }
 
-    public MatchPattern(Class<? extends Node> nodeClass, String name, MatchPattern first, Position[] inputs, boolean singleUser) {
-        this(nodeClass, name, singleUser, new MatchPattern[]{first}, inputs);
+    public MatchPattern(Class<? extends Node> nodeClass, String name, MatchPattern first, Position[] inputs, boolean singleUser, boolean ignoresSideEffects) {
+        this(nodeClass, name, singleUser, ignoresSideEffects, new MatchPattern[]{first}, inputs);
     }
 
-    public MatchPattern(Class<? extends Node> nodeClass, String name, MatchPattern first, MatchPattern second, Position[] inputs, boolean singleUser) {
-        this(nodeClass, name, singleUser, new MatchPattern[]{first, second}, inputs);
+    public MatchPattern(Class<? extends Node> nodeClass, String name, MatchPattern first, MatchPattern second, Position[] inputs, boolean singleUser, boolean ignoresSideEffects) {
+        this(nodeClass, name, singleUser, ignoresSideEffects, new MatchPattern[]{first, second}, inputs);
     }
 
-    public MatchPattern(Class<? extends Node> nodeClass, String name, MatchPattern first, MatchPattern second, MatchPattern third, Position[] inputs, boolean singleUser) {
-        this(nodeClass, name, singleUser, new MatchPattern[]{first, second, third}, inputs);
+    public MatchPattern(Class<? extends Node> nodeClass, String name, MatchPattern first, MatchPattern second, MatchPattern third, Position[] inputs, boolean singleUser, boolean ignoresSideEffects) {
+        this(nodeClass, name, singleUser, ignoresSideEffects, new MatchPattern[]{first, second, third}, inputs);
     }
 
     Class<? extends Node> nodeClass() {
@@ -215,8 +234,8 @@
         if (result != Result.OK) {
             return result;
         }
-        if (singleUser && !atRoot) {
-            result = context.consume(node);
+        if (singleUser) {
+            result = context.consume(node, ignoresSideEffects, atRoot);
             if (result != Result.OK) {
                 return result;
             }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchStatement.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchStatement.java	Thu Mar 28 19:39:14 2019 +0100
@@ -26,8 +26,6 @@
 
 import static org.graalvm.compiler.debug.DebugOptions.LogVerbose;
 
-import java.util.List;
-
 import org.graalvm.compiler.core.gen.NodeLIRBuilder;
 import org.graalvm.compiler.core.match.MatchPattern.MatchResultCode;
 import org.graalvm.compiler.core.match.MatchPattern.Result;
@@ -38,6 +36,8 @@
 import org.graalvm.compiler.nodeinfo.Verbosity;
 
 import jdk.vm.ci.meta.Value;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.cfg.Block;
 
 /**
  * A named {@link MatchPattern} along with a {@link MatchGenerator} that can be evaluated to replace
@@ -80,20 +80,21 @@
      *
      * @param builder the current builder instance.
      * @param node the node to be matched
-     * @param nodes the nodes in the current block
+     * @param block the current block
+     * @param schedule the schedule that's being used
      * @return true if the statement matched something and set a {@link ComplexMatchResult} to be
      *         evaluated by the NodeLIRBuilder.
      */
-    public boolean generate(NodeLIRBuilder builder, int index, Node node, List<Node> nodes) {
+    public boolean generate(NodeLIRBuilder builder, int index, Node node, Block block, StructuredGraph.ScheduleResult schedule) {
         DebugContext debug = node.getDebug();
-        assert index == nodes.indexOf(node);
+        assert index == schedule.getBlockToNodesMap().get(block).indexOf(node);
         // Check that the basic shape matches
         Result result = pattern.matchShape(node, this);
         if (result != Result.OK) {
             return false;
         }
         // Now ensure that the other safety constraints are matched.
-        MatchContext context = new MatchContext(builder, this, index, node, nodes);
+        MatchContext context = new MatchContext(builder, this, index, node, block, schedule);
         result = pattern.matchUsage(node, context);
         if (result == Result.OK) {
             // Invoke the generator method and set the result if it's non null.
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchableNode.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchableNode.java	Thu Mar 28 19:39:14 2019 +0100
@@ -64,4 +64,6 @@
      * Can a node with multiple uses be safely matched by a rule.
      */
     boolean shareable() default false;
+
+    boolean ignoresSideEffects() default false;
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugContext.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugContext.java	Thu Mar 28 19:39:14 2019 +0100
@@ -239,15 +239,9 @@
             this.unscopedTimers = parseUnscopedMetricSpec(Timers.getValue(options), "".equals(timeValue), true);
             this.unscopedMemUseTrackers = parseUnscopedMetricSpec(MemUseTrackers.getValue(options), "".equals(trackMemUseValue), true);
 
-            if (unscopedTimers != null || timeValue != null) {
-                if (!GraalServices.isCurrentThreadCpuTimeSupported()) {
-                    throw new IllegalArgumentException("Time and Timers options require VM support for querying CPU time");
-                }
-            }
-
             if (unscopedMemUseTrackers != null || trackMemUseValue != null) {
                 if (!GraalServices.isThreadAllocatedMemorySupported()) {
-                    throw new IllegalArgumentException("MemUseTrackers and TrackMemUse options require VM support for querying thread allocated memory");
+                    TTY.println("WARNING: Missing VM support for MemUseTrackers and TrackMemUse options so all reported memory usage will be 0");
                 }
             }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/LogStream.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/LogStream.java	Thu Mar 28 19:39:14 2019 +0100
@@ -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
@@ -87,7 +87,7 @@
     /**
      * The system dependent line separator.
      */
-    public static final String LINE_SEPARATOR = System.getProperty("line.separator");
+    public static final String LINE_SEPARATOR = System.lineSeparator();
 
     /**
      * Creates a new log stream.
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/MemUseTrackerKey.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/MemUseTrackerKey.java	Thu Mar 28 19:39:14 2019 +0100
@@ -56,6 +56,6 @@
     MemUseTrackerKey doc(String string);
 
     static long getCurrentThreadAllocatedBytes() {
-        return GraalServices.getCurrentThreadAllocatedBytes();
+        return GraalServices.isThreadAllocatedMemorySupported() ? GraalServices.getCurrentThreadAllocatedBytes() : 0;
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/Versions.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/Versions.java	Thu Mar 28 19:39:14 2019 +0100
@@ -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
@@ -32,11 +32,13 @@
 import java.util.HashMap;
 import java.util.Map;
 
+import jdk.vm.ci.services.Services;
+
 /** Avoid using directly. Only public for the needs of unit testing. */
 public final class Versions {
     static final Versions VERSIONS;
     static {
-        String home = System.getProperty("java.home");
+        String home = Services.getSavedProperties().get("java.home");
         VERSIONS = new Versions(home == null ? null : new File(home).toPath());
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Edges.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Edges.java	Thu Mar 28 19:39:14 2019 +0100
@@ -26,7 +26,6 @@
 
 import static org.graalvm.compiler.graph.Graph.isModificationCountsEnabled;
 import static org.graalvm.compiler.graph.Node.NOT_ITERABLE;
-import static org.graalvm.compiler.graph.UnsafeAccess.UNSAFE;
 
 import java.util.ArrayList;
 import java.util.Iterator;
@@ -34,6 +33,9 @@
 import org.graalvm.compiler.core.common.Fields;
 import org.graalvm.compiler.core.common.FieldsScanner;
 import org.graalvm.compiler.graph.NodeClass.EdgeInfo;
+import org.graalvm.compiler.serviceprovider.GraalUnsafeAccess;
+
+import sun.misc.Unsafe;
 
 /**
  * Describes {@link Node} fields representing the set of inputs for the node or the set of the
@@ -41,6 +43,8 @@
  */
 public abstract class Edges extends Fields {
 
+    private static final Unsafe UNSAFE = GraalUnsafeAccess.getUnsafe();
+
     /**
      * Constants denoting whether a set of edges are inputs or successors.
      */
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Node.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Node.java	Thu Mar 28 19:39:14 2019 +0100
@@ -27,7 +27,7 @@
 import static org.graalvm.compiler.graph.Edges.Type.Inputs;
 import static org.graalvm.compiler.graph.Edges.Type.Successors;
 import static org.graalvm.compiler.graph.Graph.isModificationCountsEnabled;
-import static org.graalvm.compiler.graph.UnsafeAccess.UNSAFE;
+import static org.graalvm.compiler.serviceprovider.GraalUnsafeAccess.getUnsafe;
 
 import java.lang.annotation.ElementType;
 import java.lang.annotation.RetentionPolicy;
@@ -61,6 +61,7 @@
 import org.graalvm.compiler.nodeinfo.Verbosity;
 import org.graalvm.compiler.options.OptionValues;
 
+import jdk.vm.ci.services.Services;
 import sun.misc.Unsafe;
 
 /**
@@ -86,9 +87,11 @@
 @NodeInfo
 public abstract class Node implements Cloneable, Formattable, NodeInterface {
 
+    private static final Unsafe UNSAFE = getUnsafe();
+
     public static final NodeClass<?> TYPE = null;
 
-    public static final boolean TRACK_CREATION_POSITION = Boolean.getBoolean("debug.graal.TrackNodeCreationPosition");
+    public static final boolean TRACK_CREATION_POSITION = Boolean.parseBoolean(Services.getSavedProperties().get("debug.graal.TrackNodeCreationPosition"));
 
     static final int DELETED_ID_START = -1000000000;
     static final int INITIAL_ID = -1;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeClass.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeClass.java	Thu Mar 28 19:39:14 2019 +0100
@@ -24,11 +24,13 @@
 
 package org.graalvm.compiler.graph;
 
+import static org.graalvm.compiler.core.common.Fields.translateInto;
 import static org.graalvm.compiler.debug.GraalError.shouldNotReachHere;
+import static org.graalvm.compiler.graph.Edges.translateInto;
 import static org.graalvm.compiler.graph.Graph.isModificationCountsEnabled;
 import static org.graalvm.compiler.graph.InputEdges.translateInto;
 import static org.graalvm.compiler.graph.Node.WithAllEdges;
-import static org.graalvm.compiler.graph.UnsafeAccess.UNSAFE;
+import static org.graalvm.compiler.serviceprovider.GraalUnsafeAccess.getUnsafe;
 
 import java.lang.annotation.Annotation;
 import java.lang.reflect.AnnotatedElement;
@@ -69,6 +71,8 @@
 import org.graalvm.compiler.nodeinfo.NodeSize;
 import org.graalvm.compiler.nodeinfo.Verbosity;
 
+import sun.misc.Unsafe;
+
 /**
  * Metadata for every {@link Node} type. The metadata includes:
  * <ul>
@@ -79,6 +83,7 @@
  */
 public final class NodeClass<T> extends FieldIntrospection<T> {
 
+    private static final Unsafe UNSAFE = getUnsafe();
     // Timers for creation of a NodeClass instance
     private static final TimerKey Init_FieldScanning = DebugContext.timer("NodeClass.Init.FieldScanning");
     private static final TimerKey Init_FieldScanningInner = DebugContext.timer("NodeClass.Init.FieldScanning.Inner");
@@ -128,7 +133,7 @@
     public static <T> NodeClass<T> get(Class<T> clazz) {
         int numTries = 0;
         while (true) {
-            boolean shouldBeInitializedBefore = UnsafeAccess.UNSAFE.shouldBeInitialized(clazz);
+            boolean shouldBeInitializedBefore = UNSAFE.shouldBeInitialized(clazz);
 
             NodeClass<T> result = getUnchecked(clazz);
             if (result != null || clazz == NODE_CLASS) {
@@ -141,13 +146,13 @@
              * information without failing gates.
              */
             numTries++;
-            boolean shouldBeInitializedAfter = UnsafeAccess.UNSAFE.shouldBeInitialized(clazz);
+            boolean shouldBeInitializedAfter = UNSAFE.shouldBeInitialized(clazz);
             String msg = "GR-9537 Reflective field access of TYPE field returned null. This is probably a bug in HotSpot class initialization. " +
                             " clazz: " + clazz.getTypeName() + ", numTries: " + numTries +
                             ", shouldBeInitializedBefore: " + shouldBeInitializedBefore + ", shouldBeInitializedAfter: " + shouldBeInitializedAfter;
             if (numTries <= 100) {
                 TTY.println(msg);
-                UnsafeAccess.UNSAFE.ensureClassInitialized(clazz);
+                UNSAFE.ensureClassInitialized(clazz);
             } else {
                 throw GraalError.shouldNotReachHere(msg);
             }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeSourcePosition.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeSourcePosition.java	Thu Mar 28 19:39:14 2019 +0100
@@ -40,11 +40,12 @@
 import jdk.vm.ci.meta.JavaMethod;
 import jdk.vm.ci.meta.MetaUtil;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.services.Services;
 
 public class NodeSourcePosition extends BytecodePosition implements Iterable<NodeSourcePosition> {
 
-    private static final boolean STRICT_SOURCE_POSITION = Boolean.getBoolean("debug.graal.SourcePositionStrictChecks");
-    private static final boolean SOURCE_POSITION_BYTECODES = Boolean.getBoolean("debug.graal.SourcePositionDisassemble");
+    private static final boolean STRICT_SOURCE_POSITION = Boolean.parseBoolean(Services.getSavedProperties().get("debug.graal.SourcePositionStrictChecks"));
+    private static final boolean SOURCE_POSITION_BYTECODES = Boolean.parseBoolean(Services.getSavedProperties().get("debug.graal.SourcePositionDisassemble"));
 
     private final int hashCode;
     private final Marker marker;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/UnsafeAccess.java	Thu Mar 28 11:06:00 2019 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-/*
- * Copyright (c) 2012, 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.graph;
-
-import java.lang.reflect.Field;
-
-import sun.misc.Unsafe;
-
-/**
- * Package private access to the {@link Unsafe} capability.
- */
-class UnsafeAccess {
-
-    static final Unsafe UNSAFE = initUnsafe();
-
-    private static Unsafe initUnsafe() {
-        try {
-            // Fast path when we are trusted.
-            return Unsafe.getUnsafe();
-        } catch (SecurityException se) {
-            // Slow path when we are not trusted.
-            try {
-                Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
-                theUnsafe.setAccessible(true);
-                return (Unsafe) theUnsafe.get(Unsafe.class);
-            } catch (Exception e) {
-                throw new RuntimeException("exception while trying to get Unsafe", e);
-            }
-        }
-    }
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackendFactory.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackendFactory.java	Thu Mar 28 19:39:14 2019 +0100
@@ -166,7 +166,8 @@
                     HotSpotHostForeignCallsProvider foreignCalls, HotSpotMetaAccessProvider metaAccess, HotSpotSnippetReflectionProvider snippetReflection,
                     HotSpotReplacementsImpl replacements, HotSpotWordTypes wordTypes) {
         Plugins plugins = HotSpotGraphBuilderPlugins.create(compilerConfiguration, config, wordTypes, metaAccess, constantReflection, snippetReflection, foreignCalls, replacements);
-        AArch64GraphBuilderPlugins.register(plugins, replacements.getDefaultReplacementBytecodeProvider(), false);
+        AArch64GraphBuilderPlugins.register(plugins, replacements.getDefaultReplacementBytecodeProvider(), false, //
+                        /* registerMathPlugins */true);
         return plugins;
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotLIRGenerator.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotLIRGenerator.java	Thu Mar 28 19:39:14 2019 +0100
@@ -113,7 +113,7 @@
     private HotSpotDebugInfoBuilder debugInfoBuilder;
 
     protected AArch64HotSpotLIRGenerator(HotSpotProviders providers, GraalHotSpotVMConfig config, LIRGenerationResult lirGenRes) {
-        this(new AArch64LIRKindTool(), new AArch64ArithmeticLIRGenerator(), new AArch64HotSpotMoveFactory(), providers, config, lirGenRes);
+        this(new AArch64LIRKindTool(), new AArch64ArithmeticLIRGenerator(null), new AArch64HotSpotMoveFactory(), providers, config, lirGenRes);
     }
 
     protected AArch64HotSpotLIRGenerator(LIRKindTool lirKindTool, AArch64ArithmeticLIRGenerator arithmeticLIRGen, MoveFactory moveFactory, HotSpotProviders providers, GraalHotSpotVMConfig config,
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64IndirectCallOp.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64IndirectCallOp.java	Thu Mar 28 19:39:14 2019 +0100
@@ -73,7 +73,9 @@
         crb.recordMark(config.MARKID_INLINE_INVOKE);
         Register callReg = asRegister(targetAddress);
         assert !callReg.equals(METHOD);
+        int pcOffset = masm.position();
         AArch64Call.indirectCall(crb, masm, callReg, callTarget, state);
+        crb.recordInlineInvokeCallOp(pcOffset, getPosition());
     }
 
     @Override
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64ArrayCompareToStub.java	Thu Mar 28 19:39:14 2019 +0100
@@ -0,0 +1,72 @@
+/*
+ * 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.hotspot.amd64;
+
+import org.graalvm.compiler.api.replacements.Snippet;
+import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
+import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.hotspot.stubs.SnippetStub;
+import org.graalvm.compiler.options.OptionValues;
+import org.graalvm.compiler.replacements.nodes.ArrayCompareToNode;
+import jdk.internal.vm.compiler.word.Pointer;
+
+import jdk.vm.ci.meta.JavaKind;
+
+public final class AMD64ArrayCompareToStub extends SnippetStub {
+
+    public static final ForeignCallDescriptor STUB_BYTE_ARRAY_COMPARE_TO_BYTE_ARRAY = new ForeignCallDescriptor(
+                    "byteArrayCompareToByteArray", int.class, Pointer.class, Pointer.class, int.class, int.class);
+    public static final ForeignCallDescriptor STUB_BYTE_ARRAY_COMPARE_TO_CHAR_ARRAY = new ForeignCallDescriptor(
+                    "byteArrayCompareToCharArray", int.class, Pointer.class, Pointer.class, int.class, int.class);
+    public static final ForeignCallDescriptor STUB_CHAR_ARRAY_COMPARE_TO_BYTE_ARRAY = new ForeignCallDescriptor(
+                    "charArrayCompareToByteArray", int.class, Pointer.class, Pointer.class, int.class, int.class);
+    public static final ForeignCallDescriptor STUB_CHAR_ARRAY_COMPARE_TO_CHAR_ARRAY = new ForeignCallDescriptor(
+                    "charArrayCompareToCharArray", int.class, Pointer.class, Pointer.class, int.class, int.class);
+
+    public AMD64ArrayCompareToStub(ForeignCallDescriptor foreignCallDescriptor, OptionValues options, HotSpotProviders providers, HotSpotForeignCallLinkage linkage) {
+        super(foreignCallDescriptor.getName(), options, providers, linkage);
+    }
+
+    @Snippet
+    private static int byteArrayCompareToByteArray(Pointer array1, Pointer array2, int length1, int length2) {
+        return ArrayCompareToNode.compareTo(array1, array2, length1, length2, JavaKind.Byte, JavaKind.Byte);
+    }
+
+    @Snippet
+    private static int byteArrayCompareToCharArray(Pointer array1, Pointer array2, int length1, int length2) {
+        return ArrayCompareToNode.compareTo(array1, array2, length1, length2, JavaKind.Byte, JavaKind.Char);
+    }
+
+    @Snippet
+    private static int charArrayCompareToByteArray(Pointer array1, Pointer array2, int length1, int length2) {
+        return ArrayCompareToNode.compareTo(array1, array2, length1, length2, JavaKind.Char, JavaKind.Byte);
+    }
+
+    @Snippet
+    private static int charArrayCompareToCharArray(Pointer array1, Pointer array2, int length1, int length2) {
+        return ArrayCompareToNode.compareTo(array1, array2, length1, length2, JavaKind.Char, JavaKind.Char);
+    }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64ArrayEqualsStub.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64ArrayEqualsStub.java	Thu Mar 28 19:39:14 2019 +0100
@@ -31,6 +31,7 @@
 import org.graalvm.compiler.hotspot.stubs.SnippetStub;
 import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.replacements.nodes.ArrayEqualsNode;
+import org.graalvm.compiler.replacements.nodes.ArrayRegionEqualsNode;
 import jdk.internal.vm.compiler.word.Pointer;
 
 import jdk.vm.ci.meta.JavaKind;
@@ -54,6 +55,13 @@
     public static final ForeignCallDescriptor STUB_DOUBLE_ARRAY_EQUALS = new ForeignCallDescriptor(
                     "doubleArraysEquals", boolean.class, Pointer.class, Pointer.class, int.class);
 
+    public static final ForeignCallDescriptor STUB_BYTE_ARRAY_EQUALS_DIRECT = new ForeignCallDescriptor(
+                    "byteArraysEqualsDirect", boolean.class, Pointer.class, Pointer.class, int.class);
+    public static final ForeignCallDescriptor STUB_CHAR_ARRAY_EQUALS_DIRECT = new ForeignCallDescriptor(
+                    "charArraysEqualsDirect", boolean.class, Pointer.class, Pointer.class, int.class);
+    public static final ForeignCallDescriptor STUB_CHAR_ARRAY_EQUALS_BYTE_ARRAY = new ForeignCallDescriptor(
+                    "charArrayEqualsByteArray", boolean.class, Pointer.class, Pointer.class, int.class);
+
     public AMD64ArrayEqualsStub(ForeignCallDescriptor foreignCallDescriptor, OptionValues options, HotSpotProviders providers, HotSpotForeignCallLinkage linkage) {
         super(foreignCallDescriptor.getName(), options, providers, linkage);
     }
@@ -97,4 +105,19 @@
     private static boolean doubleArraysEquals(Pointer array1, Pointer array2, int length) {
         return ArrayEqualsNode.equals(array1, array2, length, JavaKind.Double);
     }
+
+    @Snippet
+    private static boolean byteArraysEqualsDirect(Pointer array1, Pointer array2, int length) {
+        return ArrayRegionEqualsNode.regionEquals(array1, array2, length, JavaKind.Byte, JavaKind.Byte);
+    }
+
+    @Snippet
+    private static boolean charArraysEqualsDirect(Pointer array1, Pointer array2, int length) {
+        return ArrayRegionEqualsNode.regionEquals(array1, array2, length, JavaKind.Char, JavaKind.Char);
+    }
+
+    @Snippet
+    private static boolean charArrayEqualsByteArray(Pointer array1, Pointer array2, int length) {
+        return ArrayRegionEqualsNode.regionEquals(array1, array2, length, JavaKind.Char, JavaKind.Byte);
+    }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotForeignCallsProvider.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotForeignCallsProvider.java	Thu Mar 28 19:39:14 2019 +0100
@@ -137,6 +137,22 @@
                         registerStubCall(AMD64ArrayEqualsStub.STUB_FLOAT_ARRAY_EQUALS, LEAF, REEXECUTABLE, NO_LOCATIONS)));
         link(new AMD64ArrayEqualsStub(AMD64ArrayEqualsStub.STUB_DOUBLE_ARRAY_EQUALS, options, providers,
                         registerStubCall(AMD64ArrayEqualsStub.STUB_DOUBLE_ARRAY_EQUALS, LEAF, REEXECUTABLE, NO_LOCATIONS)));
+        link(new AMD64ArrayEqualsStub(AMD64ArrayEqualsStub.STUB_BYTE_ARRAY_EQUALS_DIRECT, options, providers,
+                        registerStubCall(AMD64ArrayEqualsStub.STUB_BYTE_ARRAY_EQUALS_DIRECT, LEAF, REEXECUTABLE, NO_LOCATIONS)));
+        link(new AMD64ArrayEqualsStub(AMD64ArrayEqualsStub.STUB_CHAR_ARRAY_EQUALS_DIRECT, options, providers,
+                        registerStubCall(AMD64ArrayEqualsStub.STUB_CHAR_ARRAY_EQUALS_DIRECT, LEAF, REEXECUTABLE, NO_LOCATIONS)));
+        link(new AMD64ArrayEqualsStub(AMD64ArrayEqualsStub.STUB_CHAR_ARRAY_EQUALS_BYTE_ARRAY, options, providers,
+                        registerStubCall(AMD64ArrayEqualsStub.STUB_CHAR_ARRAY_EQUALS_BYTE_ARRAY, LEAF, REEXECUTABLE, NO_LOCATIONS)));
+
+        link(new AMD64ArrayCompareToStub(AMD64ArrayCompareToStub.STUB_BYTE_ARRAY_COMPARE_TO_BYTE_ARRAY, options, providers,
+                        registerStubCall(AMD64ArrayCompareToStub.STUB_BYTE_ARRAY_COMPARE_TO_BYTE_ARRAY, LEAF, REEXECUTABLE, NO_LOCATIONS)));
+        link(new AMD64ArrayCompareToStub(AMD64ArrayCompareToStub.STUB_BYTE_ARRAY_COMPARE_TO_CHAR_ARRAY, options, providers,
+                        registerStubCall(AMD64ArrayCompareToStub.STUB_BYTE_ARRAY_COMPARE_TO_CHAR_ARRAY, LEAF, REEXECUTABLE, NO_LOCATIONS)));
+        link(new AMD64ArrayCompareToStub(AMD64ArrayCompareToStub.STUB_CHAR_ARRAY_COMPARE_TO_BYTE_ARRAY, options, providers,
+                        registerStubCall(AMD64ArrayCompareToStub.STUB_CHAR_ARRAY_COMPARE_TO_BYTE_ARRAY, LEAF, REEXECUTABLE, NO_LOCATIONS)));
+        link(new AMD64ArrayCompareToStub(AMD64ArrayCompareToStub.STUB_CHAR_ARRAY_COMPARE_TO_CHAR_ARRAY, options, providers,
+                        registerStubCall(AMD64ArrayCompareToStub.STUB_CHAR_ARRAY_COMPARE_TO_CHAR_ARRAY, LEAF, REEXECUTABLE, NO_LOCATIONS)));
+
         super.initialize(providers, options);
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Thu Mar 28 19:39:14 2019 +0100
@@ -676,32 +676,4 @@
     protected StrategySwitchOp createStrategySwitchOp(SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Variable key, AllocatableValue temp) {
         return new AMD64HotSpotStrategySwitchOp(strategy, keyTargets, defaultTarget, key, temp);
     }
-
-    @Override
-    public ForeignCallLinkage lookupArrayEqualsStub(JavaKind kind, int constantLength) {
-        if (constantLength >= 0 && constantLength * kind.getByteCount() < 2 * getMaxVectorSize()) {
-            // Yield constant-length arrays comparison assembly
-            return null;
-        }
-        switch (kind) {
-            case Boolean:
-                return getForeignCalls().lookupForeignCall(AMD64ArrayEqualsStub.STUB_BOOLEAN_ARRAY_EQUALS);
-            case Byte:
-                return getForeignCalls().lookupForeignCall(AMD64ArrayEqualsStub.STUB_BYTE_ARRAY_EQUALS);
-            case Char:
-                return getForeignCalls().lookupForeignCall(AMD64ArrayEqualsStub.STUB_CHAR_ARRAY_EQUALS);
-            case Short:
-                return getForeignCalls().lookupForeignCall(AMD64ArrayEqualsStub.STUB_SHORT_ARRAY_EQUALS);
-            case Int:
-                return getForeignCalls().lookupForeignCall(AMD64ArrayEqualsStub.STUB_INT_ARRAY_EQUALS);
-            case Long:
-                return getForeignCalls().lookupForeignCall(AMD64ArrayEqualsStub.STUB_LONG_ARRAY_EQUALS);
-            case Float:
-                return getForeignCalls().lookupForeignCall(AMD64ArrayEqualsStub.STUB_FLOAT_ARRAY_EQUALS);
-            case Double:
-                return getForeignCalls().lookupForeignCall(AMD64ArrayEqualsStub.STUB_DOUBLE_ARRAY_EQUALS);
-            default:
-                return null;
-        }
-    }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java	Thu Mar 28 19:39:14 2019 +0100
@@ -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
@@ -28,9 +28,11 @@
 import static jdk.vm.ci.code.ValueUtil.isStackSlot;
 import static org.graalvm.compiler.hotspot.HotSpotBackend.EXCEPTION_HANDLER_IN_CALLER;
 
+import org.graalvm.compiler.api.replacements.Snippet;
 import org.graalvm.compiler.core.amd64.AMD64NodeLIRBuilder;
 import org.graalvm.compiler.core.amd64.AMD64NodeMatchRules;
 import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
 import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
 import org.graalvm.compiler.core.gen.DebugInfoBuilder;
 import org.graalvm.compiler.hotspot.HotSpotDebugInfoBuilder;
@@ -54,6 +56,8 @@
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.spi.NodeValueMap;
+import org.graalvm.compiler.replacements.nodes.ArrayCompareToNode;
+import org.graalvm.compiler.replacements.nodes.ArrayEqualsNode;
 
 import jdk.vm.ci.amd64.AMD64;
 import jdk.vm.ci.amd64.AMD64Kind;
@@ -66,8 +70,11 @@
 import jdk.vm.ci.hotspot.HotSpotCallingConventionType;
 import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
 import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.JavaKind;
 import jdk.vm.ci.meta.JavaType;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
 import jdk.vm.ci.meta.Value;
+import org.graalvm.compiler.replacements.nodes.ArrayRegionEqualsNode;
 
 /**
  * LIR generator specialized for AMD64 HotSpot.
@@ -196,4 +203,98 @@
         Value[] parameters = visitInvokeArguments(gen.getRegisterConfig().getCallingConvention(HotSpotCallingConventionType.JavaCall, null, sig, gen), node.arguments());
         append(new AMD64BreakpointOp(parameters));
     }
+
+    private ForeignCallLinkage lookupForeignCall(ForeignCallDescriptor descriptor) {
+        return getGen().getForeignCalls().lookupForeignCall(descriptor);
+    }
+
+    @Override
+    public ForeignCallLinkage lookupGraalStub(ValueNode valueNode) {
+        ResolvedJavaMethod method = valueNode.graph().method();
+        if (method == null || method.getAnnotation(Snippet.class) != null) {
+            // Emit assembly for snippet stubs
+            return null;
+        }
+
+        if (valueNode instanceof ArrayEqualsNode) {
+            ArrayEqualsNode arrayEqualsNode = (ArrayEqualsNode) valueNode;
+            JavaKind kind = arrayEqualsNode.getKind();
+            ValueNode length = arrayEqualsNode.getLength();
+
+            if (length.isConstant()) {
+                int constantLength = length.asJavaConstant().asInt();
+                if (constantLength >= 0 && constantLength * kind.getByteCount() < 2 * getGen().getMaxVectorSize()) {
+                    // Yield constant-length arrays comparison assembly
+                    return null;
+                }
+            }
+
+            switch (kind) {
+                case Boolean:
+                    return lookupForeignCall(AMD64ArrayEqualsStub.STUB_BOOLEAN_ARRAY_EQUALS);
+                case Byte:
+                    return lookupForeignCall(AMD64ArrayEqualsStub.STUB_BYTE_ARRAY_EQUALS);
+                case Char:
+                    return lookupForeignCall(AMD64ArrayEqualsStub.STUB_CHAR_ARRAY_EQUALS);
+                case Short:
+                    return lookupForeignCall(AMD64ArrayEqualsStub.STUB_SHORT_ARRAY_EQUALS);
+                case Int:
+                    return lookupForeignCall(AMD64ArrayEqualsStub.STUB_INT_ARRAY_EQUALS);
+                case Long:
+                    return lookupForeignCall(AMD64ArrayEqualsStub.STUB_LONG_ARRAY_EQUALS);
+                case Float:
+                    return lookupForeignCall(AMD64ArrayEqualsStub.STUB_FLOAT_ARRAY_EQUALS);
+                case Double:
+                    return lookupForeignCall(AMD64ArrayEqualsStub.STUB_DOUBLE_ARRAY_EQUALS);
+                default:
+                    return null;
+            }
+        } else if (valueNode instanceof ArrayCompareToNode) {
+            ArrayCompareToNode arrayCompareToNode = (ArrayCompareToNode) valueNode;
+            JavaKind kind1 = arrayCompareToNode.getKind1();
+            JavaKind kind2 = arrayCompareToNode.getKind2();
+
+            if (kind1 == JavaKind.Byte) {
+                if (kind2 == JavaKind.Byte) {
+                    return lookupForeignCall(AMD64ArrayCompareToStub.STUB_BYTE_ARRAY_COMPARE_TO_BYTE_ARRAY);
+                } else if (kind2 == JavaKind.Char) {
+                    return lookupForeignCall(AMD64ArrayCompareToStub.STUB_BYTE_ARRAY_COMPARE_TO_CHAR_ARRAY);
+                }
+            } else if (kind1 == JavaKind.Char) {
+                if (kind2 == JavaKind.Byte) {
+                    return lookupForeignCall(AMD64ArrayCompareToStub.STUB_CHAR_ARRAY_COMPARE_TO_BYTE_ARRAY);
+                } else if (kind2 == JavaKind.Char) {
+                    return lookupForeignCall(AMD64ArrayCompareToStub.STUB_CHAR_ARRAY_COMPARE_TO_CHAR_ARRAY);
+                }
+            }
+        } else if (valueNode instanceof ArrayRegionEqualsNode) {
+            ArrayRegionEqualsNode arrayRegionEqualsNode = (ArrayRegionEqualsNode) valueNode;
+            JavaKind kind1 = arrayRegionEqualsNode.getKind1();
+            JavaKind kind2 = arrayRegionEqualsNode.getKind2();
+            ValueNode length = arrayRegionEqualsNode.getLength();
+
+            if (length.isConstant()) {
+                int constantLength = length.asJavaConstant().asInt();
+                if (constantLength >= 0 && constantLength * (Math.max(kind1.getByteCount(), kind2.getByteCount())) < 2 * getGen().getMaxVectorSize()) {
+                    // Yield constant-length arrays comparison assembly
+                    return null;
+                }
+            }
+
+            if (kind1 == kind2) {
+                switch (kind1) {
+                    case Byte:
+                        return lookupForeignCall(AMD64ArrayEqualsStub.STUB_BYTE_ARRAY_EQUALS_DIRECT);
+                    case Char:
+                        return lookupForeignCall(AMD64ArrayEqualsStub.STUB_CHAR_ARRAY_EQUALS_DIRECT);
+                    default:
+                        return null;
+                }
+            } else if (kind1 == JavaKind.Char && kind2 == JavaKind.Byte) {
+                return lookupForeignCall(AMD64ArrayEqualsStub.STUB_CHAR_ARRAY_EQUALS_BYTE_ARRAY);
+            }
+        }
+
+        return null;
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/NodeCostDumpUtil.java	Thu Mar 28 19:39:14 2019 +0100
@@ -0,0 +1,237 @@
+/*
+ * 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.hotspot.test;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+import java.util.stream.Collectors;
+
+import org.graalvm.compiler.debug.CSVUtil;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
+import org.graalvm.compiler.nodes.spi.Virtualizable;
+
+public class NodeCostDumpUtil {
+
+    private static final String prefix1 = "com.oracle.";
+    private static final String prefix2 = "org.graalvm.";
+    private static final String FMT = CSVUtil.buildFormatString("%s", "%s", "%s", "%s", "%s", "%s", "%s", "%s");
+
+    private static String getArgumentRegex(String arg) {
+        if (arg.length() == 0) {
+            return null;
+        }
+        try {
+            Pattern.compile(arg);
+            return arg;
+        } catch (PatternSyntaxException e) {
+            // silently ignore
+            System.err.println("Invalid regex given, defaulting to \".*\" regex..");
+            return null;
+        }
+    }
+
+    public static void main(String[] args) {
+        if (args.length != 1) {
+            System.err.println("NodeCostDumpUtil expects exactly one argument, the node name regex to match against.");
+            System.exit(-1);
+        }
+        final String pattern = getArgumentRegex(args[0]);
+        String version = System.getProperty("java.specification.version");
+        if (version.compareTo("1.9") >= 0) {
+            System.err.printf("NodeCostDumpUtil does not support JDK versions greater than 1.8, current version is %s.\n", version);
+            System.exit(-1);
+        }
+        String[] jvmciCP = System.getProperty("jvmci.class.path.append").split(File.pathSeparator);
+        String[] primarySuiteCP = System.getProperty("primary.suite.cp").split(File.pathSeparator);
+        ClassLoader applicationClassLoader = Thread.currentThread().getContextClassLoader();
+        HashSet<Class<?>> classes = new HashSet<>();
+        try {
+            Set<String> uniquePaths = new HashSet<>(Arrays.asList(primarySuiteCP));
+            uniquePaths.addAll(Arrays.asList(jvmciCP));
+            for (String path : uniquePaths) {
+                if (new File(path).exists()) {
+                    if (path.endsWith(".jar")) {
+                        try (FileSystem jarFileSystem = FileSystems.newFileSystem(URI.create("jar:file:" + path), Collections.emptyMap())) {
+                            initAllClasses(jarFileSystem.getPath("/"), applicationClassLoader, classes);
+                        }
+                    } else {
+                        initAllClasses(FileSystems.getDefault().getPath(path), applicationClassLoader, classes);
+                    }
+                }
+            }
+        } catch (IOException ex) {
+            GraalError.shouldNotReachHere();
+        }
+        System.err.printf("Loaded %d classes...\n", classes.size());
+        List<Class<?>> nodeClasses = new ArrayList<>();
+        for (Class<?> loaded : classes) {
+            if (Node.class.isAssignableFrom(loaded) && !loaded.isArray()) {
+                nodeClasses.add(loaded);
+            }
+        }
+        System.err.printf("Loaded %s node classes...\n", nodeClasses.size());
+        List<NodeClass<?>> nc = new ArrayList<>();
+        for (Class<?> c : nodeClasses) {
+            try {
+                nc.add(NodeClass.get(c));
+            } catch (Throwable t) {
+                // Silently ignore problems here
+            }
+        }
+        System.err.printf("Read TYPE field from %s node classes...\n", nc.size());
+        nc = nc.stream().filter(x -> x != null).collect(Collectors.toList());
+        nc.sort((x, y) -> {
+            String a = x.getJavaClass().getName();
+            String b = y.getJavaClass().getName();
+            return a.compareTo(b);
+        });
+        CSVUtil.Escape.println(System.out, FMT, "NodeName", "Size", "Overrides Size Method", "Cycles", "Overrides Cycles Method", "Canonicalizable", "MemoryCheckPoint", "Virtualizable");
+        for (NodeClass<?> nodeclass : nc) {
+            String packageStrippedName = null;
+            try {
+                packageStrippedName = nodeclass.getJavaClass().getCanonicalName().replace(prefix1, "").replace(prefix2, "");
+            } catch (Throwable t) {
+                // do nothing
+                continue;
+            }
+            if (pattern != null && !packageStrippedName.matches(pattern)) {
+                continue;
+            }
+            boolean overridesSizeMethod = false;
+            boolean overridesCyclesMethod = false;
+            Class<?> c = nodeclass.getJavaClass();
+            try {
+                c.getDeclaredMethod("estimatedNodeSize");
+                overridesSizeMethod = true;
+            } catch (Throwable t) {
+                // do nothing
+            }
+            try {
+                c.getDeclaredMethod("estimatedNodeCycles");
+                overridesCyclesMethod = true;
+            } catch (Throwable t) {
+                // do nothing
+            }
+            CSVUtil.Escape.println(System.out, FMT, packageStrippedName, nodeclass.size(), overridesSizeMethod, nodeclass.cycles(), overridesCyclesMethod, canonicalizable(c), memoryCheckPoint(c),
+                            virtualizable(c));
+        }
+    }
+
+    private static boolean canonicalizable(Class<?> c) {
+        return Canonicalizable.class.isAssignableFrom(c);
+    }
+
+    private static boolean virtualizable(Class<?> c) {
+        return Virtualizable.class.isAssignableFrom(c);
+    }
+
+    private static boolean memoryCheckPoint(Class<?> c) {
+        return MemoryCheckpoint.class.isAssignableFrom(c);
+    }
+
+    private static void initAllClasses(final Path root, ClassLoader classLoader, HashSet<Class<?>> classes) {
+        try {
+            Files.walkFileTree(root, new SimpleFileVisitor<Path>() {
+                @Override
+                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+                    String className = root.relativize(file).toString();
+                    ClassLoader c = classLoader;
+                    if (className.endsWith(".class")) {
+                        String prefix = prefixed(className);
+                        if (prefix != null) {
+                            String stripped = stripClassName(className);
+                            c = new URLClassLoader(new URL[]{new File(constructURLPart(stripped, className, prefix)).toURI().toURL()}, classLoader);
+                            className = constructClazzPart(stripped, prefix);
+                        } else {
+                            String clazzPart = className.replace('/', '.');
+                            className = clazzPart.substring(0, clazzPart.length() - ".class".length());
+                        }
+                        try {
+                            Class<?> systemClass = Class.forName(className, false, c);
+                            if (systemClass.getEnclosingClass() != null) {
+                                try {
+                                    classes.add(systemClass.getEnclosingClass());
+                                } catch (Throwable t) {
+                                    // do nothing
+                                }
+                            }
+                            classes.add(systemClass);
+                        } catch (Throwable ignored) {
+                        }
+                    }
+                    return FileVisitResult.CONTINUE;
+                }
+            });
+        } catch (IOException ex) {
+            GraalError.shouldNotReachHere();
+        }
+    }
+
+    private static String prefixed(String className) {
+        if (className.contains(prefix1) && className.indexOf(prefix1) > 0) {
+            return prefix1;
+        } else if (className.contains(prefix2) && className.indexOf(prefix2) > 0) {
+            return prefix2;
+        }
+        return null;
+    }
+
+    private static String stripClassName(String className) {
+        return className.replace('/', '.');
+    }
+
+    private static String constructClazzPart(String stripped, String prefix) {
+        String clazzPart = stripped.substring(stripped.lastIndexOf(prefix), stripped.length());
+        return clazzPart.substring(0, clazzPart.length() - ".class".length());
+    }
+
+    private static String constructURLPart(String stripped, String className, String prefix) {
+        return className.substring(0, stripped.lastIndexOf(prefix));
+    }
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/StringInternConstantTest.java	Thu Mar 28 19:39:14 2019 +0100
@@ -0,0 +1,73 @@
+/*
+ * 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.hotspot.test;
+
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.ReturnNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.junit.Test;
+
+import jdk.vm.ci.hotspot.HotSpotObjectConstant;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import static org.hamcrest.CoreMatchers.instanceOf;
+import org.junit.Assert;
+
+/**
+ * Tests constant folding of {@link String#intern()}.
+ */
+public class StringInternConstantTest extends GraalCompilerTest {
+
+    private static final String A_CONSTANT_STRING = "a constant string";
+
+    @Test
+    public void test1() {
+        ResolvedJavaMethod method = getResolvedJavaMethod("constantIntern");
+        StructuredGraph graph = parseForCompile(method);
+
+        FixedNode firstFixed = graph.start().next();
+        Assert.assertThat(firstFixed, instanceOf(ReturnNode.class));
+
+        ReturnNode ret = (ReturnNode) firstFixed;
+        if (ret.result() instanceof ConstantNode) {
+            String expected = A_CONSTANT_STRING.intern();
+            Constant constant = ((ConstantNode) ret.result()).getValue();
+            if (constant instanceof HotSpotObjectConstant) {
+                String returnedString = ((HotSpotObjectConstant) constant).asObject(String.class);
+                Assert.assertSame("result", expected, returnedString);
+            } else {
+                Assert.fail("expected HotSpotObjectConstant, got: " + constant.getClass());
+            }
+        } else {
+            Assert.fail("result not constant: " + ret.result());
+        }
+    }
+
+    public static String constantIntern() {
+        return A_CONSTANT_STRING.intern();
+    }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/BootstrapWatchDog.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/BootstrapWatchDog.java	Thu Mar 28 19:39:14 2019 +0100
@@ -39,6 +39,7 @@
 import org.graalvm.compiler.options.OptionValues;
 
 import jdk.vm.ci.code.CompilationRequest;
+import jdk.vm.ci.services.Services;
 
 /**
  * A watch dog that monitors the duration and compilation rate during a
@@ -108,7 +109,7 @@
     /**
      * Set to true to debug the watch dog.
      */
-    private static final boolean DEBUG = Boolean.getBoolean("debug.graal.BootstrapWatchDog");
+    private static final boolean DEBUG = Boolean.parseBoolean(Services.getSavedProperties().get("debug.graal.BootstrapWatchDog"));
 
     /**
      * Seconds to delay before starting to measure the compilation rate.
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationStatistics.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationStatistics.java	Thu Mar 28 19:39:14 2019 +0100
@@ -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
@@ -48,6 +48,7 @@
 
 import jdk.vm.ci.hotspot.HotSpotInstalledCode;
 import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
+import jdk.vm.ci.services.Services;
 
 @SuppressWarnings("unused")
 public final class CompilationStatistics {
@@ -189,7 +190,7 @@
                         timeLeft = RESOLUTION;
                     }
                 }
-                String timelineName = System.getProperty("stats.timeline.name");
+                String timelineName = Services.getSavedProperties().get("stats.timeline.name");
                 if (timelineName != null && !timelineName.isEmpty()) {
                     out.printf("%s%c", CSVUtil.Escape.escape(timelineName), CSVUtil.SEPARATOR);
                 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationTask.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationTask.java	Thu Mar 28 19:39:14 2019 +0100
@@ -57,7 +57,6 @@
 import jdk.vm.ci.hotspot.HotSpotCompilationRequest;
 import jdk.vm.ci.hotspot.HotSpotCompilationRequestResult;
 import jdk.vm.ci.hotspot.HotSpotInstalledCode;
-import jdk.vm.ci.hotspot.HotSpotJVMCICompilerFactory;
 import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
 import jdk.vm.ci.hotspot.HotSpotNmethod;
 import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
@@ -93,6 +92,7 @@
     private final boolean installAsDefault;
 
     private final boolean useProfilingInfo;
+    private final boolean shouldRetainLocalVariables;
     private final OptionValues options;
 
     final class HotSpotCompilationWrapper extends CompilationWrapper<HotSpotCompilationRequestResult> {
@@ -187,7 +187,7 @@
             try (DebugContext.Scope s = debug.scope("Compiling", new DebugDumpScope(getIdString(), true))) {
                 // Begin the compilation event.
                 compilationEvent.begin();
-                result = compiler.compile(method, entryBCI, useProfilingInfo, compilationId, options, debug);
+                result = compiler.compile(method, entryBCI, useProfilingInfo, shouldRetainLocalVariables, compilationId, options, debug);
             } catch (Throwable e) {
                 throw debug.handle(e);
             } finally {
@@ -213,10 +213,16 @@
 
     public CompilationTask(HotSpotJVMCIRuntime jvmciRuntime, HotSpotGraalCompiler compiler, HotSpotCompilationRequest request, boolean useProfilingInfo, boolean installAsDefault,
                     OptionValues options) {
+        this(jvmciRuntime, compiler, request, useProfilingInfo, false, installAsDefault, options);
+    }
+
+    public CompilationTask(HotSpotJVMCIRuntime jvmciRuntime, HotSpotGraalCompiler compiler, HotSpotCompilationRequest request, boolean useProfilingInfo, boolean shouldRetainLocalVariables,
+                    boolean installAsDefault, OptionValues options) {
         this.jvmciRuntime = jvmciRuntime;
         this.compiler = compiler;
         this.compilationId = new HotSpotCompilationIdentifier(request);
         this.useProfilingInfo = useProfilingInfo;
+        this.shouldRetainLocalVariables = shouldRetainLocalVariables;
         this.installAsDefault = installAsDefault;
 
         /*
@@ -321,15 +327,14 @@
         // Log a compilation event.
         EventProvider.CompilationEvent compilationEvent = eventProvider.newCompilationEvent();
 
-        if (installAsDefault) {
+        if (installAsDefault || isOSR) {
             // If there is already compiled code for this method on our level we simply return.
             // JVMCI compiles are always at the highest compile level, even in non-tiered mode so we
             // only need to check for that value.
             if (method.hasCodeAtLevel(entryBCI, config.compilationLevelFullOptimization)) {
                 return HotSpotCompilationRequestResult.failure("Already compiled", false);
             }
-            if (HotSpotGraalCompilerFactory.checkGraalCompileOnlyFilter(method.getDeclaringClass().toJavaName(), method.getName(), method.getSignature().toString(),
-                            HotSpotJVMCICompilerFactory.CompilationLevel.FullOptimization) != HotSpotJVMCICompilerFactory.CompilationLevel.FullOptimization) {
+            if (HotSpotGraalCompilerFactory.shouldExclude(method)) {
                 return HotSpotCompilationRequestResult.failure("GraalCompileOnly excluded", false);
             }
         }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationWatchDog.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationWatchDog.java	Thu Mar 28 19:39:14 2019 +0100
@@ -35,6 +35,7 @@
 import org.graalvm.compiler.options.OptionValues;
 
 import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.services.Services;
 
 /**
  * A watch dog for reporting long running compilations. This is designed to be an always on
@@ -166,7 +167,7 @@
     /**
      * Set to true to debug the watch dog.
      */
-    private static final boolean DEBUG = Boolean.getBoolean("debug.graal.CompilationWatchDog");
+    private static final boolean DEBUG = Boolean.parseBoolean(Services.getSavedProperties().get("debug.graal.CompilationWatchDog"));
 
     private void trace(String format, Object... args) {
         if (DEBUG) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java	Thu Mar 28 19:39:14 2019 +0100
@@ -316,14 +316,16 @@
     public final int jvmAccWrittenFlags = getConstant("JVM_ACC_WRITTEN_FLAGS", Integer.class);
     public final int jvmAccSynthetic = getConstant("JVM_ACC_SYNTHETIC", Integer.class);
 
-    public final int jvmciCompileStateCanPostOnExceptionsOffset = getJvmciCompileStateCanPostOnExceptionsOffset();
+    public final int jvmciCompileStateCanPostOnExceptionsOffset = getJvmciJvmtiCapabilityOffset("_jvmti_can_post_on_exceptions");
+    public final int jvmciCompileStateCanPopFrameOffset = getJvmciJvmtiCapabilityOffset("_jvmti_can_pop_frame");
+    public final int jvmciCompileStateCanAccessLocalVariablesOffset = getJvmciJvmtiCapabilityOffset("_jvmti_can_access_local_variables");
 
     // Integer.MIN_VALUE if not available
-    private int getJvmciCompileStateCanPostOnExceptionsOffset() {
-        int offset = getFieldOffset("JVMCICompileState::_jvmti_can_post_on_exceptions", Integer.class, "jbyte", Integer.MIN_VALUE);
+    private int getJvmciJvmtiCapabilityOffset(String name) {
+        int offset = getFieldOffset("JVMCICompileState::" + name, Integer.class, "jbyte", Integer.MIN_VALUE);
         if (offset == Integer.MIN_VALUE) {
             // JDK 12
-            offset = getFieldOffset("JVMCIEnv::_jvmti_can_post_on_exceptions", Integer.class, "jbyte", Integer.MIN_VALUE);
+            offset = getFieldOffset("JVMCIEnv::" + name, Integer.class, "jbyte", Integer.MIN_VALUE);
         }
         return offset;
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfigBase.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfigBase.java	Thu Mar 28 19:39:14 2019 +0100
@@ -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,9 +36,10 @@
 import jdk.vm.ci.hotspot.HotSpotVMConfigAccess;
 import jdk.vm.ci.hotspot.HotSpotVMConfigStore;
 import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.services.Services;
 
 /**
- * This is a source with different versions for various JDKs.
+ * Base class of class hierarchy for accessing HotSpot VM configuration.
  */
 public abstract class GraalHotSpotVMConfigBase extends HotSpotVMConfigAccess {
 
@@ -62,6 +63,18 @@
         return true;
     }
 
+    private static String getProperty(String name, String def) {
+        String value = Services.getSavedProperties().get(name);
+        if (value == null) {
+            return def;
+        }
+        return value;
+    }
+
+    private static String getProperty(String name) {
+        return getProperty(name, null);
+    }
+
     /**
      * Contains values that are different between JDK versions.
      */
@@ -78,14 +91,14 @@
 
     public final String osName = getHostOSName();
     public final String osArch = getHostArchitectureName();
-    public final boolean windowsOs = System.getProperty("os.name", "").startsWith("Windows");
-    public final boolean linuxOs = System.getProperty("os.name", "").startsWith("Linux");
+    public final boolean windowsOs = getProperty("os.name", "").startsWith("Windows");
+    public final boolean linuxOs = getProperty("os.name", "").startsWith("Linux");
 
     /**
      * Gets the host operating system name.
      */
     private static String getHostOSName() {
-        String osName = System.getProperty("os.name");
+        String osName = getProperty("os.name");
         switch (osName) {
             case "Linux":
                 osName = "linux";
@@ -108,7 +121,7 @@
     }
 
     private static String getHostArchitectureName() {
-        String arch = System.getProperty("os.arch");
+        String arch = getProperty("os.arch");
         switch (arch) {
             case "x86_64":
                 arch = "amd64";
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompiler.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompiler.java	Thu Mar 28 19:39:14 2019 +0100
@@ -25,6 +25,7 @@
 package org.graalvm.compiler.hotspot;
 
 import static org.graalvm.compiler.core.common.GraalOptions.OptAssumptions;
+import org.graalvm.compiler.serviceprovider.GraalUnsafeAccess;
 
 import java.io.ByteArrayOutputStream;
 import java.io.PrintStream;
@@ -71,9 +72,11 @@
 import jdk.vm.ci.meta.SpeculationLog;
 import jdk.vm.ci.meta.TriState;
 import jdk.vm.ci.runtime.JVMCICompiler;
+import sun.misc.Unsafe;
 
 public class HotSpotGraalCompiler implements GraalJVMCICompiler {
 
+    private static final Unsafe UNSAFE = GraalUnsafeAccess.getUnsafe();
     private final HotSpotJVMCIRuntime jvmciRuntime;
     private final HotSpotGraalRuntimeProvider graalRuntime;
     private final CompilationCounters compilationCounters;
@@ -131,7 +134,7 @@
             if (compilationCounters != null) {
                 compilationCounters.countCompilation(method);
             }
-            CompilationTask task = new CompilationTask(jvmciRuntime, this, hsRequest, true, installAsDefault, options);
+            CompilationTask task = new CompilationTask(jvmciRuntime, this, hsRequest, true, shouldRetainLocalVariables(hsRequest.getJvmciEnv()), installAsDefault, options);
             CompilationRequestResult r = null;
             try (DebugContext debug = graalRuntime.openDebugContext(options, task.getCompilationIdentifier(), method, getDebugHandlersFactories(), DebugContext.DEFAULT_LOG_STREAM);
                             Activation a = debug.activate()) {
@@ -142,6 +145,24 @@
         }
     }
 
+    private boolean shouldRetainLocalVariables(long envAddress) {
+        GraalHotSpotVMConfig config = graalRuntime.getVMConfig();
+        if (envAddress == 0) {
+            return false;
+        }
+        if (config.jvmciCompileStateCanPopFrameOffset != Integer.MIN_VALUE) {
+            if ((UNSAFE.getByte(envAddress + config.jvmciCompileStateCanPopFrameOffset) & 0xFF) != 0) {
+                return true;
+            }
+        }
+        if (config.jvmciCompileStateCanAccessLocalVariablesOffset != Integer.MIN_VALUE) {
+            if ((UNSAFE.getByte(envAddress + config.jvmciCompileStateCanAccessLocalVariablesOffset) & 0xFF) != 0) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     public StructuredGraph createGraph(ResolvedJavaMethod method, int entryBCI, boolean useProfilingInfo, CompilationIdentifier compilationId, OptionValues options, DebugContext debug) {
         HotSpotBackend backend = graalRuntime.getHostBackend();
         HotSpotProviders providers = backend.getProviders();
@@ -161,6 +182,11 @@
 
     public CompilationResult compileHelper(CompilationResultBuilderFactory crbf, CompilationResult result, StructuredGraph graph, ResolvedJavaMethod method, int entryBCI, boolean useProfilingInfo,
                     OptionValues options) {
+        return compileHelper(crbf, result, graph, method, entryBCI, useProfilingInfo, false, options);
+    }
+
+    public CompilationResult compileHelper(CompilationResultBuilderFactory crbf, CompilationResult result, StructuredGraph graph, ResolvedJavaMethod method, int entryBCI, boolean useProfilingInfo,
+                    boolean shouldRetainLocalVariables, OptionValues options) {
 
         HotSpotBackend backend = graalRuntime.getHostBackend();
         HotSpotProviders providers = backend.getProviders();
@@ -181,7 +207,7 @@
 
         result.setEntryBCI(entryBCI);
         boolean shouldDebugNonSafepoints = providers.getCodeCache().shouldDebugNonSafepoints();
-        PhaseSuite<HighTierContext> graphBuilderSuite = configGraphBuilderSuite(providers.getSuites().getDefaultGraphBuilderSuite(), shouldDebugNonSafepoints, isOSR);
+        PhaseSuite<HighTierContext> graphBuilderSuite = configGraphBuilderSuite(providers.getSuites().getDefaultGraphBuilderSuite(), shouldDebugNonSafepoints, shouldRetainLocalVariables, isOSR);
         GraalCompiler.compileGraph(graph, method, providers, backend, graphBuilderSuite, optimisticOpts, profilingInfo, suites, lirSuites, result, crbf, true);
 
         if (!isOSR && useProfilingInfo) {
@@ -193,9 +219,14 @@
     }
 
     public CompilationResult compile(ResolvedJavaMethod method, int entryBCI, boolean useProfilingInfo, CompilationIdentifier compilationId, OptionValues options, DebugContext debug) {
+        return compile(method, entryBCI, useProfilingInfo, false, compilationId, options, debug);
+    }
+
+    public CompilationResult compile(ResolvedJavaMethod method, int entryBCI, boolean useProfilingInfo, boolean shouldRetainLocalVariables, CompilationIdentifier compilationId, OptionValues options,
+                    DebugContext debug) {
         StructuredGraph graph = createGraph(method, entryBCI, useProfilingInfo, compilationId, options, debug);
         CompilationResult result = new CompilationResult(compilationId);
-        return compileHelper(CompilationResultBuilderFactory.Default, result, graph, method, entryBCI, useProfilingInfo, options);
+        return compileHelper(CompilationResultBuilderFactory.Default, result, graph, method, entryBCI, useProfilingInfo, shouldRetainLocalVariables, options);
     }
 
     protected OptimisticOptimizations getOptimisticOpts(ProfilingInfo profilingInfo, OptionValues options) {
@@ -217,27 +248,26 @@
      * @param suite the graph builder suite
      * @param shouldDebugNonSafepoints specifies if extra debug info should be generated (default is
      *            false)
+     * @param shouldRetainLocalVariables specifies if local variables should be retained for
+     *            debugging purposes (default is false)
      * @param isOSR specifies if extra OSR-specific post-processing is required (default is false)
      * @return a new suite derived from {@code suite} if any of the GBS parameters did not have a
      *         default value otherwise {@code suite}
      */
-    protected PhaseSuite<HighTierContext> configGraphBuilderSuite(PhaseSuite<HighTierContext> suite, boolean shouldDebugNonSafepoints, boolean isOSR) {
-        if (shouldDebugNonSafepoints || isOSR) {
+    protected PhaseSuite<HighTierContext> configGraphBuilderSuite(PhaseSuite<HighTierContext> suite, boolean shouldDebugNonSafepoints, boolean shouldRetainLocalVariables, boolean isOSR) {
+        if (shouldDebugNonSafepoints || shouldRetainLocalVariables || isOSR) {
             PhaseSuite<HighTierContext> newGbs = suite.copy();
-
+            GraphBuilderPhase graphBuilderPhase = (GraphBuilderPhase) newGbs.findPhase(GraphBuilderPhase.class).previous();
+            GraphBuilderConfiguration graphBuilderConfig = graphBuilderPhase.getGraphBuilderConfig();
             if (shouldDebugNonSafepoints) {
-                GraphBuilderPhase graphBuilderPhase = (GraphBuilderPhase) newGbs.findPhase(GraphBuilderPhase.class).previous();
-                GraphBuilderConfiguration graphBuilderConfig = graphBuilderPhase.getGraphBuilderConfig();
                 graphBuilderConfig = graphBuilderConfig.withNodeSourcePosition(true);
-                GraphBuilderPhase newGraphBuilderPhase = new GraphBuilderPhase(graphBuilderConfig);
-                newGbs.findPhase(GraphBuilderPhase.class).set(newGraphBuilderPhase);
             }
+            if (shouldRetainLocalVariables) {
+                graphBuilderConfig = graphBuilderConfig.withRetainLocalVariables(true);
+            }
+            GraphBuilderPhase newGraphBuilderPhase = new GraphBuilderPhase(graphBuilderConfig);
+            newGbs.findPhase(GraphBuilderPhase.class).set(newGraphBuilderPhase);
             if (isOSR) {
-                // We must not clear non liveness for OSR compilations.
-                GraphBuilderPhase graphBuilderPhase = (GraphBuilderPhase) newGbs.findPhase(GraphBuilderPhase.class).previous();
-                GraphBuilderConfiguration graphBuilderConfig = graphBuilderPhase.getGraphBuilderConfig();
-                GraphBuilderPhase newGraphBuilderPhase = new GraphBuilderPhase(graphBuilderConfig);
-                newGbs.findPhase(GraphBuilderPhase.class).set(newGraphBuilderPhase);
                 newGbs.appendPhase(new OnStackReplacementPhase());
             }
             return newGbs;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompilerFactory.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompilerFactory.java	Thu Mar 28 19:39:14 2019 +0100
@@ -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
@@ -25,7 +25,9 @@
 package org.graalvm.compiler.hotspot;
 
 import static jdk.vm.ci.common.InitTimer.timer;
+import static jdk.vm.ci.hotspot.HotSpotJVMCICompilerFactory.CompilationLevelAdjustment.None;
 import static jdk.vm.ci.services.Services.IS_BUILDING_NATIVE_IMAGE;
+import static jdk.vm.ci.services.Services.IS_IN_NATIVE_IMAGE;
 import static org.graalvm.compiler.hotspot.HotSpotGraalOptionValues.GRAAL_OPTION_PROPERTY_PREFIX;
 
 import java.io.PrintStream;
@@ -42,8 +44,10 @@
 import jdk.vm.ci.common.InitTimer;
 import jdk.vm.ci.hotspot.HotSpotJVMCICompilerFactory;
 import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
-import jdk.vm.ci.hotspot.HotSpotSignature;
+import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
+import jdk.vm.ci.meta.Signature;
 import jdk.vm.ci.runtime.JVMCIRuntime;
+import jdk.vm.ci.services.Services;
 
 public final class HotSpotGraalCompilerFactory extends HotSpotJVMCICompilerFactory {
 
@@ -70,7 +74,7 @@
 
     @Override
     public void onSelection() {
-        JVMCIVersionCheck.check(false);
+        JVMCIVersionCheck.check(Services.getSavedProperties(), false);
         assert options == null : "cannot select " + getClass() + " service more than once";
         options = HotSpotGraalOptionValues.defaultOptions();
         initializeGraalCompilePolicyFields(options);
@@ -79,8 +83,10 @@
          * Exercise this code path early to encourage loading now. This doesn't solve problem of
          * deadlock during class loading but seems to eliminate it in practice.
          */
-        adjustCompilationLevelInternal(Object.class, "hashCode", "()I", CompilationLevel.FullOptimization);
-        adjustCompilationLevelInternal(Object.class, "hashCode", "()I", CompilationLevel.Simple);
+        if (isGraalPredicate != null && isGraalPredicate.getCompilationLevelAdjustment() != None) {
+            adjustCompilationLevelInternal(Object.class, CompilationLevel.FullOptimization);
+            adjustCompilationLevelInternal(Object.class, CompilationLevel.Simple);
+        }
         if (IS_BUILDING_NATIVE_IMAGE) {
             // Triggers initialization of all option descriptors
             Options.CompileGraalWithC1Only.getName();
@@ -88,7 +94,7 @@
     }
 
     private static void initializeGraalCompilePolicyFields(OptionValues options) {
-        compileGraalWithC1Only = Options.CompileGraalWithC1Only.getValue(options);
+        compileGraalWithC1Only = Options.CompileGraalWithC1Only.getValue(options) && !IS_IN_NATIVE_IMAGE;
         String optionValue = Options.GraalCompileOnly.getValue(options);
         if (optionValue != null) {
             MethodFilter[] filter = MethodFilter.parse(optionValue);
@@ -123,7 +129,7 @@
     public HotSpotGraalCompiler createCompiler(JVMCIRuntime runtime) {
         CompilerConfigurationFactory factory = CompilerConfigurationFactory.selectFactory(null, options);
         if (isGraalPredicate != null) {
-            isGraalPredicate.onCompilerConfigurationFactorySelection(factory);
+            isGraalPredicate.onCompilerConfigurationFactorySelection((HotSpotJVMCIRuntime) runtime, factory);
         }
         HotSpotGraalCompiler compiler = createCompiler("VM", runtime, options, factory);
         // Only the HotSpotGraalRuntime associated with the compiler created via
@@ -154,27 +160,13 @@
 
     @Override
     public CompilationLevelAdjustment getCompilationLevelAdjustment() {
-        if (graalCompileOnlyFilter != null) {
-            return CompilationLevelAdjustment.ByFullSignature;
-        }
-        if (compileGraalWithC1Only) {
-            // We only decide using the class declaring the method
-            // so no need to have the method name and signature
-            // symbols converted to a String.
-            return CompilationLevelAdjustment.ByHolder;
-        }
-        return CompilationLevelAdjustment.None;
+        return isGraalPredicate != null ? isGraalPredicate.getCompilationLevelAdjustment() : None;
     }
 
     @Override
     public CompilationLevel adjustCompilationLevel(Object declaringClassObject, String name, String signature, boolean isOsr, CompilationLevel level) {
-        if (declaringClassObject instanceof String) {
-            // This must be SVM mode in which case only GraalCompileC1Only matters since Graal and
-            // JVMCI are already compiled.
-            return checkGraalCompileOnlyFilter((String) declaringClassObject, name, signature, level);
-        }
         Class<?> declaringClass = (Class<?>) declaringClassObject;
-        return adjustCompilationLevelInternal(declaringClass, name, signature, level);
+        return adjustCompilationLevelInternal(declaringClass, level);
     }
 
     static {
@@ -184,32 +176,28 @@
         assert HotSpotGraalCompilerFactory.class.getName().equals("org.graalvm.compiler.hotspot.HotSpotGraalCompilerFactory");
     }
 
-    private CompilationLevel adjustCompilationLevelInternal(Class<?> declaringClass, String name, String signature, CompilationLevel level) {
-        if (compileGraalWithC1Only) {
-            if (level.ordinal() > CompilationLevel.Simple.ordinal()) {
-                if (isGraalPredicate.apply(declaringClass)) {
-                    return CompilationLevel.Simple;
-                }
-            }
-        }
-        return checkGraalCompileOnlyFilter(declaringClass.getName(), name, signature, level);
-    }
-
-    public static CompilationLevel checkGraalCompileOnlyFilter(String declaringClassName, String name, String signature, CompilationLevel level) {
-        if (graalCompileOnlyFilter != null) {
-            if (level == CompilationLevel.FullOptimization) {
-                HotSpotSignature sig = null;
-                for (MethodFilter filter : graalCompileOnlyFilter) {
-                    if (filter.hasSignature() && sig == null) {
-                        sig = new HotSpotSignature(HotSpotJVMCIRuntime.runtime(), signature);
-                    }
-                    if (filter.matches(declaringClassName, name, sig)) {
-                        return level;
-                    }
-                }
+    private CompilationLevel adjustCompilationLevelInternal(Class<?> declaringClass, CompilationLevel level) {
+        assert isGraalPredicate != null;
+        if (level.ordinal() > CompilationLevel.Simple.ordinal()) {
+            if (isGraalPredicate.apply(declaringClass)) {
                 return CompilationLevel.Simple;
             }
         }
         return level;
     }
+
+    static boolean shouldExclude(HotSpotResolvedJavaMethod method) {
+        if (graalCompileOnlyFilter != null) {
+            String javaClassName = method.getDeclaringClass().toJavaName();
+            String name = method.getName();
+            Signature signature = method.getSignature();
+            for (MethodFilter filter : graalCompileOnlyFilter) {
+                if (filter.matches(javaClassName, name, signature)) {
+                    return false;
+                }
+            }
+            return true;
+        }
+        return false;
+    }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java	Thu Mar 28 19:39:14 2019 +0100
@@ -87,6 +87,7 @@
 import jdk.vm.ci.meta.ResolvedJavaType;
 import jdk.vm.ci.runtime.JVMCI;
 import jdk.vm.ci.runtime.JVMCIBackend;
+import jdk.vm.ci.services.Services;
 
 //JaCoCo Exclude
 
@@ -95,7 +96,7 @@
  */
 public final class HotSpotGraalRuntime implements HotSpotGraalRuntimeProvider {
 
-    private static final boolean IS_AOT = Boolean.getBoolean("com.oracle.graalvm.isaot");
+    private static final boolean IS_AOT = Boolean.parseBoolean(Services.getSavedProperties().get("com.oracle.graalvm.isaot"));
 
     private static boolean checkArrayIndexScaleInvariants(MetaAccessProvider metaAccess) {
         assert metaAccess.getArrayIndexScale(JavaKind.Byte) == 1;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotTTYStreamProvider.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotTTYStreamProvider.java	Thu Mar 28 19:39:14 2019 +0100
@@ -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
@@ -44,6 +44,7 @@
 import org.graalvm.compiler.serviceprovider.ServiceProvider;
 
 import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
+import jdk.vm.ci.services.Services;
 
 @ServiceProvider(TTYStreamProvider.class)
 public class HotSpotTTYStreamProvider implements TTYStreamProvider {
@@ -151,7 +152,7 @@
                     if (inputArguments != null) {
                         ps.println("VM Arguments: " + String.join(" ", inputArguments));
                     }
-                    String cmd = System.getProperty("sun.java.command");
+                    String cmd = Services.getSavedProperties().get("sun.java.command");
                     if (cmd != null) {
                         ps.println("sun.java.command=" + cmd);
                     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/IsGraalPredicate.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/IsGraalPredicate.java	Thu Mar 28 19:39:14 2019 +0100
@@ -25,12 +25,13 @@
 package org.graalvm.compiler.hotspot;
 
 import jdk.vm.ci.hotspot.HotSpotJVMCICompilerFactory;
+import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
 
 /**
  * Determines if a given class is a JVMCI or Graal class for the purpose of
  * {@link HotSpotGraalCompilerFactory.Options#CompileGraalWithC1Only}.
  */
-public class IsGraalPredicate {
+class IsGraalPredicate extends IsGraalPredicateBase {
     /**
      * Module containing {@link HotSpotJVMCICompilerFactory}.
      */
@@ -47,15 +48,17 @@
      */
     private Module compilerConfigurationModule;
 
-    public IsGraalPredicate() {
+    IsGraalPredicate() {
         jvmciModule = HotSpotJVMCICompilerFactory.class.getModule();
         graalModule = HotSpotGraalCompilerFactory.class.getModule();
     }
 
-    void onCompilerConfigurationFactorySelection(CompilerConfigurationFactory factory) {
+    @Override
+    void onCompilerConfigurationFactorySelection(HotSpotJVMCIRuntime runtime, CompilerConfigurationFactory factory) {
         compilerConfigurationModule = factory.getClass().getModule();
     }
 
+    @Override
     boolean apply(Class<?> declaringClass) {
         Module module = declaringClass.getModule();
         return jvmciModule == module || graalModule == module || compilerConfigurationModule == module;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/IsGraalPredicateBase.java	Thu Mar 28 19:39:14 2019 +0100
@@ -0,0 +1,46 @@
+/*
+ * 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.compiler.hotspot;
+
+import jdk.vm.ci.hotspot.HotSpotJVMCICompilerFactory;
+import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
+
+/**
+ * Determines if a given class is a JVMCI or Graal class for the purpose of
+ * {@link HotSpotGraalCompilerFactory.Options#CompileGraalWithC1Only}.
+ */
+abstract class IsGraalPredicateBase {
+
+    @SuppressWarnings("unused")
+    void onCompilerConfigurationFactorySelection(HotSpotJVMCIRuntime runtime, CompilerConfigurationFactory factory) {
+    }
+
+    abstract boolean apply(Class<?> declaringClass);
+
+    HotSpotJVMCICompilerFactory.CompilationLevelAdjustment getCompilationLevelAdjustment() {
+        return HotSpotJVMCICompilerFactory.CompilationLevelAdjustment.ByHolder;
+    }
+}
+
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/JVMCIVersionCheck.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/JVMCIVersionCheck.java	Thu Mar 28 19:39:14 2019 +0100
@@ -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
@@ -25,6 +25,9 @@
 package org.graalvm.compiler.hotspot;
 
 import java.util.Formatter;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
 
 /**
  * Mechanism for checking that the current Java runtime environment supports the minimum JVMCI API
@@ -38,20 +41,22 @@
  */
 class JVMCIVersionCheck {
 
-    // 0.55 introduces new HotSpotSpeculationLog API
+    // 0.57 introduces HotSpotJVMCIRuntime.excludeFromJVMCICompilation
     private static final int JVMCI8_MIN_MAJOR_VERSION = 0;
-    private static final int JVMCI8_MIN_MINOR_VERSION = 55;
+    private static final int JVMCI8_MIN_MINOR_VERSION = 57;
 
-    private static void failVersionCheck(boolean exit, String reason, Object... args) {
+    private static void failVersionCheck(Map<String, String> props, boolean exit, String reason, Object... args) {
         Formatter errorMessage = new Formatter().format(reason, args);
-        String javaHome = System.getProperty("java.home");
-        String vmName = System.getProperty("java.vm.name");
+        String javaHome = props.get("java.home");
+        String vmName = props.get("java.vm.name");
         errorMessage.format("Set the JVMCI_VERSION_CHECK environment variable to \"ignore\" to suppress ");
         errorMessage.format("this error or to \"warn\" to emit a warning and continue execution.%n");
         errorMessage.format("Currently used Java home directory is %s.%n", javaHome);
         errorMessage.format("Currently used VM configuration is: %s%n", vmName);
-        if (System.getProperty("java.specification.version").compareTo("1.9") < 0) {
-            errorMessage.format("Download the latest JVMCI JDK 8 from http://www.oracle.com/technetwork/oracle-labs/program-languages/downloads/index.html");
+        if (props.get("java.specification.version").compareTo("1.9") < 0) {
+            errorMessage.format("Download the latest JVMCI JDK 8 from " +
+                            "http://www.oracle.com/technetwork/oracle-labs/program-languages/downloads/index.html or " +
+                            "https://github.com/graalvm/openjdk8-jvmci-builder/releases");
         } else {
             errorMessage.format("Download JDK 11 or later.");
         }
@@ -68,10 +73,10 @@
         }
     }
 
-    static void check(boolean exitOnFailure) {
+    static void check(Map<String, String> props, boolean exitOnFailure) {
         // Don't use regular expressions to minimize Graal startup time
-        String javaSpecVersion = System.getProperty("java.specification.version");
-        String vmVersion = System.getProperty("java.vm.version");
+        String javaSpecVersion = props.get("java.specification.version");
+        String vmVersion = props.get("java.vm.version");
         if (javaSpecVersion.compareTo("1.9") < 0) {
             int start = vmVersion.indexOf("-jvmci-");
             if (start >= 0) {
@@ -82,7 +87,7 @@
                     try {
                         major = Integer.parseInt(vmVersion.substring(start, end));
                     } catch (NumberFormatException e) {
-                        failVersionCheck(exitOnFailure, "The VM does not support the minimum JVMCI API version required by Graal.%n" +
+                        failVersionCheck(props, exitOnFailure, "The VM does not support the minimum JVMCI API version required by Graal.%n" +
                                         "Cannot read JVMCI major version from java.vm.version property: %s.%n", vmVersion);
                         return;
                     }
@@ -95,22 +100,22 @@
                     try {
                         minor = Integer.parseInt(vmVersion.substring(start, end));
                     } catch (NumberFormatException e) {
-                        failVersionCheck(exitOnFailure, "The VM does not support the minimum JVMCI API version required by Graal.%n" +
+                        failVersionCheck(props, exitOnFailure, "The VM does not support the minimum JVMCI API version required by Graal.%n" +
                                         "Cannot read JVMCI minor version from java.vm.version property: %s.%n", vmVersion);
                         return;
                     }
                     if (major >= JVMCI8_MIN_MAJOR_VERSION && minor >= JVMCI8_MIN_MINOR_VERSION) {
                         return;
                     }
-                    failVersionCheck(exitOnFailure, "The VM does not support the minimum JVMCI API version required by Graal: %d.%d < %d.%d.%n",
+                    failVersionCheck(props, exitOnFailure, "The VM does not support the minimum JVMCI API version required by Graal: %d.%d < %d.%d.%n",
                                     major, minor, JVMCI8_MIN_MAJOR_VERSION, JVMCI8_MIN_MINOR_VERSION);
                     return;
                 }
             }
-            failVersionCheck(exitOnFailure, "The VM does not support the minimum JVMCI API version required by Graal.%n" +
+            failVersionCheck(props, exitOnFailure, "The VM does not support the minimum JVMCI API version required by Graal.%n" +
                             "Cannot read JVMCI version from java.vm.version property: %s.%n", vmVersion);
         } else if (javaSpecVersion.compareTo("11") < 0) {
-            failVersionCheck(exitOnFailure, "Graal is not compatible with the JVMCI API in JDK 9 and 10.%n");
+            failVersionCheck(props, exitOnFailure, "Graal is not compatible with the JVMCI API in JDK 9 and 10.%n");
         } else {
             if (vmVersion.contains("SNAPSHOT")) {
                 return;
@@ -124,11 +129,11 @@
                 try {
                     int build = Integer.parseInt(buildString);
                     if (build < 20) {
-                        failVersionCheck(exitOnFailure, "Graal requires build 20 or later of JDK 11 early access binary, got build %d.%n", build);
+                        failVersionCheck(props, exitOnFailure, "Graal requires build 20 or later of JDK 11 early access binary, got build %d.%n", build);
                         return;
                     }
                 } catch (NumberFormatException e) {
-                    failVersionCheck(exitOnFailure, "Could not parse the JDK 11 early access build number from java.vm.version property: %s.%n", vmVersion);
+                    failVersionCheck(props, exitOnFailure, "Could not parse the JDK 11 early access build number from java.vm.version property: %s.%n", vmVersion);
                     return;
                 }
             } else {
@@ -141,6 +146,11 @@
      * Command line interface for performing the check.
      */
     public static void main(String[] args) {
-        check(true);
+        Properties sprops = System.getProperties();
+        Map<String, String> props = new HashMap<>(sprops.size());
+        for (String name : sprops.stringPropertyNames()) {
+            props.put(name, sprops.getProperty(name));
+        }
+        check(props, true);
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/NodeCostDumpUtil.java	Thu Mar 28 11:06:00 2019 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,236 +0,0 @@
-/*
- * Copyright (c) 2016, 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.hotspot;
-
-import java.io.File;
-import java.io.IOException;
-import java.net.URI;
-import java.net.URL;
-import java.net.URLClassLoader;
-import java.nio.file.FileSystem;
-import java.nio.file.FileSystems;
-import java.nio.file.FileVisitResult;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.SimpleFileVisitor;
-import java.nio.file.attribute.BasicFileAttributes;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.regex.Pattern;
-import java.util.regex.PatternSyntaxException;
-import java.util.stream.Collectors;
-
-import org.graalvm.compiler.debug.CSVUtil;
-import org.graalvm.compiler.debug.GraalError;
-import org.graalvm.compiler.graph.Node;
-import org.graalvm.compiler.graph.NodeClass;
-import org.graalvm.compiler.graph.spi.Canonicalizable;
-import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
-import org.graalvm.compiler.nodes.spi.Virtualizable;
-
-public class NodeCostDumpUtil {
-
-    private static final String prefix1 = "com.oracle.";
-    private static final String prefix2 = "org.graalvm.";
-    private static final String FMT = CSVUtil.buildFormatString("%s", "%s", "%s", "%s", "%s", "%s", "%s", "%s");
-
-    private static String getArgumentRegex(String arg) {
-        if (arg.length() == 0) {
-            return null;
-        }
-        try {
-            Pattern.compile(arg);
-            return arg;
-        } catch (PatternSyntaxException e) {
-            // silently ignore
-            System.err.println("Invalid regex given, defaulting to \".*\" regex..");
-            return null;
-        }
-    }
-
-    public static void main(String[] args) {
-        if (args.length != 1) {
-            System.err.println("NodeCostDumpUtil expects exactly one argument, the node name regex to match against.");
-            System.exit(-1);
-        }
-        final String pattern = getArgumentRegex(args[0]);
-        String version = System.getProperty("java.specification.version");
-        if (version.compareTo("1.9") >= 0) {
-            System.err.printf("NodeCostDumpUtil does not support JDK versions greater than 1.8, current version is %s.\n", version);
-            System.exit(-1);
-        }
-        String[] jvmciCP = System.getProperty("jvmci.class.path.append").split(File.pathSeparator);
-        String[] primarySuiteCP = System.getProperty("primary.suite.cp").split(File.pathSeparator);
-        ClassLoader applicationClassLoader = Thread.currentThread().getContextClassLoader();
-        HashSet<Class<?>> classes = new HashSet<>();
-        try {
-            Set<String> uniquePaths = new HashSet<>(Arrays.asList(primarySuiteCP));
-            uniquePaths.addAll(Arrays.asList(jvmciCP));
-            for (String path : uniquePaths) {
-                if (new File(path).exists()) {
-                    if (path.endsWith(".jar")) {
-                        try (FileSystem jarFileSystem = FileSystems.newFileSystem(URI.create("jar:file:" + path), Collections.emptyMap())) {
-                            initAllClasses(jarFileSystem.getPath("/"), applicationClassLoader, classes);
-                        }
-                    } else {
-                        initAllClasses(FileSystems.getDefault().getPath(path), applicationClassLoader, classes);
-                    }
-                }
-            }
-        } catch (IOException ex) {
-            GraalError.shouldNotReachHere();
-        }
-        System.err.printf("Loaded %d classes...\n", classes.size());
-        List<Class<?>> nodeClasses = new ArrayList<>();
-        for (Class<?> loaded : classes) {
-            if (Node.class.isAssignableFrom(loaded) && !loaded.isArray()) {
-                nodeClasses.add(loaded);
-            }
-        }
-        System.err.printf("Loaded %s node classes...\n", nodeClasses.size());
-        List<NodeClass<?>> nc = new ArrayList<>();
-        for (Class<?> c : nodeClasses) {
-            try {
-                nc.add(NodeClass.get(c));
-            } catch (Throwable t) {
-                // Silently ignore problems here
-            }
-        }
-        System.err.printf("Read TYPE field from %s node classes...\n", nc.size());
-        nc = nc.stream().filter(x -> x != null).collect(Collectors.toList());
-        nc.sort((x, y) -> {
-            String a = x.getJavaClass().getName();
-            String b = y.getJavaClass().getName();
-            return a.compareTo(b);
-        });
-        CSVUtil.Escape.println(System.out, FMT, "NodeName", "Size", "Overrides Size Method", "Cycles", "Overrides Cycles Method", "Canonicalizable", "MemoryCheckPoint", "Virtualizable");
-        for (NodeClass<?> nodeclass : nc) {
-            String packageStrippedName = null;
-            try {
-                packageStrippedName = nodeclass.getJavaClass().getCanonicalName().replace(prefix1, "").replace(prefix2, "");
-            } catch (Throwable t) {
-                // do nothing
-                continue;
-            }
-            if (pattern != null && !packageStrippedName.matches(pattern)) {
-                continue;
-            }
-            boolean overridesSizeMethod = false;
-            boolean overridesCyclesMethod = false;
-            Class<?> c = nodeclass.getJavaClass();
-            try {
-                c.getDeclaredMethod("estimatedNodeSize");
-                overridesSizeMethod = true;
-            } catch (Throwable t) {
-                // do nothing
-            }
-            try {
-                c.getDeclaredMethod("estimatedNodeCycles");
-                overridesCyclesMethod = true;
-            } catch (Throwable t) {
-                // do nothing
-            }
-            CSVUtil.Escape.println(System.out, FMT, packageStrippedName, nodeclass.size(), overridesSizeMethod, nodeclass.cycles(), overridesCyclesMethod, canonicalizable(c), memoryCheckPoint(c),
-                            virtualizable(c));
-        }
-    }
-
-    private static boolean canonicalizable(Class<?> c) {
-        return Canonicalizable.class.isAssignableFrom(c);
-    }
-
-    private static boolean virtualizable(Class<?> c) {
-        return Virtualizable.class.isAssignableFrom(c);
-    }
-
-    private static boolean memoryCheckPoint(Class<?> c) {
-        return MemoryCheckpoint.class.isAssignableFrom(c);
-    }
-
-    private static void initAllClasses(final Path root, ClassLoader classLoader, HashSet<Class<?>> classes) {
-        try {
-            Files.walkFileTree(root, new SimpleFileVisitor<Path>() {
-                @Override
-                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
-                    String className = root.relativize(file).toString();
-                    ClassLoader c = classLoader;
-                    if (className.endsWith(".class")) {
-                        String prefix = prefixed(className);
-                        if (prefix != null) {
-                            String stripped = stripClassName(className);
-                            c = new URLClassLoader(new URL[]{new File(constructURLPart(stripped, className, prefix)).toURI().toURL()}, classLoader);
-                            className = constructClazzPart(stripped, prefix);
-                        } else {
-                            String clazzPart = className.replace('/', '.');
-                            className = clazzPart.substring(0, clazzPart.length() - ".class".length());
-                        }
-                        try {
-                            Class<?> systemClass = Class.forName(className, false, c);
-                            if (systemClass.getEnclosingClass() != null) {
-                                try {
-                                    classes.add(systemClass.getEnclosingClass());
-                                } catch (Throwable t) {
-                                    // do nothing
-                                }
-                            }
-                            classes.add(systemClass);
-                        } catch (Throwable ignored) {
-                        }
-                    }
-                    return FileVisitResult.CONTINUE;
-                }
-            });
-        } catch (IOException ex) {
-            GraalError.shouldNotReachHere();
-        }
-    }
-
-    private static String prefixed(String className) {
-        if (className.contains(prefix1) && className.indexOf(prefix1) > 0) {
-            return prefix1;
-        } else if (className.contains(prefix2) && className.indexOf(prefix2) > 0) {
-            return prefix2;
-        }
-        return null;
-    }
-
-    private static String stripClassName(String className) {
-        return className.replace('/', '.');
-    }
-
-    private static String constructClazzPart(String stripped, String prefix) {
-        String clazzPart = stripped.substring(stripped.lastIndexOf(prefix), stripped.length());
-        return clazzPart.substring(0, clazzPart.length() - ".class".length());
-    }
-
-    private static String constructURLPart(String stripped, String className, String prefix) {
-        return className.substring(0, stripped.lastIndexOf(prefix));
-    }
-
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/SymbolicSnippetEncoder.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/SymbolicSnippetEncoder.java	Thu Mar 28 19:39:14 2019 +0100
@@ -48,7 +48,6 @@
 import org.graalvm.compiler.api.runtime.GraalJVMCICompiler;
 import org.graalvm.compiler.api.runtime.GraalRuntime;
 import org.graalvm.compiler.bytecode.BytecodeProvider;
-import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
 import org.graalvm.compiler.core.common.type.AbstractObjectStamp;
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.core.common.type.StampPair;
@@ -88,7 +87,6 @@
 import org.graalvm.compiler.nodes.java.AccessFieldNode;
 import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
 import org.graalvm.compiler.nodes.spi.DelegatingReplacements;
-import org.graalvm.compiler.nodes.spi.StampProvider;
 import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
 import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.phases.OptimisticOptimizations;
@@ -112,7 +110,6 @@
 import jdk.vm.ci.meta.JavaKind;
 import jdk.vm.ci.meta.JavaType;
 import jdk.vm.ci.meta.MemoryAccessProvider;
-import jdk.vm.ci.meta.MetaAccessProvider;
 import jdk.vm.ci.meta.MethodHandleAccessProvider;
 import jdk.vm.ci.meta.ResolvedJavaField;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
@@ -311,10 +308,7 @@
                 PEGraphDecoder graphDecoder = new PEGraphDecoder(
                                 providers.getCodeCache().getTarget().arch,
                                 result,
-                                providers.getMetaAccess(),
-                                providers.getConstantReflection(),
-                                providers.getConstantFieldProvider(),
-                                providers.getStampProvider(),
+                                providers,
                                 null, // loopExplosionPlugin
                                 replacements.getGraphBuilderPlugins().getInvocationPlugins(),
                                 new InlineInvokePlugin[0],
@@ -407,10 +401,7 @@
                 PEGraphDecoder graphDecoder = new PEGraphDecoder(
                                 architecture,
                                 result,
-                                providers.getMetaAccess(),
-                                providers.getConstantReflection(),
-                                providers.getConstantFieldProvider(),
-                                providers.getStampProvider(),
+                                providers,
                                 null,
                                 replacements.getGraphBuilderPlugins().getInvocationPlugins(),
                                 new InlineInvokePlugin[0],
@@ -993,17 +984,15 @@
         }
 
         @Override
-        protected GraphBuilderPhase.Instance createGraphBuilder(MetaAccessProvider metaAccess, StampProvider stampProvider, ConstantReflectionProvider constantReflection,
-                        ConstantFieldProvider constantFieldProvider, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, IntrinsicContext initialIntrinsicContext) {
-            return new HotSpotSnippetGraphBuilderPhase(metaAccess, stampProvider, constantReflection, constantFieldProvider, graphBuilderConfig, optimisticOpts,
-                            initialIntrinsicContext);
+        protected GraphBuilderPhase.Instance createGraphBuilder(Providers providers, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts,
+                        IntrinsicContext initialIntrinsicContext) {
+            return new HotSpotSnippetGraphBuilderPhase(providers, graphBuilderConfig, optimisticOpts, initialIntrinsicContext);
         }
     }
 
     static class HotSpotSnippetGraphBuilderPhase extends GraphBuilderPhase.Instance {
-        HotSpotSnippetGraphBuilderPhase(MetaAccessProvider metaAccess, StampProvider stampProvider, ConstantReflectionProvider constantReflection, ConstantFieldProvider constantFieldProvider,
-                        GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, IntrinsicContext initialIntrinsicContext) {
-            super(metaAccess, stampProvider, constantReflection, constantFieldProvider, graphBuilderConfig, optimisticOpts, initialIntrinsicContext);
+        HotSpotSnippetGraphBuilderPhase(Providers theProviders, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, IntrinsicContext initialIntrinsicContext) {
+            super(theProviders, graphBuilderConfig, optimisticOpts, initialIntrinsicContext);
         }
 
         @Override
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/debug/BenchmarkCounters.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/debug/BenchmarkCounters.java	Thu Mar 28 19:39:14 2019 +0100
@@ -416,7 +416,9 @@
                         if (waitingForEnd) {
                             waitingForEnd = false;
                             running = false;
-                            BenchmarkCounters.dump(options, getPrintStream(options), (System.nanoTime() - startTime) / 1000000000d, jvmciRuntime.collectCounters(), 100);
+                            try (PrintStreamScope scope = getPrintStream(options)) {
+                                BenchmarkCounters.dump(options, scope.out, (System.nanoTime() - startTime) / 1000000000d, jvmciRuntime.collectCounters(), 100);
+                            }
                         }
                         break;
                 }
@@ -445,18 +447,19 @@
         if (Options.TimedDynamicCounters.getValue(options) > 0) {
             Thread thread = new Thread() {
                 long lastTime = System.nanoTime();
-                PrintStream out = getPrintStream(options);
 
                 @Override
                 public void run() {
-                    while (true) {
-                        try {
-                            Thread.sleep(Options.TimedDynamicCounters.getValue(options));
-                        } catch (InterruptedException e) {
+                    try (PrintStreamScope scope = getPrintStream(options)) {
+                        while (true) {
+                            try {
+                                Thread.sleep(Options.TimedDynamicCounters.getValue(options));
+                            } catch (InterruptedException e) {
+                            }
+                            long time = System.nanoTime();
+                            dump(options, scope.out, (time - lastTime) / 1000000000d, jvmciRuntime.collectCounters(), 10);
+                            lastTime = time;
                         }
-                        long time = System.nanoTime();
-                        dump(options, out, (time - lastTime) / 1000000000d, jvmciRuntime.collectCounters(), 10);
-                        lastTime = time;
                     }
                 }
             };
@@ -472,22 +475,39 @@
 
     public static void shutdown(HotSpotJVMCIRuntime jvmciRuntime, OptionValues options, long compilerStartTime) {
         if (Options.GenericDynamicCounters.getValue(options)) {
-            dump(options, getPrintStream(options), (System.nanoTime() - compilerStartTime) / 1000000000d, jvmciRuntime.collectCounters(), 100);
+            try (PrintStreamScope scope = getPrintStream(options)) {
+                dump(options, scope.out, (System.nanoTime() - compilerStartTime) / 1000000000d, jvmciRuntime.collectCounters(), 100);
+            }
         }
     }
 
-    private static PrintStream getPrintStream(OptionValues options) {
-        if (Options.BenchmarkCountersFile.getValue(options) != null) {
-            try {
+    static class PrintStreamScope implements AutoCloseable {
+        final PrintStream out;
 
-                File file = new File(Options.BenchmarkCountersFile.getValue(options));
-                TTY.println("Writing benchmark counters to '%s'", file.getAbsolutePath());
-                return new PrintStream(file);
-            } catch (IOException e) {
-                TTY.out().println(e.getMessage());
-                TTY.out().println("Fallback to default");
+        PrintStreamScope(OptionValues options) {
+            PrintStream ps = TTY.out;
+            if (Options.BenchmarkCountersFile.getValue(options) != null) {
+                try {
+                    File file = new File(Options.BenchmarkCountersFile.getValue(options));
+                    TTY.println("Writing benchmark counters to '%s'", file.getAbsolutePath());
+                    ps = new PrintStream(file);
+                } catch (IOException e) {
+                    TTY.out().println(e.getMessage());
+                    TTY.out().println("Fallback to default");
+                }
+            }
+            this.out = ps;
+        }
+
+        @Override
+        public void close() {
+            if (out != TTY.out) {
+                this.out.close();
             }
         }
-        return TTY.out;
+    }
+
+    private static PrintStreamScope getPrintStream(OptionValues options) {
+        return new PrintStreamScope(options);
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotNodePlugin.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotNodePlugin.java	Thu Mar 28 19:39:14 2019 +0100
@@ -28,8 +28,6 @@
 import static jdk.vm.ci.meta.DeoptimizationReason.TransferToInterpreter;
 import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode;
 
-import java.lang.reflect.Field;
-
 import org.graalvm.compiler.core.common.CompilationIdentifier;
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.core.common.type.StampPair;
@@ -56,6 +54,7 @@
 import org.graalvm.compiler.nodes.memory.address.AddressNode;
 import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
 import org.graalvm.compiler.nodes.util.ConstantFoldUtil;
+import org.graalvm.compiler.serviceprovider.GraalUnsafeAccess;
 import org.graalvm.compiler.word.Word;
 import org.graalvm.compiler.word.WordOperationPlugin;
 import jdk.internal.vm.compiler.word.LocationIdentity;
@@ -83,6 +82,7 @@
  * </ul>
  */
 public final class HotSpotNodePlugin implements NodePlugin, TypePlugin {
+    private static final Unsafe UNSAFE = GraalUnsafeAccess.getUnsafe();
     protected final WordOperationPlugin wordOperationPlugin;
     private final GraalHotSpotVMConfig config;
     private final HotSpotWordTypes wordTypes;
@@ -243,21 +243,5 @@
     }
 
     private static final LocationIdentity JAVA_THREAD_SHOULD_POST_ON_EXCEPTIONS_FLAG_LOCATION = NamedLocationIdentity.mutable("JavaThread::_should_post_on_exceptions_flag");
-    static final Unsafe UNSAFE = initUnsafe();
+}
 
-    static Unsafe initUnsafe() {
-        try {
-            // Fast path when we are trusted.
-            return Unsafe.getUnsafe();
-        } catch (SecurityException se) {
-            // Slow path when we are not trusted.
-            try {
-                Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
-                theUnsafe.setAccessible(true);
-                return (Unsafe) theUnsafe.get(Unsafe.class);
-            } catch (Exception e) {
-                throw new RuntimeException("exception while trying to get Unsafe", e);
-            }
-        }
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotObjdumpDisassemblerProvider.java	Thu Mar 28 19:39:14 2019 +0100
@@ -0,0 +1,167 @@
+/*
+ * 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.hotspot.meta;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.graalvm.compiler.code.CompilationResult;
+import org.graalvm.compiler.code.CompilationResult.CodeAnnotation;
+import org.graalvm.compiler.code.DisassemblerProvider;
+import org.graalvm.compiler.serviceprovider.ServiceProvider;
+
+import jdk.vm.ci.code.CodeCacheProvider;
+import jdk.vm.ci.code.CodeUtil;
+import jdk.vm.ci.code.CodeUtil.DefaultRefMapFormatter;
+import jdk.vm.ci.code.CodeUtil.RefMapFormatter;
+import jdk.vm.ci.code.InstalledCode;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterConfig;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.code.site.Call;
+import jdk.vm.ci.code.site.DataPatch;
+import jdk.vm.ci.code.site.Infopoint;
+import jdk.vm.ci.code.site.Mark;
+import jdk.vm.ci.hotspot.HotSpotCodeCacheProvider;
+import jdk.vm.ci.services.Services;
+
+/**
+ * This disassembles the code immediatly with objdump.
+ */
+@ServiceProvider(DisassemblerProvider.class)
+public class HotSpotObjdumpDisassemblerProvider extends HotSpotDisassemblerProvider {
+
+    /**
+     * Uses objdump to disassemble the compiled code.
+     */
+    @Override
+    public String disassembleCompiledCode(CodeCacheProvider codeCache, CompilationResult compResult) {
+        File tmp = null;
+        try {
+            tmp = File.createTempFile("compiledBinary", ".bin");
+            try (FileOutputStream fos = new FileOutputStream(tmp)) {
+                fos.write(compResult.getTargetCode());
+            }
+            String[] cmdline;
+            String arch = Services.getSavedProperties().get("os.arch");
+            if (arch.equals("amd64")) {
+                cmdline = new String[]{"objdump", "-D", "-b", "binary", "-M", "x86-64", "-m", "i386", tmp.getAbsolutePath()};
+            } else if (arch.equals("aarch64")) {
+                cmdline = new String[]{"objdump", "-D", "-b", "binary", "-m", "aarch64", tmp.getAbsolutePath()};
+            } else {
+                return null;
+            }
+
+            Pattern p = Pattern.compile(" *(([0-9a-fA-F]+):\t.*)");
+
+            TargetDescription target = codeCache.getTarget();
+            RegisterConfig regConfig = codeCache.getRegisterConfig();
+            Register fp = regConfig.getFrameRegister();
+            RefMapFormatter slotFormatter = new DefaultRefMapFormatter(target.wordSize, fp, 0);
+
+            Map<Integer, String> annotations = new HashMap<>();
+            for (DataPatch site : compResult.getDataPatches()) {
+                putAnnotation(annotations, site.pcOffset, "{" + site.reference.toString() + "}");
+            }
+            for (Mark mark : compResult.getMarks()) {
+                putAnnotation(annotations, mark.pcOffset, codeCache.getMarkName(mark));
+            }
+            for (CodeAnnotation a : compResult.getCodeAnnotations()) {
+                putAnnotation(annotations, a.position, a.toString());
+            }
+            for (Infopoint infopoint : compResult.getInfopoints()) {
+                if (infopoint instanceof Call) {
+                    Call call = (Call) infopoint;
+                    if (call.debugInfo != null) {
+                        putAnnotation(annotations, call.pcOffset + call.size, CodeUtil.append(new StringBuilder(100), call.debugInfo, slotFormatter).toString());
+                    }
+                    putAnnotation(annotations, call.pcOffset, "{" + codeCache.getTargetName(call) + "}");
+                } else {
+                    if (infopoint.debugInfo != null) {
+                        putAnnotation(annotations, infopoint.pcOffset, CodeUtil.append(new StringBuilder(100), infopoint.debugInfo, slotFormatter).toString());
+                    }
+                    putAnnotation(annotations, infopoint.pcOffset, "{infopoint: " + infopoint.reason + "}");
+                }
+            }
+
+            Process proc = Runtime.getRuntime().exec(cmdline);
+            InputStream is = proc.getInputStream();
+
+            InputStreamReader isr = new InputStreamReader(is);
+            BufferedReader br = new BufferedReader(isr);
+            String line;
+
+            StringBuilder sb = new StringBuilder();
+            while ((line = br.readLine()) != null) {
+                Matcher m = p.matcher(line);
+                if (m.find()) {
+                    int address = Integer.parseInt(m.group(2), 16);
+                    String annotation = annotations.get(address);
+                    if (annotation != null) {
+                        annotation = annotation.replace("\n", "\n; ");
+                        sb.append("; ").append(annotation).append('\n');
+                    }
+                    line = m.replaceAll("0x$1");
+                }
+                sb.append(line).append("\n");
+            }
+            BufferedReader ebr = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
+            while ((line = ebr.readLine()) != null) {
+                System.err.println(line);
+            }
+            ebr.close();
+            return sb.toString();
+        } catch (IOException e) {
+            if (tmp != null) {
+                tmp.delete();
+            }
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    private static void putAnnotation(Map<Integer, String> annotations, int idx, String txt) {
+        String newAnnoation = annotations.getOrDefault(idx, "") + "\n" + txt;
+        annotations.put(idx, newAnnoation);
+    }
+
+    @Override
+    public String disassembleInstalledCode(CodeCacheProvider codeCache, CompilationResult compResult, InstalledCode code) {
+        return ((HotSpotCodeCacheProvider) codeCache).disassemble(code);
+    }
+
+    @Override
+    public String getName() {
+        return "hsdis-objdump";
+    }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotSuitesProvider.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotSuitesProvider.java	Thu Mar 28 19:39:14 2019 +0100
@@ -142,8 +142,7 @@
 
                 StructuredGraph targetGraph = new StructuredGraph.Builder(graph.getOptions(), graph.getDebug(), AllowAssumptions.YES).method(graph.method()).trackNodeSourcePosition(
                                 graph.trackNodeSourcePosition()).build();
-                SimplifyingGraphDecoder graphDecoder = new SimplifyingGraphDecoder(runtime.getTarget().arch, targetGraph, context.getMetaAccess(), context.getConstantReflection(),
-                                context.getConstantFieldProvider(), context.getStampProvider(), !ImmutableCode.getValue(graph.getOptions()));
+                SimplifyingGraphDecoder graphDecoder = new SimplifyingGraphDecoder(runtime.getTarget().arch, targetGraph, context, !ImmutableCode.getValue(graph.getOptions()));
                 graphDecoder.decode(encodedGraph);
             }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/AheadOfTimeVerificationPhase.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/AheadOfTimeVerificationPhase.java	Thu Mar 28 19:39:14 2019 +0100
@@ -44,17 +44,21 @@
 public class AheadOfTimeVerificationPhase extends VerifyPhase<PhaseContext> {
 
     @Override
-    protected boolean verify(StructuredGraph graph, PhaseContext context) {
+    protected void verify(StructuredGraph graph, PhaseContext context) {
         for (ConstantNode node : getConstantNodes(graph)) {
             if (isIllegalObjectConstant(node)) {
                 throw new VerificationError("illegal object constant: " + node);
             }
         }
-        return true;
     }
 
     public static boolean isIllegalObjectConstant(ConstantNode node) {
-        return isObject(node) && !isNullReference(node) && !isInternedString(node) && !isDirectMethodHandle(node) && !isBoundMethodHandle(node);
+        return isObject(node) &&
+                        !isNullReference(node) &&
+                        !isInternedString(node) &&
+                        !isDirectMethodHandle(node) &&
+                        !isBoundMethodHandle(node) &&
+                        !isVarHandle(node);
     }
 
     private static boolean isObject(ConstantNode node) {
@@ -79,6 +83,14 @@
         return StampTool.typeOrNull(node).getName().startsWith("Ljava/lang/invoke/BoundMethodHandle");
     }
 
+    private static boolean isVarHandle(ConstantNode node) {
+        if (!isObject(node)) {
+            return false;
+        }
+        String name = StampTool.typeOrNull(node).getName();
+        return name.equals("Ljava/lang/invoke/VarHandle$AccessDescriptor;");
+    }
+
     private static boolean isInternedString(ConstantNode node) {
         if (!isObject(node)) {
             return false;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java	Thu Mar 28 19:39:14 2019 +0100
@@ -420,6 +420,8 @@
 import org.graalvm.compiler.nodes.java.RegisterFinalizerNode;
 import org.graalvm.compiler.nodes.java.StoreFieldNode;
 import org.graalvm.compiler.nodes.java.StoreIndexedNode;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
+import org.graalvm.compiler.nodes.spi.Replacements;
 import org.graalvm.compiler.nodes.spi.StampProvider;
 import org.graalvm.compiler.nodes.type.StampTool;
 import org.graalvm.compiler.nodes.util.GraphUtil;
@@ -714,10 +716,7 @@
         this.debug = graph.getDebug();
         this.graphBuilderConfig = graphBuilderInstance.graphBuilderConfig;
         this.optimisticOpts = graphBuilderInstance.optimisticOpts;
-        this.metaAccess = graphBuilderInstance.metaAccess;
-        this.stampProvider = graphBuilderInstance.stampProvider;
-        this.constantReflection = graphBuilderInstance.constantReflection;
-        this.constantFieldProvider = graphBuilderInstance.constantFieldProvider;
+        this.providers = graphBuilderInstance.providers;
         this.stream = new BytecodeStream(code.getCode());
         this.profilingInfo = graph.useProfilingInfo() ? code.getProfilingInfo() : null;
         this.constantPool = code.getConstantPool();
@@ -778,7 +777,7 @@
 
     @SuppressWarnings("try")
     protected void buildRootMethod() {
-        FrameStateBuilder startFrameState = new FrameStateBuilder(this, code, graph);
+        FrameStateBuilder startFrameState = new FrameStateBuilder(this, code, graph, graphBuilderConfig.retainLocalVariables());
         startFrameState.initializeForMethodStart(graph.getAssumptions(), graphBuilderConfig.eagerResolving() || intrinsicContext != null, graphBuilderConfig.getPlugins());
 
         try (IntrinsicScope s = intrinsicContext != null ? new IntrinsicScope(this) : null) {
@@ -1121,7 +1120,7 @@
 
         AbstractBeginNode dispatchBegin;
         if (exceptionObject == null) {
-            ExceptionObjectNode newExceptionObject = graph.add(new ExceptionObjectNode(metaAccess));
+            ExceptionObjectNode newExceptionObject = graph.add(new ExceptionObjectNode(getMetaAccess()));
             dispatchBegin = newExceptionObject;
             dispatchState.push(JavaKind.Object, dispatchBegin);
             dispatchState.setRethrowException(true);
@@ -1166,7 +1165,7 @@
     }
 
     protected ValueNode genLoadIndexed(ValueNode array, ValueNode index, GuardingNode boundsCheck, JavaKind kind) {
-        return LoadIndexedNode.create(graph.getAssumptions(), array, index, boundsCheck, kind, metaAccess, constantReflection);
+        return LoadIndexedNode.create(graph.getAssumptions(), array, index, boundsCheck, kind, getMetaAccess(), getConstantReflection());
     }
 
     protected void genStoreIndexed(ValueNode array, ValueNode index, GuardingNode boundsCheck, GuardingNode storeCheck, JavaKind kind, ValueNode value) {
@@ -1242,7 +1241,7 @@
     }
 
     protected ValueNode genNormalizeCompare(ValueNode x, ValueNode y, boolean isUnorderedLess) {
-        return NormalizeCompareNode.create(x, y, isUnorderedLess, JavaKind.Int, constantReflection);
+        return NormalizeCompareNode.create(x, y, isUnorderedLess, JavaKind.Int, getConstantReflection());
     }
 
     protected ValueNode genFloatConvert(FloatConvert op, ValueNode input) {
@@ -1273,15 +1272,15 @@
     }
 
     protected LogicNode genObjectEquals(ValueNode x, ValueNode y) {
-        return ObjectEqualsNode.create(constantReflection, metaAccess, options, x, y, NodeView.DEFAULT);
+        return ObjectEqualsNode.create(getConstantReflection(), getMetaAccess(), options, x, y, NodeView.DEFAULT);
     }
 
     protected LogicNode genIntegerEquals(ValueNode x, ValueNode y) {
-        return IntegerEqualsNode.create(constantReflection, metaAccess, options, null, x, y, NodeView.DEFAULT);
+        return IntegerEqualsNode.create(getConstantReflection(), getMetaAccess(), options, null, x, y, NodeView.DEFAULT);
     }
 
     protected LogicNode genIntegerLessThan(ValueNode x, ValueNode y) {
-        return IntegerLessThanNode.create(constantReflection, metaAccess, options, null, x, y, NodeView.DEFAULT);
+        return IntegerLessThanNode.create(getConstantReflection(), getMetaAccess(), options, null, x, y, NodeView.DEFAULT);
     }
 
     protected ValueNode genUnique(ValueNode x) {
@@ -1372,7 +1371,7 @@
             return null;
         }
         ValueNode length = append(genArrayLength(receiver));
-        LogicNode condition = genUnique(IntegerBelowNode.create(constantReflection, metaAccess, options, null, index, length, NodeView.DEFAULT));
+        LogicNode condition = genUnique(IntegerBelowNode.create(getConstantReflection(), getMetaAccess(), options, null, index, length, NodeView.DEFAULT));
         return emitBytecodeExceptionCheck(condition, true, BytecodeExceptionKind.OUT_OF_BOUNDS, index, length);
     }
 
@@ -1380,8 +1379,8 @@
         if (elementKind != JavaKind.Object || StampTool.isPointerAlwaysNull(value) || !needsExplicitStoreCheckException(array, value)) {
             return null;
         }
-        ValueNode arrayClass = genUnique(LoadHubNode.create(array, stampProvider, metaAccess, constantReflection));
-        ValueNode componentHub = append(LoadArrayComponentHubNode.create(arrayClass, stampProvider, metaAccess, constantReflection));
+        ValueNode arrayClass = genUnique(LoadHubNode.create(array, getStampProvider(), getMetaAccess(), getConstantReflection()));
+        ValueNode componentHub = append(LoadArrayComponentHubNode.create(arrayClass, getStampProvider(), getMetaAccess(), getConstantReflection()));
         LogicNode condition = genUnique(InstanceOfDynamicNode.create(graph.getAssumptions(), getConstantReflection(), componentHub, value, true));
         return emitBytecodeExceptionCheck(condition, true, BytecodeExceptionKind.ARRAY_STORE, value);
     }
@@ -1391,7 +1390,7 @@
             return null;
         }
         ConstantNode zero = ConstantNode.defaultForKind(y.getStackKind(), graph);
-        LogicNode condition = genUnique(IntegerEqualsNode.create(constantReflection, metaAccess, options, null, y, zero, NodeView.DEFAULT));
+        LogicNode condition = genUnique(IntegerEqualsNode.create(getConstantReflection(), getMetaAccess(), options, null, y, zero, NodeView.DEFAULT));
         return emitBytecodeExceptionCheck(condition, false, BytecodeExceptionKind.DIVISION_BY_ZERO);
     }
 
@@ -1400,7 +1399,7 @@
             return null;
         }
 
-        BytecodeExceptionNode exception = graph.add(new BytecodeExceptionNode(metaAccess, exceptionKind, arguments));
+        BytecodeExceptionNode exception = graph.add(new BytecodeExceptionNode(getMetaAccess(), exceptionKind, arguments));
         AbstractBeginNode passingSuccessor = graph.add(new BeginNode());
 
         FixedNode trueSuccessor = passingOnTrue ? passingSuccessor : exception;
@@ -1416,7 +1415,7 @@
     }
 
     protected ValueNode genArrayLength(ValueNode x) {
-        return ArrayLengthNode.create(x, constantReflection);
+        return ArrayLengthNode.create(x, getConstantReflection());
     }
 
     protected void genStoreField(ValueNode receiver, ResolvedJavaField field, ValueNode value) {
@@ -1567,7 +1566,7 @@
                 FrameState stateBefore = createCurrentFrameState();
                 appendixNode = invokeDynamicPlugin.genAppendixNode(this, cpi, opcode, appendix, stateBefore);
             } else {
-                appendixNode = ConstantNode.forConstant(appendix, metaAccess, graph);
+                appendixNode = ConstantNode.forConstant(appendix, getMetaAccess(), graph);
             }
 
             frameState.push(JavaKind.Object, appendixNode);
@@ -1629,10 +1628,7 @@
     protected final ProfilingInfo profilingInfo;
     protected final OptimisticOptimizations optimisticOpts;
     protected final ConstantPool constantPool;
-    protected final MetaAccessProvider metaAccess;
-    private final ConstantReflectionProvider constantReflection;
-    private final ConstantFieldProvider constantFieldProvider;
-    private final StampProvider stampProvider;
+    protected final CoreProviders providers;
     protected final IntrinsicContext intrinsicContext;
 
     @Override
@@ -1954,7 +1950,7 @@
         }
 
         String error(String format, Object... a) {
-            return String.format(format, a) + String.format("%n\tplugin at %s", plugin.getApplySourceLocation(metaAccess));
+            return String.format(format, a) + String.format("%n\tplugin at %s", plugin.getApplySourceLocation(getMetaAccess()));
         }
 
         boolean check(boolean pluginResult) {
@@ -2039,11 +2035,12 @@
             Mark mark = graph.getMark();
             FixedWithNextNode currentLastInstr = lastInstr;
             ValueNode nonNullReceiver = pluginReceiver.get();
-            Stamp methodStamp = stampProvider.createMethodStamp();
-            LoadHubNode hub = graph.unique(new LoadHubNode(stampProvider, nonNullReceiver));
+            Stamp methodStamp = getStampProvider().createMethodStamp();
+            LoadHubNode hub = graph.unique(new LoadHubNode(getStampProvider(), nonNullReceiver));
             LoadMethodNode actual = append(new LoadMethodNode(methodStamp, targetMethod, receiverType, method.getDeclaringClass(), hub));
             ConstantNode expected = graph.unique(ConstantNode.forConstant(methodStamp, targetMethod.getEncoding(), getMetaAccess()));
-            LogicNode compare = graph.addOrUniqueWithInputs(CompareNode.createCompareNode(constantReflection, metaAccess, options, null, CanonicalCondition.EQ, actual, expected, NodeView.DEFAULT));
+            LogicNode compare = graph.addOrUniqueWithInputs(
+                            CompareNode.createCompareNode(getConstantReflection(), getMetaAccess(), options, null, CanonicalCondition.EQ, actual, expected, NodeView.DEFAULT));
 
             JavaTypeProfile profile = null;
             if (profilingInfo != null && this.optimisticOpts.useTypeCheckHints(getOptions())) {
@@ -2321,7 +2318,7 @@
                         }
                         return false;
                     }
-                    if (canInlinePartialIntrinsicExit() && InlinePartialIntrinsicExitDuringParsing.getValue(options) && !IS_BUILDING_NATIVE_IMAGE) {
+                    if (canInlinePartialIntrinsicExit()) {
                         // Otherwise inline the original method. Any frame state created
                         // during the inlining will exclude frame(s) in the
                         // intrinsic method (see FrameStateBuilder.create(int bci)).
@@ -2384,7 +2381,7 @@
      * intrinsic) can be inlined.
      */
     protected boolean canInlinePartialIntrinsicExit() {
-        return true;
+        return InlinePartialIntrinsicExitDuringParsing.getValue(options) && !IS_BUILDING_NATIVE_IMAGE && method.getAnnotation(Snippet.class) == null;
     }
 
     private void printInlining(ResolvedJavaMethod targetMethod, ResolvedJavaMethod inlinedMethod, boolean success, String msg) {
@@ -2446,7 +2443,7 @@
 
         try (IntrinsicScope s = calleeIntrinsicContext != null && !parsingIntrinsic() ? new IntrinsicScope(this, targetMethod.getSignature().toParameterKinds(!targetMethod.isStatic()), args) : null) {
             BytecodeParser parser = graphBuilderInstance.createBytecodeParser(graph, this, targetMethod, INVOCATION_ENTRY_BCI, calleeIntrinsicContext);
-            FrameStateBuilder startFrameState = new FrameStateBuilder(parser, parser.code, graph);
+            FrameStateBuilder startFrameState = new FrameStateBuilder(parser, parser.code, graph, graphBuilderConfig.retainLocalVariables());
             if (!targetMethod.isStatic()) {
                 args[0] = nullCheckedValue(args[0]);
             }
@@ -2679,7 +2676,7 @@
         JsrScope scope = currentBlock.getJsrScope();
         int retAddress = scope.nextReturnAddress();
         ConstantNode returnBciNode = getJsrConstant(retAddress);
-        LogicNode guard = IntegerEqualsNode.create(constantReflection, metaAccess, options, null, local, returnBciNode, NodeView.DEFAULT);
+        LogicNode guard = IntegerEqualsNode.create(getConstantReflection(), getMetaAccess(), options, null, local, returnBciNode, NodeView.DEFAULT);
         guard = graph.addOrUniqueWithInputs(guard);
         append(new FixedGuardNode(guard, JavaSubroutineMismatch, InvalidateReprofile));
         if (!successor.getJsrScope().equals(scope.pop())) {
@@ -2731,7 +2728,7 @@
 
     protected ConstantNode appendConstant(JavaConstant constant) {
         assert constant != null;
-        return ConstantNode.forConstant(constant, metaAccess, graph);
+        return ConstantNode.forConstant(constant, getMetaAccess(), graph);
     }
 
     @Override
@@ -3602,12 +3599,17 @@
 
     @Override
     public StampProvider getStampProvider() {
-        return stampProvider;
+        return providers.getStampProvider();
     }
 
     @Override
     public MetaAccessProvider getMetaAccess() {
-        return metaAccess;
+        return providers.getMetaAccess();
+    }
+
+    @Override
+    public Replacements getReplacements() {
+        return providers.getReplacements();
     }
 
     @Override
@@ -3623,12 +3625,12 @@
 
     @Override
     public ConstantReflectionProvider getConstantReflection() {
-        return constantReflection;
+        return providers.getConstantReflection();
     }
 
     @Override
     public ConstantFieldProvider getConstantFieldProvider() {
-        return constantFieldProvider;
+        return providers.getConstantFieldProvider();
     }
 
     /**
@@ -3753,7 +3755,7 @@
 
     private JavaKind refineComponentType(ValueNode array, JavaKind kind) {
         if (kind == JavaKind.Byte) {
-            JavaType type = array.stamp(NodeView.DEFAULT).javaType(metaAccess);
+            JavaType type = array.stamp(NodeView.DEFAULT).javaType(getMetaAccess());
             if (type.isArray()) {
                 JavaType componentType = type.getComponentType();
                 if (componentType != null) {
@@ -4308,7 +4310,7 @@
     }
 
     private void genNewPrimitiveArray(int typeCode) {
-        ResolvedJavaType elementType = metaAccess.lookupJavaType(arrayTypeCodeToClass(typeCode));
+        ResolvedJavaType elementType = getMetaAccess().lookupJavaType(arrayTypeCodeToClass(typeCode));
         ValueNode length = frameState.pop(JavaKind.Int);
 
         for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) {
@@ -4492,7 +4494,7 @@
 
     @Override
     public AbstractBeginNode genExplicitExceptionEdge(BytecodeExceptionKind exceptionKind) {
-        BytecodeExceptionNode exceptionNode = graph.add(new BytecodeExceptionNode(metaAccess, exceptionKind));
+        BytecodeExceptionNode exceptionNode = graph.add(new BytecodeExceptionNode(getMetaAccess(), exceptionKind));
         exceptionNode.setStateAfter(createFrameState(bci(), exceptionNode));
         AbstractBeginNode exceptionDispatch = handleException(exceptionNode, bci(), false);
         exceptionNode.setNext(exceptionDispatch);
@@ -5113,3 +5115,4 @@
         return n == 0 ? "" : format("%" + n + "s", "");
     }
 }
+
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/FrameStateBuilder.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/FrameStateBuilder.java	Thu Mar 28 19:39:14 2019 +0100
@@ -118,17 +118,18 @@
      * @param graph the target graph of Graal nodes created by the builder
      */
     public FrameStateBuilder(GraphBuilderTool tool, ResolvedJavaMethod method, StructuredGraph graph) {
-        this(tool, new ResolvedJavaMethodBytecode(method), graph);
+        this(tool, new ResolvedJavaMethodBytecode(method), graph, false);
     }
 
     /**
      * Creates a new frame state builder for the given code attribute, method and the given target
-     * graph.
+     * graph. Additionally specifies if nonLiveLocals should be retained.
      *
      * @param code the bytecode in which the frame exists
      * @param graph the target graph of Graal nodes created by the builder
+     * @param shouldRetainLocalVariables specifies if nonLiveLocals should be retained in state.
      */
-    public FrameStateBuilder(GraphBuilderTool tool, Bytecode code, StructuredGraph graph) {
+    public FrameStateBuilder(GraphBuilderTool tool, Bytecode code, StructuredGraph graph, boolean shouldRetainLocalVariables) {
         this.tool = tool;
         if (tool instanceof BytecodeParser) {
             this.parser = (BytecodeParser) tool;
@@ -144,7 +145,7 @@
 
         this.monitorIds = EMPTY_MONITOR_ARRAY;
         this.graph = graph;
-        this.clearNonLiveLocals = GraalOptions.OptClearNonLiveLocals.getValue(graph.getOptions());
+        this.clearNonLiveLocals = GraalOptions.OptClearNonLiveLocals.getValue(graph.getOptions()) && !shouldRetainLocalVariables;
         this.canVerifyKind = true;
     }
 
@@ -630,12 +631,12 @@
 
     public void clearNonLiveLocals(BciBlock block, LocalLiveness liveness, boolean liveIn) {
         /*
-         * (lstadler) if somebody is tempted to remove/disable this clearing code: it's possible to
-         * remove it for normal compilations, but not for OSR compilations - otherwise dead object
-         * slots at the OSR entry aren't cleared. it is also not enough to rely on PiNodes with
-         * Kind.Illegal, because the conflicting branch might not have been parsed.
+         * Non-live local clearing is mandatory for the entry block of an OSR compilation so that
+         * dead object slots at the OSR entry are cleared. It's not sufficient to rely on PiNodes
+         * with Kind.Illegal, because the conflicting branch might not have been parsed.
          */
-        if (!clearNonLiveLocals) {
+        boolean isOSREntryBlock = graph.isOSR() && getMethod().equals(graph.method()) && graph.getEntryBCI() == block.startBci;
+        if (!clearNonLiveLocals && !isOSREntryBlock) {
             return;
         }
         if (liveIn) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/GraphBuilderPhase.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/GraphBuilderPhase.java	Thu Mar 28 19:39:14 2019 +0100
@@ -24,17 +24,14 @@
 
 package org.graalvm.compiler.java;
 
-import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
 import org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext;
-import org.graalvm.compiler.nodes.spi.StampProvider;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.phases.BasePhase;
 import org.graalvm.compiler.phases.OptimisticOptimizations;
 import org.graalvm.compiler.phases.tiers.HighTierContext;
 
-import jdk.vm.ci.meta.ConstantReflectionProvider;
-import jdk.vm.ci.meta.MetaAccessProvider;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 
 /**
@@ -55,8 +52,7 @@
 
     @Override
     protected void run(StructuredGraph graph, HighTierContext context) {
-        new Instance(context.getMetaAccess(), context.getStampProvider(), context.getConstantReflection(), context.getConstantFieldProvider(), graphBuilderConfig, context.getOptimisticOptimizations(),
-                        null).run(graph);
+        new Instance(context, graphBuilderConfig, context.getOptimisticOptimizations(), null).run(graph);
     }
 
     public GraphBuilderConfiguration getGraphBuilderConfig() {
@@ -66,22 +62,15 @@
     // Fully qualified name is a workaround for JDK-8056066
     public static class Instance extends org.graalvm.compiler.phases.Phase {
 
-        protected final MetaAccessProvider metaAccess;
-        protected final StampProvider stampProvider;
-        protected final ConstantReflectionProvider constantReflection;
-        protected final ConstantFieldProvider constantFieldProvider;
+        protected final CoreProviders providers;
         protected final GraphBuilderConfiguration graphBuilderConfig;
         protected final OptimisticOptimizations optimisticOpts;
         private final IntrinsicContext initialIntrinsicContext;
 
-        public Instance(MetaAccessProvider metaAccess, StampProvider stampProvider, ConstantReflectionProvider constantReflection, ConstantFieldProvider constantFieldProvider,
-                        GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, IntrinsicContext initialIntrinsicContext) {
+        public Instance(CoreProviders providers, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, IntrinsicContext initialIntrinsicContext) {
             this.graphBuilderConfig = graphBuilderConfig;
             this.optimisticOpts = optimisticOpts;
-            this.metaAccess = metaAccess;
-            this.stampProvider = stampProvider;
-            this.constantReflection = constantReflection;
-            this.constantFieldProvider = constantFieldProvider;
+            this.providers = providers;
             this.initialIntrinsicContext = initialIntrinsicContext;
         }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ArithmeticLIRGeneratorTool.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ArithmeticLIRGeneratorTool.java	Thu Mar 28 19:39:14 2019 +0100
@@ -24,10 +24,8 @@
 
 package org.graalvm.compiler.lir.aarch64;
 
-import org.graalvm.compiler.lir.Variable;
 import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool;
 
-import jdk.vm.ci.aarch64.AArch64Kind;
 import jdk.vm.ci.meta.Value;
 
 /**
@@ -53,6 +51,4 @@
     }
 
     Value emitRound(Value value, RoundingMode mode);
-
-    void emitCompareOp(AArch64Kind cmpKind, Variable left, Value right);
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64Call.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64Call.java	Thu Mar 28 19:39:14 2019 +0100
@@ -215,7 +215,7 @@
                  * Offset might not fit into a 28-bit immediate, generate an indirect call with a
                  * 64-bit immediate address which is fixed up by HotSpot.
                  */
-                masm.movNativeAddress(scratch, 0L);
+                masm.movNativeAddress(scratch, 0L, true);
                 masm.blr(scratch);
             }
         } else {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64Compare.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64Compare.java	Thu Mar 28 19:39:14 2019 +0100
@@ -24,22 +24,21 @@
 
 package org.graalvm.compiler.lir.aarch64;
 
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.CONST;
 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
 import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant;
 import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant;
-import static jdk.vm.ci.code.ValueUtil.asRegister;
-import static jdk.vm.ci.code.ValueUtil.isRegister;
 
-import org.graalvm.compiler.core.common.NumUtil;
 import org.graalvm.compiler.asm.aarch64.AArch64Assembler;
 import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
+import org.graalvm.compiler.core.common.NumUtil;
 import org.graalvm.compiler.core.common.calc.Condition;
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.lir.LIRInstructionClass;
 import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
 
-import jdk.vm.ci.aarch64.AArch64Kind;
 import jdk.vm.ci.meta.JavaConstant;
 import jdk.vm.ci.meta.Value;
 
@@ -53,8 +52,7 @@
 
         public CompareOp(Value x, Value y) {
             super(TYPE);
-            assert ((AArch64Kind) x.getPlatformKind()).isInteger() && ((AArch64Kind) y.getPlatformKind()).isInteger();
-            assert x.getPlatformKind() == y.getPlatformKind();
+            assert x.getPlatformKind() == y.getPlatformKind() : x.getPlatformKind() + " " + y.getPlatformKind();
             this.x = x;
             this.y = y;
         }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ControlFlow.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ControlFlow.java	Thu Mar 28 19:39:14 2019 +0100
@@ -24,22 +24,24 @@
 
 package org.graalvm.compiler.lir.aarch64;
 
+import static jdk.vm.ci.aarch64.AArch64.lr;
 import static jdk.vm.ci.code.ValueUtil.asAllocatableValue;
 import static jdk.vm.ci.code.ValueUtil.asRegister;
 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL;
 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
 
 import java.util.function.Function;
 
 import jdk.vm.ci.meta.AllocatableValue;
 import org.graalvm.compiler.asm.Label;
-import org.graalvm.compiler.core.common.NumUtil;
 import org.graalvm.compiler.asm.aarch64.AArch64Assembler;
 import org.graalvm.compiler.asm.aarch64.AArch64Assembler.ConditionFlag;
 import org.graalvm.compiler.asm.aarch64.AArch64Assembler.ExtendType;
 import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
 import org.graalvm.compiler.code.CompilationResult.JumpTable;
 import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.NumUtil;
 import org.graalvm.compiler.core.common.calc.Condition;
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.lir.ConstantValue;
@@ -47,6 +49,7 @@
 import org.graalvm.compiler.lir.LabelRef;
 import org.graalvm.compiler.lir.Opcode;
 import org.graalvm.compiler.lir.StandardOp;
+import org.graalvm.compiler.lir.StandardOp.BlockEndOp;
 import org.graalvm.compiler.lir.SwitchStrategy;
 import org.graalvm.compiler.lir.SwitchStrategy.BaseSwitchClosure;
 import org.graalvm.compiler.lir.Variable;
@@ -59,6 +62,21 @@
 import jdk.vm.ci.meta.Value;
 
 public class AArch64ControlFlow {
+    public static final class ReturnOp extends AArch64BlockEndOp implements BlockEndOp {
+        public static final LIRInstructionClass<ReturnOp> TYPE = LIRInstructionClass.create(ReturnOp.class);
+        @Use({REG, ILLEGAL}) protected Value x;
+
+        public ReturnOp(Value x) {
+            super(TYPE);
+            this.x = x;
+        }
+
+        @Override
+        protected void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            crb.frameContext.leave(crb);
+            masm.ret(lr);
+        }
+    }
 
     public abstract static class AbstractBranchOp extends AArch64BlockEndOp implements StandardOp.BranchOp {
         private final LabelRef trueDestination;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64MathIntrinsicBinaryOp.java	Thu Mar 28 19:39:14 2019 +0100
@@ -0,0 +1,84 @@
+/*
+ * 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.lir.aarch64;
+
+import static jdk.vm.ci.aarch64.AArch64.v0;
+import static jdk.vm.ci.aarch64.AArch64.v1;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Variable;
+import org.graalvm.compiler.lir.gen.LIRGenerator;
+
+import jdk.vm.ci.aarch64.AArch64;
+import jdk.vm.ci.aarch64.AArch64Kind;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterValue;
+import jdk.vm.ci.meta.Value;
+
+public abstract class AArch64MathIntrinsicBinaryOp extends AArch64LIRInstruction {
+
+    @Def protected Value output;
+    @Use protected Value input0;
+    @Use protected Value input1;
+    @Temp protected Value[] temps;
+
+    public AArch64MathIntrinsicBinaryOp(LIRInstructionClass<? extends AArch64LIRInstruction> type, Register... registers) {
+        super(type);
+        input0 = v0.asValue(LIRKind.value(AArch64Kind.V64_WORD));
+        input1 = v0.asValue(LIRKind.value(AArch64Kind.V64_WORD));
+        output = v0.asValue(LIRKind.value(AArch64Kind.V64_WORD));
+
+        temps = registersToValues(registers);
+    }
+
+    protected static Value[] registersToValues(Register[] registers) {
+        Value[] temps = new Value[registers.length];
+        for (int i = 0; i < registers.length; i++) {
+            Register register = registers[i];
+            if (AArch64.CPU.equals(register.getRegisterCategory())) {
+                temps[i] = register.asValue(LIRKind.value(AArch64Kind.V64_WORD));
+            } else if (AArch64.SIMD.equals(register.getRegisterCategory())) {
+                temps[i] = register.asValue(LIRKind.value(AArch64Kind.V64_WORD));
+            } else {
+                throw GraalError.shouldNotReachHere("Unsupported register type in math stubs.");
+            }
+        }
+        return temps;
+    }
+
+    public final Variable emitLIRWrapper(LIRGenerator gen, Value x, Value y) {
+        LIRKind kind = LIRKind.combine(x, y);
+        RegisterValue v0value = v0.asValue(kind);
+        gen.emitMove(v0value, x);
+        RegisterValue v1value = v1.asValue(kind);
+        gen.emitMove(v1value, y);
+        gen.append(this);
+        Variable result = gen.newVariable(kind);
+        gen.emitMove(result, v0value);
+        return result;
+    }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64Move.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64Move.java	Thu Mar 28 19:39:14 2019 +0100
@@ -31,18 +31,25 @@
 import static jdk.vm.ci.code.ValueUtil.asStackSlot;
 import static jdk.vm.ci.code.ValueUtil.isRegister;
 import static jdk.vm.ci.code.ValueUtil.isStackSlot;
+import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.COMPOSITE;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.CONST;
 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL;
 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK;
 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.UNINITIALIZED;
 import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant;
 import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant;
 
+import org.graalvm.compiler.asm.Label;
 import org.graalvm.compiler.asm.aarch64.AArch64Address;
+import org.graalvm.compiler.asm.aarch64.AArch64Assembler;
 import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
 import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler.ScratchRegister;
+import org.graalvm.compiler.core.common.CompressEncoding;
 import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.spi.LIRKindTool;
 import org.graalvm.compiler.core.common.type.DataPointerConstant;
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.lir.LIRFrameState;
@@ -54,6 +61,7 @@
 import org.graalvm.compiler.lir.StandardOp.ValueMoveOp;
 import org.graalvm.compiler.lir.VirtualStackSlot;
 import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+import org.graalvm.compiler.options.OptionValues;
 
 import jdk.vm.ci.aarch64.AArch64Kind;
 import jdk.vm.ci.code.MemoryBarriers;
@@ -507,10 +515,14 @@
                 break;
             case Object:
                 if (input.isNull()) {
-                    masm.mov(dst, 0);
+                    if (crb.mustReplaceWithNullRegister(input)) {
+                        masm.mov(64, dst, crb.nullRegister);
+                    } else {
+                        masm.mov(dst, 0);
+                    }
                 } else if (crb.target.inlineObjects) {
                     crb.recordInlineDataInCode(input);
-                    masm.movNativeAddress(dst, 0xDEADDEADDEADDEADL);
+                    masm.mov(dst, 0xDEADDEADDEADDEADL, true);
                 } else {
                     masm.ldr(64, dst, (AArch64Address) crb.recordDataReferenceInCode(input, 8));
                 }
@@ -561,4 +573,131 @@
         return masm.makeAddress(sp, displacement, scratchReg, transferSize, /* allowOverwrite */false);
     }
 
+    public abstract static class PointerCompressionOp extends AArch64LIRInstruction {
+
+        @Def({REG, HINT}) private AllocatableValue result;
+        @Use({REG, CONST}) private Value input;
+        @Alive({REG, ILLEGAL, UNINITIALIZED}) private AllocatableValue baseRegister;
+
+        protected final CompressEncoding encoding;
+        protected final boolean nonNull;
+        protected final LIRKindTool lirKindTool;
+
+        protected PointerCompressionOp(LIRInstructionClass<? extends PointerCompressionOp> type, AllocatableValue result, Value input,
+                        AllocatableValue baseRegister, CompressEncoding encoding, boolean nonNull, LIRKindTool lirKindTool) {
+
+            super(type);
+            this.result = result;
+            this.input = input;
+            this.baseRegister = baseRegister;
+            this.encoding = encoding;
+            this.nonNull = nonNull;
+            this.lirKindTool = lirKindTool;
+        }
+
+        public static boolean hasBase(OptionValues options, CompressEncoding encoding) {
+            return GeneratePIC.getValue(options) || encoding.hasBase();
+        }
+
+        public final Value getInput() {
+            return input;
+        }
+
+        public final AllocatableValue getResult() {
+            return result;
+        }
+
+        protected final Register getResultRegister() {
+            return asRegister(result);
+        }
+
+        protected final Register getBaseRegister(CompilationResultBuilder crb) {
+            return hasBase(crb.getOptions(), encoding) ? asRegister(baseRegister) : Register.None;
+        }
+
+        protected final int getShift() {
+            return encoding.getShift();
+        }
+
+        protected final void move(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            AArch64Move.move(crb, masm, result, input);
+        }
+    }
+
+    public static class CompressPointerOp extends PointerCompressionOp {
+        public static final LIRInstructionClass<CompressPointerOp> TYPE = LIRInstructionClass.create(CompressPointerOp.class);
+
+        public CompressPointerOp(AllocatableValue result, Value input, AllocatableValue baseRegister, CompressEncoding encoding, boolean nonNull, LIRKindTool lirKindTool) {
+            this(TYPE, result, input, baseRegister, encoding, nonNull, lirKindTool);
+        }
+
+        private CompressPointerOp(LIRInstructionClass<? extends PointerCompressionOp> type, AllocatableValue result, Value input,
+                        AllocatableValue baseRegister, CompressEncoding encoding, boolean nonNull, LIRKindTool lirKindTool) {
+
+            super(type, result, input, baseRegister, encoding, nonNull, lirKindTool);
+        }
+
+        @Override
+        protected void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            Register resultRegister = getResultRegister();
+            Register ptr = asRegister(getInput());
+            Register base = getBaseRegister(crb);
+            // result = (ptr - base) >> shift
+            if (!encoding.hasBase()) {
+                if (encoding.hasShift()) {
+                    masm.lshr(64, resultRegister, ptr, encoding.getShift());
+                } else {
+                    masm.movx(resultRegister, ptr);
+                }
+            } else if (nonNull) {
+                masm.sub(64, resultRegister, ptr, base);
+                if (encoding.hasShift()) {
+                    masm.lshr(64, resultRegister, resultRegister, encoding.getShift());
+                }
+            } else {
+                // if ptr is null it still has to be null after compression
+                masm.cmp(64, ptr, 0);
+                masm.cmov(64, resultRegister, ptr, base, AArch64Assembler.ConditionFlag.NE);
+                masm.sub(64, resultRegister, resultRegister, base);
+                if (encoding.hasShift()) {
+                    masm.lshr(64, resultRegister, resultRegister, encoding.getShift());
+                }
+            }
+        }
+    }
+
+    public static class UncompressPointerOp extends PointerCompressionOp {
+        public static final LIRInstructionClass<UncompressPointerOp> TYPE = LIRInstructionClass.create(UncompressPointerOp.class);
+
+        public UncompressPointerOp(AllocatableValue result, Value input, AllocatableValue baseRegister, CompressEncoding encoding, boolean nonNull, LIRKindTool lirKindTool) {
+            this(TYPE, result, input, baseRegister, encoding, nonNull, lirKindTool);
+        }
+
+        private UncompressPointerOp(LIRInstructionClass<? extends PointerCompressionOp> type, AllocatableValue result, Value input,
+                        AllocatableValue baseRegister, CompressEncoding encoding, boolean nonNull, LIRKindTool lirKindTool) {
+            super(type, result, input, baseRegister, encoding, nonNull, lirKindTool);
+        }
+
+        @Override
+        protected void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+            Register inputRegister = asRegister(getInput());
+            Register resultRegister = getResultRegister();
+            Register base = encoding.hasBase() ? getBaseRegister(crb) : null;
+
+            // result = base + (ptr << shift)
+            if (nonNull || base == null) {
+                masm.add(64, resultRegister, base == null ? zr : base, inputRegister, AArch64Assembler.ShiftType.LSL, encoding.getShift());
+            } else {
+                // if ptr is null it has to be null after decompression
+                Label done = new Label();
+                if (!resultRegister.equals(inputRegister)) {
+                    masm.mov(32, resultRegister, inputRegister);
+                }
+                masm.cbz(32, resultRegister, done);
+                masm.add(64, resultRegister, base, resultRegister, AArch64Assembler.ShiftType.LSL, encoding.getShift());
+                masm.bind(done);
+            }
+        }
+    }
+
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ArrayIndexOfOp.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ArrayIndexOfOp.java	Thu Mar 28 19:39:14 2019 +0100
@@ -655,3 +655,4 @@
         return ((AMD64) tool.target().arch).getFeatures().contains(cpuFeature);
     }
 }
+
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64Binary.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64Binary.java	Thu Mar 28 19:39:14 2019 +0100
@@ -137,6 +137,11 @@
                 opcode.emit(masm, size, asRegister(result), (AMD64Address) crb.asAddress(input));
             }
         }
+
+        public AMD64RMOp getOpcode() {
+            return opcode;
+        }
+
     }
 
     /**
@@ -263,6 +268,11 @@
             }
             return false;
         }
+
+        public AMD64RMOp getOpcode() {
+            return opcode;
+        }
+
     }
 
     /**
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64BinaryConsumer.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64BinaryConsumer.java	Thu Mar 28 19:39:14 2019 +0100
@@ -131,6 +131,10 @@
         protected boolean shouldAnnotate() {
             return false;
         }
+
+        public AMD64MIOp getOpcode() {
+            return opcode;
+        }
     }
 
     /**
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/LIRGenerator.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/LIRGenerator.java	Thu Mar 28 19:39:14 2019 +0100
@@ -46,6 +46,7 @@
 import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
 import org.graalvm.compiler.core.common.spi.LIRKindTool;
 import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.debug.DebugCloseable;
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.debug.TTY;
 import org.graalvm.compiler.graph.NodeSourcePosition;
@@ -386,6 +387,24 @@
         return blockScope;
     }
 
+    private final class MatchScope implements DebugCloseable {
+
+        private MatchScope(AbstractBlockBase<?> block) {
+            currentBlock = block;
+        }
+
+        @Override
+        public void close() {
+            currentBlock = null;
+        }
+
+    }
+
+    public final DebugCloseable getMatchScope(AbstractBlockBase<?> block) {
+        MatchScope matchScope = new MatchScope(block);
+        return matchScope;
+    }
+
     @Override
     public void emitIncomingValues(Value[] params) {
         ((LabelOp) res.getLIR().getLIRforBlock(getCurrentBlock()).get(0)).setIncomingValues(params);
@@ -457,7 +476,8 @@
         double minDensity = 1 / Math.sqrt(strategy.getAverageEffort());
         Optional<Hasher> hasher = hasherFor(keyConstants, minDensity);
         double hashTableSwitchDensity = hasher.map(h -> keyCount / (double) h.cardinality()).orElse(0d);
-        long valueRange = keyConstants[keyCount - 1].asLong() - keyConstants[0].asLong() + 1;
+        // The value range computation below may overflow, so compute it as a long.
+        long valueRange = (long) keyConstants[keyCount - 1].asInt() - (long) keyConstants[0].asInt() + 1;
         double tableSwitchDensity = keyCount / (double) valueRange;
 
         /*
@@ -479,7 +499,7 @@
                     targets[i] = defaultTarget;
                 }
                 for (int i = 0; i < keyCount; i++) {
-                    int idx = h.hash(keyConstants[i].asLong());
+                    int idx = h.hash(keyConstants[i].asInt());
                     keys[idx] = keyConstants[i];
                     targets[idx] = keyTargets[i];
                 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/LIRGeneratorTool.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/LIRGeneratorTool.java	Thu Mar 28 19:39:14 2019 +0100
@@ -269,11 +269,6 @@
     Variable emitArrayEquals(JavaKind kind, Value array1, Value array2, Value length, int constantLength, boolean directPointers);
 
     @SuppressWarnings("unused")
-    default ForeignCallLinkage lookupArrayEqualsStub(JavaKind kind, int constantLength) {
-        return null;
-    }
-
-    @SuppressWarnings("unused")
     default Variable emitArrayEquals(JavaKind kind1, JavaKind kind2, Value array1, Value array2, Value length, int constantLength, boolean directPointers) {
         throw GraalError.unimplemented("Array.equals with different types substitution is not implemented on this architecture");
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/hashing/HashFunction.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/hashing/HashFunction.java	Thu Mar 28 19:39:14 2019 +0100
@@ -49,7 +49,7 @@
      * @param min {@code value} is guaranteed to be greater or equal to this minimum
      * @return the hash value within int range
      */
-    public abstract int apply(long value, long min);
+    public abstract int apply(int value, int min);
 
     /**
      * Generates LIR that implements the hash function in terms of value and min.
@@ -109,25 +109,25 @@
                       (gen, prime) -> (val, min) -> gen.emitShr(gen.emitMul(val, prime, false), min));
 
         addWithPrimes("rotateRight(val, prime)", 3,
-                      prime -> (val, min) -> Long.rotateRight(val, prime),
+                      prime -> (val, min) -> Integer.rotateRight(val, prime),
                       (gen, prime) -> (val, min) -> gen.emitRor(val, prime));
 
         addWithPrimes("rotateRight(val, prime) + val", 4,
-                      prime -> (val, min) -> Long.rotateRight(val, prime) + val,
+                      prime -> (val, min) -> Integer.rotateRight(val, prime) + val,
                       (gen, prime) -> (val, min) -> gen.emitAdd(gen.emitRor(val, prime), val, false));
 
         addWithPrimes("rotateRight(val, prime) ^ val", 4,
-                      prime -> (val, min) -> Long.rotateRight(val, prime) ^ val,
+                      prime -> (val, min) -> Integer.rotateRight(val, prime) ^ val,
                       (gen, prime) -> (val, min) -> gen.emitXor(gen.emitRor(val, prime), val));
       //@formatter:on
     }
 
-    private static void add(String toString, int effort, BiFunction<Long, Long, Long> f, Function<ArithmeticLIRGenerator, BiFunction<Value, Value, Value>> gen) {
+    private static void add(String toString, int effort, BiFunction<Integer, Integer, Integer> f, Function<ArithmeticLIRGenerator, BiFunction<Value, Value, Value>> gen) {
         instances.add(new HashFunction() {
 
             @Override
-            public int apply(long value, long min) {
-                return f.apply(value, min).intValue();
+            public int apply(int value, int min) {
+                return f.apply(value, min);
             }
 
             @Override
@@ -147,7 +147,7 @@
         });
     }
 
-    private static void addWithPrimes(String toString, int effort, Function<Integer, BiFunction<Long, Long, Long>> f,
+    private static void addWithPrimes(String toString, int effort, Function<Integer, BiFunction<Integer, Integer, Integer>> f,
                     BiFunction<ArithmeticLIRGenerator, Value, BiFunction<Value, Value, Value>> gen) {
         for (int p : mersennePrimes) {
             add(toString, effort, f.apply(p), g -> gen.apply(g, g.getLIRGen().emitJavaConstant(JavaConstant.forInt(p))));
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/hashing/Hasher.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/hashing/Hasher.java	Thu Mar 28 19:39:14 2019 +0100
@@ -30,6 +30,7 @@
 import java.util.Set;
 import java.util.TreeSet;
 
+import jdk.vm.ci.meta.JavaKind;
 import org.graalvm.compiler.lir.gen.ArithmeticLIRGenerator;
 
 import jdk.vm.ci.meta.JavaConstant;
@@ -51,11 +52,12 @@
      * @return an optional hasher
      */
     public static Optional<Hasher> forKeys(JavaConstant[] keys, double minDensity) {
+        assert checkKeyKind(keys);
         if (keys.length <= 2) {
             return Optional.empty();
         } else {
             int maxCardinality = (int) Math.round(keys.length / minDensity);
-            assertSorted(keys);
+            assert checkIfSorted(keys);
             TreeSet<Hasher> candidates = new TreeSet<>(new Comparator<Hasher>() {
                 @Override
                 public int compare(Hasher o1, Hasher o2) {
@@ -67,7 +69,7 @@
                     }
                 }
             });
-            long min = keys[0].asLong();
+            int min = keys[0].asInt();
             for (HashFunction f : HashFunction.instances()) {
                 for (int cardinality = keys.length; cardinality < maxCardinality; cardinality++) {
                     if (isValid(keys, min, f, cardinality)) {
@@ -84,16 +86,28 @@
         }
     }
 
-    private static void assertSorted(JavaConstant[] keys) {
-        for (int i = 1; i < keys.length; i++) {
-            assert keys[i - 1].asLong() < keys[i].asLong();
+    private static boolean checkKeyKind(JavaConstant[] keys) {
+        for (int i = 0; i < keys.length; i++) {
+            if (keys[i].getJavaKind() != JavaKind.Int) {
+                throw new AssertionError(String.format("Key at index %d is not an int: %s", i, keys[i]));
+            }
         }
+        return true;
     }
 
-    private static boolean isValid(JavaConstant[] keys, long min, HashFunction function, int cardinality) {
+    private static boolean checkIfSorted(JavaConstant[] keys) {
+        for (int i = 1; i < keys.length; i++) {
+            if (keys[i - 1].asInt() >= keys[i].asInt()) {
+                throw new AssertionError("Keys array is not sorted");
+            }
+        }
+        return true;
+    }
+
+    private static boolean isValid(JavaConstant[] keys, int min, HashFunction function, int cardinality) {
         Set<Integer> seen = new HashSet<>(keys.length);
         for (JavaConstant key : keys) {
-            int hash = function.apply(key.asLong(), min) & (cardinality - 1);
+            int hash = function.apply(key.asInt(), min) & (cardinality - 1);
             if (!seen.add(hash)) {
                 return false;
             }
@@ -103,9 +117,9 @@
 
     private final HashFunction function;
     private final int cardinality;
-    private final long min;
+    private final int min;
 
-    private Hasher(HashFunction function, int cardinality, long min) {
+    private Hasher(HashFunction function, int cardinality, int min) {
         this.function = function;
         this.cardinality = cardinality;
         this.min = min;
@@ -117,7 +131,7 @@
      * @param value the value to be hashed
      * @return the hash value
      */
-    public int hash(long value) {
+    public int hash(int value) {
         return function.apply(value, min) & (cardinality - 1);
     }
 
@@ -129,7 +143,7 @@
      * @return the hashed lir value
      */
     public Value hash(Value value, ArithmeticLIRGenerator gen) {
-        Value h = function.gen(value, gen.getLIRGen().emitJavaConstant(JavaConstant.forLong(min)), gen);
+        Value h = function.gen(value, gen.getLIRGen().emitJavaConstant(JavaConstant.forInt(min)), gen);
         return gen.emitAnd(h, gen.getLIRGen().emitJavaConstant(JavaConstant.forInt(cardinality - 1)));
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/SimplifyingGraphDecoder.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/SimplifyingGraphDecoder.java	Thu Mar 28 19:39:14 2019 +0100
@@ -44,7 +44,7 @@
 import org.graalvm.compiler.nodes.java.ArrayLengthNode;
 import org.graalvm.compiler.nodes.java.LoadFieldNode;
 import org.graalvm.compiler.nodes.java.LoadIndexedNode;
-import org.graalvm.compiler.nodes.spi.StampProvider;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.nodes.util.GraphUtil;
 import org.graalvm.compiler.options.OptionValues;
 
@@ -61,10 +61,7 @@
  */
 public class SimplifyingGraphDecoder extends GraphDecoder {
 
-    protected final MetaAccessProvider metaAccess;
-    protected final ConstantReflectionProvider constantReflection;
-    protected final ConstantFieldProvider constantFieldProvider;
-    protected final StampProvider stampProvider;
+    protected final CoreProviders providers;
     protected final boolean canonicalizeReads;
     protected final CanonicalizerTool canonicalizerTool;
 
@@ -85,17 +82,17 @@
 
         @Override
         public MetaAccessProvider getMetaAccess() {
-            return metaAccess;
+            return providers.getMetaAccess();
         }
 
         @Override
         public ConstantReflectionProvider getConstantReflection() {
-            return constantReflection;
+            return providers.getConstantReflection();
         }
 
         @Override
         public ConstantFieldProvider getConstantFieldProvider() {
-            return constantFieldProvider;
+            return providers.getConstantFieldProvider();
         }
 
         @Override
@@ -135,14 +132,9 @@
         }
     }
 
-    public SimplifyingGraphDecoder(Architecture architecture, StructuredGraph graph, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection,
-                    ConstantFieldProvider constantFieldProvider, StampProvider stampProvider,
-                    boolean canonicalizeReads) {
+    public SimplifyingGraphDecoder(Architecture architecture, StructuredGraph graph, CoreProviders providers, boolean canonicalizeReads) {
         super(architecture, graph);
-        this.metaAccess = metaAccess;
-        this.constantReflection = constantReflection;
-        this.constantFieldProvider = constantFieldProvider;
-        this.stampProvider = stampProvider;
+        this.providers = providers;
         this.canonicalizeReads = canonicalizeReads;
         this.canonicalizerTool = new PECanonicalizerTool(graph.getAssumptions(), graph.getOptions());
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/JavaWriteNode.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/JavaWriteNode.java	Thu Mar 28 19:39:14 2019 +0100
@@ -24,6 +24,8 @@
 
 package org.graalvm.compiler.nodes.extended;
 
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
 import org.graalvm.compiler.nodes.StateSplit;
@@ -72,4 +74,9 @@
     public boolean isCompressible() {
         return compressible;
     }
+
+    @Override
+    public Stamp getAccessStamp() {
+        return StampFactory.forKind(writeKind);
+    }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderConfiguration.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderConfiguration.java	Thu Mar 28 19:39:14 2019 +0100
@@ -201,6 +201,7 @@
     private final List<ResolvedJavaType> skippedExceptionTypes;
     private final boolean insertFullInfopoints;
     private final boolean trackNodeSourcePosition;
+    private final boolean retainLocalVariables;
     private final Plugins plugins;
 
     public enum BytecodeExceptionMode {
@@ -229,6 +230,7 @@
                     boolean omitAssertions,
                     boolean insertFullInfopoints,
                     boolean trackNodeSourcePosition,
+                    boolean retainLocalVariables,
                     List<ResolvedJavaType> skippedExceptionTypes,
                     Plugins plugins) {
         this.eagerResolving = eagerResolving;
@@ -237,6 +239,7 @@
         this.omitAssertions = omitAssertions;
         this.insertFullInfopoints = insertFullInfopoints;
         this.trackNodeSourcePosition = trackNodeSourcePosition;
+        this.retainLocalVariables = retainLocalVariables;
         this.skippedExceptionTypes = skippedExceptionTypes;
         this.plugins = plugins;
     }
@@ -255,6 +258,7 @@
                         omitAssertions,
                         insertFullInfopoints,
                         trackNodeSourcePosition,
+                        retainLocalVariables,
                         skippedExceptionTypes,
                         newPlugins);
         return result;
@@ -274,6 +278,7 @@
                         omitAssertions,
                         insertFullInfopoints,
                         trackNodeSourcePosition,
+                        retainLocalVariables,
                         skippedExceptionTypes,
                         plugins);
     }
@@ -286,6 +291,7 @@
                         omitAssertions,
                         insertFullInfopoints,
                         trackNodeSourcePosition,
+                        retainLocalVariables,
                         skippedExceptionTypes,
                         plugins);
     }
@@ -298,6 +304,7 @@
                         omitAssertions,
                         insertFullInfopoints,
                         trackNodeSourcePosition,
+                        retainLocalVariables,
                         Collections.unmodifiableList(Arrays.asList(newSkippedExceptionTypes)),
                         plugins);
     }
@@ -309,6 +316,7 @@
                         omitAssertions,
                         insertFullInfopoints,
                         trackNodeSourcePosition,
+                        retainLocalVariables,
                         skippedExceptionTypes,
                         plugins);
     }
@@ -321,6 +329,7 @@
                         newOmitAssertions,
                         insertFullInfopoints,
                         trackNodeSourcePosition,
+                        retainLocalVariables,
                         skippedExceptionTypes,
                         plugins);
     }
@@ -333,6 +342,7 @@
                         omitAssertions,
                         newInsertFullInfopoints,
                         trackNodeSourcePosition,
+                        retainLocalVariables,
                         skippedExceptionTypes,
                         plugins);
     }
@@ -345,6 +355,20 @@
                         omitAssertions,
                         insertFullInfopoints,
                         newTrackNodeSourcePosition,
+                        retainLocalVariables,
+                        skippedExceptionTypes,
+                        plugins);
+    }
+
+    public GraphBuilderConfiguration withRetainLocalVariables(boolean newRetainLocalVariables) {
+        return new GraphBuilderConfiguration(
+                        eagerResolving,
+                        unresolvedIsError,
+                        bytecodeExceptionMode,
+                        omitAssertions,
+                        insertFullInfopoints,
+                        trackNodeSourcePosition,
+                        newRetainLocalVariables,
                         skippedExceptionTypes,
                         plugins);
     }
@@ -369,6 +393,10 @@
         return trackNodeSourcePosition;
     }
 
+    public boolean retainLocalVariables() {
+        return retainLocalVariables;
+    }
+
     public boolean insertFullInfopoints() {
         return insertFullInfopoints;
     }
@@ -381,6 +409,7 @@
                         /* omitAssertions: */ false,
                         /* insertFullInfopoints: */ false,
                         /* trackNodeSourcePosition: */ false,
+                        /* retainLocalVariables */ false,
                         Collections.emptyList(),
                         plugins);
     }
@@ -393,6 +422,7 @@
                         /* omitAssertions: */ false,
                         /* insertFullInfopoints: */ false,
                         /* trackNodeSourcePosition: */ false,
+                        /* retainLocalVariables */ false,
                         Collections.emptyList(),
                         plugins);
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderTool.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderTool.java	Thu Mar 28 19:39:14 2019 +0100
@@ -28,6 +28,7 @@
 import org.graalvm.compiler.debug.DebugContext;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.Replacements;
 import org.graalvm.compiler.nodes.spi.StampProvider;
 import org.graalvm.compiler.options.OptionValues;
 
@@ -52,6 +53,8 @@
 
     MetaAccessProvider getMetaAccess();
 
+    Replacements getReplacements();
+
     default Assumptions getAssumptions() {
         return getGraph().getAssumptions();
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/NodePlugin.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/NodePlugin.java	Thu Mar 28 19:39:14 2019 +0100
@@ -243,3 +243,4 @@
         return false;
     }
 }
+
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/AbstractWriteNode.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/AbstractWriteNode.java	Thu Mar 28 19:39:14 2019 +0100
@@ -27,6 +27,7 @@
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
 
+import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.graph.NodeClass;
@@ -90,4 +91,6 @@
         updateUsages(lastLocationAccess, newLla);
         lastLocationAccess = newLla;
     }
+
+    public abstract Stamp getAccessStamp();
 }
--- /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/spi/CoreProviders.java	Thu Mar 28 19:39:14 2019 +0100
@@ -0,0 +1,48 @@
+/*
+ * 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.spi;
+
+import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
+import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
+
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.MetaAccessProvider;
+
+public interface CoreProviders {
+
+    MetaAccessProvider getMetaAccess();
+
+    ConstantReflectionProvider getConstantReflection();
+
+    ConstantFieldProvider getConstantFieldProvider();
+
+    LoweringProvider getLowerer();
+
+    Replacements getReplacements();
+
+    StampProvider getStampProvider();
+
+    ForeignCallsProvider getForeignCalls();
+}
--- /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/spi/CoreProvidersImpl.java	Thu Mar 28 19:39:14 2019 +0100
@@ -0,0 +1,87 @@
+/*
+ * 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.spi;
+
+import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
+import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
+
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.MetaAccessProvider;
+
+public class CoreProvidersImpl implements CoreProviders {
+    protected final MetaAccessProvider metaAccess;
+    protected final ConstantReflectionProvider constantReflection;
+    protected final ConstantFieldProvider constantFieldProvider;
+    protected final LoweringProvider lowerer;
+    protected final Replacements replacements;
+    protected final StampProvider stampProvider;
+    protected final ForeignCallsProvider foreignCalls;
+
+    protected CoreProvidersImpl(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, ConstantFieldProvider constantFieldProvider, LoweringProvider lowerer,
+                    Replacements replacements, StampProvider stampProvider, ForeignCallsProvider foreignCalls) {
+        this.metaAccess = metaAccess;
+        this.constantReflection = constantReflection;
+        this.constantFieldProvider = constantFieldProvider;
+        this.lowerer = lowerer;
+        this.replacements = replacements;
+        this.stampProvider = stampProvider;
+        this.foreignCalls = foreignCalls;
+    }
+
+    @Override
+    public MetaAccessProvider getMetaAccess() {
+        return metaAccess;
+    }
+
+    @Override
+    public ConstantReflectionProvider getConstantReflection() {
+        return constantReflection;
+    }
+
+    @Override
+    public ConstantFieldProvider getConstantFieldProvider() {
+        return constantFieldProvider;
+    }
+
+    @Override
+    public LoweringProvider getLowerer() {
+        return lowerer;
+    }
+
+    @Override
+    public Replacements getReplacements() {
+        return replacements;
+    }
+
+    @Override
+    public StampProvider getStampProvider() {
+        return stampProvider;
+    }
+
+    @Override
+    public ForeignCallsProvider getForeignCalls() {
+        return foreignCalls;
+    }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/LoweringTool.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/LoweringTool.java	Thu Mar 28 19:39:14 2019 +0100
@@ -40,6 +40,8 @@
 
 public interface LoweringTool {
 
+    CoreProviders getProviders();
+
     MetaAccessProvider getMetaAccess();
 
     LoweringProvider getLowerer();
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/NodeLIRBuilderTool.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/NodeLIRBuilderTool.java	Thu Mar 28 19:39:14 2019 +0100
@@ -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,6 +28,7 @@
 import java.util.List;
 
 import org.graalvm.compiler.core.common.cfg.BlockMap;
+import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.graph.NodeSourcePosition;
@@ -96,4 +97,11 @@
     }
 
     void emitReadExceptionObject(ValueNode node);
+
+    @SuppressWarnings("unused")
+    default ForeignCallLinkage lookupGraalStub(ValueNode valueNode) {
+        return null;
+    }
+
+    void matchBlock(Block b, StructuredGraph graph, StructuredGraph.ScheduleResult blockMap);
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionsParser.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionsParser.java	Thu Mar 28 19:39:14 2019 +0100
@@ -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
@@ -36,6 +36,8 @@
 import jdk.internal.vm.compiler.collections.EconomicMap;
 import jdk.internal.vm.compiler.collections.MapCursor;
 
+import jdk.vm.ci.services.Services;
+
 /**
  * This class contains methods for parsing Graal options and matching them against a set of
  * {@link OptionDescriptors}. The {@link OptionDescriptors} are loaded via a {@link ServiceLoader}.
@@ -51,7 +53,7 @@
         if (IS_IN_NATIVE_IMAGE || cachedOptionDescriptors != null) {
             return cachedOptionDescriptors;
         }
-        boolean java8OrEarlier = System.getProperty("java.specification.version").compareTo("1.9") < 0;
+        boolean java8OrEarlier = Services.getSavedProperties().get("java.specification.version").compareTo("1.9") < 0;
         ClassLoader loader;
         if (java8OrEarlier) {
             // On JDK 8, Graal and its extensions are loaded by same class loader.
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/LoweringPhase.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/LoweringPhase.java	Thu Mar 28 19:39:14 2019 +0100
@@ -38,6 +38,7 @@
 import java.util.List;
 
 import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
+import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.debug.DebugCloseable;
 import org.graalvm.compiler.debug.GraalError;
@@ -68,6 +69,7 @@
 import org.graalvm.compiler.nodes.extended.GuardedNode;
 import org.graalvm.compiler.nodes.extended.GuardingNode;
 import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.nodes.spi.Lowerable;
 import org.graalvm.compiler.nodes.spi.LoweringProvider;
 import org.graalvm.compiler.nodes.spi.LoweringTool;
@@ -144,6 +146,11 @@
         }
 
         @Override
+        public CoreProviders getProviders() {
+            return context;
+        }
+
+        @Override
         public ConstantReflectionProvider getConstantReflection() {
             return context.getConstantReflection();
         }
@@ -168,6 +175,10 @@
             return context.getReplacements();
         }
 
+        public ForeignCallsProvider getForeignCalls() {
+            return context.getForeignCalls();
+        }
+
         @Override
         public AnchoringNode getCurrentGuardAnchor() {
             return guardAnchor;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ProfileCompiledMethodsPhase.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ProfileCompiledMethodsPhase.java	Thu Mar 28 19:39:14 2019 +0100
@@ -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
@@ -69,6 +69,8 @@
 import org.graalvm.compiler.phases.Phase;
 import org.graalvm.compiler.phases.schedule.SchedulePhase;
 
+import jdk.vm.ci.services.Services;
+
 /**
  * This phase add counters for the dynamically executed number of nodes. Incrementing the counter
  * for each node would be too costly, so this phase takes the compromise that it trusts split
@@ -87,9 +89,17 @@
     private static final String GROUP_NAME_WITHOUT = "~profiled weight (invoke-free sections)";
     private static final String GROUP_NAME_INVOKES = "~profiled invokes";
 
-    private static final boolean WITH_SECTION_HEADER = Boolean.parseBoolean(System.getProperty("ProfileCompiledMethodsPhase.WITH_SECTION_HEADER", "false"));
-    private static final boolean WITH_INVOKE_FREE_SECTIONS = Boolean.parseBoolean(System.getProperty("ProfileCompiledMethodsPhase.WITH_FREE_SECTIONS", "false"));
-    private static final boolean WITH_INVOKES = Boolean.parseBoolean(System.getProperty("ProfileCompiledMethodsPhase.WITH_INVOKES", "true"));
+    private static String getProperty(String name, String def) {
+        String value = Services.getSavedProperties().get(name);
+        if (value == null) {
+            return def;
+        }
+        return value;
+    }
+
+    private static final boolean WITH_SECTION_HEADER = Boolean.parseBoolean(getProperty("ProfileCompiledMethodsPhase.WITH_SECTION_HEADER", "false"));
+    private static final boolean WITH_INVOKE_FREE_SECTIONS = Boolean.parseBoolean(getProperty("ProfileCompiledMethodsPhase.WITH_FREE_SECTIONS", "false"));
+    private static final boolean WITH_INVOKES = Boolean.parseBoolean(getProperty("ProfileCompiledMethodsPhase.WITH_INVOKES", "true"));
 
     @Override
     protected void run(StructuredGraph graph) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/InliningData.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/InliningData.java	Thu Mar 28 19:39:14 2019 +0100
@@ -154,6 +154,8 @@
             return "it is marked non-inlinable";
         } else if (countRecursiveInlining(method) > MaximumRecursiveInlining.getValue(options)) {
             return "it exceeds the maximum recursive inlining depth";
+        } else if (!method.hasBytecodes()) {
+            return "it has no bytecodes to inline";
         } else {
             if (new OptimisticOptimizations(rootGraph.getProfilingInfo(method), options).lessOptimisticThan(context.getOptimisticOptimizations())) {
                 return "the callee uses less optimistic optimizations than caller";
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/VerifyPhase.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/VerifyPhase.java	Thu Mar 28 19:39:14 2019 +0100
@@ -26,11 +26,12 @@
 
 import org.graalvm.compiler.nodes.StructuredGraph;
 
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
 /***
- * This phase serves as a verification, in order to check the graph for certain properties. The
- * {@link #verify(StructuredGraph, Object)} method will be used as an assertion, and implements the
- * actual check. Instead of returning false, it is also valid to throw an {@link VerificationError}
- * in the implemented {@link #verify(StructuredGraph, Object)} method.
+ * Verifies a {@linkplain #verify graph} or {@linkplain #verifyClass class} against one or more
+ * invariants.
  */
 public abstract class VerifyPhase<C> extends BasePhase<C> {
 
@@ -55,13 +56,23 @@
 
     @Override
     protected final void run(StructuredGraph graph, C context) {
-        assert verify(graph, context);
+        verify(graph, context);
     }
 
     /**
-     * Performs the actual verification.
+     * Checks {@code graph} against some invariants.
      *
      * @throws VerificationError if the verification fails
      */
-    protected abstract boolean verify(StructuredGraph graph, C context);
+    protected abstract void verify(StructuredGraph graph, C context);
+
+    /**
+     * Checks {@code clazz} against some invariants.
+     *
+     * @param clazz the class to verify
+     * @param metaAccess an object to get a {@link ResolvedJavaType} for {@code clazz}
+     * @throws VerificationError if the class violates some invariant
+     */
+    public void verifyClass(Class<?> clazz, MetaAccessProvider metaAccess) {
+    }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/tiers/PhaseContext.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/tiers/PhaseContext.java	Thu Mar 28 19:39:14 2019 +0100
@@ -25,66 +25,55 @@
 package org.graalvm.compiler.phases.tiers;
 
 import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
+import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
 import org.graalvm.compiler.nodes.spi.LoweringProvider;
 import org.graalvm.compiler.nodes.spi.Replacements;
 import org.graalvm.compiler.nodes.spi.StampProvider;
-import org.graalvm.compiler.phases.util.Providers;
 
 import jdk.vm.ci.meta.ConstantReflectionProvider;
 import jdk.vm.ci.meta.MetaAccessProvider;
-import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
 
-public class PhaseContext {
+public class PhaseContext implements CoreProviders {
 
-    private final MetaAccessProvider metaAccess;
-    private final ConstantReflectionProvider constantReflection;
-    private final ConstantFieldProvider constantFieldProvider;
-    private final LoweringProvider lowerer;
-    private final Replacements replacements;
-    private final StampProvider stampProvider;
-    private final ForeignCallsProvider foreignCalls;
+    private final CoreProviders providers;
 
-    public PhaseContext(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, ConstantFieldProvider constantFieldProvider, LoweringProvider lowerer, Replacements replacements,
-                    StampProvider stampProvider, ForeignCallsProvider foreignCalls) {
-        this.metaAccess = metaAccess;
-        this.constantReflection = constantReflection;
-        this.constantFieldProvider = constantFieldProvider;
-        this.lowerer = lowerer;
-        this.replacements = replacements;
-        this.stampProvider = stampProvider;
-        this.foreignCalls = foreignCalls;
+    public PhaseContext(CoreProviders providers) {
+        this.providers = providers;
     }
 
-    public PhaseContext(Providers providers) {
-        this(providers.getMetaAccess(), providers.getConstantReflection(), providers.getConstantFieldProvider(), providers.getLowerer(), providers.getReplacements(), providers.getStampProvider(),
-                        providers.getForeignCalls());
+    @Override
+    public MetaAccessProvider getMetaAccess() {
+        return providers.getMetaAccess();
     }
 
-    public MetaAccessProvider getMetaAccess() {
-        return metaAccess;
+    @Override
+    public ConstantReflectionProvider getConstantReflection() {
+        return providers.getConstantReflection();
     }
 
-    public ConstantReflectionProvider getConstantReflection() {
-        return constantReflection;
+    @Override
+    public ConstantFieldProvider getConstantFieldProvider() {
+        return providers.getConstantFieldProvider();
     }
 
-    public ConstantFieldProvider getConstantFieldProvider() {
-        return constantFieldProvider;
+    @Override
+    public LoweringProvider getLowerer() {
+        return providers.getLowerer();
     }
 
-    public LoweringProvider getLowerer() {
-        return lowerer;
+    @Override
+    public Replacements getReplacements() {
+        return providers.getReplacements();
     }
 
-    public Replacements getReplacements() {
-        return replacements;
+    @Override
+    public StampProvider getStampProvider() {
+        return providers.getStampProvider();
     }
 
-    public StampProvider getStampProvider() {
-        return stampProvider;
-    }
-
+    @Override
     public ForeignCallsProvider getForeignCalls() {
-        return foreignCalls;
+        return providers.getForeignCalls();
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/util/Providers.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/util/Providers.java	Thu Mar 28 19:39:14 2019 +0100
@@ -27,6 +27,7 @@
 import org.graalvm.compiler.core.common.spi.CodeGenProviders;
 import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
 import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
+import org.graalvm.compiler.nodes.spi.CoreProvidersImpl;
 import org.graalvm.compiler.nodes.spi.LoweringProvider;
 import org.graalvm.compiler.nodes.spi.Replacements;
 import org.graalvm.compiler.nodes.spi.StampProvider;
@@ -39,27 +40,14 @@
 /**
  * A set of providers, some of which may not be present (i.e., null).
  */
-public class Providers implements CodeGenProviders {
+public class Providers extends CoreProvidersImpl implements CodeGenProviders {
 
-    private final MetaAccessProvider metaAccess;
     private final CodeCacheProvider codeCache;
-    private final LoweringProvider lowerer;
-    private final ConstantReflectionProvider constantReflection;
-    private final ConstantFieldProvider constantFieldProvider;
-    private final ForeignCallsProvider foreignCalls;
-    private final Replacements replacements;
-    private final StampProvider stampProvider;
 
     public Providers(MetaAccessProvider metaAccess, CodeCacheProvider codeCache, ConstantReflectionProvider constantReflection, ConstantFieldProvider constantFieldProvider,
                     ForeignCallsProvider foreignCalls, LoweringProvider lowerer, Replacements replacements, StampProvider stampProvider) {
-        this.metaAccess = metaAccess;
+        super(metaAccess, constantReflection, constantFieldProvider, lowerer, replacements, stampProvider, foreignCalls);
         this.codeCache = codeCache;
-        this.constantReflection = constantReflection;
-        this.constantFieldProvider = constantFieldProvider;
-        this.foreignCalls = foreignCalls;
-        this.lowerer = lowerer;
-        this.replacements = replacements;
-        this.stampProvider = stampProvider;
     }
 
     public Providers(Providers copyFrom) {
@@ -73,41 +61,10 @@
     }
 
     @Override
-    public MetaAccessProvider getMetaAccess() {
-        return metaAccess;
-    }
-
-    @Override
     public CodeCacheProvider getCodeCache() {
         return codeCache;
     }
 
-    @Override
-    public ForeignCallsProvider getForeignCalls() {
-        return foreignCalls;
-    }
-
-    public LoweringProvider getLowerer() {
-        return lowerer;
-    }
-
-    @Override
-    public ConstantReflectionProvider getConstantReflection() {
-        return constantReflection;
-    }
-
-    public ConstantFieldProvider getConstantFieldProvider() {
-        return constantFieldProvider;
-    }
-
-    public Replacements getReplacements() {
-        return replacements;
-    }
-
-    public StampProvider getStampProvider() {
-        return stampProvider;
-    }
-
     public Providers copyWith(MetaAccessProvider substitution) {
         assert this.getClass() == Providers.class : "must override";
         return new Providers(substitution, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, replacements, stampProvider);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/CFGPrinterObserver.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/CFGPrinterObserver.java	Thu Mar 28 19:39:14 2019 +0100
@@ -64,6 +64,7 @@
 import jdk.vm.ci.code.InstalledCode;
 import jdk.vm.ci.meta.JavaMethod;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.services.Services;
 
 /**
  * Observes compilation events and uses {@link CFGPrinter} to produce a control flow graph for the
@@ -256,11 +257,19 @@
 
         static {
             DisassemblerProvider selected = null;
+            String arch = Services.getSavedProperties().get("os.arch");
             for (DisassemblerProvider d : GraalServices.load(DisassemblerProvider.class)) {
                 String name = d.getName().toLowerCase();
-                if (name.contains("hcf") || name.contains("hexcodefile")) {
-                    selected = d;
-                    break;
+                if (arch.equals("aarch64")) {
+                    if (name.contains("hsdis-objdump")) {
+                        selected = d;
+                        break;
+                    }
+                } else {
+                    if (name.contains("hcf") || name.contains("hexcodefile")) {
+                        selected = d;
+                        break;
+                    }
                 }
             }
             if (selected == null) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraphPrinterDumpHandler.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraphPrinterDumpHandler.java	Thu Mar 28 19:39:14 2019 +0100
@@ -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
@@ -52,6 +52,7 @@
 
 import jdk.vm.ci.meta.JavaMethod;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.services.Services;
 
 //JaCoCo Exclude
 
@@ -86,7 +87,7 @@
         this.printerSupplier = printerSupplier;
         /* Add the JVM and Java arguments to the graph properties to help identify it. */
         this.jvmArguments = jvmArguments();
-        this.sunJavaCommand = System.getProperty("sun.java.command");
+        this.sunJavaCommand = Services.getSavedProperties().get("sun.java.command");
     }
 
     private static String jvmArguments() {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64GraphBuilderPlugins.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64GraphBuilderPlugins.java	Thu Mar 28 19:39:14 2019 +0100
@@ -59,14 +59,16 @@
 
 public class AArch64GraphBuilderPlugins {
 
-    public static void register(Plugins plugins, BytecodeProvider bytecodeProvider, boolean explicitUnsafeNullChecks) {
+    public static void register(Plugins plugins, BytecodeProvider bytecodeProvider, boolean explicitUnsafeNullChecks, boolean registerMathPlugins) {
         InvocationPlugins invocationPlugins = plugins.getInvocationPlugins();
         invocationPlugins.defer(new Runnable() {
             @Override
             public void run() {
                 registerIntegerLongPlugins(invocationPlugins, AArch64IntegerSubstitutions.class, JavaKind.Int, bytecodeProvider);
                 registerIntegerLongPlugins(invocationPlugins, AArch64LongSubstitutions.class, JavaKind.Long, bytecodeProvider);
-                registerMathPlugins(invocationPlugins);
+                if (registerMathPlugins) {
+                    registerMathPlugins(invocationPlugins);
+                }
                 registerStringLatin1Plugins(invocationPlugins, bytecodeProvider);
                 registerStringUTF16Plugins(invocationPlugins, bytecodeProvider);
                 registerUnsafePlugins(invocationPlugins, bytecodeProvider);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/CachingPEGraphDecoder.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/CachingPEGraphDecoder.java	Thu Mar 28 19:39:14 2019 +0100
@@ -31,6 +31,7 @@
 import org.graalvm.compiler.debug.DebugContext;
 import org.graalvm.compiler.graph.SourceLanguagePositionProvider;
 import org.graalvm.compiler.java.GraphBuilderPhase;
+import org.graalvm.compiler.loop.phases.ConvertDeoptimizeToGuardPhase;
 import org.graalvm.compiler.nodes.EncodedGraph;
 import org.graalvm.compiler.nodes.GraphEncoder;
 import org.graalvm.compiler.nodes.StructuredGraph;
@@ -44,7 +45,6 @@
 import org.graalvm.compiler.nodes.graphbuilderconf.ParameterPlugin;
 import org.graalvm.compiler.phases.OptimisticOptimizations;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
-import org.graalvm.compiler.loop.phases.ConvertDeoptimizeToGuardPhase;
 import org.graalvm.compiler.phases.tiers.PhaseContext;
 import org.graalvm.compiler.phases.util.Providers;
 
@@ -67,7 +67,7 @@
                     AllowAssumptions allowAssumptions, LoopExplosionPlugin loopExplosionPlugin, InvocationPlugins invocationPlugins, InlineInvokePlugin[] inlineInvokePlugins,
                     ParameterPlugin parameterPlugin,
                     NodePlugin[] nodePlugins, ResolvedJavaMethod callInlinedMethod, SourceLanguagePositionProvider sourceLanguagePositionProvider) {
-        super(architecture, graph, providers.getMetaAccess(), providers.getConstantReflection(), providers.getConstantFieldProvider(), providers.getStampProvider(), loopExplosionPlugin,
+        super(architecture, graph, providers, loopExplosionPlugin,
                         invocationPlugins, inlineInvokePlugins, parameterPlugin, nodePlugins, callInlinedMethod, sourceLanguagePositionProvider);
 
         this.providers = providers;
@@ -78,8 +78,7 @@
     }
 
     protected GraphBuilderPhase.Instance createGraphBuilderPhaseInstance(IntrinsicContext initialIntrinsicContext) {
-        return new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), providers.getConstantReflection(), providers.getConstantFieldProvider(), graphBuilderConfig,
-                        optimisticOpts, initialIntrinsicContext);
+        return new GraphBuilderPhase.Instance(providers, graphBuilderConfig, optimisticOpts, initialIntrinsicContext);
     }
 
     @SuppressWarnings("try")
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ConstantStringIndexOfSnippets.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ConstantStringIndexOfSnippets.java	Thu Mar 28 19:39:14 2019 +0100
@@ -25,6 +25,7 @@
 package org.graalvm.compiler.replacements;
 
 import static org.graalvm.compiler.replacements.SnippetTemplate.DEFAULT_REPLACER;
+import static org.graalvm.compiler.serviceprovider.GraalUnsafeAccess.getUnsafe;
 
 import org.graalvm.compiler.api.replacements.Fold;
 import org.graalvm.compiler.api.replacements.Fold.InjectedParameter;
@@ -44,8 +45,11 @@
 import jdk.vm.ci.code.TargetDescription;
 import jdk.vm.ci.meta.JavaKind;
 import jdk.vm.ci.meta.MetaAccessProvider;
+import sun.misc.Unsafe;
 
 public class ConstantStringIndexOfSnippets implements Snippets {
+    private static final Unsafe UNSAFE = getUnsafe();
+
     public static class Templates extends AbstractTemplates {
 
         private final SnippetInfo indexOfConstant = snippet(ConstantStringIndexOfSnippets.class, "indexOfConstant");
@@ -157,10 +161,10 @@
             return 0;
         }
         long base = metaAccess.getArrayBaseOffset(JavaKind.Byte);
-        char lastChar = UnsafeAccess.UNSAFE.getChar(target, base + (c - 1) * 2);
+        char lastChar = UNSAFE.getChar(target, base + (c - 1) * 2);
         int md2 = c;
         for (int i = 0; i < c - 1; i++) {
-            char currChar = UnsafeAccess.UNSAFE.getChar(target, base + i * 2);
+            char currChar = UNSAFE.getChar(target, base + i * 2);
             if (currChar == lastChar) {
                 md2 = (c - 1) - i;
             }
@@ -174,7 +178,7 @@
         int i;
         long base = metaAccess.getArrayBaseOffset(JavaKind.Byte);
         for (i = 0; i < c - 1; i++) {
-            char currChar = UnsafeAccess.UNSAFE.getChar(s, base + i * 2);
+            char currChar = UNSAFE.getChar(s, base + i * 2);
             cache |= (1 << (currChar & 63));
         }
         return cache;
@@ -212,10 +216,10 @@
         int sourceEnd = sourceCount - targetCountLess1;
 
         long base = charArrayBaseOffset(INJECTED);
-        int lastChar = UnsafeAccess.UNSAFE.getChar(target, base + targetCountLess1 * 2);
+        int lastChar = UNSAFE.getChar(target, base + targetCountLess1 * 2);
 
         outer_loop: for (long i = sourceOffset + fromIndex; i < sourceEnd;) {
-            int src = UnsafeAccess.UNSAFE.getChar(source, base + (i + targetCountLess1) * 2);
+            int src = UNSAFE.getChar(source, base + (i + targetCountLess1) * 2);
             if (src == lastChar) {
                 // With random strings and a 4-character alphabet,
                 // reverse matching at this point sets up 0.8% fewer
@@ -229,8 +233,8 @@
                     ExplodeLoopNode.explodeLoop();
                 }
                 for (long j = 0; j < targetCountLess1; j++) {
-                    char sourceChar = UnsafeAccess.UNSAFE.getChar(source, base + (i + j) * 2);
-                    if (UnsafeAccess.UNSAFE.getChar(target, base + (targetOffset + j) * 2) != sourceChar) {
+                    char sourceChar = UNSAFE.getChar(source, base + (i + j) * 2);
+                    if (UNSAFE.getChar(target, base + (targetOffset + j) * 2) != sourceChar) {
                         if ((cache & (1 << sourceChar)) == 0) {
                             if (md2 < j + 1) {
                                 i += j + 1;
@@ -270,10 +274,10 @@
         int sourceEnd = sourceCount - targetCountLess1;
 
         long base = byteArrayBaseOffset(INJECTED);
-        int lastChar = UnsafeAccess.UNSAFE.getChar(target, base + targetCountLess1 * 2);
+        int lastChar = UNSAFE.getChar(target, base + targetCountLess1 * 2);
 
         outer_loop: for (long i = fromIndex; i < sourceEnd;) {
-            int src = UnsafeAccess.UNSAFE.getChar(source, base + (i + targetCountLess1) * 2);
+            int src = UNSAFE.getChar(source, base + (i + targetCountLess1) * 2);
             if (src == lastChar) {
                 // With random strings and a 4-character alphabet,
                 // reverse matching at this point sets up 0.8% fewer
@@ -287,8 +291,8 @@
                     ExplodeLoopNode.explodeLoop();
                 }
                 for (long j = 0; j < targetCountLess1; j++) {
-                    char sourceChar = UnsafeAccess.UNSAFE.getChar(source, base + (i + j) * 2);
-                    if (UnsafeAccess.UNSAFE.getChar(target, base + j * 2) != sourceChar) {
+                    char sourceChar = UNSAFE.getChar(source, base + (i + j) * 2);
+                    if (UNSAFE.getChar(target, base + j * 2) != sourceChar) {
                         if ((cache & (1 << sourceChar)) == 0) {
                             if (md2 < j + 1) {
                                 i += j + 1;
@@ -328,10 +332,10 @@
         int sourceEnd = sourceCount - targetCountLess1;
 
         long base = byteArrayBaseOffset(INJECTED);
-        int lastByte = UnsafeAccess.UNSAFE.getByte(target, base + targetCountLess1);
+        int lastByte = UNSAFE.getByte(target, base + targetCountLess1);
 
         outer_loop: for (long i = fromIndex; i < sourceEnd;) {
-            int src = UnsafeAccess.UNSAFE.getByte(source, base + i + targetCountLess1);
+            int src = UNSAFE.getByte(source, base + i + targetCountLess1);
             if (src == lastByte) {
                 // With random strings and a 4-character alphabet,
                 // reverse matching at this point sets up 0.8% fewer
@@ -345,8 +349,8 @@
                     ExplodeLoopNode.explodeLoop();
                 }
                 for (long j = 0; j < targetCountLess1; j++) {
-                    byte sourceByte = UnsafeAccess.UNSAFE.getByte(source, base + i + j);
-                    if (UnsafeAccess.UNSAFE.getByte(target, base + j) != sourceByte) {
+                    byte sourceByte = UNSAFE.getByte(source, base + i + j);
+                    if (UNSAFE.getByte(target, base + j) != sourceByte) {
                         if ((cache & (1 << sourceByte)) == 0) {
                             if (md2 < j + 1) {
                                 i += j + 1;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/GraphKit.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/GraphKit.java	Thu Mar 28 19:39:14 2019 +0100
@@ -68,6 +68,7 @@
 import org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext;
 import org.graalvm.compiler.nodes.java.ExceptionObjectNode;
 import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
+import org.graalvm.compiler.nodes.spi.Replacements;
 import org.graalvm.compiler.nodes.spi.StampProvider;
 import org.graalvm.compiler.nodes.type.StampTool;
 import org.graalvm.compiler.phases.OptimisticOptimizations;
@@ -152,6 +153,11 @@
     }
 
     @Override
+    public Replacements getReplacements() {
+        return providers.getReplacements();
+    }
+
+    @Override
     public StampProvider getStampProvider() {
         return providers.getStampProvider();
     }
@@ -355,7 +361,6 @@
     public void inline(InvokeNode invoke, String reason, String phase) {
         ResolvedJavaMethod method = ((MethodCallTargetNode) invoke.callTarget()).targetMethod();
 
-        MetaAccessProvider metaAccess = providers.getMetaAccess();
         Plugins plugins = new Plugins(graphBuilderPlugins);
         GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault(plugins);
 
@@ -366,9 +371,7 @@
             calleeGraph = new StructuredGraph.Builder(invoke.getOptions(), invoke.getDebug()).method(method).trackNodeSourcePosition(invoke.graph().trackNodeSourcePosition()).setIsSubstitution(
                             true).build();
             IntrinsicContext initialReplacementContext = new IntrinsicContext(method, method, providers.getReplacements().getDefaultReplacementBytecodeProvider(), INLINE_AFTER_PARSING);
-            GraphBuilderPhase.Instance instance = createGraphBuilderInstance(metaAccess, providers.getStampProvider(), providers.getConstantReflection(), providers.getConstantFieldProvider(), config,
-                            OptimisticOptimizations.NONE,
-                            initialReplacementContext);
+            GraphBuilderPhase.Instance instance = createGraphBuilderInstance(providers, config, OptimisticOptimizations.NONE, initialReplacementContext);
             instance.apply(calleeGraph);
         }
 
@@ -379,9 +382,9 @@
         InliningUtil.inline(invoke, calleeGraph, false, method, reason, phase);
     }
 
-    protected GraphBuilderPhase.Instance createGraphBuilderInstance(MetaAccessProvider metaAccess, StampProvider stampProvider, ConstantReflectionProvider constantReflection,
-                    ConstantFieldProvider constantFieldProvider, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, IntrinsicContext initialIntrinsicContext) {
-        return new GraphBuilderPhase.Instance(metaAccess, stampProvider, constantReflection, constantFieldProvider, graphBuilderConfig, optimisticOpts, initialIntrinsicContext);
+    protected GraphBuilderPhase.Instance createGraphBuilderInstance(Providers theProviders, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts,
+                    IntrinsicContext initialIntrinsicContext) {
+        return new GraphBuilderPhase.Instance(theProviders, graphBuilderConfig, optimisticOpts, initialIntrinsicContext);
     }
 
     protected void pushStructure(Structure structure) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/InlineDuringParsingPlugin.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/InlineDuringParsingPlugin.java	Thu Mar 28 19:39:14 2019 +0100
@@ -35,17 +35,26 @@
 import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin;
 
 import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.services.Services;
 
 public final class InlineDuringParsingPlugin implements InlineInvokePlugin {
 
+    private static int getInteger(String name, int def) {
+        String value = Services.getSavedProperties().get(name);
+        if (value != null) {
+            return Integer.parseInt(value);
+        }
+        return def;
+    }
+
     /**
      * Budget which when exceeded reduces the effective value of
      * {@link BytecodeParserOptions#InlineDuringParsingMaxDepth} to
      * {@link #MaxDepthAfterBudgetExceeded}.
      */
-    private static final int NodeBudget = Integer.getInteger("InlineDuringParsingPlugin.NodeBudget", 2000);
+    private static final int NodeBudget = getInteger("InlineDuringParsingPlugin.NodeBudget", 2000);
 
-    private static final int MaxDepthAfterBudgetExceeded = Integer.getInteger("InlineDuringParsingPlugin.MaxDepthAfterBudgetExceeded", 3);
+    private static final int MaxDepthAfterBudgetExceeded = getInteger("InlineDuringParsingPlugin.MaxDepthAfterBudgetExceeded", 3);
 
     @Override
     public InlineInfo shouldInlineInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/IntrinsicGraphBuilder.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/IntrinsicGraphBuilder.java	Thu Mar 28 19:39:14 2019 +0100
@@ -51,6 +51,8 @@
 import org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext;
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin.Receiver;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
+import org.graalvm.compiler.nodes.spi.Replacements;
 import org.graalvm.compiler.nodes.spi.StampProvider;
 import org.graalvm.compiler.options.OptionValues;
 
@@ -70,10 +72,7 @@
  */
 public class IntrinsicGraphBuilder implements GraphBuilderContext, Receiver {
 
-    protected final MetaAccessProvider metaAccess;
-    protected final ConstantReflectionProvider constantReflection;
-    protected final ConstantFieldProvider constantFieldProvider;
-    protected final StampProvider stampProvider;
+    protected final CoreProviders providers;
     protected final StructuredGraph graph;
     protected final Bytecode code;
     protected final ResolvedJavaMethod method;
@@ -82,17 +81,12 @@
     protected ValueNode[] arguments;
     protected ValueNode returnValue;
 
-    public IntrinsicGraphBuilder(OptionValues options, DebugContext debug, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, ConstantFieldProvider constantFieldProvider,
-                    StampProvider stampProvider, Bytecode code, int invokeBci) {
-        this(options, debug, metaAccess, constantReflection, constantFieldProvider, stampProvider, code, invokeBci, AllowAssumptions.YES);
+    public IntrinsicGraphBuilder(OptionValues options, DebugContext debug, CoreProviders providers, Bytecode code, int invokeBci) {
+        this(options, debug, providers, code, invokeBci, AllowAssumptions.YES);
     }
 
-    protected IntrinsicGraphBuilder(OptionValues options, DebugContext debug, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, ConstantFieldProvider constantFieldProvider,
-                    StampProvider stampProvider, Bytecode code, int invokeBci, AllowAssumptions allowAssumptions) {
-        this.metaAccess = metaAccess;
-        this.constantReflection = constantReflection;
-        this.constantFieldProvider = constantFieldProvider;
-        this.stampProvider = stampProvider;
+    protected IntrinsicGraphBuilder(OptionValues options, DebugContext debug, CoreProviders providers, Bytecode code, int invokeBci, AllowAssumptions allowAssumptions) {
+        this.providers = providers;
         this.code = code;
         this.method = code.getMethod();
         this.graph = new StructuredGraph.Builder(options, debug, allowAssumptions).method(method).setIsSubstitution(true).trackNodeSourcePosition(true).build();
@@ -133,7 +127,9 @@
     private <T extends ValueNode> void updateLastInstruction(T v) {
         if (v instanceof FixedNode) {
             FixedNode fixedNode = (FixedNode) v;
-            lastInstr.setNext(fixedNode);
+            if (lastInstr != null) {
+                lastInstr.setNext(fixedNode);
+            }
             if (fixedNode instanceof FixedWithNextNode) {
                 FixedWithNextNode fixedWithNextNode = (FixedWithNextNode) fixedNode;
                 assert fixedWithNextNode.next() == null : "cannot append instruction to instruction which isn't end";
@@ -175,22 +171,27 @@
 
     @Override
     public StampProvider getStampProvider() {
-        return stampProvider;
+        return providers.getStampProvider();
     }
 
     @Override
     public MetaAccessProvider getMetaAccess() {
-        return metaAccess;
+        return providers.getMetaAccess();
     }
 
     @Override
     public ConstantReflectionProvider getConstantReflection() {
-        return constantReflection;
+        return providers.getConstantReflection();
     }
 
     @Override
     public ConstantFieldProvider getConstantFieldProvider() {
-        return constantFieldProvider;
+        return providers.getConstantFieldProvider();
+    }
+
+    @Override
+    public Replacements getReplacements() {
+        return providers.getReplacements();
     }
 
     @Override
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.java	Thu Mar 28 19:39:14 2019 +0100
@@ -106,6 +106,8 @@
 import org.graalvm.compiler.nodes.java.NewMultiArrayNode;
 import org.graalvm.compiler.nodes.java.StoreFieldNode;
 import org.graalvm.compiler.nodes.java.StoreIndexedNode;
+import org.graalvm.compiler.nodes.spi.CoreProviders;
+import org.graalvm.compiler.nodes.spi.Replacements;
 import org.graalvm.compiler.nodes.spi.StampProvider;
 import org.graalvm.compiler.nodes.type.StampTool;
 import org.graalvm.compiler.nodes.util.GraphUtil;
@@ -309,22 +311,27 @@
 
         @Override
         public StampProvider getStampProvider() {
-            return stampProvider;
+            return providers.getStampProvider();
         }
 
         @Override
         public MetaAccessProvider getMetaAccess() {
-            return metaAccess;
+            return providers.getMetaAccess();
         }
 
         @Override
         public ConstantReflectionProvider getConstantReflection() {
-            return constantReflection;
+            return providers.getConstantReflection();
         }
 
         @Override
         public ConstantFieldProvider getConstantFieldProvider() {
-            return constantFieldProvider;
+            return providers.getConstantFieldProvider();
+        }
+
+        @Override
+        public Replacements getReplacements() {
+            return providers.getReplacements();
         }
 
         @Override
@@ -565,11 +572,11 @@
     private final ResolvedJavaMethod callInlinedMethod;
     protected final SourceLanguagePositionProvider sourceLanguagePositionProvider;
 
-    public PEGraphDecoder(Architecture architecture, StructuredGraph graph, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, ConstantFieldProvider constantFieldProvider,
-                    StampProvider stampProvider, LoopExplosionPlugin loopExplosionPlugin, InvocationPlugins invocationPlugins, InlineInvokePlugin[] inlineInvokePlugins,
+    public PEGraphDecoder(Architecture architecture, StructuredGraph graph, CoreProviders providers, LoopExplosionPlugin loopExplosionPlugin, InvocationPlugins invocationPlugins,
+                    InlineInvokePlugin[] inlineInvokePlugins,
                     ParameterPlugin parameterPlugin,
                     NodePlugin[] nodePlugins, ResolvedJavaMethod callInlinedMethod, SourceLanguagePositionProvider sourceLanguagePositionProvider) {
-        super(architecture, graph, metaAccess, constantReflection, constantFieldProvider, stampProvider, true);
+        super(architecture, graph, providers, true);
         this.loopExplosionPlugin = loopExplosionPlugin;
         this.invocationPlugins = invocationPlugins;
         this.inlineInvokePlugins = inlineInvokePlugins;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ReplacementsImpl.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ReplacementsImpl.java	Thu Mar 28 19:39:14 2019 +0100
@@ -52,7 +52,6 @@
 import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecode;
 import org.graalvm.compiler.core.common.CompilationIdentifier;
 import org.graalvm.compiler.core.common.GraalOptions;
-import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
 import org.graalvm.compiler.debug.DebugCloseable;
 import org.graalvm.compiler.debug.DebugContext;
 import org.graalvm.compiler.debug.DebugContext.Description;
@@ -64,6 +63,7 @@
 import org.graalvm.compiler.graph.NodeSourcePosition;
 import org.graalvm.compiler.java.GraphBuilderPhase;
 import org.graalvm.compiler.java.GraphBuilderPhase.Instance;
+import org.graalvm.compiler.loop.phases.ConvertDeoptimizeToGuardPhase;
 import org.graalvm.compiler.nodes.CallTargetNode;
 import org.graalvm.compiler.nodes.Invoke;
 import org.graalvm.compiler.nodes.StateSplit;
@@ -80,14 +80,12 @@
 import org.graalvm.compiler.nodes.graphbuilderconf.MethodSubstitutionPlugin;
 import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
 import org.graalvm.compiler.nodes.spi.Replacements;
-import org.graalvm.compiler.nodes.spi.StampProvider;
 import org.graalvm.compiler.options.Option;
 import org.graalvm.compiler.options.OptionKey;
 import org.graalvm.compiler.options.OptionType;
 import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.phases.OptimisticOptimizations;
 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.tiers.PhaseContext;
 import org.graalvm.compiler.phases.util.Providers;
@@ -95,7 +93,6 @@
 import org.graalvm.compiler.word.WordOperationPlugin;
 
 import jdk.vm.ci.code.TargetDescription;
-import jdk.vm.ci.meta.ConstantReflectionProvider;
 import jdk.vm.ci.meta.MetaAccessProvider;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 import jdk.vm.ci.meta.ResolvedJavaType;
@@ -322,11 +319,8 @@
                 result = graph;
             } else {
                 Bytecode code = new ResolvedJavaMethodBytecode(method);
-                ConstantReflectionProvider constantReflection = providers.getConstantReflection();
-                ConstantFieldProvider constantFieldProvider = providers.getConstantFieldProvider();
-                StampProvider stampProvider = providers.getStampProvider();
                 try (DebugContext debug = openDebugContext("Substitution_", method)) {
-                    result = new IntrinsicGraphBuilder(options, debug, metaAccess, constantReflection, constantFieldProvider, stampProvider, code, invokeBci).buildGraph(plugin);
+                    result = new IntrinsicGraphBuilder(options, debug, providers, code, invokeBci).buildGraph(plugin);
                 }
             }
         } else {
@@ -355,8 +349,7 @@
                 Plugins plugins = new Plugins(getGraphBuilderPlugins());
                 GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault(plugins);
                 IntrinsicContext initialReplacementContext = new IntrinsicContext(method, substMethod, bytecodeProvider, ROOT_COMPILATION);
-                new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), providers.getConstantReflection(), providers.getConstantFieldProvider(), config,
-                                OptimisticOptimizations.NONE, initialReplacementContext).apply(graph);
+                new GraphBuilderPhase.Instance(providers, config, OptimisticOptimizations.NONE, initialReplacementContext).apply(graph);
                 assert !graph.isFrozen();
                 return graph;
             } catch (Throwable e) {
@@ -521,8 +514,7 @@
                                     snippetAnnotation != null ? snippetAnnotation.allowPartialIntrinsicArgumentMismatch() : true);
                 }
 
-                createGraphBuilder(metaAccess, replacements.providers.getStampProvider(), replacements.providers.getConstantReflection(), replacements.providers.getConstantFieldProvider(), config,
-                                OptimisticOptimizations.NONE, initialIntrinsicContext).apply(graph);
+                createGraphBuilder(replacements.providers, config, OptimisticOptimizations.NONE, initialIntrinsicContext).apply(graph);
 
                 new CanonicalizerPhase().apply(graph, new PhaseContext(replacements.providers));
             } catch (Throwable e) {
@@ -531,10 +523,8 @@
             return graph;
         }
 
-        protected Instance createGraphBuilder(MetaAccessProvider metaAccess, StampProvider stampProvider, ConstantReflectionProvider constantReflection, ConstantFieldProvider constantFieldProvider,
-                        GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, IntrinsicContext initialIntrinsicContext) {
-            return new GraphBuilderPhase.Instance(metaAccess, stampProvider, constantReflection, constantFieldProvider, graphBuilderConfig, optimisticOpts,
-                            initialIntrinsicContext);
+        protected Instance createGraphBuilder(Providers providers, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, IntrinsicContext initialIntrinsicContext) {
+            return new GraphBuilderPhase.Instance(providers, graphBuilderConfig, optimisticOpts, initialIntrinsicContext);
         }
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetCounterNode.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetCounterNode.java	Thu Mar 28 19:39:14 2019 +0100
@@ -28,7 +28,6 @@
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED;
 import static org.graalvm.compiler.replacements.SnippetTemplate.DEFAULT_REPLACER;
 
-import java.lang.reflect.Field;
 import java.util.Arrays;
 
 import org.graalvm.compiler.api.replacements.Fold;
@@ -51,6 +50,7 @@
 import org.graalvm.compiler.replacements.SnippetTemplate.AbstractTemplates;
 import org.graalvm.compiler.replacements.SnippetTemplate.Arguments;
 import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo;
+import org.graalvm.compiler.serviceprovider.GraalUnsafeAccess;
 import org.graalvm.compiler.word.ObjectAccess;
 import jdk.internal.vm.compiler.word.LocationIdentity;
 
@@ -129,6 +129,8 @@
 
     static class SnippetCounterSnippets implements Snippets {
 
+        private static final Unsafe UNSAFE = GraalUnsafeAccess.getUnsafe();
+
         @Fold
         static int countOffset() {
             try {
@@ -162,20 +164,4 @@
             }
         }
     }
-
-    private static final Unsafe UNSAFE = initUnsafe();
-
-    private static Unsafe initUnsafe() {
-        try {
-            return Unsafe.getUnsafe();
-        } catch (SecurityException se) {
-            try {
-                Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
-                theUnsafe.setAccessible(true);
-                return (Unsafe) theUnsafe.get(Unsafe.class);
-            } catch (Exception e) {
-                throw new RuntimeException("exception while trying to get Unsafe", e);
-            }
-        }
-    }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java	Thu Mar 28 19:39:14 2019 +0100
@@ -212,6 +212,20 @@
                 return false;
             }
         });
+        r.register1("intern", Receiver.class, new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
+                if (receiver.isConstant()) {
+                    String s = snippetReflection.asObject(String.class, (JavaConstant) receiver.get().asConstant());
+                    if (s != null) {
+                        JavaConstant interned = snippetReflection.forObject(s.intern());
+                        b.addPush(JavaKind.Object, b.add(ConstantNode.forConstant(interned, b.getMetaAccess(), b.getGraph())));
+                        return true;
+                    }
+                }
+                return false;
+            }
+        });
 
         if (Java8OrEarlier) {
             r.registerMethodSubstitution(StringSubstitutions.class, "equals", Receiver.class, Object.class);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/UnsafeAccess.java	Thu Mar 28 11:06:00 2019 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,63 +0,0 @@
-/*
- * Copyright (c) 2012, 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.replacements;
-
-import java.lang.reflect.Field;
-
-import sun.misc.Unsafe;
-
-/**
- * Package private access to the {@link Unsafe} capability.
- */
-class UnsafeAccess {
-
-    private static final Unsafe THE_UNSAFE = initUnsafe();
-
-    static final UnsafeAccess UNSAFE = new UnsafeAccess();
-
-    private static Unsafe initUnsafe() {
-        try {
-            // Fast path when we are trusted.
-            return Unsafe.getUnsafe();
-        } catch (SecurityException se) {
-            // Slow path when we are not trusted.
-            try {
-                Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
-                theUnsafe.setAccessible(true);
-                return (Unsafe) theUnsafe.get(Unsafe.class);
-            } catch (Exception e) {
-                throw new RuntimeException("exception while trying to get Unsafe", e);
-            }
-        }
-    }
-
-    public char getChar(Object target, long l) {
-        return THE_UNSAFE.getChar(target, l);
-    }
-
-    public byte getByte(Object target, long l) {
-        return THE_UNSAFE.getByte(target, l);
-    }
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileBytecodeProvider.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileBytecodeProvider.java	Thu Mar 28 19:39:14 2019 +0100
@@ -108,12 +108,13 @@
         if (classfile == null) {
             try {
                 ResolvedJavaType type = metaAccess.lookupJavaType(c);
-                InputStream in = GraalServices.getClassfileAsStream(c);
-                if (in != null) {
-                    DataInputStream stream = new DataInputStream(in);
-                    classfile = new Classfile(type, stream, this);
-                    classfiles.put(c, classfile);
-                    return classfile;
+                try (InputStream in = GraalServices.getClassfileAsStream(c)) {
+                    if (in != null) {
+                        DataInputStream stream = new DataInputStream(in);
+                        classfile = new Classfile(type, stream, this);
+                        classfiles.put(c, classfile);
+                        return classfile;
+                    }
                 }
                 throw new NoClassDefFoundError(c.getName());
             } catch (IOException e) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ArrayCompareToNode.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ArrayCompareToNode.java	Thu Mar 28 19:39:14 2019 +0100
@@ -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
@@ -24,10 +24,12 @@
 
 package org.graalvm.compiler.replacements.nodes;
 
+import static org.graalvm.compiler.core.common.GraalOptions.UseGraalStubs;
 import static org.graalvm.compiler.nodeinfo.InputType.Memory;
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_1024;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1024;
 
+import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.graph.NodeClass;
@@ -117,8 +119,25 @@
     @NodeIntrinsic
     public static native int compareTo(Object array1, Object array2, int length1, int length2, @ConstantNodeParameter JavaKind kind1, @ConstantNodeParameter JavaKind kind2);
 
+    public JavaKind getKind1() {
+        return kind1;
+    }
+
+    public JavaKind getKind2() {
+        return kind2;
+    }
+
     @Override
     public void generate(NodeLIRBuilderTool gen) {
+        if (UseGraalStubs.getValue(graph().getOptions())) {
+            ForeignCallLinkage linkage = gen.lookupGraalStub(this);
+            if (linkage != null) {
+                Value result = gen.getLIRGeneratorTool().emitForeignCall(linkage, null, gen.operand(array1), gen.operand(array2), gen.operand(length1), gen.operand(length2));
+                gen.setResult(this, result);
+                return;
+            }
+        }
+
         Value result = gen.getLIRGeneratorTool().emitArrayCompareTo(kind1, kind2, gen.operand(array1), gen.operand(array2), gen.operand(length1), gen.operand(length2));
         gen.setResult(this, result);
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ArrayEqualsNode.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ArrayEqualsNode.java	Thu Mar 28 19:39:14 2019 +0100
@@ -24,16 +24,15 @@
 
 package org.graalvm.compiler.replacements.nodes;
 
+import static org.graalvm.compiler.core.common.GraalOptions.UseGraalStubs;
 import static org.graalvm.compiler.nodeinfo.InputType.Memory;
 
-import org.graalvm.compiler.api.replacements.Snippet;
 import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
 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.lir.gen.LIRGeneratorTool;
 import org.graalvm.compiler.nodeinfo.NodeCycles;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
 import org.graalvm.compiler.nodeinfo.NodeSize;
@@ -51,14 +50,11 @@
 import org.graalvm.compiler.nodes.spi.VirtualizerTool;
 import org.graalvm.compiler.nodes.util.GraphUtil;
 import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
-import org.graalvm.compiler.options.Option;
-import org.graalvm.compiler.options.OptionKey;
 import jdk.internal.vm.compiler.word.LocationIdentity;
 
 import jdk.vm.ci.meta.ConstantReflectionProvider;
 import jdk.vm.ci.meta.JavaConstant;
 import jdk.vm.ci.meta.JavaKind;
-import jdk.vm.ci.meta.ResolvedJavaMethod;
 import jdk.vm.ci.meta.Value;
 
 // JaCoCo Exclude
@@ -69,13 +65,6 @@
 @NodeInfo(cycles = NodeCycles.CYCLES_UNKNOWN, size = NodeSize.SIZE_128)
 public final class ArrayEqualsNode extends FixedWithNextNode implements LIRLowerable, Canonicalizable, Virtualizable, MemoryAccess {
 
-    public static class Options {
-        // @formatter:off
-        @Option(help = "Use Array equals stubs instead of embedding all the emitted code.")
-        public static final OptionKey<Boolean> ArrayEqualsStubs = new OptionKey<>(true);
-        // @formatter:on
-    }
-
     public static final NodeClass<ArrayEqualsNode> TYPE = NodeClass.create(ArrayEqualsNode.class);
     /** {@link JavaKind} of the arrays to compare. */
     protected final JavaKind kind;
@@ -225,27 +214,30 @@
         return equals(array1, array2, length, JavaKind.Double);
     }
 
+    public ValueNode getLength() {
+        return length;
+    }
+
+    public JavaKind getKind() {
+        return kind;
+    }
+
     @Override
     public void generate(NodeLIRBuilderTool gen) {
-        LIRGeneratorTool tool = gen.getLIRGeneratorTool();
+        if (UseGraalStubs.getValue(graph().getOptions())) {
+            ForeignCallLinkage linkage = gen.lookupGraalStub(this);
+            if (linkage != null) {
+                Value result = gen.getLIRGeneratorTool().emitForeignCall(linkage, null, gen.operand(array1), gen.operand(array2), gen.operand(length));
+                gen.setResult(this, result);
+                return;
+            }
+        }
+
         int constantLength = -1;
         if (length.isConstant()) {
             constantLength = length.asJavaConstant().asInt();
         }
-
-        if (Options.ArrayEqualsStubs.getValue(graph().getOptions())) {
-            ResolvedJavaMethod method = graph().method();
-            if (method != null && method.getAnnotation(Snippet.class) == null) {
-                ForeignCallLinkage linkage = tool.lookupArrayEqualsStub(kind, constantLength);
-                if (linkage != null) {
-                    Value result = tool.emitForeignCall(linkage, null, gen.operand(array1), gen.operand(array2), gen.operand(length));
-                    gen.setResult(this, result);
-                    return;
-                }
-            }
-        }
-
-        Value result = tool.emitArrayEquals(kind, gen.operand(array1), gen.operand(array2), gen.operand(length), constantLength, false);
+        Value result = gen.getLIRGeneratorTool().emitArrayEquals(kind, gen.operand(array1), gen.operand(array2), gen.operand(length), constantLength, false);
         gen.setResult(this, result);
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ArrayRegionEqualsNode.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ArrayRegionEqualsNode.java	Thu Mar 28 19:39:14 2019 +0100
@@ -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,8 +24,10 @@
 
 package org.graalvm.compiler.replacements.nodes;
 
-import jdk.vm.ci.meta.JavaKind;
-import jdk.vm.ci.meta.Value;
+import static org.graalvm.compiler.core.common.GraalOptions.UseGraalStubs;
+import static org.graalvm.compiler.nodeinfo.InputType.Memory;
+
+import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.nodeinfo.NodeCycles;
@@ -42,7 +44,8 @@
 import jdk.internal.vm.compiler.word.LocationIdentity;
 import jdk.internal.vm.compiler.word.Pointer;
 
-import static org.graalvm.compiler.nodeinfo.InputType.Memory;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.Value;
 
 // JaCoCo Exclude
 
@@ -85,8 +88,29 @@
     @NodeIntrinsic
     public static native boolean regionEquals(Pointer array1, Pointer array2, int length, @ConstantNodeParameter JavaKind kind1, @ConstantNodeParameter JavaKind kind2);
 
+    public JavaKind getKind1() {
+        return kind1;
+    }
+
+    public JavaKind getKind2() {
+        return kind2;
+    }
+
+    public ValueNode getLength() {
+        return length;
+    }
+
     @Override
     public void generate(NodeLIRBuilderTool gen) {
+        if (UseGraalStubs.getValue(graph().getOptions())) {
+            ForeignCallLinkage linkage = gen.lookupGraalStub(this);
+            if (linkage != null) {
+                Value result = gen.getLIRGeneratorTool().emitForeignCall(linkage, null, gen.operand(array1), gen.operand(array2), gen.operand(length));
+                gen.setResult(this, result);
+                return;
+            }
+        }
+
         int constantLength = -1;
         if (length.isConstant()) {
             constantLength = length.asJavaConstant().asInt();
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroNode.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroNode.java	Thu Mar 28 19:39:14 2019 +0100
@@ -41,9 +41,9 @@
 import org.graalvm.compiler.nodeinfo.NodeInfo;
 import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind;
 import org.graalvm.compiler.nodes.FixedNode;
-import org.graalvm.compiler.nodes.Invokable;
 import org.graalvm.compiler.nodes.FixedWithNextNode;
 import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.Invokable;
 import org.graalvm.compiler.nodes.InvokeNode;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.GuardsStage;
@@ -58,10 +58,10 @@
 import org.graalvm.compiler.phases.common.RemoveValueProxyPhase;
 import org.graalvm.compiler.phases.common.inlining.InliningUtil;
 import org.graalvm.compiler.phases.tiers.PhaseContext;
+import jdk.internal.vm.compiler.word.LocationIdentity;
 
 import jdk.vm.ci.meta.JavaKind;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
-import jdk.internal.vm.compiler.word.LocationIdentity;
 
 /**
  * Macro nodes can be used to temporarily replace an invoke. They can, for example, be used to
@@ -160,8 +160,7 @@
      */
     @SuppressWarnings("try")
     protected StructuredGraph lowerReplacement(final StructuredGraph replacementGraph, LoweringTool tool) {
-        final PhaseContext c = new PhaseContext(tool.getMetaAccess(), tool.getConstantReflection(), tool.getConstantFieldProvider(), tool.getLowerer(), tool.getReplacements(),
-                        tool.getStampProvider(), null);
+        final PhaseContext c = new PhaseContext(tool.getProviders());
         if (!graph().hasValueProxies()) {
             new RemoveValueProxyPhase().apply(replacementGraph);
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/GraalUnsafeAccess.java	Thu Mar 28 19:39:14 2019 +0100
@@ -0,0 +1,70 @@
+/*
+ * 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
+ * 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.serviceprovider;
+
+import java.lang.reflect.Field;
+
+import sun.misc.Unsafe;
+
+/**
+ * Access to the {@link Unsafe} capability. Care must be taken not to leak the {@link #UNSAFE} value
+ * of out code loaded by the JVMCI class loader or encapsulated in the JVMCI or Graal modules into
+ * other code (e.g. via the Polyglot API).
+ */
+public class GraalUnsafeAccess {
+
+    private static final Unsafe UNSAFE = initUnsafe();
+
+    private static Unsafe initUnsafe() {
+        try {
+            // Fast path when we are trusted.
+            return Unsafe.getUnsafe();
+        } catch (SecurityException se) {
+            // Slow path when we are not trusted.
+            try {
+                Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
+                theUnsafe.setAccessible(true);
+                return (Unsafe) theUnsafe.get(Unsafe.class);
+            } catch (Exception e) {
+                throw new RuntimeException("exception while trying to get Unsafe", e);
+            }
+        }
+    }
+
+    /**
+     * Gets the {@link Unsafe} singleton.
+     *
+     * @throws SecurityException if a security manager is present and it denies
+     *             {@link RuntimePermission}("accessUnsafe")
+     */
+    public static Unsafe getUnsafe() {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPermission(new RuntimePermission("accessUnsafe"));
+        }
+        return UNSAFE;
+    }
+}
+
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/JavaVersionUtil.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/JavaVersionUtil.java	Thu Mar 28 19:39:14 2019 +0100
@@ -24,13 +24,15 @@
 
 package org.graalvm.compiler.serviceprovider;
 
+import jdk.vm.ci.services.Services;
+
 /**
  * Interface to query which JDK version Graal is running on.
  */
 public final class JavaVersionUtil {
 
     private static int getJavaSpecificationVersion() {
-        String value = System.getProperty("java.specification.version");
+        String value = Services.getSavedProperties().get("java.specification.version");
         if (value.startsWith("1.")) {
             value = value.substring(2);
         }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsClosure.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsClosure.java	Thu Mar 28 19:39:14 2019 +0100
@@ -428,7 +428,7 @@
     protected abstract class MergeProcessor {
 
         private final Block mergeBlock;
-        private final AbstractMergeNode merge;
+        protected final AbstractMergeNode merge;
 
         protected final GraphEffectList mergeEffects;
         protected final GraphEffectList afterMergeEffects;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PartialEscapeClosure.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PartialEscapeClosure.java	Thu Mar 28 19:39:14 2019 +0100
@@ -59,6 +59,7 @@
 import org.graalvm.compiler.nodes.ProxyNode;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult;
+import org.graalvm.compiler.nodes.UnwindNode;
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.ValuePhiNode;
 import org.graalvm.compiler.nodes.ValueProxyNode;
@@ -105,7 +106,6 @@
      * The indexes into this array correspond to {@link VirtualObjectNode#getObjectId()}.
      */
     public final ArrayList<VirtualObjectNode> virtualObjects = new ArrayList<>();
-    public final DebugContext debug;
 
     @Override
     public boolean needsApplyEffects() {
@@ -189,7 +189,6 @@
         super(schedule, schedule.getCFG());
         StructuredGraph graph = schedule.getCFG().graph;
         this.hasVirtualInputs = graph.createNodeBitMap();
-        this.debug = graph.getDebug();
         this.tool = new VirtualizerToolImpl(metaAccess, constantReflection, constantFieldProvider, this, graph.getAssumptions(), graph.getOptions(), debug, loweringProvider);
     }
 
@@ -687,16 +686,44 @@
             // calculate the set of virtual objects that exist in all predecessors
             int[] virtualObjTemp = intersectVirtualObjects(states);
 
+            boolean forceMaterialization = false;
+            ValueNode forcedMaterializationValue = null;
+            FrameState frameState = merge.stateAfter();
+            if (frameState != null && frameState.isExceptionHandlingBCI()) {
+                // We can not go below merges with an exception handling bci
+                // it could create allocations whose slow-path has an invalid framestate
+                forceMaterialization = true;
+                // check if we can reduce the scope of forced materialization to one phi node
+                if (frameState.stackSize() == 1 && merge.next() instanceof UnwindNode) {
+                    assert frameState.outerFrameState() == null;
+                    UnwindNode unwind = (UnwindNode) merge.next();
+                    if (unwind.exception() == frameState.stackAt(0)) {
+                        boolean nullLocals = true;
+                        for (int i = 0; i < frameState.localsSize(); i++) {
+                            if (frameState.localAt(i) != null) {
+                                nullLocals = false;
+                                break;
+                            }
+                        }
+                        if (nullLocals) {
+                            // We found that the merge is directly followed by an unwind
+                            // the Framestate only has the thrown value on the stack and no locals
+                            forcedMaterializationValue = unwind.exception();
+                        }
+                    }
+                }
+            }
+
             boolean materialized;
             do {
                 materialized = false;
 
-                if (PartialEscapeBlockState.identicalObjectStates(states)) {
+                if (!forceMaterialization && PartialEscapeBlockState.identicalObjectStates(states)) {
                     newState.adoptAddObjectStates(states[0]);
                 } else {
 
                     for (int object : virtualObjTemp) {
-                        if (PartialEscapeBlockState.identicalObjectStates(states, object)) {
+                        if (!forceMaterialization && PartialEscapeBlockState.identicalObjectStates(states, object)) {
                             newState.addObject(object, states[0].getObjectState(object).share());
                             continue;
                         }
@@ -710,6 +737,22 @@
                         for (int i = 0; i < states.length; i++) {
                             ObjectState obj = states[i].getObjectState(object);
                             ensureVirtual &= obj.getEnsureVirtualized();
+                            if (forceMaterialization) {
+                                if (forcedMaterializationValue == null) {
+                                    uniqueMaterializedValue = null;
+                                    continue;
+                                } else {
+                                    ValueNode value = forcedMaterializationValue;
+                                    if (merge.isPhiAtMerge(value)) {
+                                        value = ((ValuePhiNode) value).valueAt(i);
+                                    }
+                                    ValueNode alias = getAlias(value);
+                                    if (alias instanceof VirtualObjectNode && ((VirtualObjectNode) alias).getObjectId() == object) {
+                                        uniqueMaterializedValue = null;
+                                        continue;
+                                    }
+                                }
+                            }
                             if (obj.isVirtual()) {
                                 virtualCount++;
                                 uniqueMaterializedValue = null;
@@ -1029,6 +1072,7 @@
                              */
                             if (virtual.hasIdentity() && !isSingleUsageAllocation(getPhiValueAt(phi, i), virtualObjs, states[i])) {
                                 compatible = false;
+                                break;
                             }
                         }
                     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/UnsafeAccess.java	Thu Mar 28 11:06:00 2019 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-/*
- * Copyright (c) 2012, 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.word;
-
-import java.lang.reflect.Field;
-
-import sun.misc.Unsafe;
-
-/**
- * Package private access to the {@link Unsafe} capability.
- */
-class UnsafeAccess {
-
-    static final Unsafe UNSAFE = initUnsafe();
-
-    private static Unsafe initUnsafe() {
-        try {
-            // Fast path when we are trusted.
-            return Unsafe.getUnsafe();
-        } catch (SecurityException se) {
-            // Slow path when we are not trusted.
-            try {
-                Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
-                theUnsafe.setAccessible(true);
-                return (Unsafe) theUnsafe.get(Unsafe.class);
-            } catch (Exception e) {
-                throw new RuntimeException("exception while trying to get Unsafe", e);
-            }
-        }
-    }
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/Word.java	Thu Mar 28 11:06:00 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/Word.java	Thu Mar 28 19:39:14 2019 +0100
@@ -24,7 +24,7 @@
 
 package org.graalvm.compiler.word;
 
-import static org.graalvm.compiler.word.UnsafeAccess.UNSAFE;
+import static org.graalvm.compiler.serviceprovider.GraalUnsafeAccess.getUnsafe;
 
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
@@ -59,8 +59,12 @@
 import jdk.internal.vm.compiler.word.WordFactory;
 import jdk.internal.vm.compiler.word.impl.WordBoxFactory;
 
+import sun.misc.Unsafe;
+
 public abstract class Word implements SignedWord, UnsignedWord, Pointer {
 
+    private static final Unsafe UNSAFE = getUnsafe();
+
     static {
         BoxFactoryImpl.initialize();
     }