8198969: Update Graal
authoriveresov
Fri, 16 Mar 2018 22:59:32 -0700
changeset 49451 e06f9607f370
parent 49450 5d2adef239d6
child 49452 acb36277a784
8198969: Update Graal Reviewed-by: kvn
make/CompileToolsHotspot.gmk
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64Assembler.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/BytecodeDisassembler.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/DisassemblerProvider.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64AddressNode.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.amd64/src/org/graalvm/compiler/core/amd64/AMD64LIRGenerator.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64NodeLIRBuilder.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/TraceInliningMode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/BiDirectionalTraceBuilder.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/UniDirectionalTraceBuilder.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/AbstractObjectStamp.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/FloatStamp.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IntegerStamp.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/StampFactory.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/UnsignedLong.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/BasePhaseBinaryGraphTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalNodeTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CountedLoopTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraphEncoderTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SwitchDyingLoopTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/TrivialInliningExplosionTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnsignedLongTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompiler.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/phases/HighTier.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/target/Backend.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/.checkstyle_checks.xml
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Graph.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/InlineCacheGuardPosition.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/SourceLanguagePosition.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/SourceLanguagePositionProvider.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackend.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotDeoptimizeOp.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotMove.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64.test/src/org/graalvm/compiler/hotspot/amd64/test/StubAVXTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotAddressLowering.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotArithmeticLIRGenerator.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/AMD64HotSpotMaths.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotMove.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorld.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotLazyInitializationTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerConfigurationFactory.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/HotSpotBackend.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotCompiledCodeBuilder.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/NodeCostDumpUtil.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/lir/VerifyMaxRegisterSizePhase.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotClassInitializationPlugin.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotInvocationPlugins.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/aot/AOTInliningPolicy.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/AssertionSnippets.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HashCodeSnippets.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/LoadExceptionObjectSnippets.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/MonitorSnippets.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/NewObjectSnippets.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ObjectCloneNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/StringToBytesSnippets.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/UnsafeLoadSnippets.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/WriteBarrierSnippets.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/aot/ResolveConstantSnippets.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopySnippets.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/profiling/ProbabilisticProfileSnippets.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/profiling/ProfileSnippets.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/ForeignCallStub.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParserOptions.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/FrameStateBuilder.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/JTTTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_series.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_abs.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_cos.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_exp.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_log.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_pow.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_sin.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_sqrt.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_tan.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/UnaryMath.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.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ArrayCompareToOp.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64LFenceOp.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64Move.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/LIRInstructionClass.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/GlobalLivenessInfo.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceAssertions.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceGlobalMoveResolutionPhase.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceUtil.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TrivialTraceAllocator.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/bu/BottomUpAllocator.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanLifetimeAnalysisPhase.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/phases/LIRPhaseSuite.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/ssa/SSAUtil.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/BasicInductionVariable.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/CountedLoopInfo.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/DefaultLoopPolicies.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragment.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragmentInside.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/MathUtil.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/IntegerStampTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/PrimitiveStampBoundaryTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/AbstractFixedGuardNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/BeginNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/DeoptimizeNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/DynamicPiNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/EncodedGraph.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FixedGuardNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FrameState.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphDecoder.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphEncoder.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GuardNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InliningLog.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/Invokable.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/Invoke.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InvokeNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InvokeWithExceptionNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/LoopExitNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/PiNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StaticDeoptimizingNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StructuredGraph.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/CompareNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ConditionalNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerConvertNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerLowerThanNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/IntegerSwitchNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/ClassInitializationPlugin.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/InlineInvokePlugin.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/IntrinsicContext.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/InstanceOfDynamicNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/Replacements.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ConditionalEliminationPhase.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ConvertDeoptimizeToGuardPhase.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/NodeCounterPhase.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/InliningUtil.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/AbstractInlineInfo.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/elem/Inlineable.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/elem/InlineableGraph.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/policy/GreedyInliningPolicy.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/policy/InlineMethodSubstitutionsPolicy.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/PhaseSuite.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/contract/VerifyNodeCosts.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/BinaryGraphPrinter.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraphPrinter.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/AArch64FloatArithmeticSnippets.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64IntegerArithmeticSnippets.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64ConvertSnippets.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64GraphBuilderPlugins.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringLatin1Substitutions.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringSubstitutions.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringUTF16Substitutions.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/MethodSubstitutionTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PEGraphDecoderTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/SnippetsTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/StandardMethodSubstitutionsTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/StringCompareToTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/StringSubstitutionsTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/WordTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/BoxingSnippets.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/InstanceOfSnippetsTemplates.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/SnippetTemplate.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StringSubstitutions.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/MacroNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroStateSplitNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/GraalServices.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/JDK9Method.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/ProtocolImpl.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.micro.benchmarks/src/micro/benchmarks/StringBenchmark.java
--- a/make/CompileToolsHotspot.gmk	Fri Mar 16 11:26:05 2018 +0000
+++ b/make/CompileToolsHotspot.gmk	Fri Mar 16 22:59:32 2018 -0700
@@ -120,6 +120,7 @@
       SRC := \
           $(SRC_DIR)/org.graalvm.word/src \
           $(SRC_DIR)/org.graalvm.collections/src \
+          $(SRC_DIR)/org.graalvm.compiler.bytecode/src \
           $(SRC_DIR)/org.graalvm.compiler.replacements.verifier/src \
           $(SRC_DIR)/org.graalvm.compiler.api.replacements/src \
           $(SRC_DIR)/org.graalvm.compiler.code/src \
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64Assembler.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64Assembler.java	Fri Mar 16 22:59:32 2018 -0700
@@ -195,11 +195,6 @@
         private static final int VEX_W = 0x80;
     }
 
-    private static class AvxVectorLen {
-        private static final int AVX_128bit = 0x0;
-        private static final int AVX_256bit = 0x1;
-    }
-
     private static class VexSimdPrefix {
         private static final int VEX_SIMD_NONE = 0x0;
         private static final int VEX_SIMD_66 = 0x1;
@@ -208,11 +203,44 @@
     }
 
     private static class VexOpcode {
+        private static final int VEX_OPCODE_NONE = 0x0;
         private static final int VEX_OPCODE_0F = 0x1;
         private static final int VEX_OPCODE_0F_38 = 0x2;
         private static final int VEX_OPCODE_0F_3A = 0x3;
     }
 
+    public static class AvxVectorLen {
+        public static final int AVX_128bit = 0x0;
+        public static final int AVX_256bit = 0x1;
+        public static final int AVX_512bit = 0x2;
+        public static final int AVX_NoVec = 0x4;
+    }
+
+    public static class EvexTupleType {
+        public static final int EVEX_FV = 0;
+        public static final int EVEX_HV = 4;
+        public static final int EVEX_FVM = 6;
+        public static final int EVEX_T1S = 7;
+        public static final int EVEX_T1F = 11;
+        public static final int EVEX_T2 = 13;
+        public static final int EVEX_T4 = 15;
+        public static final int EVEX_T8 = 17;
+        public static final int EVEX_HVM = 18;
+        public static final int EVEX_QVM = 19;
+        public static final int EVEX_OVM = 20;
+        public static final int EVEX_M128 = 21;
+        public static final int EVEX_DUP = 22;
+        public static final int EVEX_ETUP = 23;
+    }
+
+    public static class EvexInputSizeInBits {
+        public static final int EVEX_8bit = 0;
+        public static final int EVEX_16bit = 1;
+        public static final int EVEX_32bit = 2;
+        public static final int EVEX_64bit = 3;
+        public static final int EVEX_NObit = 4;
+    }
+
     private AMD64InstructionAttr curAttributes;
 
     AMD64InstructionAttr getCurAttributes() {
@@ -873,6 +901,7 @@
                         opc = VexOpcode.VEX_OPCODE_0F_3A;
                         break;
                     default:
+                        opc = VexOpcode.VEX_OPCODE_NONE;
                         isSimd = false;
                         break;
                 }
@@ -1770,6 +1799,13 @@
         emitOperandHelper(dst, src, 0);
     }
 
+    public final void bsfq(Register dst, Register src) {
+        int encode = prefixqAndEncode(dst.encoding(), src.encoding());
+        emitByte(0x0F);
+        emitByte(0xBC);
+        emitByte(0xC0 | encode);
+    }
+
     public final void bsrl(Register dst, Register src) {
         int encode = prefixAndEncode(dst.encoding(), src.encoding());
         emitByte(0x0F);
@@ -1857,6 +1893,26 @@
         emitByte(0xC0 | encode);
     }
 
+    public final void evmovdquq(Register dst, AMD64Address src, int vectorLen) {
+        assert supports(CPUFeature.AVX512F);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(vectorLen, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true, target);
+        attributes.setAddressAttributes(/* tuple_type */ EvexTupleType.EVEX_FVM, /* input_size_in_bits */ EvexInputSizeInBits.EVEX_NObit);
+        attributes.setIsEvexInstruction();
+        vexPrefix(src, Register.None, dst, VexSimdPrefix.VEX_SIMD_F3, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0x6F);
+        emitOperandHelper(dst, src, 0);
+    }
+
+    public final void evpcmpeqb(Register kdst, Register nds, AMD64Address src, int vectorLen) {
+        assert supports(CPUFeature.AVX512BW);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(vectorLen, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false, target);
+        attributes.setIsEvexInstruction();
+        attributes.setAddressAttributes(/* tuple_type */ EvexTupleType.EVEX_FVM, /* input_size_in_bits */ EvexInputSizeInBits.EVEX_NObit);
+        vexPrefix(src, nds, kdst, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0x74);
+        emitOperandHelper(kdst, src, 0);
+    }
+
     public final void hlt() {
         emitByte(0xF4);
     }
@@ -1982,6 +2038,32 @@
         }
     }
 
+    // This instruction produces ZF or CF flags
+    public final void kortestql(Register src1, Register src2) {
+        assert supports(CPUFeature.AVX512BW);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false, target);
+        int encode = vexPrefixAndEncode(src1, Register.None, src2, VexSimdPrefix.VEX_SIMD_NONE, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0x98);
+        emitByte(0xC0 | encode);
+    }
+
+    public final void kmovql(Register dst, Register src) {
+        assert supports(CPUFeature.AVX512BW);
+        if (src.getRegisterCategory().equals(AMD64.MASK)) {
+            // kmovql(KRegister dst, KRegister src)
+            AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false, target);
+            int encode = vexPrefixAndEncode(dst, Register.None, src, VexSimdPrefix.VEX_SIMD_NONE, VexOpcode.VEX_OPCODE_0F, attributes);
+            emitByte(0x90);
+            emitByte(0xC0 | encode);
+        } else {
+            // kmovql(KRegister dst, Register src)
+            AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false, target);
+            int encode = vexPrefixAndEncode(dst, Register.None, src, VexSimdPrefix.VEX_SIMD_F2, VexOpcode.VEX_OPCODE_0F, attributes);
+            emitByte(0x92);
+            emitByte(0xC0 | encode);
+        }
+    }
+
     public final void lead(Register dst, AMD64Address src) {
         prefix(src, dst);
         emitByte(0x8D);
@@ -2050,6 +2132,15 @@
         emitOperandHelper(dst, src, 0);
     }
 
+    /**
+     * @param wide use 4 byte encoding for displacements that would normally fit in a byte
+     */
+    public final void movl(Register dst, AMD64Address src, boolean wide) {
+        prefix(src, dst);
+        emitByte(0x8B);
+        emitOperandHelper(dst, src, wide, 0);
+    }
+
     public final void movl(AMD64Address dst, int imm32) {
         prefix(dst);
         emitByte(0xC7);
@@ -2291,6 +2382,10 @@
         NOT.emit(this, DWORD, dst);
     }
 
+    public final void notq(Register dst) {
+        NOT.emit(this, QWORD, dst);
+    }
+
     @Override
     public final void ensureUniquePC() {
         nop();
@@ -2540,7 +2635,7 @@
         emitByte(0xC0 | encode);
     }
 
-    void pcmpestri(Register dst, AMD64Address src, int imm8) {
+    public final void pcmpestri(Register dst, AMD64Address src, int imm8) {
         assert supports(CPUFeature.SSE4_2);
         AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
         simdPrefix(dst, Register.None, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F_3A, attributes);
@@ -2549,7 +2644,7 @@
         emitByte(imm8);
     }
 
-    void pcmpestri(Register dst, Register src, int imm8) {
+    public final void pcmpestri(Register dst, Register src, int imm8) {
         assert supports(CPUFeature.SSE4_2);
         AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
         int encode = simdPrefixAndEncode(dst, Register.None, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F_3A, attributes);
@@ -2558,6 +2653,26 @@
         emitByte(imm8);
     }
 
+    public final void pmovzxbw(Register dst, AMD64Address src) {
+        assert supports(CPUFeature.SSE4_2);
+        // XXX legacy_mode should be: _legacy_mode_bw
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false, target);
+        attributes.setAddressAttributes(/* tuple_type */ EvexTupleType.EVEX_HVM, /* input_size_in_bits */ EvexInputSizeInBits.EVEX_NObit);
+        simdPrefix(dst, Register.None, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F_38, attributes);
+        emitByte(0x30);
+        emitOperandHelper(dst, src, 0);
+    }
+
+    public final void vpmovzxbw(Register dst, AMD64Address src, int vectorLen) {
+        assert supports(CPUFeature.AVX);
+        // XXX legacy_mode should be: _legacy_mode_bw
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(vectorLen, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false, target);
+        attributes.setAddressAttributes(/* tuple_type */ EvexTupleType.EVEX_HVM, /* input_size_in_bits */ EvexInputSizeInBits.EVEX_NObit);
+        vexPrefix(src, Register.None, dst, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F_38, attributes);
+        emitByte(0x30);
+        emitOperandHelper(dst, src, 0);
+    }
+
     public final void push(Register src) {
         int encode = prefixAndEncode(src.encoding);
         emitByte(0x50 | encode);
@@ -2634,6 +2749,15 @@
         emitByte(0xC0 | encode);
     }
 
+    public final void vpxor(Register dst, Register nds, AMD64Address src) {
+        assert supports(CPUFeature.AVX);
+        AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_256bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true, target);
+        attributes.setAddressAttributes(/* tuple_type */ EvexTupleType.EVEX_FV, /* input_size_in_bits */ EvexInputSizeInBits.EVEX_32bit);
+        vexPrefix(src, nds, dst, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes);
+        emitByte(0xEF);
+        emitOperandHelper(dst, src, 0);
+    }
+
     public final void pslld(Register dst, int imm8) {
         assert isUByte(imm8) : "invalid value";
         assert dst.getRegisterCategory().equals(AMD64.XMM);
@@ -3843,4 +3967,11 @@
         emitByte(0x0f);
         emitByte(0x0b);
     }
+
+    public void lfence() {
+        emitByte(0x0f);
+        emitByte(0xae);
+        emitByte(0xe8);
+
+    }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/BytecodeDisassembler.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/BytecodeDisassembler.java	Fri Mar 16 22:59:32 2018 -0700
@@ -321,4 +321,61 @@
         }
         // @formatter:on
     }
+
+    public static JavaMethod getInvokedMethodAt(ResolvedJavaMethod method, int invokeBci) {
+        if (method.getCode() == null) {
+            return null;
+        }
+        ConstantPool cp = method.getConstantPool();
+        BytecodeStream stream = new BytecodeStream(method.getCode());
+        int opcode = stream.currentBC();
+        while (opcode != Bytecodes.END) {
+            int bci = stream.currentBCI();
+            if (bci == invokeBci) {
+                if (stream.nextBCI() > bci + 1) {
+                    switch (opcode) {
+                        case INVOKEVIRTUAL:
+                        case INVOKESPECIAL:
+                        case INVOKESTATIC: {
+                            int cpi = stream.readCPI();
+                            JavaMethod callee = cp.lookupMethod(cpi, opcode);
+                            return callee;
+                        }
+                        case INVOKEINTERFACE: {
+                            int cpi = stream.readCPI();
+                            JavaMethod callee = cp.lookupMethod(cpi, opcode);
+                            return callee;
+                        }
+                        case INVOKEDYNAMIC: {
+                            int cpi = stream.readCPI4();
+                            JavaMethod callee = cp.lookupMethod(cpi, opcode);
+                            return callee;
+                        }
+                        default:
+                            throw new InternalError(BytecodeDisassembler.disassembleOne(method, invokeBci));
+                    }
+                }
+            }
+            stream.next();
+            opcode = stream.currentBC();
+        }
+        return null;
+    }
+
+    public static int getBytecodeAt(ResolvedJavaMethod method, int invokeBci) {
+        if (method.getCode() == null) {
+            return -1;
+        }
+        BytecodeStream stream = new BytecodeStream(method.getCode());
+        int opcode = stream.currentBC();
+        while (opcode != Bytecodes.END) {
+            int bci = stream.currentBCI();
+            if (bci == invokeBci) {
+                return opcode;
+            }
+            stream.next();
+            opcode = stream.currentBC();
+        }
+        return -1;
+    }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/DisassemblerProvider.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/DisassemblerProvider.java	Fri Mar 16 22:59:32 2018 -0700
@@ -58,7 +58,7 @@
     }
 
     /**
-     * Gets the name denoting the format of the disassmembly return by this object.
+     * Gets the name denoting the format of the disassembly returned by this object.
      */
     String getName();
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64AddressNode.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64AddressNode.java	Fri Mar 16 22:59:32 2018 -0700
@@ -25,6 +25,7 @@
 
 import org.graalvm.compiler.asm.amd64.AMD64Address.Scale;
 import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.type.IntegerStamp;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.graph.spi.Simplifiable;
 import org.graalvm.compiler.graph.spi.SimplifierTool;
@@ -72,7 +73,7 @@
     }
 
     public void canonicalizeIndex(SimplifierTool tool) {
-        if (index instanceof AddNode) {
+        if (index instanceof AddNode && ((IntegerStamp) index.stamp(NodeView.DEFAULT)).getBits() == 64) {
             AddNode add = (AddNode) index;
             ValueNode valX = add.getX();
             if (valX instanceof PhiNode) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64ArithmeticLIRGenerator.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64ArithmeticLIRGenerator.java	Fri Mar 16 22:59:32 2018 -0700
@@ -66,15 +66,14 @@
 import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant;
 import static org.graalvm.compiler.lir.amd64.AMD64Arithmetic.DREM;
 import static org.graalvm.compiler.lir.amd64.AMD64Arithmetic.FREM;
+import static org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicBinaryOp.BinaryIntrinsicOpcode.POW;
 import static org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicUnaryOp.UnaryIntrinsicOpcode.COS;
+import static org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicUnaryOp.UnaryIntrinsicOpcode.EXP;
 import static org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicUnaryOp.UnaryIntrinsicOpcode.LOG;
 import static org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicUnaryOp.UnaryIntrinsicOpcode.LOG10;
 import static org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicUnaryOp.UnaryIntrinsicOpcode.SIN;
 import static org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicUnaryOp.UnaryIntrinsicOpcode.TAN;
-import static org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicUnaryOp.UnaryIntrinsicOpcode.EXP;
-import static org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicBinaryOp.BinaryIntrinsicOpcode.POW;
 
-import org.graalvm.compiler.core.common.NumUtil;
 import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic;
 import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MIOp;
 import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MOp;
@@ -83,10 +82,11 @@
 import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp;
 import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RRMOp;
 import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64Shift;
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.AVXOp;
 import org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize;
 import org.graalvm.compiler.asm.amd64.AMD64Assembler.SSEOp;
-import org.graalvm.compiler.asm.amd64.AMD64Assembler.AVXOp;
 import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.NumUtil;
 import org.graalvm.compiler.core.common.calc.FloatConvert;
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.lir.ConstantValue;
@@ -107,6 +107,7 @@
 import org.graalvm.compiler.lir.amd64.AMD64SignExtendOp;
 import org.graalvm.compiler.lir.amd64.AMD64Unary;
 import org.graalvm.compiler.lir.gen.ArithmeticLIRGenerator;
+import org.graalvm.compiler.lir.gen.LIRGenerator;
 
 import jdk.vm.ci.amd64.AMD64;
 import jdk.vm.ci.amd64.AMD64.CPUFeature;
@@ -114,6 +115,7 @@
 import jdk.vm.ci.code.CodeUtil;
 import jdk.vm.ci.code.Register;
 import jdk.vm.ci.code.RegisterValue;
+import jdk.vm.ci.code.TargetDescription;
 import jdk.vm.ci.meta.AllocatableValue;
 import jdk.vm.ci.meta.Constant;
 import jdk.vm.ci.meta.JavaConstant;
@@ -122,7 +124,6 @@
 import jdk.vm.ci.meta.VMConstant;
 import jdk.vm.ci.meta.Value;
 import jdk.vm.ci.meta.ValueKind;
-import jdk.vm.ci.code.TargetDescription;
 
 /**
  * This class implements the AMD64 specific portion of the LIR generator.
@@ -131,6 +132,40 @@
 
     private static final RegisterValue RCX_I = AMD64.rcx.asValue(LIRKind.value(AMD64Kind.DWORD));
 
+    public AMD64ArithmeticLIRGenerator(Maths maths) {
+        this.maths = maths == null ? new Maths() {
+        } : maths;
+    }
+
+    private final Maths maths;
+
+    /**
+     * Interface for emitting LIR for selected {@link Math} routines. A {@code null} return value
+     * for any method in this interface means the caller must emit the LIR itself.
+     */
+    public interface Maths {
+
+        @SuppressWarnings("unused")
+        default Variable emitLog(LIRGenerator gen, Value input, boolean base10) {
+            return null;
+        }
+
+        @SuppressWarnings("unused")
+        default Variable emitCos(LIRGenerator gen, Value input) {
+            return null;
+        }
+
+        @SuppressWarnings("unused")
+        default Variable emitSin(LIRGenerator gen, Value input) {
+            return null;
+        }
+
+        @SuppressWarnings("unused")
+        default Variable emitTan(LIRGenerator gen, Value input) {
+            return null;
+        }
+    }
+
     @Override
     public Variable emitNegate(Value inputVal) {
         AllocatableValue input = getLIRGen().asAllocatable(inputVal);
@@ -1042,33 +1077,49 @@
 
     @Override
     public Value emitMathLog(Value input, boolean base10) {
-        Variable result = getLIRGen().newVariable(LIRKind.combine(input));
-        AllocatableValue stackSlot = getLIRGen().getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(AMD64Kind.QWORD));
-        getLIRGen().append(new AMD64MathIntrinsicUnaryOp(getAMD64LIRGen(), base10 ? LOG10 : LOG, result, getLIRGen().asAllocatable(input), stackSlot));
+        LIRGenerator gen = getLIRGen();
+        Variable result = maths.emitLog(gen, input, base10);
+        if (result == null) {
+            result = gen.newVariable(LIRKind.combine(input));
+            AllocatableValue stackSlot = gen.getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(AMD64Kind.QWORD));
+            gen.append(new AMD64MathIntrinsicUnaryOp(getAMD64LIRGen(), base10 ? LOG10 : LOG, result, gen.asAllocatable(input), stackSlot));
+        }
         return result;
     }
 
     @Override
     public Value emitMathCos(Value input) {
-        Variable result = getLIRGen().newVariable(LIRKind.combine(input));
-        AllocatableValue stackSlot = getLIRGen().getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(AMD64Kind.QWORD));
-        getLIRGen().append(new AMD64MathIntrinsicUnaryOp(getAMD64LIRGen(), COS, result, getLIRGen().asAllocatable(input), stackSlot));
+        LIRGenerator gen = getLIRGen();
+        Variable result = maths.emitCos(gen, input);
+        if (result == null) {
+            result = gen.newVariable(LIRKind.combine(input));
+            AllocatableValue stackSlot = gen.getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(AMD64Kind.QWORD));
+            gen.append(new AMD64MathIntrinsicUnaryOp(getAMD64LIRGen(), COS, result, gen.asAllocatable(input), stackSlot));
+        }
         return result;
     }
 
     @Override
     public Value emitMathSin(Value input) {
-        Variable result = getLIRGen().newVariable(LIRKind.combine(input));
-        AllocatableValue stackSlot = getLIRGen().getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(AMD64Kind.QWORD));
-        getLIRGen().append(new AMD64MathIntrinsicUnaryOp(getAMD64LIRGen(), SIN, result, getLIRGen().asAllocatable(input), stackSlot));
+        LIRGenerator gen = getLIRGen();
+        Variable result = maths.emitSin(gen, input);
+        if (result == null) {
+            result = gen.newVariable(LIRKind.combine(input));
+            AllocatableValue stackSlot = gen.getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(AMD64Kind.QWORD));
+            gen.append(new AMD64MathIntrinsicUnaryOp(getAMD64LIRGen(), SIN, result, gen.asAllocatable(input), stackSlot));
+        }
         return result;
     }
 
     @Override
     public Value emitMathTan(Value input) {
-        Variable result = getLIRGen().newVariable(LIRKind.combine(input));
-        AllocatableValue stackSlot = getLIRGen().getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(AMD64Kind.QWORD));
-        getLIRGen().append(new AMD64MathIntrinsicUnaryOp(getAMD64LIRGen(), TAN, result, getLIRGen().asAllocatable(input), stackSlot));
+        LIRGenerator gen = getLIRGen();
+        Variable result = maths.emitTan(gen, input);
+        if (result == null) {
+            result = gen.newVariable(LIRKind.combine(input));
+            AllocatableValue stackSlot = gen.getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(AMD64Kind.QWORD));
+            gen.append(new AMD64MathIntrinsicUnaryOp(getAMD64LIRGen(), TAN, result, gen.asAllocatable(input), stackSlot));
+        }
         return result;
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64LIRGenerator.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64LIRGenerator.java	Fri Mar 16 22:59:32 2018 -0700
@@ -59,6 +59,7 @@
 import org.graalvm.compiler.lir.Variable;
 import org.graalvm.compiler.lir.amd64.AMD64AddressValue;
 import org.graalvm.compiler.lir.amd64.AMD64ArithmeticLIRGeneratorTool;
+import org.graalvm.compiler.lir.amd64.AMD64ArrayCompareToOp;
 import org.graalvm.compiler.lir.amd64.AMD64ArrayEqualsOp;
 import org.graalvm.compiler.lir.amd64.AMD64Binary;
 import org.graalvm.compiler.lir.amd64.AMD64BinaryConsumer;
@@ -74,6 +75,7 @@
 import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.ReturnOp;
 import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.StrategySwitchOp;
 import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.TableSwitchOp;
+import org.graalvm.compiler.lir.amd64.AMD64LFenceOp;
 import org.graalvm.compiler.lir.amd64.AMD64Move;
 import org.graalvm.compiler.lir.amd64.AMD64Move.CompareAndSwapOp;
 import org.graalvm.compiler.lir.amd64.AMD64Move.MembarOp;
@@ -490,6 +492,20 @@
     }
 
     @Override
+    public Variable emitArrayCompareTo(JavaKind kind1, JavaKind kind2, Value array1, Value array2, Value length1, Value length2) {
+        LIRKind resultKind = LIRKind.value(AMD64Kind.DWORD);
+        RegisterValue raxRes = AMD64.rax.asValue(resultKind);
+        RegisterValue cnt1 = AMD64.rcx.asValue(length1.getValueKind());
+        RegisterValue cnt2 = AMD64.rdx.asValue(length2.getValueKind());
+        emitMove(cnt1, length1);
+        emitMove(cnt2, length2);
+        append(new AMD64ArrayCompareToOp(this, kind1, kind2, raxRes, array1, array2, cnt1, cnt2));
+        Variable result = newVariable(resultKind);
+        emitMove(result, raxRes);
+        return result;
+    }
+
+    @Override
     public Variable emitArrayEquals(JavaKind kind, Value array1, Value array2, Value length) {
         Variable result = newVariable(LIRKind.value(AMD64Kind.DWORD));
         append(new AMD64ArrayEqualsOp(this, kind, result, array1, array2, asAllocatable(length)));
@@ -554,4 +570,8 @@
     public LIRInstruction createZapArgumentSpace(StackSlot[] zappedStack, JavaConstant[] zapValues) {
         return new AMD64ZapStackOp(zappedStack, zapValues);
     }
+
+    public void emitLFence() {
+        append(new AMD64LFenceOp());
+    }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64NodeLIRBuilder.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64NodeLIRBuilder.java	Fri Mar 16 22:59:32 2018 -0700
@@ -23,6 +23,8 @@
 
 package org.graalvm.compiler.core.amd64;
 
+import static org.graalvm.compiler.core.amd64.AMD64NodeLIRBuilder.Options.MitigateSpeculativeExecutionAttacks;
+
 import org.graalvm.compiler.core.gen.NodeLIRBuilder;
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.lir.LIRFrameState;
@@ -37,6 +39,11 @@
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.calc.IntegerDivRemNode;
 import org.graalvm.compiler.nodes.calc.IntegerDivRemNode.Op;
+import org.graalvm.compiler.nodes.cfg.Block;
+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 jdk.vm.ci.amd64.AMD64;
 import jdk.vm.ci.meta.AllocatableValue;
@@ -44,6 +51,13 @@
 
 public abstract class AMD64NodeLIRBuilder extends NodeLIRBuilder {
 
+    public static class Options {
+        // @formatter:off
+        @Option(help = "AMD64: Emit lfence instructions at the beginning of basic blocks", type = OptionType.Expert)
+        public static final OptionKey<Boolean> MitigateSpeculativeExecutionAttacks = new OptionKey<>(false);
+        // @formatter:on
+    }
+
     public AMD64NodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool gen, AMD64NodeMatchRules nodeMatchRules) {
         super(graph, gen, nodeMatchRules);
     }
@@ -121,4 +135,21 @@
     public AMD64LIRGenerator getLIRGeneratorTool() {
         return (AMD64LIRGenerator) gen;
     }
+
+    @Override
+    public void doBlockPrologue(Block block, OptionValues options) {
+        if (MitigateSpeculativeExecutionAttacks.getValue(options)) {
+            boolean hasControlSplitPredecessor = false;
+            for (Block b : block.getPredecessors()) {
+                if (b.getSuccessorCount() > 1) {
+                    hasControlSplitPredecessor = true;
+                    break;
+                }
+            }
+            boolean isStartBlock = block.getPredecessorCount() == 0;
+            if (hasControlSplitPredecessor || isStartBlock) {
+                getLIRGeneratorTool().emitLFence();
+            }
+        }
+    }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/GraalOptions.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/GraalOptions.java	Fri Mar 16 22:59:32 2018 -0700
@@ -259,6 +259,9 @@
     @Option(help = "", type = OptionType.Debug)
     public static final OptionKey<Boolean> OptDevirtualizeInvokesOptimistically = new OptionKey<>(true);
 
+    @Option(help = "Track the NodeSourcePosition.", type = OptionType.Debug)
+    public static final OptionKey<Boolean> TrackNodeSourcePosition = new OptionKey<>(false);
+
     @Option(help = "Allow backend to match complex expressions.", type = OptionType.Debug)
     public static final OptionKey<Boolean> MatchExpressions = new OptionKey<>(true);
 
@@ -273,8 +276,7 @@
 
     @Option(help = "Enable experimental Trace Register Allocation.", type = OptionType.Debug)
     public static final OptionKey<Boolean> TraceRA = new OptionKey<>(false);
-
-    @Option(help = "How to trace inlining decisions, one of: None, Linear, Tree", type = OptionType.Debug)
-    public static final OptionKey<TraceInliningMode> TraceInlining = new OptionKey<>(TraceInliningMode.None);
+    @Option(help = "Enable tracing of inlining decision.", type = OptionType.Debug)
+    public static final OptionKey<Boolean> TraceInlining = new OptionKey<>(false);
 
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/TraceInliningMode.java	Fri Mar 16 11:26:05 2018 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,39 +0,0 @@
-/*
- * Copyright (c) 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;
-
-public enum TraceInliningMode {
-    None(false),
-    Linear(true),
-    Tree(true);
-
-    private final boolean tracing;
-
-    TraceInliningMode(boolean tracing) {
-        this.tracing = tracing;
-    }
-
-    public boolean isTracing() {
-        return tracing;
-    }
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/BiDirectionalTraceBuilder.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/BiDirectionalTraceBuilder.java	Fri Mar 16 22:59:32 2018 -0700
@@ -84,7 +84,7 @@
             AbstractBlockBase<?> block = worklist.pollFirst();
             assert block != null;
             if (!processed(block)) {
-                Trace trace = new Trace(startTrace(debug, block));
+                Trace trace = new Trace(findTrace(debug, block));
                 for (AbstractBlockBase<?> traceBlock : trace.getBlocks()) {
                     blockToTrace[traceBlock.getId()] = trace;
                 }
@@ -101,13 +101,13 @@
      * @param debug
      */
     @SuppressWarnings("try")
-    private Collection<AbstractBlockBase<?>> startTrace(DebugContext debug, AbstractBlockBase<?> block) {
+    private Collection<AbstractBlockBase<?>> findTrace(DebugContext debug, AbstractBlockBase<?> initBlock) {
         ArrayDeque<AbstractBlockBase<?>> trace = new ArrayDeque<>();
-        try (Indent i = debug.logAndIndent("StartTrace: %s", block)) {
+        try (Indent i = debug.logAndIndent("StartTrace: %s", initBlock)) {
             try (Indent indentFront = debug.logAndIndent("Head:")) {
-                for (AbstractBlockBase<?> currentBlock = block; currentBlock != null; currentBlock = selectPredecessor(currentBlock)) {
-                    addBlockToTrace(debug, currentBlock);
-                    trace.addFirst(currentBlock);
+                for (AbstractBlockBase<?> block = initBlock; block != null; block = selectPredecessor(block)) {
+                    addBlockToTrace(debug, block);
+                    trace.addFirst(block);
                 }
             }
             /* Number head blocks. Can not do this in the loop as we go backwards. */
@@ -117,11 +117,11 @@
             }
 
             try (Indent indentBack = debug.logAndIndent("Tail:")) {
-                for (AbstractBlockBase<?> currentBlock = selectSuccessor(block); currentBlock != null; currentBlock = selectSuccessor(currentBlock)) {
-                    addBlockToTrace(debug, currentBlock);
-                    trace.addLast(currentBlock);
+                for (AbstractBlockBase<?> block = selectSuccessor(initBlock); block != null; block = selectSuccessor(block)) {
+                    addBlockToTrace(debug, block);
+                    trace.addLast(block);
                     /* This time we can number the blocks immediately as we go forwards. */
-                    currentBlock.setLinearScanNumber(blockNr++);
+                    block.setLinearScanNumber(blockNr++);
                 }
             }
         }
@@ -129,18 +129,18 @@
         return trace;
     }
 
-    private void addBlockToTrace(DebugContext debug, AbstractBlockBase<?> currentBlock) {
-        debug.log("add %s (prob: %f)", currentBlock, currentBlock.probability());
-        processed.set(currentBlock.getId());
+    private void addBlockToTrace(DebugContext debug, AbstractBlockBase<?> block) {
+        debug.log("add %s (prob: %f)", block, block.probability());
+        processed.set(block.getId());
     }
 
     /**
      * @return The unprocessed predecessor with the highest probability, or {@code null}.
      */
-    private AbstractBlockBase<?> selectPredecessor(AbstractBlockBase<?> currentBlock) {
+    private AbstractBlockBase<?> selectPredecessor(AbstractBlockBase<?> block) {
         AbstractBlockBase<?> next = null;
-        for (AbstractBlockBase<?> pred : currentBlock.getPredecessors()) {
-            if (!processed(pred) && !isBackEdge(pred, currentBlock) && (next == null || pred.probability() > next.probability())) {
+        for (AbstractBlockBase<?> pred : block.getPredecessors()) {
+            if (!processed(pred) && !isBackEdge(pred, block) && (next == null || pred.probability() > next.probability())) {
                 next = pred;
             }
         }
@@ -155,9 +155,9 @@
     /**
      * @return The unprocessed successor with the highest probability, or {@code null}.
      */
-    private AbstractBlockBase<?> selectSuccessor(AbstractBlockBase<?> currentBlock) {
+    private AbstractBlockBase<?> selectSuccessor(AbstractBlockBase<?> block) {
         AbstractBlockBase<?> next = null;
-        for (AbstractBlockBase<?> succ : currentBlock.getSuccessors()) {
+        for (AbstractBlockBase<?> succ : block.getSuccessors()) {
             if (!processed(succ) && (next == null || succ.probability() > next.probability())) {
                 next = succ;
             }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/UniDirectionalTraceBuilder.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/UniDirectionalTraceBuilder.java	Fri Mar 16 22:59:32 2018 -0700
@@ -33,7 +33,7 @@
 import org.graalvm.compiler.debug.Indent;
 
 /**
- * Computes traces by starting at a trace head and keep adding predecessors as long as possible.
+ * Computes traces by starting at a trace head and keep adding successors as long as possible.
  */
 public final class UniDirectionalTraceBuilder {
 
@@ -87,7 +87,7 @@
             AbstractBlockBase<?> block = worklist.poll();
             assert block != null;
             if (!processed(block)) {
-                Trace trace = new Trace(startTrace(debug, block));
+                Trace trace = new Trace(findTrace(debug, block));
                 for (AbstractBlockBase<?> traceBlock : trace.getBlocks()) {
                     blockToTrace[traceBlock.getId()] = trace;
                 }
@@ -102,17 +102,17 @@
      * Build a new trace starting at {@code block}.
      */
     @SuppressWarnings("try")
-    private List<AbstractBlockBase<?>> startTrace(DebugContext debug, AbstractBlockBase<?> block) {
-        assert checkPredecessorsProcessed(block);
+    private List<AbstractBlockBase<?>> findTrace(DebugContext debug, AbstractBlockBase<?> traceStart) {
+        assert checkPredecessorsProcessed(traceStart);
         ArrayList<AbstractBlockBase<?>> trace = new ArrayList<>();
         int blockNumber = 0;
-        try (Indent i = debug.logAndIndent("StartTrace: %s", block)) {
-            for (AbstractBlockBase<?> currentBlock = block; currentBlock != null; currentBlock = selectNext(currentBlock)) {
-                debug.log("add %s (prob: %f)", currentBlock, currentBlock.probability());
-                processed.set(currentBlock.getId());
-                trace.add(currentBlock);
-                unblock(currentBlock);
-                currentBlock.setLinearScanNumber(blockNumber++);
+        try (Indent i = debug.logAndIndent("StartTrace: %s", traceStart)) {
+            for (AbstractBlockBase<?> block = traceStart; block != null; block = selectNext(block)) {
+                debug.log("add %s (prob: %f)", block, block.probability());
+                processed.set(block.getId());
+                trace.add(block);
+                unblock(block);
+                block.setLinearScanNumber(blockNumber++);
             }
         }
         return trace;
@@ -120,11 +120,7 @@
 
     private boolean checkPredecessorsProcessed(AbstractBlockBase<?> block) {
         for (AbstractBlockBase<?> pred : block.getPredecessors()) {
-            if (!processed(pred)) {
-                assert false : "Predecessor unscheduled: " + pred;
-                return false;
-            }
-
+            assert processed(pred) : "Predecessor unscheduled: " + pred;
         }
         return true;
     }
@@ -133,8 +129,8 @@
      * Decrease the {@link #blocked} count for all predecessors and add them to the worklist once
      * the count reaches 0.
      */
-    private void unblock(AbstractBlockBase<?> currentBlock) {
-        for (AbstractBlockBase<?> successor : currentBlock.getSuccessors()) {
+    private void unblock(AbstractBlockBase<?> block) {
+        for (AbstractBlockBase<?> successor : block.getSuccessors()) {
             if (!processed(successor)) {
                 int blockCount = --blocked[successor.getId()];
                 assert blockCount >= 0;
@@ -148,11 +144,11 @@
     /**
      * @return The unprocessed predecessor with the highest probability, or {@code null}.
      */
-    private AbstractBlockBase<?> selectNext(AbstractBlockBase<?> currentBlock) {
+    private AbstractBlockBase<?> selectNext(AbstractBlockBase<?> block) {
         AbstractBlockBase<?> next = null;
-        for (AbstractBlockBase<?> succ : currentBlock.getSuccessors()) {
-            if (!processed(succ) && (next == null || succ.probability() > next.probability())) {
-                next = succ;
+        for (AbstractBlockBase<?> successor : block.getSuccessors()) {
+            if (!processed(successor) && (next == null || successor.probability() > next.probability())) {
+                next = successor;
             }
         }
         return next;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/AbstractObjectStamp.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/AbstractObjectStamp.java	Fri Mar 16 22:59:32 2018 -0700
@@ -191,8 +191,6 @@
         boolean joinExactType = exactType || other.exactType;
         if (Objects.equals(type, other.type)) {
             joinType = type;
-        } else if (type == null && other.type == null) {
-            joinType = null;
         } else if (type == null) {
             joinType = other.type;
         } else if (other.type == null) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/FloatStamp.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/FloatStamp.java	Fri Mar 16 22:59:32 2018 -0700
@@ -176,11 +176,15 @@
         StringBuilder str = new StringBuilder();
         str.append('f');
         str.append(getBits());
-        str.append(nonNaN ? "!" : "");
-        if (lowerBound == upperBound) {
-            str.append(" [").append(lowerBound).append(']');
-        } else if (lowerBound != Double.NEGATIVE_INFINITY || upperBound != Double.POSITIVE_INFINITY) {
-            str.append(" [").append(lowerBound).append(" - ").append(upperBound).append(']');
+        if (hasValues()) {
+            str.append(nonNaN ? "!" : "");
+            if (lowerBound == upperBound) {
+                str.append(" [").append(lowerBound).append(']');
+            } else if (lowerBound != Double.NEGATIVE_INFINITY || upperBound != Double.POSITIVE_INFINITY) {
+                str.append(" [").append(lowerBound).append(" - ").append(upperBound).append(']');
+            }
+        } else {
+            str.append("<empty>");
         }
         return str.toString();
     }
@@ -200,6 +204,12 @@
         if (otherStamp == this) {
             return this;
         }
+        if (isEmpty()) {
+            return this;
+        }
+        if (otherStamp.isEmpty()) {
+            return otherStamp;
+        }
         FloatStamp other = (FloatStamp) otherStamp;
         assert getBits() == other.getBits();
         double meetUpperBound = meetBounds(upperBound, other.upperBound, Math::max);
@@ -383,6 +393,9 @@
 
                         @Override
                         public Stamp foldStamp(Stamp s) {
+                            if (s.isEmpty()) {
+                                return s;
+                            }
                             FloatStamp stamp = (FloatStamp) s;
                             Stamp folded = maybeFoldConstant(this, stamp);
                             if (folded != null) {
@@ -412,6 +425,12 @@
 
                         @Override
                         public Stamp foldStamp(Stamp s1, Stamp s2) {
+                            if (s1.isEmpty()) {
+                                return s1;
+                            }
+                            if (s2.isEmpty()) {
+                                return s2;
+                            }
                             FloatStamp stamp1 = (FloatStamp) s1;
                             FloatStamp stamp2 = (FloatStamp) s2;
                             Stamp folded = maybeFoldConstant(this, stamp1, stamp2);
@@ -454,6 +473,12 @@
 
                         @Override
                         public Stamp foldStamp(Stamp s1, Stamp s2) {
+                            if (s1.isEmpty()) {
+                                return s1;
+                            }
+                            if (s2.isEmpty()) {
+                                return s2;
+                            }
                             FloatStamp stamp1 = (FloatStamp) s1;
                             FloatStamp stamp2 = (FloatStamp) s2;
                             Stamp folded = maybeFoldConstant(this, stamp1, stamp2);
@@ -496,6 +521,12 @@
 
                         @Override
                         public Stamp foldStamp(Stamp s1, Stamp s2) {
+                            if (s1.isEmpty()) {
+                                return s1;
+                            }
+                            if (s2.isEmpty()) {
+                                return s2;
+                            }
                             FloatStamp stamp1 = (FloatStamp) s1;
                             FloatStamp stamp2 = (FloatStamp) s2;
                             Stamp folded = maybeFoldConstant(this, stamp1, stamp2);
@@ -544,6 +575,12 @@
 
                         @Override
                         public Stamp foldStamp(Stamp s1, Stamp s2) {
+                            if (s1.isEmpty()) {
+                                return s1;
+                            }
+                            if (s2.isEmpty()) {
+                                return s2;
+                            }
                             FloatStamp stamp1 = (FloatStamp) s1;
                             FloatStamp stamp2 = (FloatStamp) s2;
                             Stamp folded = maybeFoldConstant(this, stamp1, stamp2);
@@ -586,6 +623,12 @@
 
                         @Override
                         public Stamp foldStamp(Stamp s1, Stamp s2) {
+                            if (s1.isEmpty()) {
+                                return s1;
+                            }
+                            if (s2.isEmpty()) {
+                                return s2;
+                            }
                             FloatStamp stamp1 = (FloatStamp) s1;
                             FloatStamp stamp2 = (FloatStamp) s2;
                             Stamp folded = maybeFoldConstant(this, stamp1, stamp2);
@@ -615,6 +658,9 @@
 
                         @Override
                         public Stamp foldStamp(Stamp s) {
+                            if (s.isEmpty()) {
+                                return s;
+                            }
                             FloatStamp stamp = (FloatStamp) s;
                             JavaConstant constant = stamp.asConstant();
                             if (constant != null) {
@@ -653,6 +699,12 @@
 
                         @Override
                         public Stamp foldStamp(Stamp s1, Stamp s2) {
+                            if (s1.isEmpty()) {
+                                return s1;
+                            }
+                            if (s2.isEmpty()) {
+                                return s2;
+                            }
                             FloatStamp stamp1 = (FloatStamp) s1;
                             FloatStamp stamp2 = (FloatStamp) s2;
                             Stamp folded = maybeFoldConstant(this, stamp1, stamp2);
@@ -701,6 +753,12 @@
 
                         @Override
                         public Stamp foldStamp(Stamp s1, Stamp s2) {
+                            if (s1.isEmpty()) {
+                                return s1;
+                            }
+                            if (s2.isEmpty()) {
+                                return s2;
+                            }
                             FloatStamp stamp1 = (FloatStamp) s1;
                             FloatStamp stamp2 = (FloatStamp) s2;
                             Stamp folded = maybeFoldConstant(this, stamp1, stamp2);
@@ -747,6 +805,12 @@
 
                         @Override
                         public Stamp foldStamp(Stamp s1, Stamp s2) {
+                            if (s1.isEmpty()) {
+                                return s1;
+                            }
+                            if (s2.isEmpty()) {
+                                return s2;
+                            }
                             FloatStamp stamp1 = (FloatStamp) s1;
                             FloatStamp stamp2 = (FloatStamp) s2;
                             Stamp folded = maybeFoldConstant(this, stamp1, stamp2);
@@ -789,6 +853,9 @@
 
                         @Override
                         public Stamp foldStamp(Stamp s) {
+                            if (s.isEmpty()) {
+                                return s;
+                            }
                             FloatStamp stamp = (FloatStamp) s;
                             Stamp folded = maybeFoldConstant(this, stamp);
                             if (folded != null) {
@@ -818,6 +885,9 @@
 
                         @Override
                         public Stamp foldStamp(Stamp s) {
+                            if (s.isEmpty()) {
+                                return s;
+                            }
                             FloatStamp stamp = (FloatStamp) s;
                             Stamp folded = maybeFoldConstant(this, stamp);
                             if (folded != null) {
@@ -839,6 +909,9 @@
 
                         @Override
                         public Stamp foldStamp(Stamp stamp) {
+                            if (stamp.isEmpty()) {
+                                return StampFactory.empty(JavaKind.Int);
+                            }
                             FloatStamp floatStamp = (FloatStamp) stamp;
                             assert floatStamp.getBits() == 32;
                             boolean mustHaveZero = !floatStamp.isNonNaN();
@@ -865,6 +938,9 @@
 
                         @Override
                         public Stamp foldStamp(Stamp stamp) {
+                            if (stamp.isEmpty()) {
+                                return StampFactory.empty(JavaKind.Long);
+                            }
                             FloatStamp floatStamp = (FloatStamp) stamp;
                             assert floatStamp.getBits() == 32;
                             boolean mustHaveZero = !floatStamp.isNonNaN();
@@ -891,6 +967,9 @@
 
                         @Override
                         public Stamp foldStamp(Stamp stamp) {
+                            if (stamp.isEmpty()) {
+                                return StampFactory.empty(JavaKind.Int);
+                            }
                             FloatStamp floatStamp = (FloatStamp) stamp;
                             assert floatStamp.getBits() == 64;
                             boolean mustHaveZero = !floatStamp.isNonNaN();
@@ -917,6 +996,9 @@
 
                         @Override
                         public Stamp foldStamp(Stamp stamp) {
+                            if (stamp.isEmpty()) {
+                                return StampFactory.empty(JavaKind.Long);
+                            }
                             FloatStamp floatStamp = (FloatStamp) stamp;
                             assert floatStamp.getBits() == 64;
                             boolean mustHaveZero = !floatStamp.isNonNaN();
@@ -943,6 +1025,9 @@
 
                         @Override
                         public Stamp foldStamp(Stamp stamp) {
+                            if (stamp.isEmpty()) {
+                                return StampFactory.empty(JavaKind.Double);
+                            }
                             FloatStamp floatStamp = (FloatStamp) stamp;
                             assert floatStamp.getBits() == 32;
                             return StampFactory.forFloat(JavaKind.Double, floatStamp.lowerBound(), floatStamp.upperBound(), floatStamp.isNonNaN());
@@ -959,6 +1044,9 @@
 
                         @Override
                         public Stamp foldStamp(Stamp stamp) {
+                            if (stamp.isEmpty()) {
+                                return StampFactory.empty(JavaKind.Float);
+                            }
                             FloatStamp floatStamp = (FloatStamp) stamp;
                             assert floatStamp.getBits() == 64;
                             return StampFactory.forFloat(JavaKind.Float, (float) floatStamp.lowerBound(), (float) floatStamp.upperBound(), floatStamp.isNonNaN());
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IntegerStamp.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IntegerStamp.java	Fri Mar 16 22:59:32 2018 -0700
@@ -122,11 +122,11 @@
         return new IntegerStamp(bits, lowerBoundTmp, upperBoundTmp, defaultMask & (downMask | boundedDownMask), defaultMask & upMask & boundedUpMask);
     }
 
-    static long significantBit(long bits, long value) {
+    private static long significantBit(long bits, long value) {
         return (value >>> (bits - 1)) & 1;
     }
 
-    static long minValueForMasks(int bits, long downMask, long upMask) {
+    private static long minValueForMasks(int bits, long downMask, long upMask) {
         if (significantBit(bits, upMask) == 0) {
             // Value is always positive. Minimum value always positive.
             assert significantBit(bits, downMask) == 0;
@@ -137,7 +137,7 @@
         }
     }
 
-    static long maxValueForMasks(int bits, long downMask, long upMask) {
+    private static long maxValueForMasks(int bits, long downMask, long upMask) {
         if (significantBit(bits, downMask) == 1) {
             // Value is always negative. Maximum value always negative.
             assert significantBit(bits, upMask) == 1;
@@ -330,6 +330,12 @@
         if (otherStamp == this) {
             return this;
         }
+        if (isEmpty()) {
+            return otherStamp;
+        }
+        if (otherStamp.isEmpty()) {
+            return this;
+        }
         IntegerStamp other = (IntegerStamp) otherStamp;
         return createStamp(other, Math.max(upperBound, other.upperBound), Math.min(lowerBound, other.lowerBound), downMask & other.downMask, upMask | other.upMask);
     }
@@ -413,7 +419,7 @@
         return super.equals(other);
     }
 
-    public static long upMaskFor(int bits, long lowerBound, long upperBound) {
+    private static long upMaskFor(int bits, long lowerBound, long upperBound) {
         long mask = lowerBound | upperBound;
         if (mask == 0) {
             return 0;
@@ -595,6 +601,9 @@
 
                         @Override
                         public Stamp foldStamp(Stamp s) {
+                            if (s.isEmpty()) {
+                                return s;
+                            }
                             IntegerStamp stamp = (IntegerStamp) s;
                             int bits = stamp.getBits();
                             if (stamp.lowerBound == stamp.upperBound) {
@@ -622,6 +631,12 @@
 
                         @Override
                         public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
+                            if (stamp1.isEmpty()) {
+                                return stamp1;
+                            }
+                            if (stamp2.isEmpty()) {
+                                return stamp2;
+                            }
                             IntegerStamp a = (IntegerStamp) stamp1;
                             IntegerStamp b = (IntegerStamp) stamp2;
 
@@ -715,6 +730,12 @@
 
                         @Override
                         public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
+                            if (stamp1.isEmpty()) {
+                                return stamp1;
+                            }
+                            if (stamp2.isEmpty()) {
+                                return stamp2;
+                            }
                             IntegerStamp a = (IntegerStamp) stamp1;
                             IntegerStamp b = (IntegerStamp) stamp2;
 
@@ -885,6 +906,12 @@
 
                         @Override
                         public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
+                            if (stamp1.isEmpty()) {
+                                return stamp1;
+                            }
+                            if (stamp2.isEmpty()) {
+                                return stamp2;
+                            }
                             IntegerStamp a = (IntegerStamp) stamp1;
                             IntegerStamp b = (IntegerStamp) stamp2;
                             JavaKind javaKind = a.getStackKind();
@@ -952,6 +979,12 @@
 
                         @Override
                         public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
+                            if (stamp1.isEmpty()) {
+                                return stamp1;
+                            }
+                            if (stamp2.isEmpty()) {
+                                return stamp2;
+                            }
                             IntegerStamp a = (IntegerStamp) stamp1;
                             IntegerStamp b = (IntegerStamp) stamp2;
                             JavaKind javaKind = a.getStackKind();
@@ -1046,6 +1079,12 @@
 
                         @Override
                         public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
+                            if (stamp1.isEmpty()) {
+                                return stamp1;
+                            }
+                            if (stamp2.isEmpty()) {
+                                return stamp2;
+                            }
                             IntegerStamp a = (IntegerStamp) stamp1;
                             IntegerStamp b = (IntegerStamp) stamp2;
                             assert a.getBits() == b.getBits();
@@ -1083,6 +1122,12 @@
 
                         @Override
                         public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
+                            if (stamp1.isEmpty()) {
+                                return stamp1;
+                            }
+                            if (stamp2.isEmpty()) {
+                                return stamp2;
+                            }
                             IntegerStamp a = (IntegerStamp) stamp1;
                             IntegerStamp b = (IntegerStamp) stamp2;
                             assert a.getBits() == b.getBits();
@@ -1121,6 +1166,9 @@
 
                         @Override
                         public Stamp foldStamp(Stamp stamp) {
+                            if (stamp.isEmpty()) {
+                                return stamp;
+                            }
                             IntegerStamp integerStamp = (IntegerStamp) stamp;
                             int bits = integerStamp.getBits();
                             long defaultMask = CodeUtil.mask(bits);
@@ -1140,6 +1188,12 @@
 
                         @Override
                         public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
+                            if (stamp1.isEmpty()) {
+                                return stamp1;
+                            }
+                            if (stamp2.isEmpty()) {
+                                return stamp2;
+                            }
                             IntegerStamp a = (IntegerStamp) stamp1;
                             IntegerStamp b = (IntegerStamp) stamp2;
                             assert a.getBits() == b.getBits();
@@ -1167,6 +1221,12 @@
 
                         @Override
                         public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
+                            if (stamp1.isEmpty()) {
+                                return stamp1;
+                            }
+                            if (stamp2.isEmpty()) {
+                                return stamp2;
+                            }
                             IntegerStamp a = (IntegerStamp) stamp1;
                             IntegerStamp b = (IntegerStamp) stamp2;
                             assert a.getBits() == b.getBits();
@@ -1192,6 +1252,12 @@
 
                         @Override
                         public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
+                            if (stamp1.isEmpty()) {
+                                return stamp1;
+                            }
+                            if (stamp2.isEmpty()) {
+                                return stamp2;
+                            }
                             IntegerStamp a = (IntegerStamp) stamp1;
                             IntegerStamp b = (IntegerStamp) stamp2;
                             assert a.getBits() == b.getBits();
@@ -1269,8 +1335,7 @@
                                         upMask |= value.upMask() << (i & shiftMask);
                                     }
                                 }
-                                Stamp result = IntegerStamp.stampForMask(bits, downMask, upMask & defaultMask);
-                                return result;
+                                return IntegerStamp.stampForMask(bits, downMask, upMask & defaultMask);
                             }
                             return value.unrestricted();
                         }
@@ -1392,6 +1457,9 @@
 
                         @Override
                         public Stamp foldStamp(Stamp input) {
+                            if (input.isEmpty()) {
+                                return input;
+                            }
                             IntegerStamp stamp = (IntegerStamp) input;
                             int bits = stamp.getBits();
                             if (stamp.lowerBound == stamp.upperBound) {
@@ -1419,6 +1487,9 @@
 
                         @Override
                         public Stamp foldStamp(int inputBits, int resultBits, Stamp input) {
+                            if (input.isEmpty()) {
+                                return StampFactory.forInteger(resultBits).empty();
+                            }
                             IntegerStamp stamp = (IntegerStamp) input;
                             assert inputBits == stamp.getBits();
                             assert inputBits <= resultBits;
@@ -1458,6 +1529,9 @@
 
                         @Override
                         public Stamp foldStamp(int inputBits, int resultBits, Stamp input) {
+                            if (input.isEmpty()) {
+                                return StampFactory.forInteger(resultBits).empty();
+                            }
                             IntegerStamp stamp = (IntegerStamp) input;
                             assert inputBits == stamp.getBits();
                             assert inputBits <= resultBits;
@@ -1487,6 +1561,9 @@
 
                         @Override
                         public Stamp foldStamp(int inputBits, int resultBits, Stamp input) {
+                            if (input.isEmpty()) {
+                                return StampFactory.forInteger(resultBits).empty();
+                            }
                             IntegerStamp stamp = (IntegerStamp) input;
                             assert inputBits == stamp.getBits();
                             assert resultBits <= inputBits;
@@ -1526,6 +1603,9 @@
 
                         @Override
                         public Stamp foldStamp(Stamp input) {
+                            if (input.isEmpty()) {
+                                return StampFactory.empty(JavaKind.Float);
+                            }
                             IntegerStamp stamp = (IntegerStamp) input;
                             assert stamp.getBits() == 32;
                             float lowerBound = stamp.lowerBound();
@@ -1544,6 +1624,9 @@
 
                         @Override
                         public Stamp foldStamp(Stamp input) {
+                            if (input.isEmpty()) {
+                                return StampFactory.empty(JavaKind.Float);
+                            }
                             IntegerStamp stamp = (IntegerStamp) input;
                             assert stamp.getBits() == 64;
                             float lowerBound = stamp.lowerBound();
@@ -1562,6 +1645,9 @@
 
                         @Override
                         public Stamp foldStamp(Stamp input) {
+                            if (input.isEmpty()) {
+                                return StampFactory.empty(JavaKind.Double);
+                            }
                             IntegerStamp stamp = (IntegerStamp) input;
                             assert stamp.getBits() == 32;
                             double lowerBound = stamp.lowerBound();
@@ -1580,6 +1666,9 @@
 
                         @Override
                         public Stamp foldStamp(Stamp input) {
+                            if (input.isEmpty()) {
+                                return StampFactory.empty(JavaKind.Double);
+                            }
                             IntegerStamp stamp = (IntegerStamp) input;
                             assert stamp.getBits() == 64;
                             double lowerBound = stamp.lowerBound();
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/StampFactory.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/StampFactory.java	Fri Mar 16 22:59:32 2018 -0700
@@ -161,6 +161,10 @@
         return IntegerStamp.create(bits, CodeUtil.minValue(bits), CodeUtil.maxValue(bits), 0, CodeUtil.mask(bits));
     }
 
+    public static IntegerStamp forUnsignedInteger(int bits) {
+        return forUnsignedInteger(bits, 0, NumUtil.maxValueUnsigned(bits), 0, CodeUtil.mask(bits));
+    }
+
     public static IntegerStamp forUnsignedInteger(int bits, long unsignedLowerBound, long unsignedUpperBound) {
         return forUnsignedInteger(bits, unsignedLowerBound, unsignedUpperBound, 0, CodeUtil.mask(bits));
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/UnsignedLong.java	Fri Mar 16 22:59:32 2018 -0700
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2018, 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;
+
+public final class UnsignedLong {
+    private final long value;
+
+    public UnsignedLong(long value) {
+        this.value = value;
+    }
+
+    public long asLong() {
+        return value;
+    }
+
+    public boolean equals(long unsignedValue) {
+        return value == unsignedValue;
+    }
+
+    public boolean isLessThan(long unsignedValue) {
+        return Long.compareUnsigned(value, unsignedValue) < 0;
+    }
+
+    public boolean isLessOrEqualTo(long unsignedValue) {
+        return Long.compareUnsigned(value, unsignedValue) <= 0;
+    }
+
+    public UnsignedLong times(long unsignedValue) {
+        if (unsignedValue != 0 && Long.compareUnsigned(value, Long.divideUnsigned(0xffff_ffff_ffff_ffffL, unsignedValue)) > 0) {
+            throw new ArithmeticException();
+        }
+        return new UnsignedLong(value * unsignedValue);
+    }
+
+    public UnsignedLong minus(long unsignedValue) {
+        if (Long.compareUnsigned(value, unsignedValue) < 0) {
+            throw new ArithmeticException();
+        }
+        return new UnsignedLong(value - unsignedValue);
+    }
+
+    public UnsignedLong plus(long unsignedValue) {
+        if (Long.compareUnsigned(0xffff_ffff_ffff_ffffL - unsignedValue, value) < 0) {
+            throw new ArithmeticException();
+        }
+        return new UnsignedLong(value + unsignedValue);
+    }
+
+    public UnsignedLong wrappingPlus(long unsignedValue) {
+        return new UnsignedLong(value + unsignedValue);
+    }
+
+    public UnsignedLong wrappingTimes(long unsignedValue) {
+        return new UnsignedLong(value * unsignedValue);
+    }
+
+    @Override
+    public String toString() {
+        return "UnsignedLong(" + Long.toUnsignedString(value) + ")";
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        UnsignedLong that = (UnsignedLong) o;
+        return value == that.value;
+    }
+
+    @Override
+    public int hashCode() {
+        return Long.hashCode(value);
+    }
+}
--- /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/BasePhaseBinaryGraphTest.java	Fri Mar 16 22:59:32 2018 -0700
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2011, 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.test;
+
+import org.graalvm.compiler.debug.DebugContext;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.phases.BasePhase;
+import org.graalvm.compiler.printer.BinaryGraphPrinter;
+import static org.junit.Assert.assertEquals;
+import org.junit.Before;
+import org.junit.Test;
+
+public class BasePhaseBinaryGraphTest {
+    private MyPhase phase;
+    private BinaryGraphPrinter printer;
+
+    @Before
+    public void createPhase() {
+        phase = new MyPhase();
+    }
+
+    @Before
+    public void createPrinter() throws Exception {
+        printer = new BinaryGraphPrinter(DebugContext.DISABLED, null);
+    }
+
+    @Test
+    public void phaseNameIsRecognizedAsType() {
+        String res = printer.typeName(phase.getName());
+        assertEquals(MyPhase.class.getName(), res);
+    }
+
+    private static final class MyPhase extends BasePhase<Void> {
+        @Override
+        protected void run(StructuredGraph graph, Void context) {
+        }
+
+        @Override
+        protected CharSequence getName() {
+            return super.getName();
+        }
+    }
+}
--- /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/ConditionalNodeTest.java	Fri Mar 16 22:59:32 2018 -0700
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 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.test;
+
+import org.junit.Test;
+
+public class ConditionalNodeTest extends GraalCompilerTest {
+
+    @SuppressWarnings("unused") private static int sink0;
+    @SuppressWarnings("unused") private static int sink1;
+
+    @Test
+    public void test0() {
+        test("conditionalTest0", 0);
+        test("conditionalTest0", 1);
+    }
+
+    public static int conditionalTest0(int a) {
+        int value;
+        if (a == 1) {
+            value = -1;
+            sink1 = 0;
+        } else {
+            value = 6;
+            sink1 = 1;
+        }
+        sink0 = 1;
+        return Math.max(value, 6);
+    }
+
+    @Test
+    public void test1() {
+        test("conditionalTest1", 0);
+        test("conditionalTest1", 1);
+    }
+
+    public static int conditionalTest1(int a) {
+        int value;
+        if (a == 1) {
+            value = -1;
+            sink1 = 0;
+        } else {
+            value = 6;
+            sink1 = 1;
+        }
+        sink0 = 1;
+        return Math.max(6, value);
+    }
+
+    @Test
+    public void test2() {
+        test("conditionalTest2", 0);
+        test("conditionalTest2", 1);
+    }
+
+    public static int conditionalTest2(int a) {
+        int value;
+        if (a == 1) {
+            value = -1;
+            sink1 = 0;
+        } else {
+            value = 6;
+            sink1 = 1;
+        }
+        sink0 = 1;
+        return Math.min(value, -1);
+    }
+
+    @Test
+    public void test3() {
+        test("conditionalTest3", 0);
+        test("conditionalTest3", 1);
+    }
+
+    public static int conditionalTest3(int a) {
+        int value;
+        if (a == 1) {
+            value = -1;
+            sink1 = 0;
+        } else {
+            value = 6;
+            sink1 = 1;
+        }
+        sink0 = 1;
+        return Math.min(-1, value);
+    }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CountedLoopTest.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CountedLoopTest.java	Fri Mar 16 22:59:32 2018 -0700
@@ -30,6 +30,7 @@
 import org.graalvm.compiler.loop.InductionVariable;
 import org.graalvm.compiler.loop.LoopsData;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
 import org.graalvm.compiler.nodes.NodeView;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.ValueNode;
@@ -52,25 +53,47 @@
         ValueNode get(InductionVariable iv);
     }
 
+    @FunctionalInterface
+    private interface StaticIVProperty {
+        long get(InductionVariable iv);
+    }
+
+    @FunctionalInterface
+    private interface IVPredicate {
+        boolean test(InductionVariable iv);
+    }
+
     /**
      * Get a property of an induction variable.
-     *
-     * @param property
      */
-    private static int get(IVProperty property, int iv) {
+    private static int get(@SuppressWarnings("unused") IVProperty property, @SuppressWarnings("unused") StaticIVProperty staticProperty, @SuppressWarnings("unused") IVPredicate constantCheck,
+                    int iv) {
+        return iv;
+    }
+
+    private static int get(@SuppressWarnings("unused") IVProperty property, int iv) {
+        return iv;
+    }
+
+    private static long get(@SuppressWarnings("unused") IVProperty property, @SuppressWarnings("unused") StaticIVProperty staticProperty, @SuppressWarnings("unused") IVPredicate constantCheck,
+                    long iv) {
+        return iv;
+    }
+
+    private static long get(@SuppressWarnings("unused") IVProperty property, long iv) {
         return iv;
     }
 
     private static class Result {
-        public int extremum;
-        public int exitValue;
+        public long extremum;
+        public long exitValue;
 
         @Override
         public int hashCode() {
             final int prime = 31;
             int result = 1;
-            result = prime * result + exitValue;
-            result = prime * result + extremum;
+            result = prime * result + Long.hashCode(exitValue);
+            result = prime * result + Long.hashCode(extremum);
             return result;
         }
 
@@ -95,7 +118,7 @@
         Result ret = new Result();
         for (i = start; i < limit; i += inc) {
             GraalDirectives.controlFlowAnchor();
-            ret.extremum = get(InductionVariable::extremumNode, i);
+            ret.extremum = get(InductionVariable::extremumNode, InductionVariable::constantExtremum, InductionVariable::isConstantExtremum, i);
         }
         ret.exitValue = get(InductionVariable::exitValueNode, i);
         return ret;
@@ -103,32 +126,42 @@
 
     @Test
     public void increment1() {
-        test("incrementSnippet", 0, 256, 1);
+        testCounted("incrementSnippet", 0, 256, 1);
     }
 
     @Test
     public void increment2() {
-        test("incrementSnippet", 0, 256, 2);
+        testCounted("incrementSnippet", 0, 256, 2);
     }
 
     @Test
     public void increment3() {
-        test("incrementSnippet", 0, 256, 3);
+        testCounted("incrementSnippet", 0, 256, 3);
     }
 
     @Test
     public void increment4() {
-        test("incrementSnippet", -10, Integer.MAX_VALUE, 1);
+        testCounted("incrementSnippet", -10, 1, Integer.MAX_VALUE);
     }
 
     @Test
     public void increment5() {
-        test("incrementSnippet", 256, 256, 1);
+        testCounted("incrementSnippet", 256, 256, 1);
     }
 
     @Test
     public void increment6() {
-        test("incrementSnippet", 257, 256, 1);
+        testCounted("incrementSnippet", 257, 256, 1);
+    }
+
+    @Test
+    public void increment7() {
+        testCounted("incrementSnippet", -10, Integer.MAX_VALUE, 1);
+    }
+
+    @Test
+    public void increment8() {
+        testCounted("incrementSnippet", -10, Integer.MAX_VALUE - 1, 2);
     }
 
     public static Result incrementEqSnippet(int start, int limit, int step) {
@@ -137,7 +170,7 @@
         Result ret = new Result();
         for (i = start; i <= limit; i += inc) {
             GraalDirectives.controlFlowAnchor();
-            ret.extremum = get(InductionVariable::extremumNode, i);
+            ret.extremum = get(InductionVariable::extremumNode, InductionVariable::constantExtremum, InductionVariable::isConstantExtremum, i);
         }
         ret.exitValue = get(InductionVariable::exitValueNode, i);
         return ret;
@@ -145,32 +178,42 @@
 
     @Test
     public void incrementEq1() {
-        test("incrementEqSnippet", 0, 256, 1);
+        testCounted("incrementEqSnippet", 0, 256, 1);
     }
 
     @Test
     public void incrementEq2() {
-        test("incrementEqSnippet", 0, 256, 2);
+        testCounted("incrementEqSnippet", 0, 256, 2);
     }
 
     @Test
     public void incrementEq3() {
-        test("incrementEqSnippet", 0, 256, 3);
+        testCounted("incrementEqSnippet", 0, 256, 3);
     }
 
     @Test
     public void incrementEq4() {
-        test("incrementEqSnippet", -10, 0, Integer.MAX_VALUE);
+        testCounted("incrementEqSnippet", -10, 0, Integer.MAX_VALUE);
     }
 
     @Test
     public void incrementEq5() {
-        test("incrementEqSnippet", 256, 256, 1);
+        testCounted("incrementEqSnippet", 256, 256, 1);
     }
 
     @Test
     public void incrementEq6() {
-        test("incrementEqSnippet", 257, 256, 1);
+        testCounted("incrementEqSnippet", 257, 256, 1);
+    }
+
+    @Test
+    public void incrementEq7() {
+        testCounted("incrementEqSnippet", -10, Integer.MAX_VALUE - 1, 1);
+    }
+
+    @Test
+    public void incrementEq8() {
+        testCounted("incrementEqSnippet", -10, Integer.MAX_VALUE - 2, 2);
     }
 
     public static Result decrementSnippet(int start, int limit, int step) {
@@ -179,7 +222,7 @@
         Result ret = new Result();
         for (i = start; i > limit; i -= dec) {
             GraalDirectives.controlFlowAnchor();
-            ret.extremum = get(InductionVariable::extremumNode, i);
+            ret.extremum = get(InductionVariable::extremumNode, InductionVariable::constantExtremum, InductionVariable::isConstantExtremum, i);
         }
         ret.exitValue = get(InductionVariable::exitValueNode, i);
         return ret;
@@ -187,17 +230,27 @@
 
     @Test
     public void decrement1() {
-        test("decrementSnippet", 256, 0, 1);
+        testCounted("decrementSnippet", 256, 0, 1);
     }
 
     @Test
     public void decrement2() {
-        test("decrementSnippet", 256, 0, 2);
+        testCounted("decrementSnippet", 256, 0, 2);
     }
 
     @Test
     public void decrement3() {
-        test("decrementSnippet", 256, 0, 3);
+        testCounted("decrementSnippet", 256, 0, 3);
+    }
+
+    @Test
+    public void decrement4() {
+        testCounted("decrementSnippet", Integer.MAX_VALUE, -10, 1);
+    }
+
+    @Test
+    public void decrement5() {
+        testCounted("decrementSnippet", Integer.MAX_VALUE, -10, 2);
     }
 
     public static Result decrementEqSnippet(int start, int limit, int step) {
@@ -206,7 +259,7 @@
         Result ret = new Result();
         for (i = start; i >= limit; i -= dec) {
             GraalDirectives.controlFlowAnchor();
-            ret.extremum = get(InductionVariable::extremumNode, i);
+            ret.extremum = get(InductionVariable::extremumNode, InductionVariable::constantExtremum, InductionVariable::isConstantExtremum, i);
         }
         ret.exitValue = get(InductionVariable::exitValueNode, i);
         return ret;
@@ -214,22 +267,32 @@
 
     @Test
     public void decrementEq1() {
-        test("decrementEqSnippet", 256, 0, 1);
+        testCounted("decrementEqSnippet", 256, 0, 1);
     }
 
     @Test
     public void decrementEq2() {
-        test("decrementEqSnippet", 256, 0, 2);
+        testCounted("decrementEqSnippet", 256, 0, 2);
     }
 
     @Test
     public void decrementEq3() {
-        test("decrementEqSnippet", 256, 0, 3);
+        testCounted("decrementEqSnippet", 256, 0, 3);
     }
 
     @Test
     public void decrementEq4() {
-        test("decrementEqSnippet", -10, 0, Integer.MAX_VALUE);
+        testCounted("decrementEqSnippet", -10, 0, Integer.MAX_VALUE);
+    }
+
+    @Test
+    public void decrementEq5() {
+        testCounted("decrementEqSnippet", Integer.MAX_VALUE, -10, 1);
+    }
+
+    @Test
+    public void decrementEq6() {
+        testCounted("decrementEqSnippet", Integer.MAX_VALUE, -10, 2);
     }
 
     public static Result twoVariablesSnippet() {
@@ -238,7 +301,7 @@
         for (int i = 0; i < 1024; i++) {
             j += 5;
             GraalDirectives.controlFlowAnchor();
-            ret.extremum = get(InductionVariable::extremumNode, j);
+            ret.extremum = get(InductionVariable::extremumNode, InductionVariable::constantExtremum, InductionVariable::isConstantExtremum, j);
         }
         ret.exitValue = get(InductionVariable::exitValueNode, j);
         return ret;
@@ -246,7 +309,83 @@
 
     @Test
     public void testTwoVariables() {
-        test("twoVariablesSnippet");
+        testCounted("twoVariablesSnippet");
+    }
+
+    public static Result incrementNeqSnippet(int limit) {
+        int i;
+        int posLimit = ((limit - 1) & 0xFFFF) + 1; // make sure limit is always strictly positive
+        Result ret = new Result();
+        for (i = 0; i != posLimit; i++) {
+            GraalDirectives.controlFlowAnchor();
+            ret.extremum = get(InductionVariable::extremumNode, InductionVariable::constantExtremum, InductionVariable::isConstantExtremum, i);
+        }
+        ret.exitValue = get(InductionVariable::exitValueNode, i);
+        return ret;
+    }
+
+    @Test
+    public void decrementNeq() {
+        testCounted("decrementNeqSnippet", 256);
+    }
+
+    public static Result decrementNeqSnippet(int limit) {
+        int i;
+        int posLimit = ((limit - 1) & 0xFFFF) + 1; // make sure limit is always strictly positive
+        Result ret = new Result();
+        for (i = posLimit; i != 0; i--) {
+            GraalDirectives.controlFlowAnchor();
+            ret.extremum = get(InductionVariable::extremumNode, InductionVariable::constantExtremum, InductionVariable::isConstantExtremum, i);
+        }
+        ret.exitValue = get(InductionVariable::exitValueNode, i);
+        return ret;
+    }
+
+    @Test
+    public void incrementNeq() {
+        testCounted("incrementNeqSnippet", 256);
+    }
+
+    public static Result incrementLongSnippet(long start, long limit, long step) {
+        long i;
+        long inc = ((step - 1) & 0xFFFF) + 1; // make sure this value is always strictly positive
+        Result ret = new Result();
+        for (i = start; i < limit; i += inc) {
+            GraalDirectives.controlFlowAnchor();
+            ret.extremum = get(InductionVariable::extremumNode, InductionVariable::constantExtremum, InductionVariable::isConstantExtremum, i);
+        }
+        ret.exitValue = get(InductionVariable::exitValueNode, i);
+        return ret;
+    }
+
+    @Test
+    public void incrementLong1() {
+        testCounted("incrementLongSnippet", 0L, 256L, 1L);
+    }
+
+    @Test
+    public void incrementLong2() {
+        testCounted("incrementLongSnippet", 0L, 256L, 2L);
+    }
+
+    @Test
+    public void incrementLong3() {
+        testCounted("incrementLongSnippet", 0L, 256L, 3L);
+    }
+
+    @Test
+    public void incrementLong4() {
+        testCounted("incrementLongSnippet", -10L, 1L, Long.MAX_VALUE);
+    }
+
+    @Test
+    public void incrementLong5() {
+        testCounted("incrementLongSnippet", 256L, 256L, 1L);
+    }
+
+    @Test
+    public void incrementLong6() {
+        testCounted("incrementLongSnippet", 257L, 256L, 1L);
     }
 
     @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
@@ -255,18 +394,31 @@
         public static final NodeClass<IVPropertyNode> TYPE = NodeClass.create(IVPropertyNode.class);
 
         private final IVProperty property;
+        private final StaticIVProperty staticProperty;
+        private final IVPredicate staticCheck;
         @Input private ValueNode iv;
 
-        protected IVPropertyNode(IVProperty property, ValueNode iv) {
+        protected IVPropertyNode(IVProperty property, StaticIVProperty staticProperty, IVPredicate staticCheck, ValueNode iv) {
             super(TYPE, iv.stamp(NodeView.DEFAULT).unrestricted());
             this.property = property;
+            this.staticProperty = staticProperty;
+            this.staticCheck = staticCheck;
             this.iv = iv;
         }
 
         public void rewrite(LoopsData loops) {
             InductionVariable inductionVariable = loops.getInductionVariable(iv);
             assert inductionVariable != null;
-            ValueNode node = property.get(inductionVariable);
+            ValueNode node = null;
+            if (staticCheck != null) {
+                assert staticProperty != null;
+                if (staticCheck.test(inductionVariable)) {
+                    node = ConstantNode.forLong(staticProperty.get(inductionVariable), graph());
+                }
+            }
+            if (node == null) {
+                node = property.get(inductionVariable);
+            }
             replaceAtUsagesAndDelete(node);
         }
 
@@ -279,7 +431,13 @@
     @Override
     protected void registerInvocationPlugins(InvocationPlugins invocationPlugins) {
         Registration r = new Registration(invocationPlugins, CountedLoopTest.class);
-        r.register2("get", IVProperty.class, int.class, new InvocationPlugin() {
+        registerPlugins(r, JavaKind.Int);
+        registerPlugins(r, JavaKind.Long);
+        super.registerInvocationPlugins(invocationPlugins);
+    }
+
+    private void registerPlugins(Registration r, JavaKind ivKind) {
+        r.register2("get", IVProperty.class, ivKind.toJavaClass(), new InvocationPlugin() {
             @Override
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg1, ValueNode arg2) {
                 IVProperty property = null;
@@ -287,14 +445,36 @@
                     property = getSnippetReflection().asObject(IVProperty.class, arg1.asJavaConstant());
                 }
                 if (property != null) {
-                    b.addPush(JavaKind.Int, new IVPropertyNode(property, arg2));
+                    b.addPush(ivKind, new IVPropertyNode(property, null, null, arg2));
                     return true;
                 } else {
                     return false;
                 }
             }
         });
-        super.registerInvocationPlugins(invocationPlugins);
+        r.register4("get", IVProperty.class, StaticIVProperty.class, IVPredicate.class, ivKind.toJavaClass(), new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg1, ValueNode arg2, ValueNode arg3, ValueNode arg4) {
+                IVProperty property = null;
+                StaticIVProperty staticProperty = null;
+                IVPredicate staticCheck = null;
+                if (arg1.isConstant()) {
+                    property = getSnippetReflection().asObject(IVProperty.class, arg1.asJavaConstant());
+                }
+                if (arg2.isConstant()) {
+                    staticProperty = getSnippetReflection().asObject(StaticIVProperty.class, arg2.asJavaConstant());
+                }
+                if (arg3.isConstant()) {
+                    staticCheck = getSnippetReflection().asObject(IVPredicate.class, arg3.asJavaConstant());
+                }
+                if (property != null && staticProperty != null && staticCheck != null) {
+                    b.addPush(ivKind, new IVPropertyNode(property, staticProperty, staticCheck, arg4));
+                    return true;
+                } else {
+                    return false;
+                }
+            }
+        });
     }
 
     @Override
@@ -308,37 +488,17 @@
         return true;
     }
 
-    public static Result incrementNeqSnippet(int limit) {
-        int i;
-        int posLimit = ((limit - 1) & 0xFFFF) + 1; // make sure limit is always strictly positive
-        Result ret = new Result();
-        for (i = 0; i != posLimit; i++) {
-            GraalDirectives.controlFlowAnchor();
-            ret.extremum = get(InductionVariable::extremumNode, i);
-        }
-        ret.exitValue = get(InductionVariable::exitValueNode, i);
-        return ret;
-    }
+    private Object[] argsToBind;
 
-    @Test
-    public void decrementNeq() {
-        test("decrementNeqSnippet", 256);
+    @Override
+    protected Object[] getArgumentToBind() {
+        return argsToBind;
     }
 
-    public static Result decrementNeqSnippet(int limit) {
-        int i;
-        int posLimit = ((limit - 1) & 0xFFFF) + 1; // make sure limit is always strictly positive
-        Result ret = new Result();
-        for (i = posLimit; i != 0; i--) {
-            GraalDirectives.controlFlowAnchor();
-            ret.extremum = get(InductionVariable::extremumNode, i);
-        }
-        ret.exitValue = get(InductionVariable::exitValueNode, i);
-        return ret;
-    }
-
-    @Test
-    public void incrementNeq() {
-        test("incrementNeqSnippet", 256);
+    public void testCounted(String snippetName, Object... args) {
+        test(snippetName, args);
+        argsToBind = args;
+        test(snippetName, args);
+        argsToBind = null;
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java	Fri Mar 16 22:59:32 2018 -0700
@@ -22,6 +22,7 @@
  */
 package org.graalvm.compiler.core.test;
 
+import static java.lang.reflect.Modifier.isStatic;
 import static jdk.vm.ci.runtime.JVMCICompiler.INVOCATION_ENTRY_BCI;
 import static org.graalvm.compiler.nodes.ConstantNode.getConstantNodes;
 import static org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin.InlineInfo.DO_NOT_INLINE_NO_EXCEPTION;
@@ -47,6 +48,7 @@
 import java.util.Set;
 import java.util.function.Supplier;
 
+import jdk.vm.ci.meta.JavaConstant;
 import org.graalvm.compiler.api.directives.GraalDirectives;
 import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
 import org.graalvm.compiler.api.test.Graal;
@@ -931,7 +933,8 @@
      */
     @SuppressWarnings("try")
     protected InstalledCode getCode(final ResolvedJavaMethod installedCodeOwner, StructuredGraph graph, boolean forceCompile, boolean installAsDefault, OptionValues options) {
-        if (!forceCompile && graph == null) {
+        boolean useCache = !forceCompile && getArgumentToBind() == null;
+        if (useCache && graph == null) {
             InstalledCode cached = cache.get(installedCodeOwner);
             if (cached != null) {
                 if (cached.isValid()) {
@@ -964,7 +967,7 @@
                             throw new GraalError("Could not install code for " + installedCodeOwner.format("%H.%n(%p)"));
                         }
                     } catch (BailoutException e) {
-                        if (retry <= BAILOUT_RETRY_LIMIT && graph == null && !e.isPermanent()) {
+                        if (retry < BAILOUT_RETRY_LIMIT && graph == null && !e.isPermanent()) {
                             // retry (if there is no predefined graph)
                             TTY.println(String.format("Restart compilation %s (%s) due to a non-permanent bailout!", installedCodeOwner, id));
                             continue;
@@ -978,7 +981,7 @@
                 throw debug.handle(e);
             }
 
-            if (!forceCompile) {
+            if (useCache) {
                 cache.put(installedCodeOwner, installedCode);
             }
             return installedCode;
@@ -1243,12 +1246,33 @@
         DebugContext debug = graph.getDebug();
         try (DebugContext.Scope ds = debug.scope("Parsing", javaMethod, graph)) {
             graphBuilderSuite.apply(graph, getDefaultHighTierContext());
+            Object[] args = getArgumentToBind();
+            if (args != null) {
+                bindArguments(graph, args);
+            }
             return graph;
         } catch (Throwable e) {
             throw debug.handle(e);
         }
     }
 
+    protected void bindArguments(StructuredGraph graph, Object[] argsToBind) {
+        ResolvedJavaMethod m = graph.method();
+        Object receiver = isStatic(m.getModifiers()) ? null : this;
+        Object[] args = argsWithReceiver(receiver, argsToBind);
+        JavaType[] parameterTypes = m.toParameterTypes();
+        assert parameterTypes.length == args.length;
+        for (ParameterNode param : graph.getNodes(ParameterNode.TYPE)) {
+            JavaConstant c = getSnippetReflection().forBoxed(parameterTypes[param.index()].getJavaKind(), args[param.index()]);
+            ConstantNode replacement = ConstantNode.forConstant(c, getMetaAccess(), graph);
+            param.replaceAtUsages(replacement);
+        }
+    }
+
+    protected Object[] getArgumentToBind() {
+        return null;
+    }
+
     protected PhaseSuite<HighTierContext> getEagerGraphBuilderSuite() {
         return getCustomGraphBuilderSuite(GraphBuilderConfiguration.getDefault(getDefaultGraphBuilderPlugins()).withEagerResolving(true).withUnresolvedIsError(true));
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraphEncoderTest.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraphEncoderTest.java	Fri Mar 16 22:59:32 2018 -0700
@@ -77,8 +77,7 @@
         }
 
         for (StructuredGraph originalGraph : originalGraphs) {
-            EncodedGraph encodedGraph = new EncodedGraph(encoder.getEncoding(), startOffsets.get(originalGraph), encoder.getObjects(), encoder.getNodeClasses(), originalGraph.getAssumptions(),
-                            originalGraph.getMethods());
+            EncodedGraph encodedGraph = new EncodedGraph(encoder.getEncoding(), startOffsets.get(originalGraph), encoder.getObjects(), encoder.getNodeClasses(), originalGraph);
             GraphEncoder.verifyEncoding(originalGraph, encodedGraph, getTarget().arch);
         }
     }
--- /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/SwitchDyingLoopTest.java	Fri Mar 16 22:59:32 2018 -0700
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2018, 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.test;
+
+import static org.graalvm.compiler.graph.test.matchers.NodeIterableCount.hasCount;
+import static org.graalvm.compiler.graph.test.matchers.NodeIterableIsEmpty.isEmpty;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThat;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.nodes.LoopBeginNode;
+import org.graalvm.compiler.nodes.ParameterNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.extended.IntegerSwitchNode;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+import org.junit.Test;
+
+import jdk.vm.ci.meta.JavaKind;
+
+public class SwitchDyingLoopTest extends GraalCompilerTest {
+
+    @SuppressWarnings("fallthrough")
+    public static int snippet(int a, int n) {
+        int r = 0;
+        loop: for (int i = 0; i < n; i++) {
+            int v = (i * 167 + 13) & 0xff;
+            switch (v & a) {
+                case 0x80:
+                    r += 1; // fall through
+                case 0x40:
+                    r += 2; // fall through
+                case 0x20:
+                    r += 3;
+                    continue;
+                case 0x08:
+                    r += 5; // fall through
+                case 0x04:
+                    r += 7; // fall through
+                case 0x02:
+                    r += 9; // fall through
+                default:
+                    break loop;
+            }
+        }
+        return r;
+    }
+
+    @Test
+    public void test() {
+        CanonicalizerPhase canonicalizerPhase = new CanonicalizerPhase();
+        HighTierContext highTierContext = getDefaultHighTierContext();
+        StructuredGraph graph = parseEager("snippet", StructuredGraph.AllowAssumptions.YES);
+        // there should be 1 loop and 1 switch
+        assertThat(graph.getNodes(LoopBeginNode.TYPE), hasCount(1));
+        assertThat(graph.getNodes(IntegerSwitchNode.TYPE), hasCount(1));
+        canonicalizerPhase.apply(graph, highTierContext);
+        // after canonicalization, the loop and switch should still be there
+        assertThat(graph.getNodes(LoopBeginNode.TYPE), hasCount(1));
+        assertThat(graph.getNodes(IntegerSwitchNode.TYPE), hasCount(1));
+        // add stamp to `a` so that paths leading to continue can be trimmed
+        ParameterNode parameter = graph.getParameter(0);
+        assertNotNull(parameter);
+        parameter.setStamp(StampFactory.forInteger(JavaKind.Int, 0, 255, 0, 0xf));
+        canonicalizerPhase.apply(graph, highTierContext);
+        // the loop should have disappeared and there should still be a switch
+        assertThat(graph.getNodes(LoopBeginNode.TYPE), isEmpty());
+        assertThat(graph.getNodes(IntegerSwitchNode.TYPE), hasCount(1));
+    }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/TrivialInliningExplosionTest.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/TrivialInliningExplosionTest.java	Fri Mar 16 22:59:32 2018 -0700
@@ -74,9 +74,9 @@
         int afterCompileSize = lastCompiledGraph.getNodeCount();
 
         // The values of afterParseSize and afterCompileSize when this
-        // test was written were 849 and 848 respectively.
-        Assert.assertTrue(afterParseSize < 2000);
-        Assert.assertTrue(afterCompileSize < 2000);
+        // test was written were 3223 and 3505 respectively.
+        Assert.assertTrue(afterParseSize < 4000);
+        Assert.assertTrue(afterCompileSize < 4000);
 
     }
 }
--- /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/UnsignedLongTest.java	Fri Mar 16 22:59:32 2018 -0700
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 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.test;
+
+import org.graalvm.compiler.core.common.util.UnsignedLong;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class UnsignedLongTest {
+    @Test
+    public void testEquals() {
+        UnsignedLong fortyTwo = new UnsignedLong(42);
+        Assert.assertTrue(fortyTwo.equals(42));
+        Assert.assertFalse(fortyTwo.equals(99));
+        UnsignedLong longFortyTwo = new UnsignedLong(0x42_0000_8888L);
+        Assert.assertTrue(longFortyTwo.equals(0x42_0000_8888L));
+        Assert.assertFalse(longFortyTwo.equals(0x99_0000_8888L));
+        UnsignedLong longUnsigned = new UnsignedLong(0x8000_7777_0000_8888L);
+        Assert.assertTrue(longUnsigned.equals(0x8000_7777_0000_8888L));
+        Assert.assertFalse(longUnsigned.equals(0xf000_7777_0000_8888L));
+    }
+
+    @Test
+    public void testIsLessThan() {
+        UnsignedLong fortyTwo = new UnsignedLong(42);
+        Assert.assertTrue(fortyTwo.isLessThan(45));
+        Assert.assertFalse(fortyTwo.isLessThan(42));
+        Assert.assertFalse(fortyTwo.isLessThan(40));
+        Assert.assertTrue(fortyTwo.isLessThan(0xffff_ffff_ffff_ffffL));
+        UnsignedLong longUnsigned = new UnsignedLong(0x8000_7777_0000_8888L);
+        Assert.assertTrue(longUnsigned.isLessThan(0xffff_ffff_ffff_ffffL));
+        Assert.assertFalse(longUnsigned.isLessThan(42));
+        Assert.assertFalse(longUnsigned.isLessThan(0x8000_0777_0000_8888L));
+        Assert.assertFalse(longUnsigned.isLessThan(0x8000_7777_0000_8888L));
+    }
+
+    @Test
+    public void testIsLessOrEqualTo() {
+        UnsignedLong fortyTwo = new UnsignedLong(42);
+        Assert.assertTrue(fortyTwo.isLessOrEqualTo(45));
+        Assert.assertTrue(fortyTwo.isLessOrEqualTo(42));
+        Assert.assertFalse(fortyTwo.isLessOrEqualTo(40));
+        Assert.assertTrue(fortyTwo.isLessOrEqualTo(0xffff_ffff_ffff_ffffL));
+        UnsignedLong longUnsigned = new UnsignedLong(0x8000_7777_0000_8888L);
+        Assert.assertTrue(longUnsigned.isLessOrEqualTo(0xffff_ffff_ffff_ffffL));
+        Assert.assertFalse(longUnsigned.isLessOrEqualTo(42));
+        Assert.assertFalse(longUnsigned.isLessOrEqualTo(0x8000_0777_0000_8888L));
+        Assert.assertTrue(longUnsigned.isLessOrEqualTo(0x8000_7777_0000_8888L));
+    }
+
+    @Test
+    public void testTimes() {
+        UnsignedLong fortyTwo = new UnsignedLong(42);
+        Assert.assertEquals(42 * 42, fortyTwo.times(42).asLong());
+        Assert.assertEquals(0xffff_ffff_ffff_fff0L, fortyTwo.times(0x618618618618618L).asLong());
+    }
+
+    @Test(expected = ArithmeticException.class)
+    public void testTimesException() {
+        UnsignedLong fortyTwo = new UnsignedLong(42);
+        fortyTwo.times(0x618618618618619L);
+    }
+
+    @Test
+    public void testMinus() {
+        UnsignedLong fortyTwo = new UnsignedLong(42);
+        Assert.assertEquals(0, fortyTwo.minus(42).asLong());
+        Assert.assertEquals(40, fortyTwo.minus(2).asLong());
+        UnsignedLong longUnsigned = new UnsignedLong(0xffff_ffff_ffff_fff0L);
+        Assert.assertEquals(0, longUnsigned.minus(0xffff_ffff_ffff_fff0L).asLong());
+    }
+
+    @Test(expected = ArithmeticException.class)
+    public void testMinusException() {
+        UnsignedLong fortyTwo = new UnsignedLong(42);
+        fortyTwo.minus(43);
+    }
+
+    @Test(expected = ArithmeticException.class)
+    public void testMinusException2() {
+        UnsignedLong longUnsigned = new UnsignedLong(0xffff_ffff_ffff_fff0L);
+        longUnsigned.minus(0xffff_ffff_ffff_fff1L);
+    }
+
+    @Test
+    public void testPlus() {
+        UnsignedLong fortyTwo = new UnsignedLong(42);
+        Assert.assertEquals(84, fortyTwo.plus(42).asLong());
+        Assert.assertEquals(44, fortyTwo.plus(2).asLong());
+        UnsignedLong longUnsigned = new UnsignedLong(0xffff_ffff_ffff_fff0L);
+        Assert.assertEquals(0xffff_ffff_ffff_ffffL, longUnsigned.plus(0xf).asLong());
+    }
+
+    @Test(expected = ArithmeticException.class)
+    public void testPlusException() {
+        UnsignedLong fortyTwo = new UnsignedLong(42);
+        fortyTwo.plus(0xffff_ffff_ffff_fff0L);
+    }
+
+    @Test(expected = ArithmeticException.class)
+    public void testPlusException2() {
+        UnsignedLong longUnsigned = new UnsignedLong(0xffff_ffff_ffff_fff0L);
+        longUnsigned.plus(42);
+    }
+
+    @Test
+    public void testWrappingTimes() {
+        UnsignedLong fortyTwo = new UnsignedLong(42);
+        Assert.assertEquals(0x1a, fortyTwo.wrappingTimes(0x618618618618619L).asLong());
+    }
+
+    @Test
+    public void testWrappingPlus() {
+        UnsignedLong fortyTwo = new UnsignedLong(42);
+        Assert.assertEquals(0x1a, fortyTwo.wrappingPlus(0xffff_ffff_ffff_fff0L).asLong());
+        UnsignedLong longUnsigned = new UnsignedLong(0xffff_ffff_ffff_fff0L);
+        Assert.assertEquals(0x1a, longUnsigned.wrappingPlus(42).asLong());
+    }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompiler.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompiler.java	Fri Mar 16 22:59:32 2018 -0700
@@ -240,6 +240,7 @@
             debug.dump(DebugContext.BASIC_LEVEL, graph, "After low tier");
 
             debug.dump(DebugContext.BASIC_LEVEL, graph.getLastSchedule(), "Final HIR schedule");
+            graph.logInliningTree();
         } catch (Throwable e) {
             throw debug.handle(e);
         } finally {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/NodeLIRBuilder.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/NodeLIRBuilder.java	Fri Mar 16 22:59:32 2018 -0700
@@ -316,6 +316,10 @@
         return values.toArray(new Value[values.size()]);
     }
 
+    public void doBlockPrologue(@SuppressWarnings("unused") Block block, @SuppressWarnings("unused") OptionValues options) {
+
+    }
+
     @Override
     @SuppressWarnings("try")
     public void doBlock(Block block, StructuredGraph graph, BlockMap<List<Node>> blockMap) {
@@ -341,6 +345,7 @@
                     }
                 }
             }
+            doBlockPrologue(block, options);
 
             List<Node> nodes = blockMap.get(block);
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/HighTier.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/HighTier.java	Fri Mar 16 22:59:32 2018 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -45,6 +45,7 @@
 import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.phases.PhaseSuite;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.NodeCounterPhase;
 import org.graalvm.compiler.phases.common.ConvertDeoptimizeToGuardPhase;
 import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
 import org.graalvm.compiler.phases.common.IncrementalCanonicalizerPhase;
@@ -74,6 +75,10 @@
 
         appendPhase(canonicalizer);
 
+        if (NodeCounterPhase.Options.NodeCounters.getValue(options)) {
+            appendPhase(new NodeCounterPhase());
+        }
+
         if (Options.Inline.getValue(options)) {
             appendPhase(new InliningPhase(canonicalizer));
             appendPhase(new DeadCodeEliminationPhase(Optional));
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/target/Backend.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/target/Backend.java	Fri Mar 16 22:59:32 2018 -0700
@@ -178,7 +178,7 @@
      * @param method the method compiled to produce {@code compiledCode} or {@code null} if the
      *            input to {@code compResult} was not a {@link ResolvedJavaMethod}
      * @param compilationRequest the compilation request or {@code null}
-     * @param compilationResult the code to be compiled
+     * @param compilationResult the code to be installed
      * @param predefinedInstalledCode a pre-allocated {@link InstalledCode} object to use as a
      *            reference to the installed code. If {@code null}, a new {@link InstalledCode}
      *            object will be created.
@@ -204,12 +204,13 @@
         }
         try (DebugContext.Scope s2 = debug.scope("CodeInstall", debugContext);
                         DebugContext.Activation a = debug.activate()) {
-            preCodeInstallationTasks(tasks, compilationResult);
 
             InstalledCode installedCode;
             try {
+                preCodeInstallationTasks(tasks, compilationResult, predefinedInstalledCode);
                 CompiledCode compiledCode = createCompiledCode(method, compilationRequest, compilationResult);
                 installedCode = getProviders().getCodeCache().installCode(method, compiledCode, predefinedInstalledCode, speculationLog, isDefault);
+                assert predefinedInstalledCode == null || installedCode == predefinedInstalledCode;
             } catch (Throwable t) {
                 failCodeInstallationTasks(tasks, t);
                 throw t;
@@ -229,9 +230,9 @@
         }
     }
 
-    private static void preCodeInstallationTasks(CodeInstallationTask[] tasks, CompilationResult compilationResult) {
+    private static void preCodeInstallationTasks(CodeInstallationTask[] tasks, CompilationResult compilationResult, InstalledCode predefinedInstalledCode) {
         for (CodeInstallationTask task : tasks) {
-            task.preProcess(compilationResult);
+            task.preProcess(compilationResult, predefinedInstalledCode);
         }
     }
 
@@ -305,23 +306,29 @@
     public abstract static class CodeInstallationTask {
         /**
          * Task to run before code installation.
+         *
+         * @param compilationResult the code about to be installed
+         * @param predefinedInstalledCode a pre-allocated {@link InstalledCode} object that will be
+         *            used as a reference to the installed code. May be {@code null}.
+         *
          */
-        @SuppressWarnings("unused")
-        public void preProcess(CompilationResult compilationResult) {
+        public void preProcess(CompilationResult compilationResult, InstalledCode predefinedInstalledCode) {
         }
 
         /**
          * Task to run after the code is installed.
+         *
+         * @param installedCode a reference to the installed code
          */
-        @SuppressWarnings("unused")
         public void postProcess(InstalledCode installedCode) {
         }
 
         /**
          * Invoked after {@link #preProcess} when code installation fails.
+         *
+         * @param cause the cause of the installation failure
          */
-        @SuppressWarnings("unused")
-        public void installFailed(Throwable t) {
+        public void installFailed(Throwable cause) {
         }
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/.checkstyle_checks.xml	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/.checkstyle_checks.xml	Fri Mar 16 22:59:32 2018 -0700
@@ -116,7 +116,7 @@
       <metadata name="net.sf.eclipsecs.core.comment" value="Illegal trailing whitespace(s) at the end of the line."/>
       <property name="format" value="\s$"/>
       <property name="message" value="Illegal trailing whitespace(s) at the end of the line."/>
-      <property name="ignoreComments" value="true"/>
+      <property name="ignoreComments" value="false"/>
       <metadata name="com.atlassw.tools.eclipse.checkstyle.comment" value="Checks for trailing spaces at the end of a line"/>
     </module>
     <module name="RegexpSinglelineJava">
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Graph.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Graph.java	Fri Mar 16 22:59:32 2018 -0700
@@ -22,6 +22,9 @@
  */
 package org.graalvm.compiler.graph;
 
+import static org.graalvm.compiler.graph.Graph.SourcePositionTracking.Default;
+import static org.graalvm.compiler.graph.Graph.SourcePositionTracking.Track;
+import static org.graalvm.compiler.graph.Graph.SourcePositionTracking.UpdateOnly;
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED;
 
@@ -33,6 +36,7 @@
 import org.graalvm.collections.EconomicMap;
 import org.graalvm.collections.Equivalence;
 import org.graalvm.collections.UnmodifiableEconomicMap;
+import org.graalvm.compiler.core.common.GraalOptions;
 import org.graalvm.compiler.debug.CounterKey;
 import org.graalvm.compiler.debug.DebugCloseable;
 import org.graalvm.compiler.debug.DebugContext;
@@ -65,6 +69,13 @@
         DeepFreeze
     }
 
+    public enum SourcePositionTracking {
+        Default,
+        Ignore,
+        UpdateOnly,
+        Track
+    }
+
     public final String name;
 
     /**
@@ -80,7 +91,7 @@
     /**
      * Records if updating of node source information is required when performing inlining.
      */
-    boolean seenNodeSourcePosition;
+    protected SourcePositionTracking trackNodeSourcePosition;
 
     /**
      * The number of valid entries in {@link #nodes}.
@@ -195,7 +206,7 @@
      *         was opened
      */
     public DebugCloseable withNodeSourcePosition(NodeSourcePosition sourcePosition) {
-        return sourcePosition != null ? new NodeSourcePositionScope(sourcePosition) : null;
+        return trackNodeSourcePosition() && sourcePosition != null ? new NodeSourcePositionScope(sourcePosition) : null;
     }
 
     /**
@@ -212,16 +223,26 @@
      * to short circuit logic for updating those positions after inlining since that requires
      * visiting every node in the graph.
      */
-    public boolean mayHaveNodeSourcePosition() {
-        assert seenNodeSourcePosition || verifyHasNoSourcePosition();
-        return seenNodeSourcePosition;
+    public boolean updateNodeSourcePosition() {
+        return trackNodeSourcePosition == Track || trackNodeSourcePosition == UpdateOnly;
+    }
+
+    public boolean trackNodeSourcePosition() {
+        return trackNodeSourcePosition == Track;
     }
 
-    private boolean verifyHasNoSourcePosition() {
-        for (Node node : getNodes()) {
-            assert node.getNodeSourcePosition() == null;
+    public void setTrackNodeSourcePosition() {
+        if (trackNodeSourcePosition != Track) {
+            assert trackNodeSourcePosition == Default : trackNodeSourcePosition;
+            trackNodeSourcePosition = Track;
         }
-        return true;
+    }
+
+    public static SourcePositionTracking trackNodeSourcePositionDefault(OptionValues options, DebugContext debug) {
+        if (GraalOptions.TrackNodeSourcePosition.getValue(options) || debug.isDumpEnabledForMethod()) {
+            return Track;
+        }
+        return Default;
     }
 
     /**
@@ -255,6 +276,7 @@
         iterableNodesLast = new ArrayList<>(NodeClass.allocatedNodeIterabledIds());
         this.name = name;
         this.options = options;
+        this.trackNodeSourcePosition = trackNodeSourcePositionDefault(options, debug);
         assert debug != null;
         this.debug = debug;
 
@@ -358,6 +380,9 @@
      */
     protected Graph copy(String newName, Consumer<UnmodifiableEconomicMap<Node, Node>> duplicationMapCallback, DebugContext debugForCopy) {
         Graph copy = new Graph(newName, options, debugForCopy);
+        if (trackNodeSourcePosition()) {
+            copy.setTrackNodeSourcePosition();
+        }
         UnmodifiableEconomicMap<Node, Node> duplicates = copy.addDuplicates(getNodes(), this, this.getNodeCount(), (EconomicMap<Node, Node>) null);
         if (duplicationMapCallback != null) {
             duplicationMapCallback.accept(duplicates);
@@ -1069,10 +1094,9 @@
         int id = nodesSize++;
         nodes[id] = node;
         node.id = id;
-        if (currentNodeSourcePosition != null) {
+        if (currentNodeSourcePosition != null && trackNodeSourcePosition()) {
             node.setNodeSourcePosition(currentNodeSourcePosition);
         }
-        seenNodeSourcePosition = seenNodeSourcePosition || node.getNodeSourcePosition() != null;
 
         updateNodeCaches(node);
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/InlineCacheGuardPosition.java	Fri Mar 16 22:59:32 2018 -0700
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 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.util.Objects;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+public class InlineCacheGuardPosition extends NodeSourcePosition {
+    private final ResolvedJavaType dispatchedType;
+    private final ResolvedJavaMethod concreteMethod;
+    private final int hashCode;
+
+    public InlineCacheGuardPosition(NodeSourcePosition callStack, ResolvedJavaType dispatchedType, ResolvedJavaMethod targetMethod) {
+        super(callStack.getCaller(), callStack.getMethod(), callStack.getBCI());
+        this.concreteMethod = targetMethod;
+        this.dispatchedType = dispatchedType;
+        this.hashCode = super.hashCode() + 7 * ((dispatchedType == null) ? 0 : dispatchedType.hashCode()) + 31 * targetMethod.hashCode();
+    }
+
+    public ResolvedJavaType getDispatchedType() {
+        return dispatchedType;
+    }
+
+    public ResolvedJavaMethod getTargetMethod() {
+        return concreteMethod;
+    }
+
+    @Override
+    public int hashCode() {
+        return hashCode;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == this) {
+            return true;
+        }
+        if (obj != null && getClass() == obj.getClass()) {
+            InlineCacheGuardPosition that = (InlineCacheGuardPosition) obj;
+            if (hashCode != that.hashCode) {
+                return false;
+            }
+            if (this.getBCI() == that.getBCI() && Objects.equals(this.getMethod(), that.getMethod()) && Objects.equals(this.getCaller(), that.getCaller()) &&
+                            Objects.equals(this.concreteMethod, that.concreteMethod) && Objects.equals(this.dispatchedType, that.dispatchedType)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return "dispatchedType=" + (dispatchedType == null ? "null" : dispatchedType.getName()) + " target_method=" + concreteMethod.getName() + " target_method_class=" +
+                        concreteMethod.getDeclaringClass().getName() + " position=" + super.toString();
+    }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Node.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Node.java	Fri Mar 16 22:59:32 2018 -0700
@@ -593,10 +593,9 @@
      * Set the source position to {@code sourcePosition}.
      */
     public void setNodeSourcePosition(NodeSourcePosition sourcePosition) {
+        assert sourcePosition != null || this.sourcePosition == null || this.sourcePosition.isPlaceholder() : "Invalid source position at node with id " + id;
         this.sourcePosition = sourcePosition;
-        if (sourcePosition != null && graph != null && !graph.seenNodeSourcePosition) {
-            graph.seenNodeSourcePosition = true;
-        }
+        // assert sourcePosition == null || graph == null || graph.trackNodeSourcePosition;
     }
 
     /**
@@ -920,6 +919,9 @@
         }
         newNode.graph = into;
         newNode.id = INITIAL_ID;
+        if (sourcePosition != null && (into == null || into.updateNodeSourcePosition())) {
+            newNode.setNodeSourcePosition(sourcePosition);
+        }
         if (into != null) {
             into.register(newNode);
         }
@@ -928,9 +930,6 @@
         if (into != null && useIntoLeafNodeCache) {
             into.putNodeIntoCache(newNode);
         }
-        if (graph != null && into != null && sourcePosition != null) {
-            newNode.setNodeSourcePosition(sourcePosition);
-        }
         newNode.afterClone(this);
         return newNode;
     }
@@ -1195,6 +1194,15 @@
         return getNodeClass().dataEquals(this, other);
     }
 
+    /**
+     * Determines if this node is equal to the other node while ignoring differences in
+     * {@linkplain Successor control-flow} edges.
+     *
+     */
+    public boolean dataFlowEquals(Node other) {
+        return this == other || nodeClass == other.getNodeClass() && this.valueEquals(other) && nodeClass.equalInputs(this, other);
+    }
+
     public final void pushInputs(NodeStack stack) {
         getNodeClass().pushInputs(this, stack);
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeClass.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeClass.java	Fri Mar 16 22:59:32 2018 -0700
@@ -104,7 +104,7 @@
      * Gets the {@link NodeClass} associated with a given {@link Class}.
      */
     public static <T> NodeClass<T> create(Class<T> c) {
-        assert get(c) == null;
+        assert getUnchecked(c) == null;
         Class<? super T> superclass = c.getSuperclass();
         NodeClass<? super T> nodeSuperclass = null;
         if (superclass != NODE_CLASS) {
@@ -114,9 +114,9 @@
     }
 
     @SuppressWarnings("unchecked")
-    public static <T> NodeClass<T> get(Class<T> superclass) {
+    private static <T> NodeClass<T> getUnchecked(Class<T> clazz) {
         try {
-            Field field = superclass.getDeclaredField("TYPE");
+            Field field = clazz.getDeclaredField("TYPE");
             field.setAccessible(true);
             return (NodeClass<T>) field.get(null);
         } catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e) {
@@ -124,6 +124,14 @@
         }
     }
 
+    public static <T> NodeClass<T> get(Class<T> clazz) {
+        NodeClass<T> result = getUnchecked(clazz);
+        if (result == null && clazz != NODE_CLASS) {
+            throw GraalError.shouldNotReachHere("TYPE field not initialized for class " + clazz.getTypeName());
+        }
+        return result;
+    }
+
     private static final Class<?> NODE_CLASS = Node.class;
     private static final Class<?> INPUT_LIST_CLASS = NodeInputList.class;
     private static final Class<?> SUCCESSOR_LIST_CLASS = NodeSuccessorList.class;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeSourcePosition.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeSourcePosition.java	Fri Mar 16 22:59:32 2018 -0700
@@ -22,31 +22,100 @@
  */
 package org.graalvm.compiler.graph;
 
+import static org.graalvm.compiler.graph.NodeSourcePosition.Marker.None;
+import static org.graalvm.compiler.graph.NodeSourcePosition.Marker.Placeholder;
+import static org.graalvm.compiler.graph.NodeSourcePosition.Marker.Substitution;
+
 import java.util.Objects;
 
+import org.graalvm.compiler.bytecode.BytecodeDisassembler;
+import org.graalvm.compiler.bytecode.Bytecodes;
+
+import jdk.vm.ci.code.BytecodeFrame;
 import jdk.vm.ci.code.BytecodePosition;
 import jdk.vm.ci.code.CodeUtil;
-import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaMethod;
 import jdk.vm.ci.meta.MetaUtil;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 
 public class NodeSourcePosition extends BytecodePosition {
 
+    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 final int hashCode;
+    private final Marker marker;
+    private final SourceLanguagePosition sourceLanguagePosition;
+
     /**
-     * The receiver of the method this frame refers to.
+     * Remove marker frames.
      */
-    private final JavaConstant receiver;
-    private final int hashCode;
+    public NodeSourcePosition trim() {
+        if (marker != None) {
+            return null;
+        }
+        NodeSourcePosition caller = getCaller();
+        if (caller != null) {
+            caller = caller.trim();
+        }
+        if (caller != getCaller()) {
+            return new NodeSourcePosition(caller, getMethod(), getBCI());
+        }
+        return this;
+    }
 
-    public NodeSourcePosition(JavaConstant receiver, NodeSourcePosition caller, ResolvedJavaMethod method, int bci) {
+    enum Marker {
+        None,
+        Placeholder,
+        Substitution
+    }
+
+    public NodeSourcePosition(NodeSourcePosition caller, ResolvedJavaMethod method, int bci) {
+        this(caller, method, bci, None);
+    }
+
+    public NodeSourcePosition(NodeSourcePosition caller, ResolvedJavaMethod method, int bci, Marker marker) {
+        this(null, caller, method, bci, marker);
+
+    }
+
+    public NodeSourcePosition(SourceLanguagePosition sourceLanguagePosition, NodeSourcePosition caller, ResolvedJavaMethod method, int bci) {
+        this(sourceLanguagePosition, caller, method, bci, None);
+    }
+
+    public NodeSourcePosition(SourceLanguagePosition sourceLanguagePosition, NodeSourcePosition caller, ResolvedJavaMethod method, int bci, Marker marker) {
         super(caller, method, bci);
         if (caller == null) {
             this.hashCode = 31 * bci + method.hashCode();
         } else {
             this.hashCode = caller.hashCode * 7 + 31 * bci + method.hashCode();
         }
-        this.receiver = receiver;
-        assert receiver == null || method.getDeclaringClass().isInstance(receiver);
+        this.marker = marker;
+        this.sourceLanguagePosition = sourceLanguagePosition;
+    }
+
+    public static NodeSourcePosition placeholder(ResolvedJavaMethod method) {
+        return new NodeSourcePosition(null, method, BytecodeFrame.INVALID_FRAMESTATE_BCI, Placeholder);
+    }
+
+    public static NodeSourcePosition placeholder(ResolvedJavaMethod method, int bci) {
+        return new NodeSourcePosition(null, method, bci, Placeholder);
+    }
+
+    public boolean isPlaceholder() {
+        return marker == Placeholder;
+    }
+
+    public static NodeSourcePosition substitution(ResolvedJavaMethod method) {
+        return new NodeSourcePosition(null, method, BytecodeFrame.INVALID_FRAMESTATE_BCI, Substitution);
+    }
+
+    public static NodeSourcePosition substitution(NodeSourcePosition caller, ResolvedJavaMethod method, int bci) {
+        return new NodeSourcePosition(caller, method, bci, Substitution);
+    }
+
+    public boolean isSubstitution() {
+        return marker == Substitution;
     }
 
     @Override
@@ -60,7 +129,7 @@
                 return false;
             }
             if (this.getBCI() == that.getBCI() && Objects.equals(this.getMethod(), that.getMethod()) && Objects.equals(this.getCaller(), that.getCaller()) &&
-                            Objects.equals(this.receiver, that.receiver)) {
+                            Objects.equals(this.sourceLanguagePosition, that.sourceLanguagePosition)) {
                 return true;
             }
         }
@@ -72,8 +141,18 @@
         return hashCode;
     }
 
-    public JavaConstant getReceiver() {
-        return receiver;
+    public int depth() {
+        int d = 0;
+        NodeSourcePosition pos = this;
+        while (pos != null) {
+            d++;
+            pos = pos.getCaller();
+        }
+        return d;
+    }
+
+    public SourceLanguagePosition getSourceLanauage() {
+        return sourceLanguagePosition;
     }
 
     @Override
@@ -81,17 +160,29 @@
         return (NodeSourcePosition) super.getCaller();
     }
 
-    public NodeSourcePosition addCaller(JavaConstant newCallerReceiver, NodeSourcePosition link) {
-        if (getCaller() == null) {
-            assert newCallerReceiver == null || receiver == null : "replacing receiver";
-            return new NodeSourcePosition(newCallerReceiver, link, getMethod(), getBCI());
-        } else {
-            return new NodeSourcePosition(receiver, getCaller().addCaller(newCallerReceiver, link), getMethod(), getBCI());
-        }
+    public NodeSourcePosition addCaller(SourceLanguagePosition newSourceLanguagePosition, NodeSourcePosition link) {
+        return addCaller(newSourceLanguagePosition, link, false);
     }
 
     public NodeSourcePosition addCaller(NodeSourcePosition link) {
-        return addCaller(null, link);
+        return addCaller(null, link, false);
+    }
+
+    public NodeSourcePosition addCaller(NodeSourcePosition link, boolean isSubstitution) {
+        return addCaller(null, link, isSubstitution);
+    }
+
+    public NodeSourcePosition addCaller(SourceLanguagePosition newSourceLanguagePosition, NodeSourcePosition link, boolean isSubstitution) {
+        if (getCaller() == null) {
+            if (isPlaceholder()) {
+                return new NodeSourcePosition(newSourceLanguagePosition, link, getMethod(), 0);
+            }
+            assert link == null || isSubstitution || verifyCaller(this, link) : link;
+
+            return new NodeSourcePosition(newSourceLanguagePosition, link, getMethod(), getBCI());
+        } else {
+            return new NodeSourcePosition(getCaller().addCaller(newSourceLanguagePosition, link, isSubstitution), getMethod(), getBCI());
+        }
     }
 
     @Override
@@ -99,9 +190,9 @@
         StringBuilder sb = new StringBuilder(100);
         NodeSourcePosition pos = this;
         while (pos != null) {
-            MetaUtil.appendLocation(sb.append("at "), pos.getMethod(), pos.getBCI());
-            if (pos.receiver != null) {
-                sb.append("receiver=" + pos.receiver + " ");
+            format(sb, pos);
+            if (pos.sourceLanguagePosition != null) {
+                sb.append(" source=" + pos.sourceLanguagePosition.toShortString());
             }
             pos = pos.getCaller();
             if (pos != null) {
@@ -110,4 +201,55 @@
         }
         return sb.toString();
     }
+
+    private static void format(StringBuilder sb, NodeSourcePosition pos) {
+        MetaUtil.appendLocation(sb.append("at "), pos.getMethod(), pos.getBCI());
+        if (SOURCE_POSITION_BYTECODES) {
+            String disassembly = BytecodeDisassembler.disassembleOne(pos.getMethod(), pos.getBCI());
+            if (disassembly != null && disassembly.length() > 0) {
+                sb.append(" // ");
+                sb.append(disassembly);
+            }
+        }
+    }
+
+    String shallowToString() {
+        StringBuilder sb = new StringBuilder(100);
+        format(sb, this);
+        return sb.toString();
+    }
+
+    public boolean verify() {
+        NodeSourcePosition current = this;
+        NodeSourcePosition caller = getCaller();
+        while (caller != null) {
+            assert verifyCaller(current, caller) : current;
+            current = caller;
+            caller = caller.getCaller();
+        }
+        return true;
+    }
+
+    private static boolean verifyCaller(NodeSourcePosition current, NodeSourcePosition caller) {
+        if (!STRICT_SOURCE_POSITION) {
+            return true;
+        }
+        if (BytecodeFrame.isPlaceholderBci(caller.getBCI())) {
+            return true;
+        }
+        int opcode = BytecodeDisassembler.getBytecodeAt(caller.getMethod(), caller.getBCI());
+        JavaMethod method = BytecodeDisassembler.getInvokedMethodAt(caller.getMethod(), caller.getBCI());
+        /*
+         * It's not really possible to match the declaring classes since this might be an interface
+         * invoke. Matching name and signature probably provides enough accuracy.
+         */
+        assert method == null || (method.getName().equals(current.getMethod().getName()) &&
+                        method.getSignature().equals(current.getMethod().getSignature())) ||
+                        caller.getMethod().getName().equals("linkToTargetMethod") ||
+                        opcode == Bytecodes.INVOKEDYNAMIC ||
+                        caller.getMethod().getDeclaringClass().getName().startsWith("Ljava/lang/invoke/LambdaForm$") ||
+                        current.getMethod().getName().equals("callInlined") : "expected " + method + " but found " +
+                                        current.getMethod();
+        return true;
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/SourceLanguagePosition.java	Fri Mar 16 22:59:32 2018 -0700
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 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.util.Map;
+
+/**
+ * Provides a path to report information about a high level language source position to the Graph
+ * Visualizer.
+ */
+public interface SourceLanguagePosition {
+
+    /**
+     * This is called during dumping of Nodes. The implementation should add any properties which
+     * describe this source position. The actual keys and values used are a private contract between
+     * the language implementation and the Graph Visualizer.
+     */
+    void addSourceInformation(Map<String, Object> props);
+
+    /**
+     * Produce a compact description of this position suitable for printing.
+     */
+    String toShortString();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/SourceLanguagePositionProvider.java	Fri Mar 16 22:59:32 2018 -0700
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 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 jdk.vm.ci.meta.JavaConstant;
+
+/**
+ * Provider of {@link SourceLanguagePosition} for a constant if it represents an AST node.
+ */
+public interface SourceLanguagePositionProvider {
+    SourceLanguagePosition getPosition(JavaConstant node);
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackend.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackend.java	Fri Mar 16 22:59:32 2018 -0700
@@ -288,33 +288,37 @@
     }
 
     private static void emitCodeBody(CompilationResultBuilder crb, LIR lir, AArch64MacroAssembler masm) {
-        /*
-         * Insert a nop at the start of the prolog so we can patch in a branch if we need to
-         * invalidate the method later.
-         */
+        emitInvalidatePlaceholder(crb, masm);
+        crb.emit(lir);
+    }
+
+    /**
+     * Insert a nop at the start of the prolog so we can patch in a branch if we need to invalidate
+     * the method later.
+     *
+     * @see "http://mail.openjdk.java.net/pipermail/aarch64-port-dev/2013-September/000273.html"
+     */
+    public static void emitInvalidatePlaceholder(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
         crb.blockComment("[nop for method invalidation]");
         masm.nop();
-
-        crb.emit(lir);
     }
 
     private void emitCodeSuffix(CompilationResultBuilder crb, AArch64MacroAssembler masm, FrameMap frameMap) {
         HotSpotProviders providers = getProviders();
         HotSpotFrameContext frameContext = (HotSpotFrameContext) crb.frameContext;
         if (!frameContext.isStub) {
+            HotSpotForeignCallsProvider foreignCalls = providers.getForeignCalls();
             try (ScratchRegister sc = masm.getScratchRegister()) {
                 Register scratch = sc.getRegister();
-                HotSpotForeignCallsProvider foreignCalls = providers.getForeignCalls();
                 crb.recordMark(config.MARKID_EXCEPTION_HANDLER_ENTRY);
                 ForeignCallLinkage linkage = foreignCalls.lookupForeignCall(EXCEPTION_HANDLER);
                 Register helper = AArch64Call.isNearCall(linkage) ? null : scratch;
                 AArch64Call.directCall(crb, masm, linkage, helper, null);
-
-                crb.recordMark(config.MARKID_DEOPT_HANDLER_ENTRY);
-                linkage = foreignCalls.lookupForeignCall(DEOPTIMIZATION_HANDLER);
-                helper = AArch64Call.isNearCall(linkage) ? null : scratch;
-                AArch64Call.directCall(crb, masm, linkage, helper, null);
             }
+            crb.recordMark(config.MARKID_DEOPT_HANDLER_ENTRY);
+            ForeignCallLinkage linkage = foreignCalls.lookupForeignCall(DEOPTIMIZATION_HANDLER);
+            masm.adr(lr, 0); // Warning: the argument is an offset from the instruction!
+            AArch64Call.directJmp(crb, masm, linkage);
         } else {
             // No need to emit the stubs for entries back into the method since
             // it has no calls that can cause such "return" entries
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotDeoptimizeOp.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotDeoptimizeOp.java	Fri Mar 16 22:59:32 2018 -0700
@@ -46,7 +46,9 @@
 
     @Override
     public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
-        AArch64Call.directCall(crb, masm, crb.foreignCalls.lookupForeignCall(UNCOMMON_TRAP_HANDLER), null, info);
+        try (AArch64MacroAssembler.ScratchRegister scratch = masm.getScratchRegister()) {
+            AArch64Call.directCall(crb, masm, crb.foreignCalls.lookupForeignCall(UNCOMMON_TRAP_HANDLER), scratch.getRegister(), info, null);
+        }
     }
 
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotMove.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotMove.java	Fri Mar 16 22:59:32 2018 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -155,22 +155,24 @@
 
         @Override
         public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
-            Register ptr = asRegister(input);
+            Register inputRegister = asRegister(input);
             Register resultRegister = asRegister(result);
-            Register base = (isRegister(baseRegister) ? asRegister(baseRegister) : zr);
+            Register base = encoding.hasBase() ? asRegister(baseRegister) : null;
+            emitUncompressCode(masm, inputRegister, resultRegister, base, encoding.getShift(), nonNull);
+        }
+
+        public static void emitUncompressCode(AArch64MacroAssembler masm, Register inputRegister, Register resReg, Register baseReg, int shift, boolean nonNull) {
             // result = base + (ptr << shift)
-            if (nonNull) {
-                masm.add(64, resultRegister, base, ptr, AArch64Assembler.ShiftType.LSL, encoding.getShift());
-            } else if (!encoding.hasBase()) {
-                masm.add(64, resultRegister, zr, ptr, AArch64Assembler.ShiftType.LSL, encoding.getShift());
+            if (nonNull || baseReg == null) {
+                masm.add(64, resReg, baseReg == null ? zr : baseReg, inputRegister, AArch64Assembler.ShiftType.LSL, shift);
             } else {
                 // if ptr is null it has to be null after decompression
                 Label done = new Label();
-                if (!resultRegister.equals(ptr)) {
-                    masm.mov(32, resultRegister, ptr);
+                if (!resReg.equals(inputRegister)) {
+                    masm.mov(32, resReg, inputRegister);
                 }
-                masm.cbz(32, resultRegister, done);
-                masm.add(64, resultRegister, base, resultRegister, AArch64Assembler.ShiftType.LSL, encoding.getShift());
+                masm.cbz(32, resReg, done);
+                masm.add(64, resReg, baseReg, resReg, AArch64Assembler.ShiftType.LSL, shift);
                 masm.bind(done);
             }
         }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64.test/src/org/graalvm/compiler/hotspot/amd64/test/StubAVXTest.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64.test/src/org/graalvm/compiler/hotspot/amd64/test/StubAVXTest.java	Fri Mar 16 22:59:32 2018 -0700
@@ -65,6 +65,7 @@
 import jdk.vm.ci.meta.MetaAccessProvider;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 import jdk.vm.ci.meta.Value;
+import org.graalvm.compiler.hotspot.HotSpotBackend;
 
 public class StubAVXTest extends LIRTest {
 
@@ -72,6 +73,10 @@
     public void checkAMD64() {
         Assume.assumeTrue("skipping AMD64 specific test", getTarget().arch instanceof AMD64);
         Assume.assumeTrue("skipping AVX test", ((AMD64) getTarget().arch).getFeatures().contains(CPUFeature.AVX));
+        if (getBackend() instanceof HotSpotBackend) {
+            HotSpotBackend backend = (HotSpotBackend) getBackend();
+            Assume.assumeTrue("skipping because of MaxVectorSize", backend.getRuntime().getVMConfig().maxVectorSize >= 32);
+        }
     }
 
     private static final DataPointerConstant avxConstant = new ArrayDataPointerConstant(new float[]{1f, 2f, 3f, 4f, 5f, 6f, 7f, 8f}, 32);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotAddressLowering.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotAddressLowering.java	Fri Mar 16 22:59:32 2018 -0700
@@ -204,7 +204,7 @@
 
                         if (init >= 0 && extremum >= 0) {
                             long shortestTrip = (extremum - init) / stride + 1;
-                            if (shortestTrip == countedLoopInfo.constantMaxTripCount()) {
+                            if (countedLoopInfo.constantMaxTripCount().equals(shortestTrip)) {
                                 return graph.unique(new ZeroExtendNode(input, INT_BITS, ADDRESS_BITS, true));
                             }
                         }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotArithmeticLIRGenerator.java	Fri Mar 16 11:26:05 2018 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,80 +0,0 @@
-/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package org.graalvm.compiler.hotspot.amd64;
-
-import static org.graalvm.compiler.hotspot.HotSpotBackend.Options.GraalArithmeticStubs;
-import static org.graalvm.compiler.hotspot.amd64.AMD64HotSpotMathIntrinsicOp.IntrinsicOpcode.COS;
-import static org.graalvm.compiler.hotspot.amd64.AMD64HotSpotMathIntrinsicOp.IntrinsicOpcode.LOG;
-import static org.graalvm.compiler.hotspot.amd64.AMD64HotSpotMathIntrinsicOp.IntrinsicOpcode.LOG10;
-import static org.graalvm.compiler.hotspot.amd64.AMD64HotSpotMathIntrinsicOp.IntrinsicOpcode.SIN;
-import static org.graalvm.compiler.hotspot.amd64.AMD64HotSpotMathIntrinsicOp.IntrinsicOpcode.TAN;
-
-import org.graalvm.compiler.core.amd64.AMD64ArithmeticLIRGenerator;
-import org.graalvm.compiler.core.common.LIRKind;
-import org.graalvm.compiler.lir.Variable;
-
-import jdk.vm.ci.meta.Value;
-
-public class AMD64HotSpotArithmeticLIRGenerator extends AMD64ArithmeticLIRGenerator {
-
-    @Override
-    public Value emitMathLog(Value input, boolean base10) {
-        if (GraalArithmeticStubs.getValue(getOptions())) {
-            return super.emitMathLog(input, base10);
-        }
-        Variable result = getLIRGen().newVariable(LIRKind.combine(input));
-        getLIRGen().append(new AMD64HotSpotMathIntrinsicOp(base10 ? LOG10 : LOG, result, getLIRGen().asAllocatable(input)));
-        return result;
-    }
-
-    @Override
-    public Value emitMathCos(Value input) {
-        if (GraalArithmeticStubs.getValue(getOptions())) {
-            return super.emitMathCos(input);
-        }
-        Variable result = getLIRGen().newVariable(LIRKind.combine(input));
-        getLIRGen().append(new AMD64HotSpotMathIntrinsicOp(COS, result, getLIRGen().asAllocatable(input)));
-        return result;
-    }
-
-    @Override
-    public Value emitMathSin(Value input) {
-        if (GraalArithmeticStubs.getValue(getOptions())) {
-            return super.emitMathSin(input);
-        }
-        Variable result = getLIRGen().newVariable(LIRKind.combine(input));
-        getLIRGen().append(new AMD64HotSpotMathIntrinsicOp(SIN, result, getLIRGen().asAllocatable(input)));
-        return result;
-    }
-
-    @Override
-    public Value emitMathTan(Value input) {
-        if (GraalArithmeticStubs.getValue(getOptions())) {
-            return super.emitMathTan(input);
-        }
-        Variable result = getLIRGen().newVariable(LIRKind.combine(input));
-        getLIRGen().append(new AMD64HotSpotMathIntrinsicOp(TAN, result, getLIRGen().asAllocatable(input)));
-        return result;
-    }
-
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Fri Mar 16 22:59:32 2018 -0700
@@ -25,13 +25,13 @@
 import static jdk.vm.ci.amd64.AMD64.rbp;
 import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
 import static org.graalvm.compiler.hotspot.HotSpotBackend.INITIALIZE_KLASS_BY_SYMBOL;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_DYNAMIC_INVOKE;
 import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_KLASS_BY_SYMBOL;
 import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_METHOD_BY_SYMBOL_AND_LOAD_COUNTERS;
 import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_STRING_BY_SYMBOL;
-import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_DYNAMIC_INVOKE;
-import static org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction.RESOLVE;
 import static org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction.INITIALIZE;
 import static org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction.LOAD_COUNTERS;
+import static org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction.RESOLVE;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -115,7 +115,7 @@
     }
 
     private AMD64HotSpotLIRGenerator(HotSpotProviders providers, GraalHotSpotVMConfig config, LIRGenerationResult lirGenRes, BackupSlotProvider backupSlotProvider) {
-        this(new AMD64HotSpotLIRKindTool(), new AMD64HotSpotArithmeticLIRGenerator(), new AMD64HotSpotMoveFactory(backupSlotProvider), providers, config, lirGenRes);
+        this(new AMD64HotSpotLIRKindTool(), new AMD64ArithmeticLIRGenerator(new AMD64HotSpotMaths()), new AMD64HotSpotMoveFactory(backupSlotProvider), providers, config, lirGenRes);
     }
 
     protected AMD64HotSpotLIRGenerator(LIRKindTool lirKindTool, AMD64ArithmeticLIRGenerator arithmeticLIRGen, MoveFactory moveFactory, HotSpotProviders providers, GraalHotSpotVMConfig config,
--- /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/AMD64HotSpotMaths.java	Fri Mar 16 22:59:32 2018 -0700
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.amd64;
+
+import static org.graalvm.compiler.hotspot.HotSpotBackend.Options.GraalArithmeticStubs;
+import static org.graalvm.compiler.hotspot.amd64.AMD64HotSpotMathIntrinsicOp.IntrinsicOpcode.COS;
+import static org.graalvm.compiler.hotspot.amd64.AMD64HotSpotMathIntrinsicOp.IntrinsicOpcode.LOG;
+import static org.graalvm.compiler.hotspot.amd64.AMD64HotSpotMathIntrinsicOp.IntrinsicOpcode.LOG10;
+import static org.graalvm.compiler.hotspot.amd64.AMD64HotSpotMathIntrinsicOp.IntrinsicOpcode.SIN;
+import static org.graalvm.compiler.hotspot.amd64.AMD64HotSpotMathIntrinsicOp.IntrinsicOpcode.TAN;
+
+import org.graalvm.compiler.core.amd64.AMD64ArithmeticLIRGenerator;
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.hotspot.HotSpotBackend.Options;
+import org.graalvm.compiler.lir.Variable;
+import org.graalvm.compiler.lir.gen.LIRGenerator;
+
+import jdk.vm.ci.meta.Value;
+
+/**
+ * Lowering of selected {@link Math} routines that depends on the value of
+ * {@link Options#GraalArithmeticStubs}.
+ */
+public class AMD64HotSpotMaths implements AMD64ArithmeticLIRGenerator.Maths {
+
+    @Override
+    public Variable emitLog(LIRGenerator gen, Value input, boolean base10) {
+        if (GraalArithmeticStubs.getValue(gen.getResult().getLIR().getOptions())) {
+            return null;
+        }
+        Variable result = gen.newVariable(LIRKind.combine(input));
+        gen.append(new AMD64HotSpotMathIntrinsicOp(base10 ? LOG10 : LOG, result, gen.asAllocatable(input)));
+        return result;
+    }
+
+    @Override
+    public Variable emitCos(LIRGenerator gen, Value input) {
+        if (GraalArithmeticStubs.getValue(gen.getResult().getLIR().getOptions())) {
+            return null;
+        }
+        Variable result = gen.newVariable(LIRKind.combine(input));
+        gen.append(new AMD64HotSpotMathIntrinsicOp(COS, result, gen.asAllocatable(input)));
+        return result;
+    }
+
+    @Override
+    public Variable emitSin(LIRGenerator gen, Value input) {
+        if (GraalArithmeticStubs.getValue(gen.getResult().getLIR().getOptions())) {
+            return null;
+        }
+        Variable result = gen.newVariable(LIRKind.combine(input));
+        gen.append(new AMD64HotSpotMathIntrinsicOp(SIN, result, gen.asAllocatable(input)));
+        return result;
+    }
+
+    @Override
+    public Variable emitTan(LIRGenerator gen, Value input) {
+        if (GraalArithmeticStubs.getValue(gen.getResult().getLIR().getOptions())) {
+            return null;
+        }
+        Variable result = gen.newVariable(LIRKind.combine(input));
+        gen.append(new AMD64HotSpotMathIntrinsicOp(TAN, result, gen.asAllocatable(input)));
+        return result;
+    }
+
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotMove.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotMove.java	Fri Mar 16 22:59:32 2018 -0700
@@ -187,21 +187,26 @@
         public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
             Register inputRegister = asRegister(input);
             Register resReg = asRegister(result);
+            Register baseReg = encoding.hasBase() ? asRegister(baseRegister) : null;
+            emitUncompressCode(masm, inputRegister, resReg, baseReg, encoding.getShift(), nonNull);
+        }
+
+        public static void emitUncompressCode(SPARCMacroAssembler masm, Register inputRegister, Register resReg, Register baseReg, int shift, boolean nonNull) {
             Register secondaryInput;
-            if (encoding.getShift() != 0) {
-                masm.sll(inputRegister, encoding.getShift(), resReg);
+            if (shift != 0) {
+                masm.sll(inputRegister, shift, resReg);
                 secondaryInput = resReg;
             } else {
                 secondaryInput = inputRegister;
             }
 
-            if (encoding.hasBase()) {
+            if (baseReg != null) {
                 if (nonNull) {
-                    masm.add(secondaryInput, asRegister(baseRegister), resReg);
+                    masm.add(secondaryInput, baseReg, resReg);
                 } else {
                     Label done = new Label();
                     BPR.emit(masm, Rc_z, ANNUL, PREDICT_TAKEN, secondaryInput, done);
-                    masm.add(asRegister(baseRegister), secondaryInput, resReg);
+                    masm.add(baseReg, secondaryInput, resReg);
                     masm.bind(done);
                 }
             }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorld.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorld.java	Fri Mar 16 22:59:32 2018 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, 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
@@ -553,6 +553,7 @@
                     classFileCounter++;
 
                     if (className.startsWith("jdk.management.") ||
+                                    className.startsWith("jdk.internal.cmm.*") ||
                                     // GR-5881: The class initializer for
                                     // sun.tools.jconsole.OutputViewer
                                     // spawns non-daemon threads for redirecting sysout and syserr.
--- /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/HotSpotLazyInitializationTest.java	Fri Mar 16 22:59:32 2018 -0700
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 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.test;
+
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.hotspot.meta.HotSpotClassInitializationPlugin;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import org.junit.Assert;
+import org.junit.Assume;
+import org.junit.Test;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+public class HotSpotLazyInitializationTest extends GraalCompilerTest {
+
+    HotSpotClassInitializationPlugin classInitPlugin = new HotSpotClassInitializationPlugin();
+
+    @Override
+    protected Plugins getDefaultGraphBuilderPlugins() {
+        Plugins plugins = super.getDefaultGraphBuilderPlugins();
+        plugins.setClassInitializationPlugin(classInitPlugin);
+        return plugins;
+    }
+
+    static boolean initializerRun = false;
+
+    static class X {
+        static {
+            initializerRun = true;
+        }
+
+        static void foo() {
+        }
+    }
+
+    public static void invokeStatic() {
+        X.foo();
+    }
+
+    // If constant pool can do eager resolve without eager initialization, then fail if the compiler
+    // causes the static initializer to run.
+    private void test(String name) {
+        ResolvedJavaMethod method = getResolvedJavaMethod(name);
+        Assume.assumeTrue("skipping for old JVMCI", classInitPlugin.supportsLazyInitialization(method.getConstantPool()));
+        parseEager(method, AllowAssumptions.NO);
+        Assert.assertFalse(initializerRun);
+    }
+
+    @Test
+    public void test1() {
+        test("invokeStatic");
+    }
+
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerConfigurationFactory.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerConfigurationFactory.java	Fri Mar 16 22:59:32 2018 -0700
@@ -24,17 +24,25 @@
 
 import static jdk.vm.ci.common.InitTimer.timer;
 
+import java.net.URL;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 import java.util.stream.Collectors;
 
 import org.graalvm.collections.EconomicMap;
 import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.debug.TTY;
+import org.graalvm.compiler.lir.phases.LIRPhase;
+import org.graalvm.compiler.lir.phases.LIRPhaseSuite;
+import org.graalvm.compiler.options.EnumOptionKey;
 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.BasePhase;
+import org.graalvm.compiler.phases.PhaseSuite;
 import org.graalvm.compiler.phases.tiers.CompilerConfiguration;
 import org.graalvm.compiler.serviceprovider.GraalServices;
 
@@ -48,12 +56,20 @@
  */
 public abstract class CompilerConfigurationFactory implements Comparable<CompilerConfigurationFactory> {
 
+    enum ShowConfigurationLevel {
+        none,
+        info,
+        verbose
+    }
+
     static class Options {
         // @formatter:off
         @Option(help = "Names the Graal compiler configuration to use. If ommitted, the compiler configuration " +
                        "with the highest auto-selection priority is used. To see the set of available configurations, " +
                        "supply the value 'help' to this option.", type = OptionType.Expert)
         public static final OptionKey<String> CompilerConfiguration = new OptionKey<>(null);
+        @Option(help = "Writes to the VM log information about the Graal compiler configuration selected.", type = OptionType.User)
+        public static final OptionKey<ShowConfigurationLevel> ShowConfiguration = new EnumOptionKey<>(ShowConfigurationLevel.none);
         // @formatter:on
     }
 
@@ -192,6 +208,52 @@
                 factory = candidates.get(0);
             }
         }
+        ShowConfigurationLevel level = Options.ShowConfiguration.getValue(options);
+        if (level != ShowConfigurationLevel.none) {
+            switch (level) {
+                case info: {
+                    printConfigInfo(factory);
+                    break;
+                }
+                case verbose: {
+                    printConfigInfo(factory);
+                    CompilerConfiguration config = factory.createCompilerConfiguration();
+                    TTY.println("High tier: " + phaseNames(config.createHighTier(options)));
+                    TTY.println("Mid tier: " + phaseNames(config.createMidTier(options)));
+                    TTY.println("Low tier: " + phaseNames(config.createLowTier(options)));
+                    TTY.println("Pre regalloc stage: " + phaseNames(config.createPreAllocationOptimizationStage(options)));
+                    TTY.println("Regalloc stage: " + phaseNames(config.createAllocationStage(options)));
+                    TTY.println("Post regalloc stage: " + phaseNames(config.createPostAllocationOptimizationStage(options)));
+                    config.createAllocationStage(options);
+                    break;
+                }
+            }
+        }
         return factory;
     }
+
+    private static void printConfigInfo(CompilerConfigurationFactory factory) {
+        URL location = factory.getClass().getResource(factory.getClass().getSimpleName() + ".class");
+        TTY.printf("Using Graal compiler configuration '%s' provided by %s loaded from %s%n", factory.name, factory.getClass().getName(), location);
+    }
+
+    private static <C> List<String> phaseNames(PhaseSuite<C> suite) {
+        Collection<BasePhase<? super C>> phases = suite.getPhases();
+        List<String> res = new ArrayList<>(phases.size());
+        for (BasePhase<?> phase : phases) {
+            res.add(phase.contractorName());
+        }
+        Collections.sort(res);
+        return res;
+    }
+
+    private static <C> List<String> phaseNames(LIRPhaseSuite<C> suite) {
+        List<LIRPhase<C>> phases = suite.getPhases();
+        List<String> res = new ArrayList<>(phases.size());
+        for (LIRPhase<?> phase : phases) {
+            res.add(phase.getClass().getName());
+        }
+        Collections.sort(res);
+        return res;
+    }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java	Fri Mar 16 22:59:32 2018 -0700
@@ -45,8 +45,9 @@
      */
     public static final GraalHotSpotVMConfig INJECTED_VMCONFIG = null;
 
+    // this uses `1.9` which will give the correct result with `1.9`, `9`, `10` etc.
     private final boolean isJDK8 = System.getProperty("java.specification.version").compareTo("1.9") < 0;
-    private final int JDKVersion = isJDK8 ? 8 : Integer.parseInt(System.getProperty("java.specification.version"));
+    private final int jdkVersion = isJDK8 ? 8 : Integer.parseInt(System.getProperty("java.specification.version"));
     public final String osName = getHostOSName();
     public final String osArch = getHostArchitectureName();
     public final boolean windowsOs = System.getProperty("os.name", "").startsWith("Windows");
@@ -160,6 +161,7 @@
     public final boolean forceUnreachable = getFlag("ForceUnreachable", Boolean.class);
     public final int codeSegmentSize = getFlag("CodeCacheSegmentSize", Integer.class);
     public final boolean foldStableValues = getFlag("FoldStableValues", Boolean.class);
+    public final int maxVectorSize = getFlag("MaxVectorSize", Integer.class);
 
     public final boolean useTLAB = getFlag("UseTLAB", Boolean.class);
     public final boolean useBiasedLocking = getFlag("UseBiasedLocking", Boolean.class);
@@ -555,12 +557,10 @@
 
     public final int logOfHRGrainBytes = getFieldValue("HeapRegion::LogOfHRGrainBytes", Integer.class, "int");
 
-    public final byte dirtyCardValue = JDKVersion >= 11 ? getConstant("CardTable::dirty_card", Byte.class) :
-                                         (JDKVersion > 8 ? getConstant("CardTableModRefBS::dirty_card", Byte.class) :
-                                         getFieldValue("CompilerToVM::Data::dirty_card", Byte.class, "int"));
-    public final byte g1YoungCardValue = JDKVersion >= 11 ? getConstant("G1CardTable::g1_young_gen", Byte.class) :
-                                           (JDKVersion > 8 ? getConstant("G1SATBCardTableModRefBS::g1_young_gen", Byte.class) :
-                                           getFieldValue("CompilerToVM::Data::g1_young_card", Byte.class, "int"));
+    public final byte dirtyCardValue = jdkVersion >= 11 ? getConstant("CardTable::dirty_card", Byte.class)
+                    : (jdkVersion > 8 ? getConstant("CardTableModRefBS::dirty_card", Byte.class) : getFieldValue("CompilerToVM::Data::dirty_card", Byte.class, "int"));
+    public final byte g1YoungCardValue = jdkVersion >= 11 ? getConstant("G1CardTable::g1_young_gen", Byte.class)
+                    : (jdkVersion > 8 ? getConstant("G1SATBCardTableModRefBS::g1_young_gen", Byte.class) : getFieldValue("CompilerToVM::Data::g1_young_card", Byte.class, "int"));
 
     public final long cardtableStartAddress = getFieldValue("CompilerToVM::Data::cardtable_start_address", Long.class, "jbyte*");
     public final int cardtableShift = getFieldValue("CompilerToVM::Data::cardtable_shift", Integer.class, "int");
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackend.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackend.java	Fri Mar 16 22:59:32 2018 -0700
@@ -91,7 +91,7 @@
     public static class Options {
         // @formatter:off
         @Option(help = "Use Graal arithmetic stubs instead of HotSpot stubs where possible")
-        public static final OptionKey<Boolean> GraalArithmeticStubs = new OptionKey<>(true);
+        public static final OptionKey<Boolean> GraalArithmeticStubs = new OptionKey<>(false); // GR-8276
         @Option(help = "Enables instruction profiling on assembler level. Valid values are a comma separated list of supported instructions." +
                         " Compare with subclasses of Assembler.InstructionCounter.", type = OptionType.Debug)
         public static final OptionKey<String> ASMInstructionProfiling = new OptionKey<>(null);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotCompiledCodeBuilder.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotCompiledCodeBuilder.java	Fri Mar 16 22:59:32 2018 -0700
@@ -22,6 +22,8 @@
  */
 package org.graalvm.compiler.hotspot;
 
+import static org.graalvm.util.CollectionsUtil.anyMatch;
+
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import java.util.ArrayList;
@@ -37,9 +39,9 @@
 import org.graalvm.compiler.code.CompilationResult.CodeAnnotation;
 import org.graalvm.compiler.code.CompilationResult.CodeComment;
 import org.graalvm.compiler.code.CompilationResult.JumpTable;
-import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.code.DataSection;
 import org.graalvm.compiler.code.SourceMapping;
+import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.graph.NodeSourcePosition;
 
 import jdk.vm.ci.code.CodeCacheProvider;
@@ -55,7 +57,6 @@
 import jdk.vm.ci.hotspot.HotSpotCompiledCode;
 import jdk.vm.ci.hotspot.HotSpotCompiledCode.Comment;
 import jdk.vm.ci.hotspot.HotSpotCompiledNmethod;
-import jdk.vm.ci.hotspot.HotSpotObjectConstant;
 import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
 import jdk.vm.ci.meta.Assumptions.Assumption;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
@@ -210,16 +211,31 @@
         sites.addAll(target.getDataPatches());
         sites.addAll(target.getMarks());
 
-        /*
-         * Translate the source mapping into appropriate info points. In HotSpot only one position
-         * can really be represented and recording the end PC seems to give the best results and
-         * corresponds with what C1 and C2 do.
-         */
         if (codeCache.shouldDebugNonSafepoints()) {
+            /*
+             * Translate the source mapping into appropriate info points. In HotSpot only one
+             * position can really be represented and recording the end PC seems to give the best
+             * results and corresponds with what C1 and C2 do. HotSpot doesn't like to see these
+             * unless -XX:+DebugNonSafepoints is enabled, so don't emit them in that case.
+             */
+            List<Site> sourcePositionSites = new ArrayList<>();
             for (SourceMapping source : target.getSourceMappings()) {
-                sites.add(new Infopoint(source.getEndOffset(), new DebugInfo(source.getSourcePosition()), InfopointReason.BYTECODE_POSITION));
-                assert verifySourcePositionReceivers(source.getSourcePosition());
+                NodeSourcePosition sourcePosition = source.getSourcePosition();
+                assert sourcePosition.verify();
+                sourcePosition = sourcePosition.trim();
+                /*
+                 * Don't add BYTECODE_POSITION info points that would potentially create conflicts.
+                 * Under certain conditions the site's pc is not the pc that gets recorded by
+                 * HotSpot (see @code {CodeInstaller::site_Call}). So, avoid adding any source
+                 * positions that can potentially map to the same pc. To do that make sure that the
+                 * source mapping doesn't contain a pc of any important Site.
+                 */
+                if (sourcePosition != null && !anyMatch(sites, s -> source.contains(s.pcOffset))) {
+                    sourcePositionSites.add(new Infopoint(source.getEndOffset(), new DebugInfo(sourcePosition), InfopointReason.BYTECODE_POSITION));
+
+                }
             }
+            sites.addAll(sourcePositionSites);
         }
 
         SiteComparator c = new SiteComparator();
@@ -245,18 +261,4 @@
         }
         return sites.toArray(new Site[sites.size()]);
     }
-
-    /**
-     * Verifies that the captured receiver type agrees with the declared type of the method.
-     */
-    private static boolean verifySourcePositionReceivers(NodeSourcePosition start) {
-        NodeSourcePosition pos = start;
-        while (pos != null) {
-            if (pos.getReceiver() != null) {
-                assert ((HotSpotObjectConstant) pos.getReceiver()).asObject(pos.getMethod().getDeclaringClass()) != null;
-            }
-            pos = pos.getCaller();
-        }
-        return true;
-    }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompilerFactory.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompilerFactory.java	Fri Mar 16 22:59:32 2018 -0700
@@ -26,8 +26,8 @@
 import static org.graalvm.compiler.hotspot.HotSpotGraalOptionValues.GRAAL_OPTION_PROPERTY_PREFIX;
 
 import java.io.PrintStream;
+import java.util.Collections;
 import java.util.Map;
-import java.util.Collections;
 
 import org.graalvm.compiler.debug.MethodFilter;
 import org.graalvm.compiler.options.Option;
@@ -36,6 +36,7 @@
 import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.options.OptionsParser;
 import org.graalvm.compiler.phases.tiers.CompilerConfiguration;
+import org.graalvm.compiler.serviceprovider.JDK9Method;
 
 import jdk.vm.ci.common.InitTimer;
 import jdk.vm.ci.hotspot.HotSpotJVMCICompilerFactory;
@@ -48,6 +49,22 @@
     private static MethodFilter[] graalCompileOnlyFilter;
     private static boolean compileGraalWithC1Only;
 
+    /**
+     * Module containing {@link HotSpotJVMCICompilerFactory}.
+     */
+    private Object jvmciModule;
+
+    /**
+     * Module containing {@link HotSpotGraalCompilerFactory}.
+     */
+    private Object graalModule;
+
+    /**
+     * Module containing the {@linkplain CompilerConfigurationFactory#selectFactory selected}
+     * configuration.
+     */
+    private Object compilerConfigurationModule;
+
     private final HotSpotGraalJVMCIServiceLocator locator;
 
     HotSpotGraalCompilerFactory(HotSpotGraalJVMCIServiceLocator locator) {
@@ -70,6 +87,10 @@
         assert options == null : "cannot select " + getClass() + " service more than once";
         options = HotSpotGraalOptionValues.HOTSPOT_OPTIONS;
         initializeGraalCompilePolicyFields(options);
+        if (!JDK9Method.Java8OrEarlier) {
+            jvmciModule = JDK9Method.getModule(HotSpotJVMCICompilerFactory.class);
+            graalModule = JDK9Method.getModule(HotSpotGraalCompilerFactory.class);
+        }
         /*
          * 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.
@@ -102,7 +123,9 @@
         @Option(help = "In tiered mode compile Graal and JVMCI using optimized first tier code.", type = OptionType.Expert)
         public static final OptionKey<Boolean> CompileGraalWithC1Only = new OptionKey<>(true);
 
-        @Option(help = "A method filter selecting what should be compiled by Graal.  All other requests will be reduced to CompilationLevel.Simple.", type = OptionType.Expert)
+        @Option(help = "A filter applied to a method the VM has selected for compilation by Graal. " +
+                       "A method not matching the filter is redirected to a lower tier compiler. " +
+                       "The filter format is the same as for the MethodFilter option.", type = OptionType.Expert)
         public static final OptionKey<String> GraalCompileOnly = new OptionKey<>(null);
         // @formatter:on
 
@@ -110,7 +133,11 @@
 
     @Override
     public HotSpotGraalCompiler createCompiler(JVMCIRuntime runtime) {
-        HotSpotGraalCompiler compiler = createCompiler(runtime, options, CompilerConfigurationFactory.selectFactory(null, options));
+        CompilerConfigurationFactory factory = CompilerConfigurationFactory.selectFactory(null, options);
+        if (!JDK9Method.Java8OrEarlier) {
+            compilerConfigurationModule = JDK9Method.getModule(factory.getClass());
+        }
+        HotSpotGraalCompiler compiler = createCompiler(runtime, options, factory);
         // Only the HotSpotGraalRuntime associated with the compiler created via
         // jdk.vm.ci.runtime.JVMCIRuntime.getCompiler() is registered for receiving
         // VM events.
@@ -160,15 +187,54 @@
         assert HotSpotGraalCompilerFactory.class.getName().equals("org.graalvm.compiler.hotspot.HotSpotGraalCompilerFactory");
     }
 
+    static final ClassLoader JVMCI_LOADER = HotSpotGraalCompilerFactory.class.getClassLoader();
+
     /*
      * This method is static so it can be exercised during initialization.
      */
-    private static CompilationLevel adjustCompilationLevelInternal(Class<?> declaringClass, String name, String signature, CompilationLevel level) {
+    private CompilationLevel adjustCompilationLevelInternal(Class<?> declaringClass, String name, String signature, CompilationLevel level) {
         if (compileGraalWithC1Only) {
             if (level.ordinal() > CompilationLevel.Simple.ordinal()) {
-                String declaringClassName = declaringClass.getName();
-                if (declaringClassName.startsWith("jdk.vm.ci") || declaringClassName.startsWith("org.graalvm") || declaringClassName.startsWith("com.oracle.graal")) {
-                    return CompilationLevel.Simple;
+                if (JDK9Method.Java8OrEarlier) {
+                    if (JVMCI_LOADER != null) {
+                        // When running with +UseJVMCIClassLoader all classes in
+                        // the JVMCI loader should be compiled with C1.
+                        try {
+                            if (declaringClass.getClassLoader() == JVMCI_LOADER) {
+                                return CompilationLevel.Simple;
+                            }
+                        } catch (SecurityException e) {
+                            // This is definitely not a JVMCI or Graal class
+                        }
+                    } else {
+                        // JVMCI and Graal are on the bootclasspath so match based on the package.
+                        String declaringClassName = declaringClass.getName();
+                        if (declaringClassName.startsWith("jdk.vm.ci")) {
+                            return CompilationLevel.Simple;
+                        }
+                        if (declaringClassName.startsWith("org.graalvm.") &&
+                                        (declaringClassName.startsWith("org.graalvm.compiler.") ||
+                                                        declaringClassName.startsWith("org.graalvm.collections.") ||
+                                                        declaringClassName.startsWith("org.graalvm.compiler.word.") ||
+                                                        declaringClassName.startsWith("org.graalvm.graphio."))) {
+                            return CompilationLevel.Simple;
+                        }
+                        if (declaringClassName.startsWith("com.oracle.graal") &&
+                                        (declaringClassName.startsWith("com.oracle.graal.enterprise") ||
+                                                        declaringClassName.startsWith("com.oracle.graal.vector") ||
+                                                        declaringClassName.startsWith("com.oracle.graal.asm"))) {
+                            return CompilationLevel.Simple;
+                        }
+                    }
+                } else {
+                    try {
+                        Object module = JDK9Method.getModule(declaringClass);
+                        if (jvmciModule == module || graalModule == module || compilerConfigurationModule == module) {
+                            return CompilationLevel.Simple;
+                        }
+                    } catch (Throwable e) {
+                        throw new InternalError(e);
+                    }
                 }
             }
         }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/NodeCostDumpUtil.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/NodeCostDumpUtil.java	Fri Mar 16 22:59:32 2018 -0700
@@ -24,7 +24,6 @@
 
 import java.io.File;
 import java.io.IOException;
-import java.lang.reflect.Field;
 import java.net.URI;
 import java.net.URL;
 import java.net.URLClassLoader;
@@ -114,14 +113,9 @@
         }
         System.err.printf("Loaded %s node classes...\n", nodeClasses.size());
         List<NodeClass<?>> nc = new ArrayList<>();
-        for (Class<?> nodeClass : nodeClasses) {
-            Field f;
+        for (Class<?> c : nodeClasses) {
             try {
-                f = nodeClass.getField("TYPE");
-                f.setAccessible(true);
-                Object val = f.get(null);
-                NodeClass<?> nodeType = (NodeClass<?>) val;
-                nc.add(nodeType);
+                nc.add(NodeClass.get(c));
             } catch (Throwable t) {
                 // Silently ignore problems here
             }
--- /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/lir/VerifyMaxRegisterSizePhase.java	Fri Mar 16 22:59:32 2018 -0700
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 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.lir;
+
+import java.util.EnumSet;
+
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+import org.graalvm.compiler.lir.LIR;
+import org.graalvm.compiler.lir.LIRInstruction;
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.lir.phases.PostAllocationOptimizationPhase;
+
+import jdk.vm.ci.code.TargetDescription;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+import jdk.vm.ci.meta.Value;
+import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
+import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
+
+/**
+ * Checks that no registers exceed the MaxVectorSize flag from the VM config.
+ */
+public final class VerifyMaxRegisterSizePhase extends PostAllocationOptimizationPhase {
+
+    private final int maxVectorSize;
+
+    public VerifyMaxRegisterSizePhase(int maxVectorSize) {
+        this.maxVectorSize = maxVectorSize;
+    }
+
+    @Override
+    protected void run(TargetDescription target, LIRGenerationResult lirGenRes, PostAllocationOptimizationContext context) {
+        LIR lir = lirGenRes.getLIR();
+        for (AbstractBlockBase<?> block : lir.getControlFlowGraph().getBlocks()) {
+            verifyBlock(lir, block);
+        }
+    }
+
+    protected void verifyBlock(LIR lir, AbstractBlockBase<?> block) {
+        for (LIRInstruction inst : lir.getLIRforBlock(block)) {
+            verifyInstruction(inst);
+        }
+    }
+
+    protected void verifyInstruction(LIRInstruction inst) {
+        inst.visitEachInput(this::verifyOperands);
+        inst.visitEachOutput(this::verifyOperands);
+        inst.visitEachAlive(this::verifyOperands);
+        inst.visitEachTemp(this::verifyOperands);
+    }
+
+    @SuppressWarnings("unused")
+    protected void verifyOperands(LIRInstruction instruction, Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
+        if (isRegister(value)) {
+            assert value.getPlatformKind().getSizeInBytes() <= maxVectorSize : "value " + value + " exceeds MaxVectorSize " + maxVectorSize;
+        }
+    }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotClassInitializationPlugin.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotClassInitializationPlugin.java	Fri Mar 16 22:59:32 2018 -0700
@@ -25,6 +25,7 @@
 import org.graalvm.compiler.core.common.type.ObjectStamp;
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.hotspot.nodes.aot.InitializeKlassNode;
 import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantNode;
 import org.graalvm.compiler.nodes.ConstantNode;
@@ -37,6 +38,11 @@
 import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 import jdk.vm.ci.meta.ResolvedJavaType;
+import jdk.vm.ci.meta.ConstantPool;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
 
 public final class HotSpotClassInitializationPlugin implements ClassInitializationPlugin {
     @Override
@@ -73,4 +79,47 @@
         result.setStateBefore(frameState);
         return result;
     }
+
+    private static final Class<? extends ConstantPool> hscp;
+    private static final MethodHandle loadReferencedTypeIIZMH;
+
+    static {
+        MethodHandle m = null;
+        Class<? extends ConstantPool> c = null;
+        try {
+            c = Class.forName("jdk.vm.ci.hotspot.HotSpotConstantPool").asSubclass(ConstantPool.class);
+            m = MethodHandles.lookup().findVirtual(c, "loadReferencedType", MethodType.methodType(void.class, int.class, int.class, boolean.class));
+        } catch (Exception e) {
+        }
+        loadReferencedTypeIIZMH = m;
+        hscp = c;
+    }
+
+    private static boolean isHotSpotConstantPool(ConstantPool cp) {
+        // jdk.vm.ci.hotspot.HotSpotConstantPool is final, so we can
+        // directly compare Classes.
+        return cp.getClass() == hscp;
+    }
+
+    @Override
+    public boolean supportsLazyInitialization(ConstantPool cp) {
+        if (loadReferencedTypeIIZMH != null && isHotSpotConstantPool(cp)) {
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public void loadReferencedType(GraphBuilderContext builder, ConstantPool cp, int cpi, int opcode) {
+        if (loadReferencedTypeIIZMH != null && isHotSpotConstantPool(cp)) {
+            try {
+                loadReferencedTypeIIZMH.invoke(cp, cpi, opcode, false);
+            } catch (Throwable t) {
+                throw GraalError.shouldNotReachHere(t);
+            }
+        } else {
+            cp.loadReferencedType(cpi, opcode);
+        }
+    }
+
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java	Fri Mar 16 22:59:32 2018 -0700
@@ -234,7 +234,7 @@
                     b.addPush(JavaKind.Object, object);
                 } else {
                     FixedGuardNode fixedGuard = b.add(new FixedGuardNode(condition, DeoptimizationReason.ClassCastException, DeoptimizationAction.InvalidateReprofile, false));
-                    b.addPush(JavaKind.Object, new DynamicPiNode(object, fixedGuard, javaClass));
+                    b.addPush(JavaKind.Object, DynamicPiNode.create(b.getAssumptions(), b.getConstantReflection(), object, fixedGuard, javaClass));
                 }
                 return true;
             }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotInvocationPlugins.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotInvocationPlugins.java	Fri Mar 16 22:59:32 2018 -0700
@@ -24,6 +24,7 @@
 
 import static org.graalvm.compiler.serviceprovider.JDK9Method.Java8OrEarlier;
 
+import java.lang.invoke.MethodHandle;
 import java.lang.reflect.Type;
 import java.util.Set;
 
@@ -129,7 +130,7 @@
                 ClassLoader cl = javaClass.getClassLoader();
                 return cl == null || cl == getClass().getClassLoader() || cl == extLoader;
             } else {
-                Object module = JDK9Method.getModule.invoke(javaClass);
+                Object module = JDK9Method.getModule(javaClass);
                 return trustedModules.contains(module);
             }
         }
@@ -148,34 +149,43 @@
         }
     }
 
+    /**
+     * Gets the set of modules whose methods can be intrinsified. This set is the module owning the
+     * class of {@code compilerConfiguration} and all its dependencies.
+     */
     private static EconomicSet<Object> initTrustedModules(CompilerConfiguration compilerConfiguration) throws GraalError {
         try {
             EconomicSet<Object> res = EconomicSet.create();
-            Object compilerConfigurationModule = JDK9Method.getModule.invoke(compilerConfiguration.getClass());
+            Object compilerConfigurationModule = JDK9Method.getModule(compilerConfiguration.getClass());
             res.add(compilerConfigurationModule);
             Class<?> moduleClass = compilerConfigurationModule.getClass();
-            Object layer = new JDK9Method(moduleClass, "getLayer").invoke(compilerConfigurationModule);
+            Object layer = JDK9Method.lookupMethodHandle(moduleClass, "getLayer").invoke(compilerConfigurationModule);
             Class<? extends Object> layerClass = layer.getClass();
-            JDK9Method getName = new JDK9Method(moduleClass, "getName");
-            Set<Object> modules = new JDK9Method(layerClass, "modules").invoke(layer);
-            Object descriptor = new JDK9Method(moduleClass, "getDescriptor").invoke(compilerConfigurationModule);
+            MethodHandle getName = JDK9Method.lookupMethodHandle(moduleClass, "getName");
+            Set<Object> modules = (Set<Object>) JDK9Method.lookupMethodHandle(layerClass, "modules").invoke(layer);
+            Object descriptor = JDK9Method.lookupMethodHandle(moduleClass, "getDescriptor").invoke(compilerConfigurationModule);
             Class<?> moduleDescriptorClass = descriptor.getClass();
-            Set<Object> requires = new JDK9Method(moduleDescriptorClass, "requires").invoke(descriptor);
-            JDK9Method requireNameGetter = null;
+            Set<Object> requires = (Set<Object>) JDK9Method.lookupMethodHandle(moduleDescriptorClass, "requires").invoke(descriptor);
+            boolean isAutomatic = (Boolean) JDK9Method.lookupMethodHandle(moduleDescriptorClass, "isAutomatic").invoke(descriptor);
+            if (isAutomatic) {
+                throw new IllegalArgumentException(String.format("The module '%s' defining the Graal compiler configuration class '%s' must not be an automatic module",
+                                getName.invoke(compilerConfigurationModule), compilerConfiguration.getClass().getName()));
+            }
+            MethodHandle requireNameGetter = null;
             for (Object require : requires) {
                 if (requireNameGetter == null) {
-                    requireNameGetter = new JDK9Method(require.getClass(), "name");
+                    requireNameGetter = JDK9Method.lookupMethodHandle(require.getClass(), "name");
                 }
-                String name = requireNameGetter.invoke(require);
+                String name = (String) requireNameGetter.invoke(require);
                 for (Object module : modules) {
-                    String moduleName = getName.invoke(module);
+                    String moduleName = (String) getName.invoke(module);
                     if (moduleName.equals(name)) {
                         res.add(module);
                     }
                 }
             }
             return res;
-        } catch (Exception e) {
+        } catch (Throwable e) {
             throw new GraalError(e);
         }
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotSuitesProvider.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotSuitesProvider.java	Fri Mar 16 22:59:32 2018 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,11 +28,13 @@
 import static org.graalvm.compiler.core.phases.HighTier.Options.Inline;
 
 import java.util.ListIterator;
+import org.graalvm.compiler.debug.Assertions;
 
 import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
 import org.graalvm.compiler.hotspot.HotSpotBackend;
 import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
 import org.graalvm.compiler.hotspot.HotSpotInstructionProfiling;
+import org.graalvm.compiler.hotspot.lir.VerifyMaxRegisterSizePhase;
 import org.graalvm.compiler.hotspot.phases.AheadOfTimeVerificationPhase;
 import org.graalvm.compiler.hotspot.phases.LoadJavaMirrorWithKlassPhase;
 import org.graalvm.compiler.hotspot.phases.WriteBarrierAdditionPhase;
@@ -139,6 +141,10 @@
                 StructuredGraph targetGraph = new StructuredGraph.Builder(graph.getOptions(), graph.getDebug(), AllowAssumptions.YES).method(graph.method()).build();
                 SimplifyingGraphDecoder graphDecoder = new SimplifyingGraphDecoder(runtime.getTarget().arch, targetGraph, context.getMetaAccess(), context.getConstantReflection(),
                                 context.getConstantFieldProvider(), context.getStampProvider(), !ImmutableCode.getValue(graph.getOptions()));
+
+                if (graph.trackNodeSourcePosition()) {
+                    targetGraph.setTrackNodeSourcePosition();
+                }
                 graphDecoder.decode(encodedGraph);
             }
 
@@ -171,6 +177,9 @@
         if (profileInstructions != null) {
             suites.getPostAllocationOptimizationStage().appendPhase(new HotSpotInstructionProfiling(profileInstructions));
         }
+        if (Assertions.detailedAssertionsEnabled(options)) {
+            suites.getPostAllocationOptimizationStage().appendPhase(new VerifyMaxRegisterSizePhase(config.maxVectorSize));
+        }
         return suites;
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/AOTInliningPolicy.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/AOTInliningPolicy.java	Fri Mar 16 22:59:32 2018 -0700
@@ -76,17 +76,17 @@
 
         OptionValues options = info.graph().getOptions();
         if (InlineEverything.getValue(options)) {
-            InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "inline everything");
+            InliningUtil.traceInlinedMethod(info, inliningDepth, fullyProcessed, "inline everything");
             return true;
         }
 
         if (isIntrinsic(replacements, info)) {
-            InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "intrinsic");
+            InliningUtil.traceInlinedMethod(info, inliningDepth, fullyProcessed, "intrinsic");
             return true;
         }
 
         if (info.shouldInline()) {
-            InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "forced inlining");
+            InliningUtil.traceInlinedMethod(info, inliningDepth, fullyProcessed, "forced inlining");
             return true;
         }
 
@@ -94,18 +94,18 @@
         int nodes = info.determineNodeCount();
 
         if (nodes < TrivialInliningSize.getValue(options) * inliningBonus) {
-            InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "trivial (relevance=%f, probability=%f, bonus=%f, nodes=%d)", relevance, probability, inliningBonus, nodes);
+            InliningUtil.traceInlinedMethod(info, inliningDepth, fullyProcessed, "trivial (relevance=%f, probability=%f, bonus=%f, nodes=%d)", relevance, probability, inliningBonus, nodes);
             return true;
         }
 
         double maximumNodes = computeMaximumSize(relevance, (int) (maxInliningSize(inliningDepth, options) * inliningBonus));
         if (nodes <= maximumNodes) {
-            InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "relevance-based (relevance=%f, probability=%f, bonus=%f, nodes=%d <= %f)", relevance, probability, inliningBonus,
+            InliningUtil.traceInlinedMethod(info, inliningDepth, fullyProcessed, "relevance-based (relevance=%f, probability=%f, bonus=%f, nodes=%d <= %f)", relevance, probability, inliningBonus,
                             nodes, maximumNodes);
             return true;
         }
 
-        InliningUtil.logNotInlinedMethod(info, inliningDepth, "relevance-based (relevance=%f, probability=%f, bonus=%f, nodes=%d > %f)", relevance, probability, inliningBonus, nodes, maximumNodes);
+        InliningUtil.traceNotInlinedMethod(info, inliningDepth, "relevance-based (relevance=%f, probability=%f, bonus=%f, nodes=%d > %f)", relevance, probability, inliningBonus, nodes, maximumNodes);
         return false;
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/AssertionSnippets.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/AssertionSnippets.java	Fri Mar 16 22:59:32 2018 -0700
@@ -86,7 +86,7 @@
             args.add("condition", assertionNode.condition());
             args.addConst("message", "failed runtime assertion in snippet/stub: " + assertionNode.message() + " (" + graph.method() + ")");
 
-            template(assertionNode.getDebug(), args).instantiate(providers.getMetaAccess(), assertionNode, DEFAULT_REPLACER, args);
+            template(assertionNode, args).instantiate(providers.getMetaAccess(), assertionNode, DEFAULT_REPLACER, args);
         }
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HashCodeSnippets.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HashCodeSnippets.java	Fri Mar 16 22:59:32 2018 -0700
@@ -87,7 +87,7 @@
             StructuredGraph graph = node.graph();
             Arguments args = new Arguments(identityHashCodeSnippet, graph.getGuardsStage(), tool.getLoweringStage());
             args.add("thisObj", node.object);
-            SnippetTemplate template = template(node.getDebug(), args);
+            SnippetTemplate template = template(node, args);
             template.instantiate(providers.getMetaAccess(), node, SnippetTemplate.DEFAULT_REPLACER, args);
         }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/LoadExceptionObjectSnippets.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/LoadExceptionObjectSnippets.java	Fri Mar 16 22:59:32 2018 -0700
@@ -101,7 +101,7 @@
             } else {
                 Arguments args = new Arguments(loadException, loadExceptionObject.graph().getGuardsStage(), tool.getLoweringStage());
                 args.addConst("threadRegister", registers.getThreadRegister());
-                template(loadExceptionObject.getDebug(), args).instantiate(providers.getMetaAccess(), loadExceptionObject, DEFAULT_REPLACER, args);
+                template(loadExceptionObject, args).instantiate(providers.getMetaAccess(), loadExceptionObject, DEFAULT_REPLACER, args);
             }
         }
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/MonitorSnippets.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/MonitorSnippets.java	Fri Mar 16 22:59:32 2018 -0700
@@ -759,7 +759,7 @@
                 args.addConst("counters", counters);
             }
 
-            template(graph.getDebug(), args).instantiate(providers.getMetaAccess(), monitorenterNode, DEFAULT_REPLACER, args);
+            template(monitorenterNode, args).instantiate(providers.getMetaAccess(), monitorenterNode, DEFAULT_REPLACER, args);
         }
 
         public void lower(MonitorExitNode monitorexitNode, HotSpotRegistersProvider registers, LoweringTool tool) {
@@ -778,7 +778,7 @@
             args.addConst("options", graph.getOptions());
             args.addConst("counters", counters);
 
-            template(graph.getDebug(), args).instantiate(providers.getMetaAccess(), monitorexitNode, DEFAULT_REPLACER, args);
+            template(monitorexitNode, args).instantiate(providers.getMetaAccess(), monitorexitNode, DEFAULT_REPLACER, args);
         }
 
         public static boolean isTracingEnabledForType(ValueNode object) {
@@ -828,7 +828,7 @@
                     invoke.setStateAfter(graph.start().stateAfter());
                     graph.addAfterFixed(graph.start(), invoke);
 
-                    StructuredGraph inlineeGraph = providers.getReplacements().getSnippet(initCounter.getMethod(), null);
+                    StructuredGraph inlineeGraph = providers.getReplacements().getSnippet(initCounter.getMethod(), null, invoke.graph().trackNodeSourcePosition(), invoke.getNodeSourcePosition());
                     InliningUtil.inline(invoke, inlineeGraph, false, null);
 
                     List<ReturnNode> rets = graph.getNodes(ReturnNode.TYPE).snapshot();
@@ -846,7 +846,7 @@
 
                         Arguments args = new Arguments(checkCounter, graph.getGuardsStage(), tool.getLoweringStage());
                         args.addConst("errMsg", msg);
-                        inlineeGraph = template(graph.getDebug(), args).copySpecializedGraph(graph.getDebug());
+                        inlineeGraph = template(invoke, args).copySpecializedGraph(graph.getDebug());
                         InliningUtil.inline(invoke, inlineeGraph, false, null);
                     }
                 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/NewObjectSnippets.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/NewObjectSnippets.java	Fri Mar 16 22:59:32 2018 -0700
@@ -626,7 +626,7 @@
             args.addConst("options", localOptions);
             args.addConst("counters", counters);
 
-            SnippetTemplate template = template(graph.getDebug(), args);
+            SnippetTemplate template = template(newInstanceNode, args);
             graph.getDebug().log("Lowering allocateInstance in %s: node=%s, template=%s, arguments=%s", graph, newInstanceNode, template, args);
             template.instantiate(providers.getMetaAccess(), newInstanceNode, DEFAULT_REPLACER, args);
         }
@@ -669,7 +669,7 @@
             args.addConst("typeContext", ProfileAllocations.getValue(localOptions) ? arrayType.toJavaName(false) : "");
             args.addConst("options", localOptions);
             args.addConst("counters", counters);
-            SnippetTemplate template = template(graph.getDebug(), args);
+            SnippetTemplate template = template(newArrayNode, args);
             graph.getDebug().log("Lowering allocateArray in %s: node=%s, template=%s, arguments=%s", graph, newArrayNode, template, args);
             template.instantiate(providers.getMetaAccess(), newArrayNode, DEFAULT_REPLACER, args);
         }
@@ -686,7 +686,7 @@
             args.addConst("options", localOptions);
             args.addConst("counters", counters);
 
-            SnippetTemplate template = template(newInstanceNode.getDebug(), args);
+            SnippetTemplate template = template(newInstanceNode, args);
             template.instantiate(providers.getMetaAccess(), newInstanceNode, DEFAULT_REPLACER, args);
         }
 
@@ -715,7 +715,7 @@
             args.add("prototypeMarkWord", lookupArrayClass(tool, JavaKind.Object).prototypeMarkWord());
             args.addConst("options", localOptions);
             args.addConst("counters", counters);
-            SnippetTemplate template = template(graph.getDebug(), args);
+            SnippetTemplate template = template(newArrayNode, args);
             template.instantiate(providers.getMetaAccess(), newArrayNode, DEFAULT_REPLACER, args);
         }
 
@@ -739,7 +739,7 @@
             args.add("hub", hub);
             args.addConst("rank", rank);
             args.addVarargs("dimensions", int.class, StampFactory.forKind(JavaKind.Int), dims);
-            template(newmultiarrayNode.getDebug(), args).instantiate(providers.getMetaAccess(), newmultiarrayNode, DEFAULT_REPLACER, args);
+            template(newmultiarrayNode, args).instantiate(providers.getMetaAccess(), newmultiarrayNode, DEFAULT_REPLACER, args);
         }
 
         private static int instanceSize(HotSpotResolvedObjectType type) {
@@ -753,7 +753,7 @@
                 Arguments args = new Arguments(verifyHeap, verifyHeapNode.graph().getGuardsStage(), tool.getLoweringStage());
                 args.addConst("threadRegister", registers.getThreadRegister());
 
-                SnippetTemplate template = template(verifyHeapNode.getDebug(), args);
+                SnippetTemplate template = template(verifyHeapNode, args);
                 template.instantiate(providers.getMetaAccess(), verifyHeapNode, DEFAULT_REPLACER, args);
             } else {
                 GraphUtil.removeFixedWithUnusedInputs(verifyHeapNode);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ObjectCloneNode.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ObjectCloneNode.java	Fri Mar 16 22:59:32 2018 -0700
@@ -86,7 +86,7 @@
                     StructuredGraph snippetGraph = null;
                     DebugContext debug = getDebug();
                     try (DebugContext.Scope s = debug.scope("ArrayCloneSnippet", snippetMethod)) {
-                        snippetGraph = replacements.getSnippet(snippetMethod, null);
+                        snippetGraph = replacements.getSnippet(snippetMethod, null, graph().trackNodeSourcePosition(), this.getNodeSourcePosition());
                     } catch (Throwable e) {
                         throw debug.handle(e);
                     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/StringToBytesSnippets.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/StringToBytesSnippets.java	Fri Mar 16 22:59:32 2018 -0700
@@ -83,7 +83,7 @@
         public void lower(StringToBytesNode stringToBytesNode, LoweringTool tool) {
             Arguments args = new Arguments(create, stringToBytesNode.graph().getGuardsStage(), tool.getLoweringStage());
             args.addConst("compilationTimeString", stringToBytesNode.getValue());
-            SnippetTemplate template = template(stringToBytesNode.getDebug(), args);
+            SnippetTemplate template = template(stringToBytesNode, args);
             template.instantiate(providers.getMetaAccess(), stringToBytesNode, DEFAULT_REPLACER, args);
         }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/UnsafeLoadSnippets.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/UnsafeLoadSnippets.java	Fri Mar 16 22:59:32 2018 -0700
@@ -65,7 +65,7 @@
             Arguments args = new Arguments(unsafeLoad, load.graph().getGuardsStage(), tool.getLoweringStage());
             args.add("object", load.object());
             args.add("offset", load.offset());
-            template(load.getDebug(), args).instantiate(providers.getMetaAccess(), load, DEFAULT_REPLACER, args);
+            template(load, args).instantiate(providers.getMetaAccess(), load, DEFAULT_REPLACER, args);
         }
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/WriteBarrierSnippets.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/WriteBarrierSnippets.java	Fri Mar 16 22:59:32 2018 -0700
@@ -434,7 +434,7 @@
                 args.add("object", address.getBase());
             }
             args.addConst("counters", counters);
-            template(writeBarrier.getDebug(), args).instantiate(providers.getMetaAccess(), writeBarrier, DEFAULT_REPLACER, args);
+            template(writeBarrier, args).instantiate(providers.getMetaAccess(), writeBarrier, DEFAULT_REPLACER, args);
         }
 
         public void lower(SerialArrayRangeWriteBarrier arrayRangeWriteBarrier, LoweringTool tool) {
@@ -442,7 +442,7 @@
             args.add("address", arrayRangeWriteBarrier.getAddress());
             args.add("length", arrayRangeWriteBarrier.getLength());
             args.addConst("elementStride", arrayRangeWriteBarrier.getElementStride());
-            template(arrayRangeWriteBarrier.getDebug(), args).instantiate(providers.getMetaAccess(), arrayRangeWriteBarrier, DEFAULT_REPLACER, args);
+            template(arrayRangeWriteBarrier, args).instantiate(providers.getMetaAccess(), arrayRangeWriteBarrier, DEFAULT_REPLACER, args);
         }
 
         public void lower(G1PreWriteBarrier writeBarrierPre, HotSpotRegistersProvider registers, LoweringTool tool) {
@@ -467,7 +467,7 @@
             args.addConst("threadRegister", registers.getThreadRegister());
             args.addConst("trace", traceBarrier(writeBarrierPre.graph()));
             args.addConst("counters", counters);
-            template(writeBarrierPre.getDebug(), args).instantiate(providers.getMetaAccess(), writeBarrierPre, DEFAULT_REPLACER, args);
+            template(writeBarrierPre, args).instantiate(providers.getMetaAccess(), writeBarrierPre, DEFAULT_REPLACER, args);
         }
 
         public void lower(G1ReferentFieldReadBarrier readBarrier, HotSpotRegistersProvider registers, LoweringTool tool) {
@@ -492,7 +492,7 @@
             args.addConst("threadRegister", registers.getThreadRegister());
             args.addConst("trace", traceBarrier(readBarrier.graph()));
             args.addConst("counters", counters);
-            template(readBarrier.getDebug(), args).instantiate(providers.getMetaAccess(), readBarrier, DEFAULT_REPLACER, args);
+            template(readBarrier, args).instantiate(providers.getMetaAccess(), readBarrier, DEFAULT_REPLACER, args);
         }
 
         public void lower(G1PostWriteBarrier writeBarrierPost, HotSpotRegistersProvider registers, LoweringTool tool) {
@@ -522,7 +522,7 @@
             args.addConst("threadRegister", registers.getThreadRegister());
             args.addConst("trace", traceBarrier(writeBarrierPost.graph()));
             args.addConst("counters", counters);
-            template(graph.getDebug(), args).instantiate(providers.getMetaAccess(), writeBarrierPost, DEFAULT_REPLACER, args);
+            template(writeBarrierPost, args).instantiate(providers.getMetaAccess(), writeBarrierPost, DEFAULT_REPLACER, args);
         }
 
         public void lower(G1ArrayRangePreWriteBarrier arrayRangeWriteBarrier, HotSpotRegistersProvider registers, LoweringTool tool) {
@@ -531,7 +531,7 @@
             args.add("length", arrayRangeWriteBarrier.getLength());
             args.addConst("elementStride", arrayRangeWriteBarrier.getElementStride());
             args.addConst("threadRegister", registers.getThreadRegister());
-            template(arrayRangeWriteBarrier.getDebug(), args).instantiate(providers.getMetaAccess(), arrayRangeWriteBarrier, DEFAULT_REPLACER, args);
+            template(arrayRangeWriteBarrier, args).instantiate(providers.getMetaAccess(), arrayRangeWriteBarrier, DEFAULT_REPLACER, args);
         }
 
         public void lower(G1ArrayRangePostWriteBarrier arrayRangeWriteBarrier, HotSpotRegistersProvider registers, LoweringTool tool) {
@@ -540,7 +540,7 @@
             args.add("length", arrayRangeWriteBarrier.getLength());
             args.addConst("elementStride", arrayRangeWriteBarrier.getElementStride());
             args.addConst("threadRegister", registers.getThreadRegister());
-            template(arrayRangeWriteBarrier.getDebug(), args).instantiate(providers.getMetaAccess(), arrayRangeWriteBarrier, DEFAULT_REPLACER, args);
+            template(arrayRangeWriteBarrier, args).instantiate(providers.getMetaAccess(), arrayRangeWriteBarrier, DEFAULT_REPLACER, args);
         }
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/aot/ResolveConstantSnippets.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/aot/ResolveConstantSnippets.java	Fri Mar 16 22:59:32 2018 -0700
@@ -36,10 +36,10 @@
 import org.graalvm.compiler.hotspot.nodes.aot.InitializeKlassStubCall;
 import org.graalvm.compiler.hotspot.nodes.aot.LoadConstantIndirectlyNode;
 import org.graalvm.compiler.hotspot.nodes.aot.LoadMethodCountersIndirectlyNode;
+import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantNode;
+import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantStubCall;
+import org.graalvm.compiler.hotspot.nodes.aot.ResolveDynamicConstantNode;
 import org.graalvm.compiler.hotspot.nodes.aot.ResolveDynamicStubCall;
-import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantNode;
-import org.graalvm.compiler.hotspot.nodes.aot.ResolveDynamicConstantNode;
-import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantStubCall;
 import org.graalvm.compiler.hotspot.nodes.aot.ResolveMethodAndLoadCountersNode;
 import org.graalvm.compiler.hotspot.nodes.aot.ResolveMethodAndLoadCountersStubCall;
 import org.graalvm.compiler.hotspot.nodes.type.MethodPointerStamp;
@@ -141,7 +141,7 @@
             Arguments args = new Arguments(snippet, graph.getGuardsStage(), tool.getLoweringStage());
             args.add("constant", value);
 
-            SnippetTemplate template = template(graph.getDebug(), args);
+            SnippetTemplate template = template(resolveConstantNode, args);
             template.instantiate(providers.getMetaAccess(), resolveConstantNode, DEFAULT_REPLACER, args);
 
             assert resolveConstantNode.hasNoUsages();
@@ -180,7 +180,7 @@
             Arguments args = new Arguments(snippet, graph.getGuardsStage(), tool.getLoweringStage());
             args.add("constant", value);
 
-            SnippetTemplate template = template(graph.getDebug(), args);
+            SnippetTemplate template = template(resolveConstantNode, args);
             template.instantiate(providers.getMetaAccess(), resolveConstantNode, DEFAULT_REPLACER, args);
 
             assert resolveConstantNode.hasNoUsages();
@@ -200,7 +200,7 @@
                 Arguments args = new Arguments(initializeKlass, graph.getGuardsStage(), tool.getLoweringStage());
                 args.add("constant", value);
 
-                SnippetTemplate template = template(graph.getDebug(), args);
+                SnippetTemplate template = template(initializeKlassNode, args);
                 template.instantiate(providers.getMetaAccess(), initializeKlassNode, DEFAULT_REPLACER, args);
                 assert initializeKlassNode.hasNoUsages();
                 if (!initializeKlassNode.isDeleted()) {
@@ -218,7 +218,7 @@
             Arguments args = new Arguments(resolveMethodAndLoadCounters, graph.getGuardsStage(), tool.getLoweringStage());
             args.add("method", method);
             args.add("klassHint", resolveMethodAndLoadCountersNode.getHub());
-            SnippetTemplate template = template(graph.getDebug(), args);
+            SnippetTemplate template = template(resolveMethodAndLoadCountersNode, args);
             template.instantiate(providers.getMetaAccess(), resolveMethodAndLoadCountersNode, DEFAULT_REPLACER, args);
 
             assert resolveMethodAndLoadCountersNode.hasNoUsages();
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopySnippets.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopySnippets.java	Fri Mar 16 22:59:32 2018 -0700
@@ -524,7 +524,7 @@
          */
         private void instantiate(Arguments args, BasicArrayCopyNode arraycopy) {
             StructuredGraph graph = arraycopy.graph();
-            SnippetTemplate template = template(graph.getDebug(), args);
+            SnippetTemplate template = template(arraycopy, args);
             UnmodifiableEconomicMap<Node, Node> replacements = template.instantiate(providers.getMetaAccess(), arraycopy, SnippetTemplate.DEFAULT_REPLACER, args, false);
             for (Node originalNode : replacements.getKeys()) {
                 if (originalNode instanceof Invoke) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/profiling/ProbabilisticProfileSnippets.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/profiling/ProbabilisticProfileSnippets.java	Fri Mar 16 22:59:32 2018 -0700
@@ -150,7 +150,7 @@
                 args.add("bci", bci);
                 args.add("targetBci", targetBci);
 
-                SnippetTemplate template = template(graph.getDebug(), args);
+                SnippetTemplate template = template(profileNode, args);
                 template.instantiate(providers.getMetaAccess(), profileNode, DEFAULT_REPLACER, args);
             } else if (profileNode instanceof ProfileInvokeNode) {
                 ProfileInvokeNode profileInvokeNode = (ProfileInvokeNode) profileNode;
@@ -163,7 +163,7 @@
                 args.add("stepLog", stepLog);
                 args.addConst("freqLog", profileInvokeNode.getNotificationFreqLog());
                 args.addConst("probLog", profileInvokeNode.getProbabilityLog());
-                SnippetTemplate template = template(graph.getDebug(), args);
+                SnippetTemplate template = template(profileNode, args);
                 template.instantiate(providers.getMetaAccess(), profileNode, DEFAULT_REPLACER, args);
             } else {
                 throw new GraalError("Unsupported profile node type: " + profileNode);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/profiling/ProfileSnippets.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/profiling/ProfileSnippets.java	Fri Mar 16 22:59:32 2018 -0700
@@ -132,7 +132,7 @@
                 args.add("bci", bci);
                 args.add("targetBci", targetBci);
 
-                SnippetTemplate template = template(graph.getDebug(), args);
+                SnippetTemplate template = template(profileNode, args);
                 template.instantiate(providers.getMetaAccess(), profileNode, DEFAULT_REPLACER, args);
             } else if (profileNode instanceof ProfileInvokeNode) {
                 ProfileInvokeNode profileInvokeNode = (ProfileInvokeNode) profileNode;
@@ -142,7 +142,7 @@
                 args.add("step", step);
                 args.add("stepLog", stepLog);
                 args.addConst("freqLog", profileInvokeNode.getNotificationFreqLog());
-                SnippetTemplate template = template(graph.getDebug(), args);
+                SnippetTemplate template = template(profileNode, args);
                 template.instantiate(providers.getMetaAccess(), profileNode, DEFAULT_REPLACER, args);
             } else {
                 throw new GraalError("Unsupported profile node type: " + profileNode);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/ForeignCallStub.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/ForeignCallStub.java	Fri Mar 16 22:59:32 2018 -0700
@@ -34,8 +34,11 @@
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.core.common.type.StampPair;
+import org.graalvm.compiler.debug.DebugCloseable;
 import org.graalvm.compiler.debug.DebugContext;
+import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.debug.JavaMethodContext;
+import org.graalvm.compiler.graph.NodeSourcePosition;
 import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage;
 import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.Transition;
 import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkageImpl;
@@ -224,33 +227,37 @@
      * %r15 on AMD64) and is only prepended if {@link #prependThread} is true.
      */
     @Override
+    @SuppressWarnings("try")
     protected StructuredGraph getGraph(DebugContext debug, CompilationIdentifier compilationId) {
         WordTypes wordTypes = providers.getWordTypes();
         Class<?>[] args = linkage.getDescriptor().getArgumentTypes();
         boolean isObjectResult = !LIRKind.isValue(linkage.getOutgoingCallingConvention().getReturn());
         StructuredGraph graph = new StructuredGraph.Builder(options, debug).name(toString()).compilationId(compilationId).build();
         graph.disableUnsafeAccessTracking();
-
-        GraphKit kit = new GraphKit(graph, providers, wordTypes, providers.getGraphBuilderPlugins());
-        ParameterNode[] params = createParameters(kit, args);
+        graph.setTrackNodeSourcePosition();
+        try {
+            ResolvedJavaMethod thisMethod = providers.getMetaAccess().lookupJavaMethod(ForeignCallStub.class.getDeclaredMethod("getGraph", DebugContext.class, CompilationIdentifier.class));
+            try (DebugCloseable context = graph.withNodeSourcePosition(NodeSourcePosition.substitution(thisMethod))) {
+                GraphKit kit = new GraphKit(graph, providers, wordTypes, providers.getGraphBuilderPlugins());
+                ParameterNode[] params = createParameters(kit, args);
+                ReadRegisterNode thread = kit.append(new ReadRegisterNode(providers.getRegisters().getThreadRegister(), wordTypes.getWordKind(), true, false));
+                ValueNode result = createTargetCall(kit, params, thread);
+                kit.createInvoke(StubUtil.class, "handlePendingException", thread, ConstantNode.forBoolean(isObjectResult, graph));
+                if (isObjectResult) {
+                    InvokeNode object = kit.createInvoke(HotSpotReplacementsUtil.class, "getAndClearObjectResult", thread);
+                    result = kit.createInvoke(StubUtil.class, "verifyObject", object);
+                }
+                kit.append(new ReturnNode(linkage.getDescriptor().getResultType() == void.class ? null : result));
+                debug.dump(DebugContext.VERBOSE_LEVEL, graph, "Initial stub graph");
 
-        ReadRegisterNode thread = kit.append(new ReadRegisterNode(providers.getRegisters().getThreadRegister(), wordTypes.getWordKind(), true, false));
-        ValueNode result = createTargetCall(kit, params, thread);
-        kit.createInvoke(StubUtil.class, "handlePendingException", thread, ConstantNode.forBoolean(isObjectResult, graph));
-        if (isObjectResult) {
-            InvokeNode object = kit.createInvoke(HotSpotReplacementsUtil.class, "getAndClearObjectResult", thread);
-            result = kit.createInvoke(StubUtil.class, "verifyObject", object);
+                kit.inlineInvokes();
+                new RemoveValueProxyPhase().apply(graph);
+
+                debug.dump(DebugContext.VERBOSE_LEVEL, graph, "Stub graph before compilation");
+            }
+        } catch (Exception e) {
+            throw GraalError.shouldNotReachHere(e);
         }
-        kit.append(new ReturnNode(linkage.getDescriptor().getResultType() == void.class ? null : result));
-
-        debug.dump(DebugContext.VERBOSE_LEVEL, graph, "Initial stub graph");
-
-        kit.inlineInvokes();
-
-        new RemoveValueProxyPhase().apply(graph);
-
-        debug.dump(DebugContext.VERBOSE_LEVEL, graph, "Stub graph before compilation");
-
         return graph;
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java	Fri Mar 16 22:59:32 2018 -0700
@@ -279,6 +279,7 @@
 import org.graalvm.compiler.bytecode.Bytes;
 import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecode;
 import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecodeProvider;
+import org.graalvm.compiler.core.common.GraalOptions;
 import org.graalvm.compiler.core.common.PermanentBailoutException;
 import org.graalvm.compiler.core.common.calc.CanonicalCondition;
 import org.graalvm.compiler.core.common.calc.Condition;
@@ -678,6 +679,8 @@
 
     private boolean finalBarrierRequired;
     private ValueNode originalReceiver;
+    private final boolean eagerInitializing;
+    private final boolean uninitializedIsError;
 
     protected BytecodeParser(GraphBuilderPhase.Instance graphBuilderInstance, StructuredGraph graph, BytecodeParser parent, ResolvedJavaMethod method,
                     int entryBCI, IntrinsicContext intrinsicContext) {
@@ -701,6 +704,14 @@
         this.entryBCI = entryBCI;
         this.parent = parent;
 
+        ClassInitializationPlugin classInitializationPlugin = graphBuilderConfig.getPlugins().getClassInitializationPlugin();
+        if (classInitializationPlugin != null && graphBuilderConfig.eagerResolving()) {
+            uninitializedIsError = eagerInitializing = !classInitializationPlugin.supportsLazyInitialization(constantPool);
+        } else {
+            eagerInitializing = graphBuilderConfig.eagerResolving();
+            uninitializedIsError = graphBuilderConfig.unresolvedIsError();
+        }
+
         assert code.getCode() != null : "method must contain bytecodes: " + method;
 
         if (TraceBytecodeParserLevel.getValue(options) != 0) {
@@ -713,6 +724,11 @@
             lnt = code.getLineNumberTable();
             previousLineNumber = -1;
         }
+
+        assert !GraalOptions.TrackNodeSourcePosition.getValue(options) || graph.trackNodeSourcePosition();
+        if (graphBuilderConfig.trackNodeSourcePosition() || (parent != null && parent.graph.trackNodeSourcePosition())) {
+            graph.setTrackNodeSourcePosition();
+        }
     }
 
     protected GraphBuilderPhase.Instance getGraphBuilderInstance() {
@@ -807,26 +823,28 @@
                 }
             }
 
-            if (method.isSynchronized()) {
-                finishPrepare(lastInstr, BytecodeFrame.BEFORE_BCI);
-
-                // add a monitor enter to the start block
-                methodSynchronizedObject = synchronizedObject(frameState, method);
-                frameState.clearNonLiveLocals(startBlock, liveness, true);
-                assert bci() == 0;
-                genMonitorEnter(methodSynchronizedObject, bci());
+            try (DebugCloseable context = openNodeContext()) {
+                if (method.isSynchronized()) {
+                    finishPrepare(lastInstr, BytecodeFrame.BEFORE_BCI);
+
+                    // add a monitor enter to the start block
+                    methodSynchronizedObject = synchronizedObject(frameState, method);
+                    frameState.clearNonLiveLocals(startBlock, liveness, true);
+                    assert bci() == 0;
+                    genMonitorEnter(methodSynchronizedObject, bci());
+                }
+
+                ProfilingPlugin profilingPlugin = this.graphBuilderConfig.getPlugins().getProfilingPlugin();
+                if (profilingPlugin != null && profilingPlugin.shouldProfile(this, method)) {
+                    FrameState stateBefore = frameState.create(bci(), getNonIntrinsicAncestor(), false, null, null);
+                    profilingPlugin.profileInvoke(this, method, stateBefore);
+                }
+
+                finishPrepare(lastInstr, 0);
+
+                genInfoPointNode(InfopointReason.METHOD_START, null);
             }
 
-            ProfilingPlugin profilingPlugin = this.graphBuilderConfig.getPlugins().getProfilingPlugin();
-            if (profilingPlugin != null && profilingPlugin.shouldProfile(this, method)) {
-                FrameState stateBefore = frameState.create(bci(), getNonIntrinsicAncestor(), false, null, null);
-                profilingPlugin.profileInvoke(this, method, stateBefore);
-            }
-
-            finishPrepare(lastInstr, 0);
-
-            genInfoPointNode(InfopointReason.METHOD_START, null);
-
             currentBlock = blockMap.getStartBlock();
             setEntryState(startBlock, frameState);
             if (startBlock.isLoopHeader) {
@@ -1338,6 +1356,8 @@
 
     protected void genInvokeStatic(int cpi, int opcode) {
         JavaMethod target = lookupMethod(cpi, opcode);
+        assert !uninitializedIsError ||
+                        (target instanceof ResolvedJavaMethod && ((ResolvedJavaMethod) target).getDeclaringClass().isInitialized()) : target;
         genInvokeStatic(target);
     }
 
@@ -2017,6 +2037,7 @@
         }
     }
 
+    @SuppressWarnings("try")
     protected boolean tryInvocationPlugin(InvokeKind invokeKind, ValueNode[] args, ResolvedJavaMethod targetMethod, JavaKind resultType, JavaType returnType) {
         InvocationPlugin plugin = graphBuilderConfig.getPlugins().getInvocationPlugins().lookupInvocation(targetMethod);
         if (plugin != null) {
@@ -2041,11 +2062,13 @@
             }
 
             InvocationPluginAssertions assertions = Assertions.assertionsEnabled() ? new InvocationPluginAssertions(plugin, args, targetMethod, resultType) : null;
-            if (plugin.execute(this, targetMethod, pluginReceiver, args)) {
-                afterInvocationPluginExecution(true, assertions, intrinsicGuard, invokeKind, args, targetMethod, resultType, returnType);
-                return true;
-            } else {
-                afterInvocationPluginExecution(false, assertions, intrinsicGuard, invokeKind, args, targetMethod, resultType, returnType);
+            try (DebugCloseable context = openNodeContext(targetMethod)) {
+                if (plugin.execute(this, targetMethod, pluginReceiver, args)) {
+                    afterInvocationPluginExecution(true, assertions, intrinsicGuard, invokeKind, args, targetMethod, resultType, returnType);
+                    return true;
+                } else {
+                    afterInvocationPluginExecution(false, assertions, intrinsicGuard, invokeKind, args, targetMethod, resultType, returnType);
+                }
             }
         }
         return false;
@@ -2112,6 +2135,7 @@
      * Tries to inline {@code targetMethod} if it is an instance field accessor. This avoids the
      * overhead of creating and using a nested {@link BytecodeParser} object.
      */
+    @SuppressWarnings("try")
     private boolean tryFastInlineAccessor(ValueNode[] args, ResolvedJavaMethod targetMethod) {
         byte[] bytecode = targetMethod.getCode();
         if (bytecode != null && bytecode.length == ACCESSOR_BYTECODE_LENGTH &&
@@ -2124,10 +2148,12 @@
                 if (field instanceof ResolvedJavaField) {
                     ValueNode receiver = invocationPluginReceiver.init(targetMethod, args).get();
                     ResolvedJavaField resolvedField = (ResolvedJavaField) field;
-                    genGetField(resolvedField, receiver);
-                    notifyBeforeInline(targetMethod);
-                    printInlining(targetMethod, targetMethod, true, "inline accessor method (bytecode parsing)");
-                    notifyAfterInline(targetMethod);
+                    try (DebugCloseable context = openNodeContext(targetMethod, 1)) {
+                        genGetField(resolvedField, receiver);
+                        notifyBeforeInline(targetMethod);
+                        printInlining(targetMethod, targetMethod, true, "inline accessor method (bytecode parsing)");
+                        notifyAfterInline(targetMethod);
+                    }
                     return true;
                 }
             }
@@ -2562,6 +2588,7 @@
 
     @Override
     public <T extends ValueNode> T append(T v) {
+        assert !graph.trackNodeSourcePosition() || graph.currentNodeSourcePosition() != null || currentBlock == blockMap.getUnwindBlock() || currentBlock instanceof ExceptionDispatchBlock;
         if (v.graph() != null) {
             return v;
         }
@@ -2670,93 +2697,97 @@
         return createTarget(block, state, false, false);
     }
 
+    @SuppressWarnings("try")
     private FixedNode createTarget(BciBlock block, FrameStateBuilder state, boolean canReuseInstruction, boolean canReuseState) {
         assert block != null && state != null;
         assert !block.isExceptionEntry || state.stackSize() == 1;
 
-        if (getFirstInstruction(block) == null) {
-            /*
-             * This is the first time we see this block as a branch target. Create and return a
-             * placeholder that later can be replaced with a MergeNode when we see this block again.
-             */
-            FixedNode targetNode;
-            if (canReuseInstruction && (block.getPredecessorCount() == 1 || !controlFlowSplit) && !block.isLoopHeader && (currentBlock.loops & ~block.loops) == 0) {
-                setFirstInstruction(block, lastInstr);
-                lastInstr = null;
-            } else {
-                setFirstInstruction(block, graph.add(new BeginNode()));
+        try (DebugCloseable context = openNodeContext(state, block.startBci)) {
+            if (getFirstInstruction(block) == null) {
+                /*
+                 * This is the first time we see this block as a branch target. Create and return a
+                 * placeholder that later can be replaced with a MergeNode when we see this block
+                 * again.
+                 */
+                FixedNode targetNode;
+                if (canReuseInstruction && (block.getPredecessorCount() == 1 || !controlFlowSplit) && !block.isLoopHeader && (currentBlock.loops & ~block.loops) == 0) {
+                    setFirstInstruction(block, lastInstr);
+                    lastInstr = null;
+                } else {
+                    setFirstInstruction(block, graph.add(new BeginNode()));
+                }
+                targetNode = getFirstInstruction(block);
+                Target target = checkLoopExit(targetNode, block, state);
+                FixedNode result = target.fixed;
+                FrameStateBuilder currentEntryState = target.state == state ? (canReuseState ? state : state.copy()) : target.state;
+                setEntryState(block, currentEntryState);
+                currentEntryState.clearNonLiveLocals(block, liveness, true);
+
+                debug.log("createTarget %s: first visit, result: %s", block, targetNode);
+                return result;
+            }
+
+            // We already saw this block before, so we have to merge states.
+            if (!getEntryState(block).isCompatibleWith(state)) {
+                throw bailout("stacks do not match; bytecodes would not verify");
             }
-            targetNode = getFirstInstruction(block);
-            Target target = checkLoopExit(targetNode, block, state);
+
+            if (getFirstInstruction(block) instanceof LoopBeginNode) {
+                assert (block.isLoopHeader && currentBlock.getId() >= block.getId()) : "must be backward branch";
+                /*
+                 * Backward loop edge. We need to create a special LoopEndNode and merge with the
+                 * loop begin node created before.
+                 */
+                LoopBeginNode loopBegin = (LoopBeginNode) getFirstInstruction(block);
+                LoopEndNode loopEnd = graph.add(new LoopEndNode(loopBegin));
+                Target target = checkLoopExit(loopEnd, block, state);
+                FixedNode result = target.fixed;
+                getEntryState(block).merge(loopBegin, target.state);
+
+                debug.log("createTarget %s: merging backward branch to loop header %s, result: %s", block, loopBegin, result);
+                return result;
+            }
+            assert currentBlock == null || currentBlock.getId() < block.getId() : "must not be backward branch";
+            assert getFirstInstruction(block).next() == null : "bytecodes already parsed for block";
+
+            if (getFirstInstruction(block) instanceof AbstractBeginNode && !(getFirstInstruction(block) instanceof AbstractMergeNode)) {
+                /*
+                 * This is the second time we see this block. Create the actual MergeNode and the
+                 * End Node for the already existing edge.
+                 */
+                AbstractBeginNode beginNode = (AbstractBeginNode) getFirstInstruction(block);
+
+                // The EndNode for the already existing edge.
+                EndNode end = graph.add(new EndNode());
+                // The MergeNode that replaces the placeholder.
+                AbstractMergeNode mergeNode = graph.add(new MergeNode());
+                FixedNode next = beginNode.next();
+
+                if (beginNode.predecessor() instanceof ControlSplitNode) {
+                    beginNode.setNext(end);
+                } else {
+                    beginNode.replaceAtPredecessor(end);
+                    beginNode.safeDelete();
+                }
+
+                mergeNode.addForwardEnd(end);
+                mergeNode.setNext(next);
+
+                setFirstInstruction(block, mergeNode);
+            }
+
+            AbstractMergeNode mergeNode = (AbstractMergeNode) getFirstInstruction(block);
+
+            // The EndNode for the newly merged edge.
+            EndNode newEnd = graph.add(new EndNode());
+            Target target = checkLoopExit(newEnd, block, state);
             FixedNode result = target.fixed;
-            FrameStateBuilder currentEntryState = target.state == state ? (canReuseState ? state : state.copy()) : target.state;
-            setEntryState(block, currentEntryState);
-            currentEntryState.clearNonLiveLocals(block, liveness, true);
-
-            debug.log("createTarget %s: first visit, result: %s", block, targetNode);
-            return result;
-        }
-
-        // We already saw this block before, so we have to merge states.
-        if (!getEntryState(block).isCompatibleWith(state)) {
-            throw bailout("stacks do not match; bytecodes would not verify");
-        }
-
-        if (getFirstInstruction(block) instanceof LoopBeginNode) {
-            assert (block.isLoopHeader && currentBlock.getId() >= block.getId()) : "must be backward branch";
-            /*
-             * Backward loop edge. We need to create a special LoopEndNode and merge with the loop
-             * begin node created before.
-             */
-            LoopBeginNode loopBegin = (LoopBeginNode) getFirstInstruction(block);
-            LoopEndNode loopEnd = graph.add(new LoopEndNode(loopBegin));
-            Target target = checkLoopExit(loopEnd, block, state);
-            FixedNode result = target.fixed;
-            getEntryState(block).merge(loopBegin, target.state);
-
-            debug.log("createTarget %s: merging backward branch to loop header %s, result: %s", block, loopBegin, result);
+            getEntryState(block).merge(mergeNode, target.state);
+            mergeNode.addForwardEnd(newEnd);
+
+            debug.log("createTarget %s: merging state, result: %s", block, result);
             return result;
         }
-        assert currentBlock == null || currentBlock.getId() < block.getId() : "must not be backward branch";
-        assert getFirstInstruction(block).next() == null : "bytecodes already parsed for block";
-
-        if (getFirstInstruction(block) instanceof AbstractBeginNode && !(getFirstInstruction(block) instanceof AbstractMergeNode)) {
-            /*
-             * This is the second time we see this block. Create the actual MergeNode and the End
-             * Node for the already existing edge.
-             */
-            AbstractBeginNode beginNode = (AbstractBeginNode) getFirstInstruction(block);
-
-            // The EndNode for the already existing edge.
-            EndNode end = graph.add(new EndNode());
-            // The MergeNode that replaces the placeholder.
-            AbstractMergeNode mergeNode = graph.add(new MergeNode());
-            FixedNode next = beginNode.next();
-
-            if (beginNode.predecessor() instanceof ControlSplitNode) {
-                beginNode.setNext(end);
-            } else {
-                beginNode.replaceAtPredecessor(end);
-                beginNode.safeDelete();
-            }
-
-            mergeNode.addForwardEnd(end);
-            mergeNode.setNext(next);
-
-            setFirstInstruction(block, mergeNode);
-        }
-
-        AbstractMergeNode mergeNode = (AbstractMergeNode) getFirstInstruction(block);
-
-        // The EndNode for the newly merged edge.
-        EndNode newEnd = graph.add(new EndNode());
-        Target target = checkLoopExit(newEnd, block, state);
-        FixedNode result = target.fixed;
-        getEntryState(block).merge(mergeNode, target.state);
-        mergeNode.addForwardEnd(newEnd);
-
-        debug.log("createTarget %s: merging state, result: %s", block, result);
-        return result;
     }
 
     /**
@@ -2965,28 +2996,28 @@
         }
 
         while (bci < endBCI) {
-            if (graphBuilderConfig.insertFullInfopoints() && !parsingIntrinsic()) {
-                currentLineNumber = lnt != null ? lnt.getLineNumber(bci) : -1;
-                if (currentLineNumber != previousLineNumber) {
-                    genInfoPointNode(InfopointReason.BYTECODE_POSITION, null);
-                    previousLineNumber = currentLineNumber;
+            try (DebugCloseable context = openNodeContext()) {
+                if (graphBuilderConfig.insertFullInfopoints() && !parsingIntrinsic()) {
+                    currentLineNumber = lnt != null ? lnt.getLineNumber(bci) : -1;
+                    if (currentLineNumber != previousLineNumber) {
+                        genInfoPointNode(InfopointReason.BYTECODE_POSITION, null);
+                        previousLineNumber = currentLineNumber;
+                    }
                 }
-            }
-
-            // read the opcode
-            int opcode = stream.currentBC();
-            assert traceState();
-            assert traceInstruction(bci, opcode, bci == block.startBci);
-            if (parent == null && bci == entryBCI) {
-                if (block.getJsrScope() != JsrScope.EMPTY_SCOPE) {
-                    throw new JsrNotSupportedBailout("OSR into a JSR scope is not supported");
+
+                // read the opcode
+                int opcode = stream.currentBC();
+                assert traceState();
+                assert traceInstruction(bci, opcode, bci == block.startBci);
+                if (parent == null && bci == entryBCI) {
+                    if (block.getJsrScope() != JsrScope.EMPTY_SCOPE) {
+                        throw new JsrNotSupportedBailout("OSR into a JSR scope is not supported");
+                    }
+                    EntryMarkerNode x = append(new EntryMarkerNode());
+                    frameState.insertProxies(value -> graph.unique(new EntryProxyNode(value, x)));
+                    x.setStateAfter(createFrameState(bci, x));
                 }
-                EntryMarkerNode x = append(new EntryMarkerNode());
-                frameState.insertProxies(value -> graph.unique(new EntryProxyNode(value, x)));
-                x.setStateAfter(createFrameState(bci, x));
-            }
-
-            try (DebugCloseable context = openNodeContext()) {
+
                 processBytecode(bci, opcode);
             } catch (BailoutException e) {
                 // Don't wrap bailouts as parser errors
@@ -3017,13 +3048,28 @@
         }
     }
 
-    private DebugCloseable openNodeContext() {
-        if ((graphBuilderConfig.trackNodeSourcePosition() || debug.isDumpEnabledForMethod()) && !parsingIntrinsic()) {
-            return graph.withNodeSourcePosition(createBytecodePosition());
+    private DebugCloseable openNodeContext(FrameStateBuilder state, int startBci) {
+        if (graph.trackNodeSourcePosition()) {
+            return graph.withNodeSourcePosition(state.createBytecodePosition(startBci));
         }
         return null;
     }
 
+    private DebugCloseable openNodeContext(ResolvedJavaMethod targetMethod) {
+        return openNodeContext(targetMethod, -1);
+    }
+
+    private DebugCloseable openNodeContext(ResolvedJavaMethod targetMethod, int bci) {
+        if (graph.trackNodeSourcePosition()) {
+            return graph.withNodeSourcePosition(new NodeSourcePosition(createBytecodePosition(), targetMethod, bci));
+        }
+        return null;
+    }
+
+    private DebugCloseable openNodeContext() {
+        return openNodeContext(frameState, bci());
+    }
+
     /* Also a hook for subclasses. */
     protected boolean forceLoopPhis() {
         return graph.isOSR();
@@ -3133,7 +3179,7 @@
         genIf(condition, trueSuccessor, falseSuccessor, probability);
     }
 
-    private double getProfileProbability(boolean negate) {
+    protected double getProfileProbability(boolean negate) {
         double probability;
         if (profilingInfo == null) {
             probability = 0.5;
@@ -3433,7 +3479,8 @@
     }
 
     protected NodeSourcePosition createBytecodePosition() {
-        return frameState.createBytecodePosition(bci());
+        NodeSourcePosition bytecodePosition = frameState.createBytecodePosition(bci());
+        return bytecodePosition;
     }
 
     public void setCurrentFrameState(FrameStateBuilder frameState) {
@@ -3454,6 +3501,7 @@
         frameState.push(kind, value);
     }
 
+    @SuppressWarnings("try")
     public void loadLocalObject(int index) {
         ValueNode value = frameState.loadLocal(index, JavaKind.Object);
 
@@ -3461,7 +3509,9 @@
         int nextBC = stream.readUByte(nextBCI);
         if (nextBCI <= currentBlock.endBci && nextBC == Bytecodes.GETFIELD) {
             stream.next();
-            genGetField(stream.readCPI(), Bytecodes.GETFIELD, value);
+            try (DebugCloseable ignored = openNodeContext()) {
+                genGetField(stream.readCPI(), Bytecodes.GETFIELD, value);
+            }
         } else {
             frameState.push(JavaKind.Object, value);
         }
@@ -3689,6 +3739,17 @@
         genIf(x, cond, y);
     }
 
+    private static void initialize(ResolvedJavaType resolvedType) {
+        /*
+         * Since we're potentially triggering class initialization here, we need synchronization to
+         * mitigate the potential for class initialization related deadlock being caused by the
+         * compiler (e.g., https://github.com/graalvm/graal-core/pull/232/files#r90788550).
+         */
+        synchronized (BytecodeParser.class) {
+            resolvedType.initialize();
+        }
+    }
+
     protected JavaType lookupType(int cpi, int bytecode) {
         maybeEagerlyResolve(cpi, bytecode);
         JavaType result = constantPool.lookupType(cpi, bytecode);
@@ -3699,32 +3760,26 @@
     private JavaMethod lookupMethod(int cpi, int opcode) {
         maybeEagerlyResolve(cpi, opcode);
         JavaMethod result = constantPool.lookupMethod(cpi, opcode);
-        /*
-         * In general, one cannot assume that the declaring class being initialized is useful, since
-         * the actual concrete receiver may be a different class (except for static calls). Also,
-         * interfaces are initialized only under special circumstances, so that this assertion would
-         * often fail for interface calls.
-         */
-        assert !graphBuilderConfig.unresolvedIsError() ||
-                        (result instanceof ResolvedJavaMethod && (opcode != INVOKESTATIC || ((ResolvedJavaMethod) result).getDeclaringClass().isInitialized())) : result;
+        assert !graphBuilderConfig.unresolvedIsError() || result instanceof ResolvedJavaMethod : result;
         return result;
     }
 
     protected JavaField lookupField(int cpi, int opcode) {
         maybeEagerlyResolve(cpi, opcode);
         JavaField result = constantPool.lookupField(cpi, method, opcode);
-
-        if (graphBuilderConfig.eagerResolving()) {
-            assert !graphBuilderConfig.unresolvedIsError() || result instanceof ResolvedJavaField : "Not resolved: " + result;
+        assert !graphBuilderConfig.unresolvedIsError() || result instanceof ResolvedJavaField : "Not resolved: " + result;
+        if (parsingIntrinsic() || eagerInitializing) {
             if (result instanceof ResolvedJavaField) {
                 ResolvedJavaType declaringClass = ((ResolvedJavaField) result).getDeclaringClass();
                 if (!declaringClass.isInitialized()) {
-                    assert declaringClass.isInterface() : "Declaring class not initialized but not an interface? " + declaringClass;
-                    declaringClass.initialize();
+                    // Even with eager initialization, superinterfaces are not always initialized.
+                    // See StaticInterfaceFieldTest
+                    assert !eagerInitializing || declaringClass.isInterface() : "Declaring class not initialized but not an interface? " + declaringClass;
+                    initialize(declaringClass);
                 }
             }
         }
-        assert !graphBuilderConfig.unresolvedIsError() || (result instanceof ResolvedJavaField && ((ResolvedJavaField) result).getDeclaringClass().isInitialized()) : result;
+        assert !uninitializedIsError || (result instanceof ResolvedJavaField && ((ResolvedJavaField) result).getDeclaringClass().isInitialized()) : result;
         return result;
     }
 
@@ -3745,7 +3800,12 @@
              * the compiler (e.g., https://github.com/graalvm/graal-core/pull/232/files#r90788550).
              */
             synchronized (BytecodeParser.class) {
-                constantPool.loadReferencedType(cpi, bytecode);
+                ClassInitializationPlugin classInitializationPlugin = graphBuilderConfig.getPlugins().getClassInitializationPlugin();
+                if (classInitializationPlugin != null) {
+                    classInitializationPlugin.loadReferencedType(this, constantPool, cpi, bytecode);
+                } else {
+                    constantPool.loadReferencedType(cpi, bytecode);
+                }
             }
         }
     }
@@ -3872,11 +3932,16 @@
     }
 
     void genNewInstance(JavaType type) {
-        if (!(type instanceof ResolvedJavaType) || !((ResolvedJavaType) type).isInitialized()) {
+        if (!(type instanceof ResolvedJavaType)) {
             handleUnresolvedNewInstance(type);
             return;
         }
         ResolvedJavaType resolvedType = (ResolvedJavaType) type;
+        ClassInitializationPlugin classInitializationPlugin = graphBuilderConfig.getPlugins().getClassInitializationPlugin();
+        if (!resolvedType.isInitialized() && classInitializationPlugin == null) {
+            handleUnresolvedNewInstance(type);
+            return;
+        }
 
         ResolvedJavaType[] skippedExceptionTypes = this.graphBuilderConfig.getSkippedExceptionTypes();
         if (skippedExceptionTypes != null) {
@@ -3888,7 +3953,6 @@
             }
         }
 
-        ClassInitializationPlugin classInitializationPlugin = graphBuilderConfig.getPlugins().getClassInitializationPlugin();
         if (classInitializationPlugin != null && classInitializationPlugin.shouldApply(this, resolvedType)) {
             FrameState stateBefore = frameState.create(bci(), getNonIntrinsicAncestor(), false, null, null);
             classInitializationPlugin.apply(this, resolvedType, stateBefore);
@@ -4078,7 +4142,7 @@
         }
     }
 
-    private boolean needsExplicitException() {
+    protected boolean needsExplicitException() {
         BytecodeExceptionMode exceptionMode = graphBuilderConfig.getBytecodeExceptionMode();
         if (exceptionMode == BytecodeExceptionMode.CheckAll || StressExplicitExceptionCode.getValue(options)) {
             return true;
@@ -4163,7 +4227,7 @@
     private ResolvedJavaField resolveStaticFieldAccess(JavaField field, ValueNode value) {
         if (field instanceof ResolvedJavaField) {
             ResolvedJavaField resolvedField = (ResolvedJavaField) field;
-            if (resolvedField.getDeclaringClass().isInitialized()) {
+            if (resolvedField.getDeclaringClass().isInitialized() || graphBuilderConfig.getPlugins().getClassInitializationPlugin() != null) {
                 return resolvedField;
             }
             /*
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParserOptions.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParserOptions.java	Fri Mar 16 22:59:32 2018 -0700
@@ -58,7 +58,7 @@
     public static final OptionKey<Boolean> TraceParserPlugins = new OptionKey<>(false);
 
     @Option(help = "Maximum depth when inlining during bytecode parsing.", type = OptionType.Debug)
-    public static final OptionKey<Integer> InlineDuringParsingMaxDepth = new OptionKey<>(3);
+    public static final OptionKey<Integer> InlineDuringParsingMaxDepth = new OptionKey<>(10);
 
     @Option(help = "When creating info points hide the methods of the substitutions.", type = OptionType.Debug)
     public static final OptionKey<Boolean> HideSubstitutionStates = new OptionKey<>(false);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/FrameStateBuilder.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/FrameStateBuilder.java	Fri Mar 16 22:59:32 2018 -0700
@@ -32,7 +32,6 @@
 import static org.graalvm.compiler.bytecode.Bytecodes.POP2;
 import static org.graalvm.compiler.bytecode.Bytecodes.SWAP;
 import static org.graalvm.compiler.debug.GraalError.shouldNotReachHere;
-import static org.graalvm.compiler.java.BytecodeParserOptions.HideSubstitutionStates;
 import static org.graalvm.compiler.nodes.FrameState.TWO_SLOT_MARKER;
 
 import java.util.ArrayList;
@@ -74,7 +73,6 @@
 
 import jdk.vm.ci.code.BytecodeFrame;
 import jdk.vm.ci.meta.Assumptions;
-import jdk.vm.ci.meta.JavaConstant;
 import jdk.vm.ci.meta.JavaKind;
 import jdk.vm.ci.meta.JavaType;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
@@ -112,8 +110,6 @@
      */
     private List<StateSplit> sideEffects;
 
-    private JavaConstant constantReceiver;
-
     /**
      * Creates a new frame state builder for the given method and the given target graph.
      *
@@ -164,7 +160,6 @@
             locals[javaIndex] = arguments[index];
             javaIndex = 1;
             index = 1;
-            constantReceiver = locals[0].asJavaConstant();
         }
         Signature sig = getMethod().getSignature();
         int max = sig.getParameterCount(false);
@@ -310,7 +305,7 @@
 
     public FrameState create(int bci, StateSplit forStateSplit) {
         if (parser != null && parser.parsingIntrinsic()) {
-            NodeSourcePosition sourcePosition = createBytecodePosition(bci, false);
+            NodeSourcePosition sourcePosition = parser.getGraph().trackNodeSourcePosition() ? createBytecodePosition(bci) : null;
             return parser.intrinsicContext.createFrameState(parser.getGraph(), this, forStateSplit, sourcePosition);
         }
 
@@ -354,25 +349,14 @@
     }
 
     public NodeSourcePosition createBytecodePosition(int bci) {
-        return createBytecodePosition(bci, HideSubstitutionStates.getValue(parser.graph.getOptions()));
+        BytecodeParser parent = parser.getParent();
+        NodeSourcePosition position = create(bci, parent);
+        return position;
     }
 
-    private NodeSourcePosition createBytecodePosition(int bci, boolean hideSubstitutionStates) {
-        BytecodeParser parent = parser.getParent();
-        if (hideSubstitutionStates) {
-            if (parser.parsingIntrinsic()) {
-                // Attribute to the method being replaced
-                return new NodeSourcePosition(constantReceiver, parent.getFrameStateBuilder().createBytecodePosition(parent.bci()), parser.intrinsicContext.getOriginalMethod(), -1);
-            }
-            // Skip intrinsic frames
-            parent = parser.getNonIntrinsicAncestor();
-        }
-        return create(constantReceiver, bci, parent, hideSubstitutionStates);
-    }
-
-    private NodeSourcePosition create(JavaConstant receiver, int bci, BytecodeParser parent, boolean hideSubstitutionStates) {
+    private NodeSourcePosition create(int bci, BytecodeParser parent) {
         if (outerSourcePosition == null && parent != null) {
-            outerSourcePosition = parent.getFrameStateBuilder().createBytecodePosition(parent.bci(), hideSubstitutionStates);
+            outerSourcePosition = parent.getFrameStateBuilder().createBytecodePosition(parent.bci());
         }
         if (bci == BytecodeFrame.AFTER_EXCEPTION_BCI && parent != null) {
             return FrameState.toSourcePosition(outerFrameState);
@@ -380,7 +364,7 @@
         if (bci == BytecodeFrame.INVALID_FRAMESTATE_BCI) {
             throw shouldNotReachHere();
         }
-        return new NodeSourcePosition(receiver, outerSourcePosition, code.getMethod(), bci);
+        return new NodeSourcePosition(outerSourcePosition, code.getMethod(), bci);
     }
 
     public FrameStateBuilder copy() {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/JTTTest.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/JTTTest.java	Fri Mar 16 22:59:32 2018 -0700
@@ -22,25 +22,14 @@
  */
 package org.graalvm.compiler.jtt;
 
-import static java.lang.reflect.Modifier.isStatic;
-
 import java.util.Collections;
 import java.util.Set;
 
 import org.graalvm.compiler.core.test.GraalCompilerTest;
-import org.graalvm.compiler.nodes.ConstantNode;
-import org.graalvm.compiler.nodes.ParameterNode;
-import org.graalvm.compiler.nodes.StructuredGraph;
-import org.graalvm.compiler.nodes.StructuredGraph.Builder;
 import org.graalvm.compiler.options.OptionValues;
-import org.graalvm.compiler.phases.PhaseSuite;
-import org.graalvm.compiler.phases.tiers.HighTierContext;
 import org.junit.Assert;
 
-import jdk.vm.ci.code.InstalledCode;
 import jdk.vm.ci.meta.DeoptimizationReason;
-import jdk.vm.ci.meta.JavaConstant;
-import jdk.vm.ci.meta.JavaType;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 
 /**
@@ -66,45 +55,35 @@
     }
 
     @Override
-    protected StructuredGraph parse(Builder builder, PhaseSuite<HighTierContext> graphBuilderSuite) {
-        StructuredGraph graph = super.parse(builder, graphBuilderSuite);
-        if (argsToBind != null) {
-            ResolvedJavaMethod m = graph.method();
-            Object receiver = isStatic(m.getModifiers()) ? null : this;
-            Object[] args = argsWithReceiver(receiver, argsToBind);
-            JavaType[] parameterTypes = m.toParameterTypes();
-            assert parameterTypes.length == args.length;
-            for (ParameterNode param : graph.getNodes(ParameterNode.TYPE)) {
-                JavaConstant c = getSnippetReflection().forBoxed(parameterTypes[param.index()].getJavaKind(), args[param.index()]);
-                ConstantNode replacement = ConstantNode.forConstant(c, getMetaAccess(), graph);
-                param.replaceAtUsages(replacement);
-            }
-        }
-        return graph;
+    protected Object[] getArgumentToBind() {
+        return argsToBind;
     }
 
-    @Override
-    protected InstalledCode getCode(ResolvedJavaMethod method, StructuredGraph graph, boolean forceCompile, boolean installAsDefault, OptionValues options) {
-        return super.getCode(method, graph, argsToBind != null, installAsDefault, options);
-    }
-
-    Double delta;
+    /**
+     * If non-null, then this is a test for a method returning a {@code double} value that must be
+     * within {@code ulpDelta}s of the expected value.
+     */
+    protected Double ulpDelta;
 
     @Override
     protected void assertDeepEquals(Object expected, Object actual) {
-        if (delta != null) {
-            Assert.assertEquals(((Number) expected).doubleValue(), ((Number) actual).doubleValue(), delta);
+        if (ulpDelta != null) {
+            double expectedDouble = (double) expected;
+            double actualDouble = (Double) actual;
+            double ulp = Math.ulp(expectedDouble);
+            double delta = ulpDelta * ulp;
+            try {
+                Assert.assertEquals(expectedDouble, actualDouble, delta);
+            } catch (AssertionError e) {
+                double diff = Math.abs(expectedDouble - actualDouble);
+                double diffUlps = diff / ulp;
+                throw new AssertionError(e.getMessage() + " // " + diffUlps + " ulps");
+            }
         } else {
             super.assertDeepEquals(expected, actual);
         }
     }
 
-    @SuppressWarnings("hiding")
-    protected void runTestWithDelta(double delta, String name, Object... args) {
-        this.delta = Double.valueOf(delta);
-        runTest(name, args);
-    }
-
     protected void runTest(String name, Object... args) {
         runTest(getInitialOptions(), name, args);
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_series.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_series.java	Fri Mar 16 22:59:32 2018 -0700
@@ -24,11 +24,9 @@
 
 package org.graalvm.compiler.jtt.hotpath;
 
-import org.junit.Ignore;
+import org.graalvm.compiler.jtt.JTTTest;
 import org.junit.Test;
 
-import org.graalvm.compiler.jtt.JTTTest;
-
 /*
  */
 public class HP_series extends JTTTest {
@@ -101,17 +99,16 @@
         return (0.0);
     }
 
-    /*
-     * This test is sensible to the implementation of Math.pow, cos and sin. Since for these
-     * functions, the specs says "The computed result must be within 1 ulp of the exact result",
-     * different implementation may return different results. The 11 ulp delta allowed for test(100)
-     * tries to account for that but is not guaranteed to work forever.
+    /**
+     * This test is sensitive to the implementation of {@link Math#pow}, {@link Math#cos} and
+     * {@link Math#sin(double)}. Since for these functions, the specs says "The computed result must
+     * be within 1 ulp of the exact result", different implementation may return different results.
+     * The 11 ulp delta allowed for test(100) tries to account for that but is not guaranteed to
+     * work forever.
      */
-    @Ignore("failure-prone because of the variabiliy of pow/cos/sin")
     @Test
     public void run0() throws Throwable {
-        double expected = 0.6248571921291398d;
-        runTestWithDelta(11 * Math.ulp(expected), "test", 100);
+        ulpDelta = 11.0D;
+        runTest("test", 100);
     }
-
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_abs.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_abs.java	Fri Mar 16 22:59:32 2018 -0700
@@ -22,13 +22,14 @@
  */
 package org.graalvm.compiler.jtt.lang;
 
+import org.graalvm.compiler.options.OptionValues;
 import org.junit.Test;
 
-import org.graalvm.compiler.jtt.JTTTest;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
 
 /*
  */
-public class Math_abs extends JTTTest {
+public class Math_abs extends UnaryMath {
 
     @SuppressWarnings("serial")
     public static class NaN extends Throwable {
@@ -78,4 +79,10 @@
         runTest("test", java.lang.Double.NaN);
     }
 
+    @Test
+    public void run7() {
+        OptionValues options = getInitialOptions();
+        ResolvedJavaMethod method = getResolvedJavaMethod("test");
+        testManyValues(options, method);
+    }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_cos.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_cos.java	Fri Mar 16 22:59:32 2018 -0700
@@ -22,13 +22,14 @@
  */
 package org.graalvm.compiler.jtt.lang;
 
+import org.graalvm.compiler.options.OptionValues;
 import org.junit.Test;
 
-import org.graalvm.compiler.jtt.JTTTest;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
 
 /*
  */
-public class Math_cos extends JTTTest {
+public class Math_cos extends UnaryMath {
 
     @SuppressWarnings("serial")
     public static class NaN extends Throwable {
@@ -58,4 +59,10 @@
         runTest("test", java.lang.Double.POSITIVE_INFINITY);
     }
 
+    @Test
+    public void run3() {
+        OptionValues options = getInitialOptions();
+        ResolvedJavaMethod method = getResolvedJavaMethod("test");
+        testManyValues(options, method);
+    }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_exp.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_exp.java	Fri Mar 16 22:59:32 2018 -0700
@@ -22,14 +22,12 @@
  */
 package org.graalvm.compiler.jtt.lang;
 
-import org.junit.Ignore;
+import org.graalvm.compiler.options.OptionValues;
 import org.junit.Test;
 
-import org.graalvm.compiler.jtt.JTTTest;
-
 /*
  */
-public class Math_exp extends JTTTest {
+public class Math_exp extends UnaryMath {
 
     public static double test(double arg) {
         return Math.exp(arg);
@@ -65,9 +63,19 @@
         runTest("test", 0.0D);
     }
 
-    @Ignore("java.lang.AssertionError: expected:<2.718281828459045> but was:<2.7182818284590455>")
     @Test
     public void run6() {
         runTest("test", 1.0D);
     }
+
+    @Test
+    public void run7() {
+        runTest("test", -1024D);
+    }
+
+    @Test
+    public void run8() {
+        OptionValues options = getInitialOptions();
+        testManyValues(options, getResolvedJavaMethod("test"));
+    }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_log.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_log.java	Fri Mar 16 22:59:32 2018 -0700
@@ -22,13 +22,14 @@
  */
 package org.graalvm.compiler.jtt.lang;
 
+import org.graalvm.compiler.options.OptionValues;
 import org.junit.Test;
 
-import org.graalvm.compiler.jtt.JTTTest;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
 
 /*
  */
-public class Math_log extends JTTTest {
+public class Math_log extends UnaryMath {
 
     @SuppressWarnings("serial")
     public static class NaN extends Throwable {
@@ -78,4 +79,10 @@
         runTest("test", -0.0d);
     }
 
+    @Test
+    public void run7() {
+        OptionValues options = getInitialOptions();
+        ResolvedJavaMethod method = getResolvedJavaMethod("test");
+        testManyValues(options, method);
+    }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_pow.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_pow.java	Fri Mar 16 22:59:32 2018 -0700
@@ -22,9 +22,11 @@
  */
 package org.graalvm.compiler.jtt.lang;
 
+import org.graalvm.compiler.jtt.JTTTest;
+import org.graalvm.compiler.options.OptionValues;
 import org.junit.Test;
 
-import org.graalvm.compiler.jtt.JTTTest;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
 
 /*
  */
@@ -88,4 +90,44 @@
     public void run10() throws Throwable {
         runTest("test", 0.999998, 1500000.0);
     }
+
+    private static final long STEP = Long.MAX_VALUE / 1_000_000;
+
+    @Test
+    public void run11() {
+        OptionValues options = getInitialOptions();
+        ResolvedJavaMethod method = getResolvedJavaMethod("test");
+        Object receiver = null;
+        long testIteration = 0;
+        for (long l = Long.MIN_VALUE;; l += STEP) {
+            double x = Double.longBitsToDouble(l);
+            double y = x;
+            testOne(options, method, receiver, testIteration, l, x, y);
+            y = l < 0 ? Double.longBitsToDouble(Long.MAX_VALUE + l) : Double.longBitsToDouble(Long.MAX_VALUE - l);
+            testOne(options, method, receiver, testIteration, l, x, y);
+            if (Long.MAX_VALUE - STEP < l) {
+                break;
+            }
+            testIteration++;
+        }
+    }
+
+    @Test
+    public void run12() {
+        long l = 4355599093822972882L;
+        double x = Double.longBitsToDouble(l);
+        OptionValues options = getInitialOptions();
+        ResolvedJavaMethod method = getResolvedJavaMethod("test");
+        Object receiver = null;
+        testOne(options, method, receiver, 1, l, x, x);
+    }
+
+    private void testOne(OptionValues options, ResolvedJavaMethod method, Object receiver, long testIteration, long l, double x, double y) throws AssertionError {
+        Result expect = executeExpected(method, receiver, x, y);
+        try {
+            testAgainstExpected(options, method, expect, EMPTY, receiver, x, y);
+        } catch (AssertionError e) {
+            throw new AssertionError(String.format("%d: While testing %g [long: %d, hex: %x]", testIteration, x, l, l), e);
+        }
+    }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_sin.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_sin.java	Fri Mar 16 22:59:32 2018 -0700
@@ -22,13 +22,14 @@
  */
 package org.graalvm.compiler.jtt.lang;
 
+import org.graalvm.compiler.options.OptionValues;
 import org.junit.Test;
 
-import org.graalvm.compiler.jtt.JTTTest;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
 
 /*
  */
-public class Math_sin extends JTTTest {
+public class Math_sin extends UnaryMath {
 
     @SuppressWarnings("serial")
     public static class NaN extends Throwable {
@@ -83,4 +84,10 @@
         runTest("test", 0.0d);
     }
 
+    @Test
+    public void run5() {
+        OptionValues options = getInitialOptions();
+        ResolvedJavaMethod method = getResolvedJavaMethod("test");
+        testManyValues(options, method);
+    }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_sqrt.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_sqrt.java	Fri Mar 16 22:59:32 2018 -0700
@@ -22,13 +22,14 @@
  */
 package org.graalvm.compiler.jtt.lang;
 
+import org.graalvm.compiler.options.OptionValues;
 import org.junit.Test;
 
-import org.graalvm.compiler.jtt.JTTTest;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
 
 /*
  */
-public class Math_sqrt extends JTTTest {
+public class Math_sqrt extends UnaryMath {
 
     @SuppressWarnings("serial")
     public static class NaN extends Throwable {
@@ -78,4 +79,10 @@
         runTest("test", -0.0d);
     }
 
+    @Test
+    public void run7() {
+        OptionValues options = getInitialOptions();
+        ResolvedJavaMethod method = getResolvedJavaMethod("test");
+        testManyValues(options, method);
+    }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_tan.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/Math_tan.java	Fri Mar 16 22:59:32 2018 -0700
@@ -22,13 +22,14 @@
  */
 package org.graalvm.compiler.jtt.lang;
 
+import org.graalvm.compiler.options.OptionValues;
 import org.junit.Test;
 
-import org.graalvm.compiler.jtt.JTTTest;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
 
 /*
  */
-public class Math_tan extends JTTTest {
+public class Math_tan extends UnaryMath {
 
     @SuppressWarnings("serial")
     public static class NaN extends Throwable {
@@ -68,4 +69,10 @@
         runTest("test", 0.0d);
     }
 
+    @Test
+    public void run5() {
+        OptionValues options = getInitialOptions();
+        ResolvedJavaMethod method = getResolvedJavaMethod("test");
+        testManyValues(options, method);
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/lang/UnaryMath.java	Fri Mar 16 22:59:32 2018 -0700
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2011, 2012, 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.jtt.lang;
+
+import org.graalvm.compiler.jtt.JTTTest;
+import org.graalvm.compiler.options.OptionValues;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+public abstract class UnaryMath extends JTTTest {
+
+    private static final long STEP = Long.MAX_VALUE / 1_000_000;
+
+    /**
+     * Tests a unary {@link Math} method on a wide range of values.
+     */
+    void testManyValues(OptionValues options, ResolvedJavaMethod method) throws AssertionError {
+        if (!Java8OrEarlier) {
+            /*
+             * GR-8276: Allow for variance on JVMCI > 8 until a JVMCI version that includes
+             * https://github.com/graalvm/graal-jvmci-8/commit/
+             * c86fb66f86b8d52a08dd2495d34879d3730f9987 or Graal has stubs that a monotonic with
+             * other HotSpot implementations of these Math routines.
+             */
+            ulpDelta = 2D;
+        } else {
+            /*
+             * Forces the assertion message shows the ulps by which a computed result is wrong.
+             */
+            ulpDelta = 0D;
+        }
+        Object receiver = null;
+        long testIteration = 0;
+        for (long l = Long.MIN_VALUE;; l += STEP) {
+            double d = Double.longBitsToDouble(l);
+            Result expect = executeExpected(method, receiver, d);
+            try {
+                testAgainstExpected(options, method, expect, EMPTY, receiver, d);
+                testIteration++;
+            } catch (AssertionError e) {
+                throw new AssertionError(String.format("%d: While testing %g [long: %d, hex: %x]", testIteration, d, l, l), e);
+            }
+            if (Long.MAX_VALUE - STEP < l) {
+                break;
+            }
+        }
+    }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64Call.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64Call.java	Fri Mar 16 22:59:32 2018 -0700
@@ -227,13 +227,15 @@
         masm.ensureUniquePC();
     }
 
-    public static void directJmp(CompilationResultBuilder crb, AArch64MacroAssembler masm, InvokeTarget target) {
-        int before = masm.position();
-        // Address is fixed up later by c++ code.
-        masm.jmp();
-        int after = masm.position();
-        crb.recordDirectCall(before, after, target, null);
-        masm.ensureUniquePC();
+    public static void directJmp(CompilationResultBuilder crb, AArch64MacroAssembler masm, InvokeTarget callTarget) {
+        try (AArch64MacroAssembler.ScratchRegister scratch = masm.getScratchRegister()) {
+            int before = masm.position();
+            masm.movNativeAddress(scratch.getRegister(), 0L);
+            masm.jmp(scratch.getRegister());
+            int after = masm.position();
+            crb.recordDirectCall(before, after, callTarget, null);
+            masm.ensureUniquePC();
+        }
     }
 
     public static void indirectJmp(CompilationResultBuilder crb, AArch64MacroAssembler masm, Register dst, InvokeTarget target) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ArrayCompareToOp.java	Fri Mar 16 22:59:32 2018 -0700
@@ -0,0 +1,595 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.lir.amd64;
+
+import static jdk.vm.ci.amd64.AMD64.k7;
+import static jdk.vm.ci.amd64.AMD64.rax;
+import static jdk.vm.ci.amd64.AMD64.rcx;
+import static jdk.vm.ci.amd64.AMD64.rdx;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Field;
+import java.util.EnumSet;
+
+import org.graalvm.compiler.asm.Label;
+import org.graalvm.compiler.asm.amd64.AMD64Address;
+import org.graalvm.compiler.asm.amd64.AMD64Address.Scale;
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.AvxVectorLen;
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.ConditionFlag;
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
+
+import jdk.vm.ci.amd64.AMD64;
+import jdk.vm.ci.amd64.AMD64.CPUFeature;
+import jdk.vm.ci.amd64.AMD64Kind;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.Value;
+import sun.misc.Unsafe;
+
+/**
+ * Emits code which compares two arrays lexicographically. If the CPU supports any vector
+ * instructions specialized code is emitted to leverage these instructions.
+ */
+@Opcode("ARRAY_COMPARE_TO")
+public final class AMD64ArrayCompareToOp extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64ArrayCompareToOp> TYPE = LIRInstructionClass.create(AMD64ArrayCompareToOp.class);
+
+    private final JavaKind kind1;
+    private final JavaKind kind2;
+    private final int array1BaseOffset;
+    private final int array2BaseOffset;
+
+    @Def({REG}) protected Value resultValue;
+    @Alive({REG}) protected Value array1Value;
+    @Alive({REG}) protected Value array2Value;
+    @Alive({REG}) protected Value length1Value;
+    @Alive({REG}) protected Value length2Value;
+    @Temp({REG}) protected Value temp1;
+    @Temp({REG}) protected Value temp2;
+
+    @Temp({REG, ILLEGAL}) protected Value vectorTemp1;
+
+    public AMD64ArrayCompareToOp(LIRGeneratorTool tool, JavaKind kind1, JavaKind kind2, Value result, Value array1, Value array2, Value length1, Value length2) {
+        super(TYPE);
+        this.kind1 = kind1;
+        this.kind2 = kind2;
+
+        // Both offsets should be the same but better be safe than sorry.
+        Class<?> array1Class = Array.newInstance(kind1.toJavaClass(), 0).getClass();
+        Class<?> array2Class = Array.newInstance(kind2.toJavaClass(), 0).getClass();
+        this.array1BaseOffset = UNSAFE.arrayBaseOffset(array1Class);
+        this.array2BaseOffset = UNSAFE.arrayBaseOffset(array2Class);
+
+        this.resultValue = result;
+        this.array1Value = array1;
+        this.array2Value = array2;
+        this.length1Value = length1;
+        this.length2Value = length2;
+
+        // Allocate some temporaries.
+        this.temp1 = tool.newVariable(LIRKind.unknownReference(tool.target().arch.getWordKind()));
+        this.temp2 = tool.newVariable(LIRKind.unknownReference(tool.target().arch.getWordKind()));
+
+        // We only need the vector temporaries if we generate SSE code.
+        if (supportsSSE42(tool.target())) {
+            this.vectorTemp1 = tool.newVariable(LIRKind.value(AMD64Kind.DOUBLE));
+        } else {
+            this.vectorTemp1 = Value.ILLEGAL;
+        }
+    }
+
+    private static boolean supportsSSE42(TargetDescription target) {
+        AMD64 arch = (AMD64) target.arch;
+        return arch.getFeatures().contains(CPUFeature.SSE4_2);
+    }
+
+    private static boolean supportsAVX2(TargetDescription target) {
+        AMD64 arch = (AMD64) target.arch;
+        return arch.getFeatures().contains(CPUFeature.AVX2);
+    }
+
+    private static boolean supportsAVX512VLBW(TargetDescription target) {
+        AMD64 arch = (AMD64) target.arch;
+        EnumSet<CPUFeature> features = arch.getFeatures();
+        return features.contains(CPUFeature.AVX512BW) && features.contains(CPUFeature.AVX512VL);
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        Register result = asRegister(resultValue);
+        Register str1 = asRegister(temp1);
+        Register str2 = asRegister(temp2);
+
+        // Load array base addresses.
+        masm.leaq(str1, new AMD64Address(asRegister(array1Value), array1BaseOffset));
+        masm.leaq(str2, new AMD64Address(asRegister(array2Value), array2BaseOffset));
+        Register cnt1 = asRegister(length1Value);
+        Register cnt2 = asRegister(length2Value);
+
+        // Checkstyle: stop
+        Label LENGTH_DIFF_LABEL = new Label();
+        Label POP_LABEL = new Label();
+        Label DONE_LABEL = new Label();
+        Label WHILE_HEAD_LABEL = new Label();
+        Label COMPARE_WIDE_VECTORS_LOOP_FAILED = new Label(); // used only _LP64 && AVX3
+        int stride, stride2;
+        int adr_stride = -1;
+        int adr_stride1 = -1;
+        int adr_stride2 = -1;
+        // Checkstyle: resume
+        int stride2x2 = 0x40;
+        AMD64Address.Scale scale = null;
+        AMD64Address.Scale scale1 = null;
+        AMD64Address.Scale scale2 = null;
+
+        // if (ae != StrIntrinsicNode::LL) {
+        if (kind1 == JavaKind.Byte && kind2 == JavaKind.Byte) {
+            stride2x2 = 0x20;
+        }
+
+        // if (ae == StrIntrinsicNode::LU || ae == StrIntrinsicNode::UL) {
+        if (kind1 != kind2) {
+            masm.shrl(cnt2, 1);
+        }
+        // Compute the minimum of the string lengths and the
+        // difference of the string lengths (stack).
+        // Do the conditional move stuff
+        masm.movl(result, cnt1);
+        masm.subl(cnt1, cnt2);
+        masm.push(cnt1);
+        masm.cmovl(ConditionFlag.LessEqual, cnt2, result);    // cnt2 = min(cnt1, cnt2)
+
+        // Is the minimum length zero?
+        masm.testl(cnt2, cnt2);
+        masm.jcc(ConditionFlag.Zero, LENGTH_DIFF_LABEL);
+        // if (ae == StrIntrinsicNode::LL) {
+        if (kind1 == JavaKind.Byte && kind2 == JavaKind.Byte) {
+            // Load first bytes
+            masm.movzbl(result, new AMD64Address(str1, 0));  // result = str1[0]
+            masm.movzbl(cnt1, new AMD64Address(str2, 0));    // cnt1 = str2[0]
+            // } else if (ae == StrIntrinsicNode::UU) {
+        } else if (kind1 == JavaKind.Char && kind2 == JavaKind.Char) {
+            // Load first characters
+            masm.movzwl(result, new AMD64Address(str1, 0));
+            masm.movzwl(cnt1, new AMD64Address(str2, 0));
+        } else {
+            masm.movzbl(result, new AMD64Address(str1, 0));
+            masm.movzwl(cnt1, new AMD64Address(str2, 0));
+        }
+        masm.subl(result, cnt1);
+        masm.jcc(ConditionFlag.NotZero, POP_LABEL);
+
+        // if (ae == StrIntrinsicNode::UU) {
+        if (kind1 == JavaKind.Char && kind2 == JavaKind.Char) {
+            // Divide length by 2 to get number of chars
+            masm.shrl(cnt2, 1);
+        }
+        masm.cmpl(cnt2, 1);
+        masm.jcc(ConditionFlag.Equal, LENGTH_DIFF_LABEL);
+
+        // Check if the strings start at the same location and setup scale and stride
+        // if (ae == StrIntrinsicNode::LL || ae == StrIntrinsicNode::UU) {
+        if (kind1 == kind2) {
+            masm.cmpptr(str1, str2);
+            masm.jcc(ConditionFlag.Equal, LENGTH_DIFF_LABEL);
+            // if (ae == StrIntrinsicNode::LL) {
+            if (kind1 == JavaKind.Byte && kind2 == JavaKind.Byte) {
+                scale = AMD64Address.Scale.Times1;
+                stride = 16;
+            } else {
+                scale = AMD64Address.Scale.Times2;
+                stride = 8;
+            }
+        } else {
+            scale1 = AMD64Address.Scale.Times1;
+            scale2 = AMD64Address.Scale.Times2;
+            // scale not used
+            stride = 8;
+        }
+
+        // if (UseAVX >= 2 && UseSSE42Intrinsics) {
+        if (supportsAVX2(crb.target) && supportsSSE42(crb.target)) {
+            Register vec1 = asRegister(vectorTemp1, AMD64Kind.DOUBLE);
+
+            // Checkstyle: stop
+            Label COMPARE_WIDE_VECTORS = new Label();
+            Label VECTOR_NOT_EQUAL = new Label();
+            Label COMPARE_WIDE_TAIL = new Label();
+            Label COMPARE_SMALL_STR = new Label();
+            Label COMPARE_WIDE_VECTORS_LOOP = new Label();
+            Label COMPARE_16_CHARS = new Label();
+            Label COMPARE_INDEX_CHAR = new Label();
+            Label COMPARE_WIDE_VECTORS_LOOP_AVX2 = new Label();
+            Label COMPARE_TAIL_LONG = new Label();
+            Label COMPARE_WIDE_VECTORS_LOOP_AVX3 = new Label();  // used only _LP64 && AVX3
+            // Checkstyle: resume
+
+            int pcmpmask = 0x19;
+            // if (ae == StrIntrinsicNode::LL) {
+            if (kind1 == JavaKind.Byte && kind2 == JavaKind.Byte) {
+                pcmpmask &= ~0x01;
+            }
+
+            // Setup to compare 16-chars (32-bytes) vectors,
+            // start from first character again because it has aligned address.
+            // if (ae == StrIntrinsicNode::LL) {
+            if (kind1 == JavaKind.Byte && kind2 == JavaKind.Byte) {
+                stride2 = 32;
+            } else {
+                stride2 = 16;
+            }
+            // if (ae == StrIntrinsicNode::LL || ae == StrIntrinsicNode::UU) {
+            if (kind1 == kind2) {
+                adr_stride = stride << scale.log2;
+            } else {
+                adr_stride1 = 8;  // stride << scale1;
+                adr_stride2 = 16; // stride << scale2;
+            }
+
+            assert result.equals(rax) && cnt2.equals(rdx) && cnt1.equals(rcx) : "pcmpestri";
+            // rax and rdx are used by pcmpestri as elements counters
+            masm.movl(result, cnt2);
+            masm.andl(cnt2, ~(stride2 - 1));   // cnt2 holds the vector count
+            masm.jcc(ConditionFlag.Zero, COMPARE_TAIL_LONG);
+
+            // fast path : compare first 2 8-char vectors.
+            masm.bind(COMPARE_16_CHARS);
+            // if (ae == StrIntrinsicNode::LL || ae == StrIntrinsicNode::UU) {
+            if (kind1 == kind2) {
+                masm.movdqu(vec1, new AMD64Address(str1, 0));
+            } else {
+                masm.pmovzxbw(vec1, new AMD64Address(str1, 0));
+            }
+            masm.pcmpestri(vec1, new AMD64Address(str2, 0), pcmpmask);
+            masm.jccb(ConditionFlag.Below, COMPARE_INDEX_CHAR);
+
+            // if (ae == StrIntrinsicNode::LL || ae == StrIntrinsicNode::UU) {
+            if (kind1 == kind2) {
+                masm.movdqu(vec1, new AMD64Address(str1, adr_stride));
+                masm.pcmpestri(vec1, new AMD64Address(str2, adr_stride), pcmpmask);
+            } else {
+                masm.pmovzxbw(vec1, new AMD64Address(str1, adr_stride1));
+                masm.pcmpestri(vec1, new AMD64Address(str2, adr_stride2), pcmpmask);
+            }
+            masm.jccb(ConditionFlag.AboveEqual, COMPARE_WIDE_VECTORS);
+            masm.addl(cnt1, stride);
+
+            // Compare the characters at index in cnt1
+            masm.bind(COMPARE_INDEX_CHAR); // cnt1 has the offset of the mismatching character
+            loadNextElements(masm, result, cnt2, str1, str2, scale, scale1, scale2, cnt1);
+            masm.subl(result, cnt2);
+            masm.jmp(POP_LABEL);
+
+            // Setup the registers to start vector comparison loop
+            masm.bind(COMPARE_WIDE_VECTORS);
+            // if (ae == StrIntrinsicNode::LL || ae == StrIntrinsicNode::UU) {
+            if (kind1 == kind2) {
+                masm.leaq(str1, new AMD64Address(str1, result, scale));
+                masm.leaq(str2, new AMD64Address(str2, result, scale));
+            } else {
+                masm.leaq(str1, new AMD64Address(str1, result, scale1));
+                masm.leaq(str2, new AMD64Address(str2, result, scale2));
+            }
+            masm.subl(result, stride2);
+            masm.subl(cnt2, stride2);
+            masm.jcc(ConditionFlag.Zero, COMPARE_WIDE_TAIL);
+            masm.negq(result);
+
+            // In a loop, compare 16-chars (32-bytes) at once using (vpxor+vptest)
+            masm.bind(COMPARE_WIDE_VECTORS_LOOP);
+
+            // if (VM_Version::supports_avx512vlbw()) { // trying 64 bytes fast loop
+            if (supportsAVX512VLBW(crb.target)) {
+                masm.cmpl(cnt2, stride2x2);
+                masm.jccb(ConditionFlag.Below, COMPARE_WIDE_VECTORS_LOOP_AVX2);
+                masm.testl(cnt2, stride2x2 - 1);   // cnt2 holds the vector count
+                // means we cannot subtract by 0x40
+                masm.jccb(ConditionFlag.NotZero, COMPARE_WIDE_VECTORS_LOOP_AVX2);
+
+                masm.bind(COMPARE_WIDE_VECTORS_LOOP_AVX3); // the hottest loop
+                // if (ae == StrIntrinsicNode::LL || ae == StrIntrinsicNode::UU) {
+                if (kind1 == kind2) {
+                    masm.evmovdquq(vec1, new AMD64Address(str1, result, scale), AvxVectorLen.AVX_512bit);
+                    // k7 == 11..11, if operands equal, otherwise k7 has some 0
+                    masm.evpcmpeqb(k7, vec1, new AMD64Address(str2, result, scale), AvxVectorLen.AVX_512bit);
+                } else {
+                    masm.vpmovzxbw(vec1, new AMD64Address(str1, result, scale1), AvxVectorLen.AVX_512bit);
+                    // k7 == 11..11, if operands equal, otherwise k7 has some 0
+                    masm.evpcmpeqb(k7, vec1, new AMD64Address(str2, result, scale2), AvxVectorLen.AVX_512bit);
+                }
+                masm.kortestql(k7, k7);
+                masm.jcc(ConditionFlag.AboveEqual, COMPARE_WIDE_VECTORS_LOOP_FAILED);     // miscompare
+                masm.addq(result, stride2x2);  // update since we already compared at this addr
+                masm.subl(cnt2, stride2x2);      // and sub the size too
+                masm.jccb(ConditionFlag.NotZero, COMPARE_WIDE_VECTORS_LOOP_AVX3);
+
+                masm.vpxor(vec1, vec1, vec1);
+                masm.jmpb(COMPARE_WIDE_TAIL);
+            }
+
+            masm.bind(COMPARE_WIDE_VECTORS_LOOP_AVX2);
+            // if (ae == StrIntrinsicNode::LL || ae == StrIntrinsicNode::UU) {
+            if (kind1 == kind2) {
+                masm.vmovdqu(vec1, new AMD64Address(str1, result, scale));
+                masm.vpxor(vec1, vec1, new AMD64Address(str2, result, scale));
+            } else {
+                masm.vpmovzxbw(vec1, new AMD64Address(str1, result, scale1), AvxVectorLen.AVX_256bit);
+                masm.vpxor(vec1, vec1, new AMD64Address(str2, result, scale2));
+            }
+            masm.vptest(vec1, vec1);
+            masm.jcc(ConditionFlag.NotZero, VECTOR_NOT_EQUAL);
+            masm.addq(result, stride2);
+            masm.subl(cnt2, stride2);
+            masm.jcc(ConditionFlag.NotZero, COMPARE_WIDE_VECTORS_LOOP);
+            // clean upper bits of YMM registers
+            masm.vpxor(vec1, vec1, vec1);
+
+            // compare wide vectors tail
+            masm.bind(COMPARE_WIDE_TAIL);
+            masm.testq(result, result);
+            masm.jcc(ConditionFlag.Zero, LENGTH_DIFF_LABEL);
+
+            masm.movl(result, stride2);
+            masm.movl(cnt2, result);
+            masm.negq(result);
+            masm.jmp(COMPARE_WIDE_VECTORS_LOOP_AVX2);
+
+            // Identifies the mismatching (higher or lower)16-bytes in the 32-byte vectors.
+            masm.bind(VECTOR_NOT_EQUAL);
+            // clean upper bits of YMM registers
+            masm.vpxor(vec1, vec1, vec1);
+            // if (ae == StrIntrinsicNode::LL || ae == StrIntrinsicNode::UU) {
+            if (kind1 == kind2) {
+                masm.leaq(str1, new AMD64Address(str1, result, scale));
+                masm.leaq(str2, new AMD64Address(str2, result, scale));
+            } else {
+                masm.leaq(str1, new AMD64Address(str1, result, scale1));
+                masm.leaq(str2, new AMD64Address(str2, result, scale2));
+            }
+            masm.jmp(COMPARE_16_CHARS);
+
+            // Compare tail chars, length between 1 to 15 chars
+            masm.bind(COMPARE_TAIL_LONG);
+            masm.movl(cnt2, result);
+            masm.cmpl(cnt2, stride);
+            masm.jcc(ConditionFlag.Less, COMPARE_SMALL_STR);
+
+            // if (ae == StrIntrinsicNode::LL || ae == StrIntrinsicNode::UU) {
+            if (kind1 == kind2) {
+                masm.movdqu(vec1, new AMD64Address(str1, 0));
+            } else {
+                masm.pmovzxbw(vec1, new AMD64Address(str1, 0));
+            }
+            masm.pcmpestri(vec1, new AMD64Address(str2, 0), pcmpmask);
+            masm.jcc(ConditionFlag.Below, COMPARE_INDEX_CHAR);
+            masm.subq(cnt2, stride);
+            masm.jcc(ConditionFlag.Zero, LENGTH_DIFF_LABEL);
+            // if (ae == StrIntrinsicNode::LL || ae == StrIntrinsicNode::UU) {
+            if (kind1 == kind2) {
+                masm.leaq(str1, new AMD64Address(str1, result, scale));
+                masm.leaq(str2, new AMD64Address(str2, result, scale));
+            } else {
+                masm.leaq(str1, new AMD64Address(str1, result, scale1));
+                masm.leaq(str2, new AMD64Address(str2, result, scale2));
+            }
+            masm.negq(cnt2);
+            masm.jmpb(WHILE_HEAD_LABEL);
+
+            masm.bind(COMPARE_SMALL_STR);
+        } else if (supportsSSE42(crb.target)) {
+            Register vec1 = asRegister(vectorTemp1, AMD64Kind.DOUBLE);
+
+            // Checkstyle: stop
+            Label COMPARE_WIDE_VECTORS = new Label();
+            Label VECTOR_NOT_EQUAL = new Label();
+            Label COMPARE_TAIL = new Label();
+            // Checkstyle: resume
+            int pcmpmask = 0x19;
+            // Setup to compare 8-char (16-byte) vectors,
+            // start from first character again because it has aligned address.
+            masm.movl(result, cnt2);
+            masm.andl(cnt2, ~(stride - 1));   // cnt2 holds the vector count
+            // if (ae == StrIntrinsicNode::LL) {
+            if (kind1 == JavaKind.Byte && kind2 == JavaKind.Byte) {
+                pcmpmask &= ~0x01;
+            }
+            masm.jcc(ConditionFlag.Zero, COMPARE_TAIL);
+            // if (ae == StrIntrinsicNode::LL || ae == StrIntrinsicNode::UU) {
+            if (kind1 == kind2) {
+                masm.leaq(str1, new AMD64Address(str1, result, scale));
+                masm.leaq(str2, new AMD64Address(str2, result, scale));
+            } else {
+                masm.leaq(str1, new AMD64Address(str1, result, scale1));
+                masm.leaq(str2, new AMD64Address(str2, result, scale2));
+            }
+            masm.negq(result);
+
+            // pcmpestri
+            // inputs:
+            // vec1- substring
+            // rax - negative string length (elements count)
+            // mem - scanned string
+            // rdx - string length (elements count)
+            // pcmpmask - cmp mode: 11000 (string compare with negated result)
+            // + 00 (unsigned bytes) or + 01 (unsigned shorts)
+            // outputs:
+            // rcx - first mismatched element index
+            assert result.equals(rax) && cnt2.equals(rdx) && cnt1.equals(rcx) : "pcmpestri";
+
+            masm.bind(COMPARE_WIDE_VECTORS);
+            // if (ae == StrIntrinsicNode::LL || ae == StrIntrinsicNode::UU) {
+            if (kind1 == kind2) {
+                masm.movdqu(vec1, new AMD64Address(str1, result, scale));
+                masm.pcmpestri(vec1, new AMD64Address(str2, result, scale), pcmpmask);
+            } else {
+                masm.pmovzxbw(vec1, new AMD64Address(str1, result, scale1));
+                masm.pcmpestri(vec1, new AMD64Address(str2, result, scale2), pcmpmask);
+            }
+            // After pcmpestri cnt1(rcx) contains mismatched element index
+
+            masm.jccb(ConditionFlag.Below, VECTOR_NOT_EQUAL);  // CF==1
+            masm.addq(result, stride);
+            masm.subq(cnt2, stride);
+            masm.jccb(ConditionFlag.NotZero, COMPARE_WIDE_VECTORS);
+
+            // compare wide vectors tail
+            masm.testq(result, result);
+            masm.jcc(ConditionFlag.Zero, LENGTH_DIFF_LABEL);
+
+            masm.movl(cnt2, stride);
+            masm.movl(result, stride);
+            masm.negq(result);
+            // if (ae == StrIntrinsicNode::LL || ae == StrIntrinsicNode::UU) {
+            if (kind1 == kind2) {
+                masm.movdqu(vec1, new AMD64Address(str1, result, scale));
+                masm.pcmpestri(vec1, new AMD64Address(str2, result, scale), pcmpmask);
+            } else {
+                masm.pmovzxbw(vec1, new AMD64Address(str1, result, scale1));
+                masm.pcmpestri(vec1, new AMD64Address(str2, result, scale2), pcmpmask);
+            }
+            masm.jccb(ConditionFlag.AboveEqual, LENGTH_DIFF_LABEL);
+
+            // Mismatched characters in the vectors
+            masm.bind(VECTOR_NOT_EQUAL);
+            masm.addq(cnt1, result);
+            loadNextElements(masm, result, cnt2, str1, str2, scale, scale1, scale2, cnt1);
+            masm.subl(result, cnt2);
+            masm.jmpb(POP_LABEL);
+
+            masm.bind(COMPARE_TAIL); // limit is zero
+            masm.movl(cnt2, result);
+            // Fallthru to tail compare
+        }
+
+        // Shift str2 and str1 to the end of the arrays, negate min
+        // if (ae == StrIntrinsicNode::LL || ae == StrIntrinsicNode::UU) {
+        if (kind1 == kind2) {
+            masm.leaq(str1, new AMD64Address(str1, cnt2, scale));
+            masm.leaq(str2, new AMD64Address(str2, cnt2, scale));
+        } else {
+            masm.leaq(str1, new AMD64Address(str1, cnt2, scale1));
+            masm.leaq(str2, new AMD64Address(str2, cnt2, scale2));
+        }
+        masm.decrementl(cnt2);  // first character was compared already
+        masm.negq(cnt2);
+
+        // Compare the rest of the elements
+        masm.bind(WHILE_HEAD_LABEL);
+        loadNextElements(masm, result, cnt1, str1, str2, scale, scale1, scale2, cnt2);
+        masm.subl(result, cnt1);
+        masm.jccb(ConditionFlag.NotZero, POP_LABEL);
+        masm.incrementq(cnt2, 1);
+        masm.jccb(ConditionFlag.NotZero, WHILE_HEAD_LABEL);
+
+        // Strings are equal up to min length. Return the length difference.
+        masm.bind(LENGTH_DIFF_LABEL);
+        masm.pop(result);
+        // if (ae == StrIntrinsicNode::UU) {
+        if (kind1 == JavaKind.Char && kind2 == JavaKind.Char) {
+            // Divide diff by 2 to get number of chars
+            masm.sarl(result, 1);
+        }
+        masm.jmpb(DONE_LABEL);
+
+        // if (VM_Version::supports_avx512vlbw()) {
+        if (supportsAVX512VLBW(crb.target)) {
+            masm.bind(COMPARE_WIDE_VECTORS_LOOP_FAILED);
+
+            masm.kmovql(cnt1, k7);
+            masm.notq(cnt1);
+            masm.bsfq(cnt2, cnt1);
+            // if (ae != StrIntrinsicNode::LL) {
+            if (kind1 != JavaKind.Byte && kind2 != JavaKind.Byte) {
+                // Divide diff by 2 to get number of chars
+                masm.sarl(cnt2, 1);
+            }
+            masm.addq(result, cnt2);
+            // if (ae == StrIntrinsicNode::LL) {
+            if (kind1 == JavaKind.Byte && kind2 == JavaKind.Byte) {
+                masm.movzbl(cnt1, new AMD64Address(str2, result, Scale.Times1));
+                masm.movzbl(result, new AMD64Address(str1, result, Scale.Times1));
+            } else if (kind1 == JavaKind.Char && kind2 == JavaKind.Char) {
+                masm.movzwl(cnt1, new AMD64Address(str2, result, scale));
+                masm.movzwl(result, new AMD64Address(str1, result, scale));
+            } else {
+                masm.movzwl(cnt1, new AMD64Address(str2, result, scale2));
+                masm.movzbl(result, new AMD64Address(str1, result, scale1));
+            }
+            masm.subl(result, cnt1);
+            masm.jmpb(POP_LABEL);
+        }
+
+        // Discard the stored length difference
+        masm.bind(POP_LABEL);
+        masm.pop(cnt1);
+
+        // That's it
+        masm.bind(DONE_LABEL);
+        // if (ae == StrIntrinsicNode::UL) {
+        if (kind1 == JavaKind.Char && kind2 == JavaKind.Byte) {
+            masm.negl(result);
+        }
+    }
+
+    private void loadNextElements(AMD64MacroAssembler masm, Register elem1, Register elem2, Register str1, Register str2,
+                    AMD64Address.Scale scale, AMD64Address.Scale scale1,
+                    AMD64Address.Scale scale2, Register index) {
+        // if (ae == StrIntrinsicNode::LL) {
+        if (kind1 == JavaKind.Byte && kind2 == JavaKind.Byte) {
+            masm.movzbl(elem1, new AMD64Address(str1, index, scale, 0));
+            masm.movzbl(elem2, new AMD64Address(str2, index, scale, 0));
+            // } else if (ae == StrIntrinsicNode::UU) {
+        } else if (kind1 == JavaKind.Char && kind2 == JavaKind.Char) {
+            masm.movzwl(elem1, new AMD64Address(str1, index, scale, 0));
+            masm.movzwl(elem2, new AMD64Address(str2, index, scale, 0));
+        } else {
+            masm.movzbl(elem1, new AMD64Address(str1, index, scale1, 0));
+            masm.movzwl(elem2, new AMD64Address(str2, index, scale2, 0));
+        }
+    }
+
+    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);
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64LFenceOp.java	Fri Mar 16 22:59:32 2018 -0700
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2018, 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.lir.amd64;
+
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+@Opcode("LFENCE")
+public final class AMD64LFenceOp extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64LFenceOp> TYPE = LIRInstructionClass.create(AMD64LFenceOp.class);
+
+    public AMD64LFenceOp() {
+        super(TYPE);
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler asm) {
+        asm.lfence();
+    }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64Move.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64Move.java	Fri Mar 16 22:59:32 2018 -0700
@@ -22,6 +22,11 @@
  */
 package org.graalvm.compiler.lir.amd64;
 
+import static java.lang.Double.doubleToRawLongBits;
+import static java.lang.Float.floatToRawIntBits;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
+import static jdk.vm.ci.code.ValueUtil.isStackSlot;
 import static org.graalvm.compiler.asm.amd64.AMD64Assembler.ConditionFlag.Equal;
 import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.COMPOSITE;
@@ -33,21 +38,16 @@
 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 static java.lang.Double.doubleToRawLongBits;
-import static java.lang.Float.floatToRawIntBits;
-import static jdk.vm.ci.code.ValueUtil.asRegister;
-import static jdk.vm.ci.code.ValueUtil.isRegister;
-import static jdk.vm.ci.code.ValueUtil.isStackSlot;
 
 import org.graalvm.compiler.asm.Label;
-import org.graalvm.compiler.core.common.CompressEncoding;
-import org.graalvm.compiler.core.common.LIRKind;
-import org.graalvm.compiler.core.common.NumUtil;
 import org.graalvm.compiler.asm.amd64.AMD64Address;
 import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MIOp;
 import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MOp;
 import org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize;
 import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.core.common.CompressEncoding;
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.NumUtil;
 import org.graalvm.compiler.core.common.spi.LIRKindTool;
 import org.graalvm.compiler.core.common.type.DataPointerConstant;
 import org.graalvm.compiler.debug.GraalError;
@@ -59,6 +59,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.amd64.AMD64;
 import jdk.vm.ci.amd64.AMD64Kind;
@@ -763,7 +764,7 @@
 
         @Def({REG, HINT}) private AllocatableValue result;
         @Use({REG, CONST}) private Value input;
-        @Alive({REG, ILLEGAL}) private AllocatableValue baseRegister;
+        @Alive({REG, ILLEGAL, UNINITIALIZED}) private AllocatableValue baseRegister;
 
         protected PointerCompressionOp(LIRInstructionClass<? extends PointerCompressionOp> type, AllocatableValue result, Value input,
                         AllocatableValue baseRegister, CompressEncoding encoding, boolean nonNull, LIRKindTool lirKindTool) {
@@ -777,8 +778,8 @@
             this.lirKindTool = lirKindTool;
         }
 
-        protected boolean hasBase(CompilationResultBuilder crb) {
-            return GeneratePIC.getValue(crb.getOptions()) || encoding.hasBase();
+        public static boolean hasBase(OptionValues options, CompressEncoding encoding) {
+            return GeneratePIC.getValue(options) || encoding.hasBase();
         }
 
         public final Value getInput() {
@@ -820,7 +821,7 @@
             move(lirKindTool.getObjectKind(), crb, masm);
 
             Register resReg = asRegister(getResult());
-            if (hasBase(crb)) {
+            if (hasBase(crb.getOptions(), encoding)) {
                 Register baseReg = getBaseRegister();
                 if (!nonNull) {
                     masm.testq(resReg, resReg);
@@ -852,15 +853,15 @@
         @Override
         public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
             move(lirKindTool.getNarrowOopKind(), crb, masm);
+            emitUncompressCode(masm, asRegister(getResult()), getShift(), hasBase(crb.getOptions(), encoding) ? getBaseRegister() : null, nonNull);
+        }
 
-            Register resReg = asRegister(getResult());
-            int shift = getShift();
+        public static void emitUncompressCode(AMD64MacroAssembler masm, Register resReg, int shift, Register baseReg, boolean nonNull) {
             if (shift != 0) {
                 masm.shlq(resReg, shift);
             }
 
-            if (hasBase(crb)) {
-                Register baseReg = getBaseRegister();
+            if (baseReg != null) {
                 if (nonNull) {
                     masm.addq(resReg, baseReg);
                     return;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/LIRInstructionClass.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/LIRInstructionClass.java	Fri Mar 16 22:59:32 2018 -0700
@@ -96,7 +96,11 @@
         try {
             Field field = clazz.getDeclaredField("TYPE");
             field.setAccessible(true);
-            return (LIRInstructionClass<T>) field.get(null);
+            LIRInstructionClass<T> result = (LIRInstructionClass<T>) field.get(null);
+            if (result == null) {
+                throw GraalError.shouldNotReachHere("TYPE field not initialized for class " + clazz.getTypeName());
+            }
+            return result;
         } catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e) {
             throw new RuntimeException(e);
         }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/GlobalLivenessInfo.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/GlobalLivenessInfo.java	Fri Mar 16 22:59:32 2018 -0700
@@ -53,7 +53,11 @@
         public final int[] emptySet;
 
         public Builder(LIR lir) {
-            info = new GlobalLivenessInfo(lir);
+            this(lir.numVariables(), lir.getControlFlowGraph().getBlocks().length);
+        }
+
+        public Builder(int numVariables, int numBlocks) {
+            info = new GlobalLivenessInfo(numVariables, numBlocks);
             emptySet = new int[0];
         }
 
@@ -97,10 +101,8 @@
     private final Value[][] blockToLocIn;
     private final Value[][] blockToLocOut;
 
-    private GlobalLivenessInfo(LIR lir) {
-        int numVariables = lir.numVariables();
+    private GlobalLivenessInfo(int numVariables, int numBlocks) {
         variables = new Variable[numVariables];
-        int numBlocks = lir.getControlFlowGraph().getBlocks().length;
         blockToVarIn = new int[numBlocks][];
         blockToVarOut = new int[numBlocks][];
         blockToLocIn = new Value[numBlocks][];
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceAssertions.java	Fri Mar 16 22:59:32 2018 -0700
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 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.lir.alloc.trace;
+
+import org.graalvm.compiler.core.common.alloc.Trace;
+import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
+
+/**
+ * A collection of assertions that are assumed to hold in various places of the Trace Register
+ * Allocation framework.
+ *
+ * The main goal is to document pieces of code that rely on specific properties of traces. In case
+ * an assumption is no longer valid, this makes it easy (assumed they are used correctly) to find
+ * places that need changes.
+ */
+final class TraceAssertions {
+
+    /**
+     * Asserts that variable indices are properly sorted.
+     */
+    public static boolean liveSetsAreSorted(GlobalLivenessInfo livenessInfo, AbstractBlockBase<?> block) {
+        return isSorted(livenessInfo.getBlockIn(block)) && isSorted(livenessInfo.getBlockOut(block));
+    }
+
+    private static boolean isSorted(int[] live) {
+        if (live.length == 0) {
+            return true;
+        }
+        int current = live[0];
+        for (int i = 1; i < live.length; i++) {
+            int last = current;
+            current = live[i];
+            if (current <= last) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Asserts that a trace head has only a single predecessor.
+     *
+     * This is not true for every trace-building algorithm (for example
+     * {@link TraceBuilderPhase.TraceBuilder#SingleBlock}).
+     */
+    public static boolean singleHeadPredecessor(Trace trace) {
+        return trace.getBlocks()[0].getPredecessorCount() == 1;
+    }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceGlobalMoveResolutionPhase.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceGlobalMoveResolutionPhase.java	Fri Mar 16 22:59:32 2018 -0700
@@ -84,32 +84,58 @@
         DebugContext debug = lir.getDebug();
         try (Indent indent = debug.logAndIndent("Trace global move resolution")) {
             for (Trace trace : resultTraces.getTraces()) {
-                for (AbstractBlockBase<?> fromBlock : trace.getBlocks()) {
-                    for (AbstractBlockBase<?> toBlock : fromBlock.getSuccessors()) {
-                        if (resultTraces.getTraceForBlock(fromBlock) != resultTraces.getTraceForBlock(toBlock)) {
-                            try (Indent indent0 = debug.logAndIndent("Handle trace edge from %s (Trace%d) to %s (Trace%d)", fromBlock, resultTraces.getTraceForBlock(fromBlock).getId(), toBlock,
-                                            resultTraces.getTraceForBlock(toBlock).getId())) {
+                resolveTrace(resultTraces, livenessInfo, lir, moveResolver, trace);
+            }
+        }
+    }
 
-                                final ArrayList<LIRInstruction> instructions;
-                                final int insertIdx;
-                                if (fromBlock.getSuccessorCount() == 1) {
-                                    instructions = lir.getLIRforBlock(fromBlock);
-                                    insertIdx = instructions.size() - 1;
-                                } else {
-                                    assert toBlock.getPredecessorCount() == 1;
-                                    instructions = lir.getLIRforBlock(toBlock);
-                                    insertIdx = 1;
-                                }
-
-                                moveResolver.setInsertPosition(instructions, insertIdx);
-                                resolveEdge(lir, livenessInfo, moveResolver, fromBlock, toBlock);
-                                moveResolver.resolveAndAppendMoves();
-                            }
-                        }
+    private static void resolveTrace(TraceBuilderResult resultTraces, GlobalLivenessInfo livenessInfo, LIR lir, TraceGlobalMoveResolver moveResolver, Trace trace) {
+        AbstractBlockBase<?>[] traceBlocks = trace.getBlocks();
+        int traceLength = traceBlocks.length;
+        // all but the last block
+        AbstractBlockBase<?> nextBlock = traceBlocks[0];
+        for (int i = 1; i < traceLength; i++) {
+            AbstractBlockBase<?> fromBlock = nextBlock;
+            nextBlock = traceBlocks[i];
+            if (fromBlock.getSuccessorCount() > 1) {
+                for (AbstractBlockBase<?> toBlock : fromBlock.getSuccessors()) {
+                    if (toBlock != nextBlock) {
+                        interTraceEdge(resultTraces, livenessInfo, lir, moveResolver, fromBlock, toBlock);
                     }
                 }
             }
         }
+        // last block
+        assert nextBlock == traceBlocks[traceLength - 1];
+        for (AbstractBlockBase<?> toBlock : nextBlock.getSuccessors()) {
+            if (resultTraces.getTraceForBlock(nextBlock) != resultTraces.getTraceForBlock(toBlock)) {
+                interTraceEdge(resultTraces, livenessInfo, lir, moveResolver, nextBlock, toBlock);
+            }
+        }
+    }
+
+    @SuppressWarnings("try")
+    private static void interTraceEdge(TraceBuilderResult resultTraces, GlobalLivenessInfo livenessInfo, LIR lir, TraceGlobalMoveResolver moveResolver, AbstractBlockBase<?> fromBlock,
+                    AbstractBlockBase<?> toBlock) {
+        DebugContext debug = lir.getDebug();
+        try (Indent indent0 = debug.logAndIndent("Handle trace edge from %s (Trace%d) to %s (Trace%d)", fromBlock, resultTraces.getTraceForBlock(fromBlock).getId(), toBlock,
+                        resultTraces.getTraceForBlock(toBlock).getId())) {
+
+            final ArrayList<LIRInstruction> instructions;
+            final int insertIdx;
+            if (fromBlock.getSuccessorCount() == 1) {
+                instructions = lir.getLIRforBlock(fromBlock);
+                insertIdx = instructions.size() - 1;
+            } else {
+                assert toBlock.getPredecessorCount() == 1;
+                instructions = lir.getLIRforBlock(toBlock);
+                insertIdx = 1;
+            }
+
+            moveResolver.setInsertPosition(instructions, insertIdx);
+            resolveEdge(lir, livenessInfo, moveResolver, fromBlock, toBlock);
+            moveResolver.resolveAndAppendMoves();
+        }
     }
 
     private static void resolveEdge(LIR lir, GlobalLivenessInfo livenessInfo, TraceGlobalMoveResolver moveResolver, AbstractBlockBase<?> fromBlock, AbstractBlockBase<?> toBlock) {
@@ -129,6 +155,10 @@
         // GLI
         Value[] locFrom = livenessInfo.getOutLocation(fromBlock);
         Value[] locTo = livenessInfo.getInLocation(toBlock);
+        if (locFrom == locTo) {
+            // a strategy might reuse the locations array if locations are the same
+            return;
+        }
         assert locFrom.length == locTo.length;
 
         for (int i = 0; i < locFrom.length; i++) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceUtil.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceUtil.java	Fri Mar 16 22:59:32 2018 -0700
@@ -36,19 +36,6 @@
 
 public class TraceUtil {
 
-    public static AbstractBlockBase<?> getBestTraceInterPredecessor(TraceBuilderResult traceResult, AbstractBlockBase<?> block) {
-        AbstractBlockBase<?> bestPred = null;
-        int bestTraceId = traceResult.getTraceForBlock(block).getId();
-        for (AbstractBlockBase<?> pred : block.getPredecessors()) {
-            int predTraceId = traceResult.getTraceForBlock(pred).getId();
-            if (predTraceId < bestTraceId) {
-                bestPred = pred;
-                bestTraceId = predTraceId;
-            }
-        }
-        return bestPred;
-    }
-
     public static boolean isShadowedRegisterValue(Value value) {
         assert value != null;
         return value instanceof ShadowedRegisterValue;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TrivialTraceAllocator.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TrivialTraceAllocator.java	Fri Mar 16 22:59:32 2018 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 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
@@ -26,12 +26,13 @@
 import static org.graalvm.compiler.lir.LIRValueUtil.isVariable;
 import static org.graalvm.compiler.lir.alloc.trace.TraceUtil.isTrivialTrace;
 
+import java.util.Arrays;
 import java.util.EnumSet;
 
 import org.graalvm.compiler.core.common.alloc.Trace;
-import org.graalvm.compiler.core.common.alloc.TraceBuilderResult;
 import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
 import org.graalvm.compiler.lir.LIR;
+import org.graalvm.compiler.lir.LIRInstruction;
 import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
 import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
 import org.graalvm.compiler.lir.StandardOp.JumpOp;
@@ -47,68 +48,67 @@
  * Allocates a trivial trace i.e. a trace consisting of a single block with no instructions other
  * than the {@link LabelOp} and the {@link JumpOp}.
  */
-final class TrivialTraceAllocator extends TraceAllocationPhase<TraceAllocationPhase.TraceAllocationContext> {
+public final class TrivialTraceAllocator extends TraceAllocationPhase<TraceAllocationPhase.TraceAllocationContext> {
 
     @Override
     protected void run(TargetDescription target, LIRGenerationResult lirGenRes, Trace trace, TraceAllocationContext context) {
         LIR lir = lirGenRes.getLIR();
-        TraceBuilderResult resultTraces = context.resultTraces;
         assert isTrivialTrace(lir, trace) : "Not a trivial trace! " + trace;
         AbstractBlockBase<?> block = trace.getBlocks()[0];
-
-        AbstractBlockBase<?> pred = TraceUtil.getBestTraceInterPredecessor(resultTraces, block);
+        assert TraceAssertions.singleHeadPredecessor(trace) : "Trace head with more than one predecessor?!" + trace;
+        AbstractBlockBase<?> pred = block.getPredecessors()[0];
 
-        Value[] variableMap = new Value[lir.numVariables()];
         GlobalLivenessInfo livenessInfo = context.livenessInfo;
-        collectMapping(block, pred, livenessInfo, variableMap);
-        assignLocations(lir, block, livenessInfo, variableMap);
+        allocate(block, pred, livenessInfo, SSAUtil.phiOutOrNull(lir, block));
     }
 
-    /**
-     * Collects the mapping from variable to location. Additionally the
-     * {@link GlobalLivenessInfo#setInLocations incoming location array} is set.
-     */
-    private static void collectMapping(AbstractBlockBase<?> block, AbstractBlockBase<?> pred, GlobalLivenessInfo livenessInfo, Value[] variableMap) {
+    public static void allocate(AbstractBlockBase<?> block, AbstractBlockBase<?> pred, GlobalLivenessInfo livenessInfo, LIRInstruction jump) {
+        // exploit that the live sets are sorted
+        assert TraceAssertions.liveSetsAreSorted(livenessInfo, block);
+        assert TraceAssertions.liveSetsAreSorted(livenessInfo, pred);
+
+        // setup incoming variables/locations
         final int[] blockIn = livenessInfo.getBlockIn(block);
         final Value[] predLocOut = livenessInfo.getOutLocation(pred);
-        final Value[] locationIn = new Value[blockIn.length];
-        for (int i = 0; i < blockIn.length; i++) {
-            int varNum = blockIn[i];
-            if (varNum >= 0) {
-                Value location = predLocOut[i];
-                variableMap[varNum] = location;
-                locationIn[i] = location;
-            } else {
-                locationIn[i] = Value.ILLEGAL;
+        int inLenght = blockIn.length;
+
+        // setup outgoing variables/locations
+        final int[] blockOut = livenessInfo.getBlockOut(block);
+        int outLength = blockOut.length;
+        final Value[] locationOut = new Value[outLength];
+
+        assert outLength <= inLenght : "Trivial Trace! There cannot be more outgoing values than incoming.";
+        for (int outIdx = 0, inIdx = 0; outIdx < outLength; inIdx++) {
+            if (blockOut[outIdx] == blockIn[inIdx]) {
+                // set the outgoing location to the incoming value
+                locationOut[outIdx++] = predLocOut[inIdx];
             }
         }
-        livenessInfo.setInLocations(block, locationIn);
+
+        /*
+         * Since we do not change any of the location we can just use the outgoing of the
+         * predecessor.
+         */
+        livenessInfo.setInLocations(block, predLocOut);
+        livenessInfo.setOutLocations(block, locationOut);
+        if (jump != null) {
+            handlePhiOut(jump, blockIn, predLocOut);
+        }
     }
 
-    /**
-     * Assigns the outgoing locations according to the {@link #collectMapping variable mapping}.
-     */
-    private static void assignLocations(LIR lir, AbstractBlockBase<?> block, GlobalLivenessInfo livenessInfo, Value[] variableMap) {
-        final int[] blockOut = livenessInfo.getBlockOut(block);
-        final Value[] locationOut = new Value[blockOut.length];
-        for (int i = 0; i < blockOut.length; i++) {
-            int varNum = blockOut[i];
-            locationOut[i] = variableMap[varNum];
-        }
-        livenessInfo.setOutLocations(block, locationOut);
-
+    private static void handlePhiOut(LIRInstruction jump, int[] varIn, Value[] locIn) {
         // handle outgoing phi values
         ValueProcedure outputConsumer = new ValueProcedure() {
             @Override
             public Value doValue(Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
                 if (isVariable(value)) {
-                    return variableMap[asVariable(value).index];
+                    // since incoming variables are sorted, we can do a binary search
+                    return locIn[Arrays.binarySearch(varIn, asVariable(value).index)];
                 }
                 return value;
             }
         };
 
-        JumpOp jump = SSAUtil.phiOut(lir, block);
         // Jumps have only alive values (outgoing phi values)
         jump.forEachAlive(outputConsumer);
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/bu/BottomUpAllocator.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/bu/BottomUpAllocator.java	Fri Mar 16 22:59:32 2018 -0700
@@ -501,11 +501,12 @@
 
             try (Indent indent = debug.logAndIndent("handle block %s", block)) {
                 currentInstructions = getLIR().getLIRforBlock(block);
-                for (currentInstructionIndex = currentInstructions.size() - 1; currentInstructionIndex >= 0; currentInstructionIndex--) {
+                final int lastInstIdx = currentInstructions.size() - 1;
+                for (currentInstructionIndex = lastInstIdx; currentInstructionIndex >= 0; currentInstructionIndex--) {
                     LIRInstruction inst = currentInstructions.get(currentInstructionIndex);
                     if (inst != null) {
                         inst.setId(currentOpId);
-                        allocateInstruction(inst, block);
+                        allocateInstruction(inst, block, currentInstructionIndex == 0, currentInstructionIndex == lastInstIdx);
                     }
                 }
                 allocatedBlocks.set(block.getId());
@@ -514,7 +515,7 @@
         }
 
         @SuppressWarnings("try")
-        private void allocateInstruction(LIRInstruction op, AbstractBlockBase<?> block) {
+        private void allocateInstruction(LIRInstruction op, AbstractBlockBase<?> block, boolean isLabel, boolean isBlockEnd) {
             assert op != null && op.id() == currentOpId;
             try (Indent indent = debug.logAndIndent("handle inst: %d: %s", op.id(), op)) {
                 try (Indent indent1 = debug.logAndIndent("output pos")) {
@@ -537,7 +538,8 @@
                     // should have
                     op.forEachTemp(allocStackOrRegisterProcedure);
                     op.forEachOutput(allocStackOrRegisterProcedure);
-                    if (op instanceof LabelOp) {
+                    if (isLabel) {
+                        assert op instanceof LabelOp;
                         processIncoming(block, op);
                     }
                 }
@@ -551,7 +553,8 @@
                     op.forEachInput(allocRegisterProcedure);
 
                     op.forEachAlive(allocStackOrRegisterProcedure);
-                    if (op instanceof BlockEndOp) {
+                    if (isBlockEnd) {
+                        assert op instanceof BlockEndOp;
                         processOutgoing(block, op);
                     }
                     op.forEachState(allocStackOrRegisterProcedure);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanLifetimeAnalysisPhase.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanLifetimeAnalysisPhase.java	Fri Mar 16 22:59:32 2018 -0700
@@ -112,10 +112,6 @@
             buildIntervals();
         }
 
-        private boolean isAllocated(AbstractBlockBase<?> currentBlock, AbstractBlockBase<?> other) {
-            return traceBuilderResult.getTraceForBlock(other).getId() < traceBuilderResult.getTraceForBlock(currentBlock).getId();
-        }
-
         /**
          * Count instructions in all blocks. The numbering follows the
          * {@linkplain TraceLinearScan#sortedBlocks() register allocation order}.
@@ -621,26 +617,29 @@
             assert allocator.instructionForId(opId) == op : "must match";
         }
 
+        /**
+         * Add register hints for incoming values, i.e., values that are not defined in the trace.
+         *
+         * Due to the dominance property of SSA form, all values live at some point in the trace
+         * that are not defined in the trace are live at the beginning of it.
+         */
         @SuppressWarnings("try")
         private void addInterTraceHints() {
             try (DebugContext.Scope s = debug.scope("InterTraceHints", allocator)) {
-                GlobalLivenessInfo livenessInfo = allocator.getGlobalLivenessInfo();
-                // set hints for phi/incoming intervals
-                for (AbstractBlockBase<?> block : sortedBlocks()) {
-                    LabelOp label = (LabelOp) getLIR().getLIRforBlock(block).get(0);
-                    for (AbstractBlockBase<?> pred : block.getPredecessors()) {
-                        addInterTraceHints(livenessInfo, pred, block, label);
-                    }
+                AbstractBlockBase<?> traceHeadBlock = sortedBlocks()[0];
+                if (traceHeadBlock.getPredecessorCount() == 0) {
+                    return;
                 }
-            } catch (Throwable e) {
-                throw debug.handle(e);
-            }
-        }
+                assert traceHeadBlock.getPredecessorCount() == 1 : "Trace head with more than one predecessor?!" + traceHeadBlock;
+
+                AbstractBlockBase<?> pred = traceHeadBlock.getPredecessors()[0];
+                assert traceBuilderResult.getTraceForBlock(pred).getId() < traceBuilderResult.getTraceForBlock(traceHeadBlock).getId() : "Not yet allocated? " + pred;
 
-        private void addInterTraceHints(GlobalLivenessInfo livenessInfo, AbstractBlockBase<?> from, AbstractBlockBase<?> to, LabelOp label) {
-            if (isAllocated(to, from)) {
-                int[] liveVars = livenessInfo.getBlockIn(to);
-                Value[] outLocation = livenessInfo.getOutLocation(from);
+                GlobalLivenessInfo livenessInfo = allocator.getGlobalLivenessInfo();
+                LabelOp label = (LabelOp) getLIR().getLIRforBlock(traceHeadBlock).get(0);
+
+                int[] liveVars = livenessInfo.getBlockIn(traceHeadBlock);
+                Value[] outLocation = livenessInfo.getOutLocation(pred);
 
                 for (int i = 0; i < liveVars.length; i++) {
                     int varNum = liveVars[i];
@@ -652,18 +651,20 @@
                         }
                     }
                 }
+            } catch (Throwable e) {
+                throw debug.handle(e);
             }
         }
 
         private void addInterTraceHint(LabelOp label, int varNum, Value fromValue) {
-            assert isRegister(fromValue) || isVariable(fromValue) || isStackSlotValue(fromValue) || isShadowedRegisterValue(fromValue) : "Wrong fromValue: " + fromValue;
+            assert isRegister(fromValue) || isStackSlotValue(fromValue) || isShadowedRegisterValue(fromValue) : "Wrong fromValue: " + fromValue;
             TraceInterval to = allocator.intervalFor(varNum);
             if (to == null) {
                 // variable not live -> do nothing
                 return;
             }
-            if (isVariableOrRegister(fromValue)) {
-                IntervalHint from = getIntervalHint((AllocatableValue) fromValue);
+            if (isRegister(fromValue)) {
+                IntervalHint from = allocator.getOrCreateFixedInterval(asRegisterValue(fromValue));
                 setHint(label, to, from, debug);
             } else if (isStackSlotValue(fromValue)) {
                 setSpillSlot(label, to, (AllocatableValue) fromValue, debug);
@@ -672,8 +673,6 @@
                 IntervalHint from = getIntervalHint(shadowedRegisterValue.getRegister());
                 setHint(label, to, from, debug);
                 setSpillSlot(label, to, shadowedRegisterValue.getStackSlot(), debug);
-            } else {
-                throw GraalError.shouldNotReachHere();
             }
         }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/LIRGeneratorTool.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/LIRGeneratorTool.java	Fri Mar 16 22:59:32 2018 -0700
@@ -252,11 +252,16 @@
 
     Variable emitByteSwap(Value operand);
 
+    @SuppressWarnings("unused")
+    default Variable emitArrayCompareTo(JavaKind kind1, JavaKind kind2, Value array1, Value array2, Value length1, Value length2) {
+        throw GraalError.unimplemented("String.compareTo substitution is not implemented on this architecture");
+    }
+
     Variable emitArrayEquals(JavaKind kind, Value array1, Value array2, Value length);
 
     @SuppressWarnings("unused")
     default Variable emitStringIndexOf(Value sourcePointer, Value sourceCount, Value targetPointer, Value targetCount, int constantTargetCount) {
-        throw GraalError.unimplemented();
+        throw GraalError.unimplemented("String.indexOf substitution is not implemented on this architecture");
     }
 
     void emitBlackhole(Value operand);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/LIRPhaseSuite.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/LIRPhaseSuite.java	Fri Mar 16 22:59:32 2018 -0700
@@ -40,6 +40,13 @@
     }
 
     /**
+     * Gets an unmodifiable view on the phases in this suite.
+     */
+    public List<LIRPhase<C>> getPhases() {
+        return Collections.unmodifiableList(phases);
+    }
+
+    /**
      * Add a new phase at the beginning of this suite.
      */
     public final void prependPhase(LIRPhase<C> phase) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/ssa/SSAUtil.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/ssa/SSAUtil.java	Fri Mar 16 22:59:32 2018 -0700
@@ -112,6 +112,13 @@
         return (JumpOp) op;
     }
 
+    public static JumpOp phiOutOrNull(LIR lir, AbstractBlockBase<?> block) {
+        if (block.getSuccessorCount() != 1) {
+            return null;
+        }
+        return phiOut(lir, block);
+    }
+
     public static int phiOutIndex(LIR lir, AbstractBlockBase<?> block) {
         assert block.getSuccessorCount() == 1;
         ArrayList<LIRInstruction> instructions = lir.getLIRforBlock(block);
@@ -181,4 +188,19 @@
         return -1;
     }
 
+    public static int numPhiOut(LIR lir, AbstractBlockBase<?> block) {
+        if (block.getSuccessorCount() != 1) {
+            // cannot be a phi_out block
+            return 0;
+        }
+        return numPhiIn(lir, block.getSuccessors()[0]);
+    }
+
+    private static int numPhiIn(LIR lir, AbstractBlockBase<?> block) {
+        if (!isMerge(block)) {
+            return 0;
+        }
+        return phiIn(lir, block).getPhiSize();
+    }
+
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/BasicInductionVariable.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/BasicInductionVariable.java	Fri Mar 16 22:59:32 2018 -0700
@@ -28,6 +28,7 @@
 
 import org.graalvm.compiler.core.common.type.IntegerStamp;
 import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.util.UnsignedLong;
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.nodes.ConstantNode;
 import org.graalvm.compiler.nodes.NodeView;
@@ -159,7 +160,7 @@
     @Override
     public ValueNode exitValueNode() {
         Stamp stamp = phi.stamp(NodeView.DEFAULT);
-        ValueNode maxTripCount = loop.counted().maxTripCountNode(false);
+        ValueNode maxTripCount = loop.counted().maxTripCountNode();
         if (!maxTripCount.stamp(NodeView.DEFAULT).isCompatible(stamp)) {
             maxTripCount = IntegerConvertNode.convert(maxTripCount, stamp, graph(), NodeView.DEFAULT);
         }
@@ -173,7 +174,11 @@
 
     @Override
     public long constantExtremum() {
-        return constantStride() * (loop.counted().constantMaxTripCount() - 1) + constantInit();
+        UnsignedLong tripCount = loop.counted().constantMaxTripCount();
+        if (tripCount.isLessThan(1)) {
+            return constantInit();
+        }
+        return tripCount.minus(1).wrappingTimes(constantStride()).wrappingPlus(constantInit()).asLong();
     }
 
     @Override
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/CountedLoopInfo.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/CountedLoopInfo.java	Fri Mar 16 22:59:32 2018 -0700
@@ -23,11 +23,12 @@
 package org.graalvm.compiler.loop;
 
 import static org.graalvm.compiler.loop.MathUtil.add;
-import static org.graalvm.compiler.loop.MathUtil.divBefore;
 import static org.graalvm.compiler.loop.MathUtil.sub;
+import static org.graalvm.compiler.loop.MathUtil.unsignedDivBefore;
 
 import org.graalvm.compiler.core.common.type.IntegerStamp;
 import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.util.UnsignedLong;
 import org.graalvm.compiler.loop.InductionVariable.Direction;
 import org.graalvm.compiler.nodes.AbstractBeginNode;
 import org.graalvm.compiler.nodes.ConstantNode;
@@ -39,6 +40,7 @@
 import org.graalvm.compiler.nodes.calc.CompareNode;
 import org.graalvm.compiler.nodes.calc.ConditionalNode;
 import org.graalvm.compiler.nodes.calc.IntegerLessThanNode;
+import org.graalvm.compiler.nodes.calc.NegateNode;
 import org.graalvm.compiler.nodes.extended.GuardingNode;
 
 import jdk.vm.ci.code.CodeUtil;
@@ -64,38 +66,58 @@
         this.ifNode = ifNode;
     }
 
+    /**
+     * Returns a node that computes the maximum trip count of this loop. That is the trip count of
+     * this loop assuming it is not exited by an other exit than the {@linkplain #getLimitTest()
+     * count check}.
+     *
+     * This count is exact if {@link #isExactTripCount()} returns true.
+     *
+     * THIS VALUE SHOULD BE TREATED AS UNSIGNED.
+     */
     public ValueNode maxTripCountNode() {
         return maxTripCountNode(false);
     }
 
+    /**
+     * Returns a node that computes the maximum trip count of this loop. That is the trip count of
+     * this loop assuming it is not exited by an other exit than the {@linkplain #getLimitTest()
+     * count check}.
+     *
+     * This count is exact if {@link #isExactTripCount()} returns true.
+     *
+     * THIS VALUE SHOULD BE TREATED AS UNSIGNED.
+     *
+     * @param assumePositive if true the check that the loop is entered at all will be omitted.
+     */
     public ValueNode maxTripCountNode(boolean assumePositive) {
         StructuredGraph graph = iv.valueNode().graph();
         Stamp stamp = iv.valueNode().stamp(NodeView.DEFAULT);
-        ValueNode range = sub(graph, end, iv.initNode());
 
         ValueNode max;
         ValueNode min;
-        ValueNode oneDirection;
+        ValueNode range;
+        ValueNode absStride;
         if (iv.direction() == Direction.Up) {
-            oneDirection = ConstantNode.forIntegerStamp(stamp, 1, graph);
+            absStride = iv.strideNode();
+            range = sub(graph, end, iv.initNode());
             max = end;
             min = iv.initNode();
         } else {
             assert iv.direction() == Direction.Down;
-            oneDirection = ConstantNode.forIntegerStamp(stamp, -1, graph);
+            absStride = graph.maybeAddOrUnique(NegateNode.create(iv.strideNode(), NodeView.DEFAULT));
+            range = sub(graph, iv.initNode(), end);
             max = iv.initNode();
             min = end;
         }
+
+        ConstantNode one = ConstantNode.forIntegerStamp(stamp, 1, graph);
         if (oneOff) {
-            range = add(graph, range, oneDirection);
+            range = add(graph, range, one);
         }
         // round-away-from-zero divison: (range + stride -/+ 1) / stride
-        ValueNode denominator = range;
-        if (!oneDirection.stamp(NodeView.DEFAULT).equals(iv.strideNode().stamp(NodeView.DEFAULT))) {
-            ValueNode subedRanged = sub(graph, range, oneDirection);
-            denominator = add(graph, subedRanged, iv.strideNode());
-        }
-        ValueNode div = divBefore(graph, loop.entryPoint(), denominator, iv.strideNode());
+        ValueNode denominator = add(graph, range, sub(graph, absStride, one));
+        ValueNode div = unsignedDivBefore(graph, loop.entryPoint(), denominator, absStride);
 
         if (assumePositive) {
             return div;
@@ -105,49 +127,44 @@
     }
 
     /**
-     * @return true if the loop has constant bounds and the trip count is representable as a
-     *         positive integer.
+     * @return true if the loop has constant bounds.
      */
     public boolean isConstantMaxTripCount() {
-        /*
-         * It's possible that the iteration range is too large to treat this as constant because it
-         * will overflow.
-         */
-        return (hasConstantBounds() && rawConstantMaxTripCount() >= 0);
-    }
-
-    /**
-     * @return true if the bounds on the iteration space are all constants.
-     */
-    public boolean hasConstantBounds() {
         return end instanceof ConstantNode && iv.isConstantInit() && iv.isConstantStride();
     }
 
-    public long constantMaxTripCount() {
+    public UnsignedLong constantMaxTripCount() {
         assert isConstantMaxTripCount();
-        return rawConstantMaxTripCount();
+        return new UnsignedLong(rawConstantMaxTripCount());
     }
 
     /**
-     * Compute the raw value of the trip count for this loop. Since we don't have unsigned values
-     * this may be outside representable positive values.
+     * Compute the raw value of the trip count for this loop. THIS IS AN UNSIGNED VALUE;
      */
-    protected long rawConstantMaxTripCount() {
+    private long rawConstantMaxTripCount() {
         assert iv.direction() != null;
-        long off = oneOff ? iv.direction() == Direction.Up ? 1 : -1 : 0;
-        long endValue = ((ConstantNode) end).asJavaConstant().asLong();
-        try {
-            // If no overflow occurs then negative values represent a trip count of 0
-            long max = Math.subtractExact(Math.addExact(endValue, off), iv.constantInit()) / iv.constantStride();
-            return Math.max(0, max);
-        } catch (ArithmeticException e) {
-            /*
-             * The computation overflowed to return a negative value. It's possible some
-             * optimization could handle this value as an unsigned and produce the right answer but
-             * we hide this value by default.
-             */
-            return -1;
+        long endValue = end.asJavaConstant().asLong();
+        long initValue = iv.constantInit();
+        long range;
+        long absStride;
+        if (iv.direction() == Direction.Up) {
+            if (endValue < initValue) {
+                return 0;
+            }
+            range = endValue - iv.constantInit();
+            absStride = iv.constantStride();
+        } else {
+            if (initValue < endValue) {
+                return 0;
+            }
+            range = iv.constantInit() - endValue;
+            absStride = -iv.constantStride();
         }
+        if (oneOff) {
+            range += 1;
+        }
+        long denominator = range + absStride - 1;
+        return Long.divideUnsigned(denominator, absStride);
     }
 
     public boolean isExactTripCount() {
@@ -164,7 +181,7 @@
         return isConstantMaxTripCount();
     }
 
-    public long constantExactTripCount() {
+    public UnsignedLong constantExactTripCount() {
         assert isExactTripCount();
         return constantMaxTripCount();
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/DefaultLoopPolicies.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/DefaultLoopPolicies.java	Fri Mar 16 22:59:32 2018 -0700
@@ -28,6 +28,7 @@
 
 import java.util.List;
 
+import org.graalvm.compiler.core.common.util.UnsignedLong;
 import org.graalvm.compiler.debug.CounterKey;
 import org.graalvm.compiler.debug.DebugContext;
 import org.graalvm.compiler.graph.Node;
@@ -89,11 +90,22 @@
         }
         OptionValues options = loop.entryPoint().getOptions();
         CountedLoopInfo counted = loop.counted();
-        long maxTrips = counted.constantMaxTripCount();
+        UnsignedLong maxTrips = counted.constantMaxTripCount();
+        if (maxTrips.equals(0)) {
+            return loop.canDuplicateLoop();
+        }
         int maxNodes = (counted.isExactTripCount() && counted.isConstantExactTripCount()) ? Options.ExactFullUnrollMaxNodes.getValue(options) : Options.FullUnrollMaxNodes.getValue(options);
         maxNodes = Math.min(maxNodes, Math.max(0, MaximumDesiredSize.getValue(options) - loop.loopBegin().graph().getNodeCount()));
         int size = Math.max(1, loop.size() - 1 - loop.loopBegin().phis().count());
-        if (maxTrips <= Options.FullUnrollMaxIterations.getValue(options) && size * (maxTrips - 1) <= maxNodes) {
+        /* @formatter:off
+         * The check below should not throw ArithmeticException because:
+         * maxTrips is guaranteed to be >= 1 by the check above
+         * - maxTrips * size can not overfow because:
+         *   - maxTrips <= FullUnrollMaxIterations <= Integer.MAX_VALUE
+         *   - 1 <= size <= Integer.MAX_VALUE
+         * @formatter:on
+         */
+        if (maxTrips.isLessOrEqualTo(Options.FullUnrollMaxIterations.getValue(options)) && maxTrips.minus(1).times(size).isLessOrEqualTo(maxNodes)) {
             // check whether we're allowed to unroll this loop
             return loop.canDuplicateLoop();
         } else {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragment.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragment.java	Fri Mar 16 22:59:32 2018 -0700
@@ -35,6 +35,7 @@
 import org.graalvm.compiler.graph.NodeBitMap;
 import org.graalvm.compiler.graph.iterators.NodeIterable;
 import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.AbstractMergeNode;
 import org.graalvm.compiler.nodes.EndNode;
 import org.graalvm.compiler.nodes.FixedNode;
 import org.graalvm.compiler.nodes.FrameState;
@@ -208,6 +209,12 @@
                     NodeWithState withState = (NodeWithState) n;
                     withState.states().forEach(state -> state.applyToVirtual(node -> nodes.mark(node)));
                 }
+                if (n instanceof AbstractMergeNode) {
+                    // if a merge is in the loop, all of its phis are also in the loop
+                    for (PhiNode phi : ((AbstractMergeNode) n).phis()) {
+                        nodes.mark(phi);
+                    }
+                }
                 nodes.mark(n);
             }
         }
@@ -246,6 +253,17 @@
                 if (n instanceof MonitorEnterNode) {
                     markFloating(worklist, ((MonitorEnterNode) n).getMonitorId(), nodes, nonLoopNodes);
                 }
+                if (n instanceof AbstractMergeNode) {
+                    /*
+                     * Since we already marked all phi nodes as being in the loop to break cycles,
+                     * we also have to iterate over their usages here.
+                     */
+                    for (PhiNode phi : ((AbstractMergeNode) n).phis()) {
+                        for (Node usage : phi.usages()) {
+                            markFloating(worklist, usage, nodes, nonLoopNodes);
+                        }
+                    }
+                }
                 for (Node usage : n.usages()) {
                     markFloating(worklist, usage, nodes, nonLoopNodes);
                 }
@@ -263,6 +281,20 @@
             this.usages = n.usages().iterator();
             this.isLoopNode = loopNodes.isMarked(n);
         }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (!(obj instanceof WorkListEntry)) {
+                return false;
+            }
+            WorkListEntry other = (WorkListEntry) obj;
+            return this.n == other.n;
+        }
+
+        @Override
+        public int hashCode() {
+            return n.hashCode();
+        }
     }
 
     static TriState isLoopNode(Node n, NodeBitMap loopNodes, NodeBitMap nonLoopNodes) {
@@ -272,32 +304,24 @@
         if (nonLoopNodes.isMarked(n)) {
             return TriState.FALSE;
         }
-        if (n instanceof FixedNode) {
+        if (n instanceof FixedNode || n instanceof PhiNode) {
+            // phi nodes are treated the same as fixed nodes in this algorithm to break cycles
             return TriState.FALSE;
         }
-        boolean mark = false;
-        if (n instanceof PhiNode) {
-            PhiNode phi = (PhiNode) n;
-            mark = loopNodes.isMarked(phi.merge());
-            if (mark) {
-                /*
-                 * This Phi is a loop node but the inputs might not be so they must be processed by
-                 * the caller.
-                 */
-                loopNodes.mark(n);
-            } else {
-                nonLoopNodes.mark(n);
-                return TriState.FALSE;
-            }
-        }
         return TriState.UNKNOWN;
     }
 
+    private static void pushWorkList(Deque<WorkListEntry> workList, Node node, NodeBitMap loopNodes) {
+        WorkListEntry entry = new WorkListEntry(node, loopNodes);
+        assert !workList.contains(entry) : "node " + node + " added to worklist twice";
+        workList.push(entry);
+    }
+
     private static void markFloating(Deque<WorkListEntry> workList, Node start, NodeBitMap loopNodes, NodeBitMap nonLoopNodes) {
         if (isLoopNode(start, loopNodes, nonLoopNodes).isKnown()) {
             return;
         }
-        workList.push(new WorkListEntry(start, loopNodes));
+        pushWorkList(workList, start, loopNodes);
         while (!workList.isEmpty()) {
             WorkListEntry currentEntry = workList.peek();
             if (currentEntry.usages.hasNext()) {
@@ -308,7 +332,7 @@
                         currentEntry.isLoopNode = true;
                     }
                 } else {
-                    workList.push(new WorkListEntry(current, loopNodes));
+                    pushWorkList(workList, current, loopNodes);
                 }
             } else {
                 workList.pop();
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragmentInside.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragmentInside.java	Fri Mar 16 22:59:32 2018 -0700
@@ -28,6 +28,7 @@
 
 import org.graalvm.collections.EconomicMap;
 import org.graalvm.collections.Equivalence;
+import org.graalvm.compiler.debug.DebugCloseable;
 import org.graalvm.compiler.debug.DebugContext;
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.graph.Graph.DuplicationReplacement;
@@ -338,6 +339,7 @@
     }
 
     @Override
+    @SuppressWarnings("try")
     protected DuplicationReplacement getDuplicationReplacement() {
         final LoopBeginNode loopBegin = loop().loopBegin();
         final StructuredGraph graph = graph();
@@ -347,34 +349,36 @@
 
             @Override
             public Node replacement(Node original) {
-                if (original == loopBegin) {
-                    Node value = seenNode.get(original);
-                    if (value != null) {
-                        return value;
-                    }
-                    AbstractBeginNode newValue = graph.add(new BeginNode());
-                    seenNode.put(original, newValue);
-                    return newValue;
-                }
-                if (original instanceof LoopExitNode && ((LoopExitNode) original).loopBegin() == loopBegin) {
-                    Node value = seenNode.get(original);
-                    if (value != null) {
-                        return value;
+                try (DebugCloseable position = original.withNodeSourcePosition()) {
+                    if (original == loopBegin) {
+                        Node value = seenNode.get(original);
+                        if (value != null) {
+                            return value;
+                        }
+                        AbstractBeginNode newValue = graph.add(new BeginNode());
+                        seenNode.put(original, newValue);
+                        return newValue;
                     }
-                    AbstractBeginNode newValue = graph.add(new BeginNode());
-                    seenNode.put(original, newValue);
-                    return newValue;
+                    if (original instanceof LoopExitNode && ((LoopExitNode) original).loopBegin() == loopBegin) {
+                        Node value = seenNode.get(original);
+                        if (value != null) {
+                            return value;
+                        }
+                        AbstractBeginNode newValue = graph.add(new BeginNode());
+                        seenNode.put(original, newValue);
+                        return newValue;
+                    }
+                    if (original instanceof LoopEndNode && ((LoopEndNode) original).loopBegin() == loopBegin) {
+                        Node value = seenNode.get(original);
+                        if (value != null) {
+                            return value;
+                        }
+                        EndNode newValue = graph.add(new EndNode());
+                        seenNode.put(original, newValue);
+                        return newValue;
+                    }
+                    return original;
                 }
-                if (original instanceof LoopEndNode && ((LoopEndNode) original).loopBegin() == loopBegin) {
-                    Node value = seenNode.get(original);
-                    if (value != null) {
-                        return value;
-                    }
-                    EndNode newValue = graph.add(new EndNode());
-                    seenNode.put(original, newValue);
-                    return newValue;
-                }
-                return original;
             }
         };
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/MathUtil.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/MathUtil.java	Fri Mar 16 22:59:32 2018 -0700
@@ -30,6 +30,9 @@
 import org.graalvm.compiler.nodes.calc.BinaryArithmeticNode;
 import org.graalvm.compiler.nodes.calc.FixedBinaryNode;
 import org.graalvm.compiler.nodes.calc.SignedDivNode;
+import org.graalvm.compiler.nodes.calc.UnsignedDivNode;
+
+import java.util.function.BiFunction;
 
 /**
  * Utility methods to perform integer math with some obvious constant folding first.
@@ -71,12 +74,28 @@
     }
 
     public static ValueNode divBefore(StructuredGraph graph, FixedNode before, ValueNode dividend, ValueNode divisor) {
+        return fixedDivBefore(graph, before, dividend, divisor, (dend, sor) -> SignedDivNode.create(dend, sor, NodeView.DEFAULT));
+    }
+
+    public static ValueNode unsignedDivBefore(StructuredGraph graph, FixedNode before, ValueNode dividend, ValueNode divisor) {
+        return fixedDivBefore(graph, before, dividend, divisor, (dend, sor) -> UnsignedDivNode.create(dend, sor, NodeView.DEFAULT));
+    }
+
+    private static ValueNode fixedDivBefore(StructuredGraph graph, FixedNode before, ValueNode dividend, ValueNode divisor, BiFunction<ValueNode, ValueNode, ValueNode> createDiv) {
         if (isConstantOne(divisor)) {
             return dividend;
         }
-        ValueNode div = graph.addOrUniqueWithInputs(SignedDivNode.create(dividend, divisor, NodeView.DEFAULT));
+        ValueNode div = graph.addOrUniqueWithInputs(createDiv.apply(dividend, divisor));
         if (div instanceof FixedBinaryNode) {
-            graph.addBeforeFixed(before, (FixedBinaryNode) div);
+            FixedBinaryNode fixedDiv = (FixedBinaryNode) div;
+            if (before.predecessor() instanceof FixedBinaryNode) {
+                FixedBinaryNode binaryPredecessor = (FixedBinaryNode) before.predecessor();
+                if (fixedDiv.dataFlowEquals(binaryPredecessor)) {
+                    fixedDiv.safeDelete();
+                    return binaryPredecessor;
+                }
+            }
+            graph.addBeforeFixed(before, fixedDiv);
         }
         return div;
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/IntegerStampTest.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/IntegerStampTest.java	Fri Mar 16 22:59:32 2018 -0700
@@ -570,4 +570,16 @@
         assertEquals(IntegerStamp.create(bits, 0, 1000), div.foldStamp(IntegerStamp.create(bits, 100, 1000), IntegerStamp.create(bits, 1, max)));
         assertEquals(IntegerStamp.create(bits, -1000, 0), div.foldStamp(IntegerStamp.create(bits, -1000, -100), IntegerStamp.create(bits, 1, max)));
     }
+
+    @Test
+    public void testEmpty() {
+        IntegerStamp intStamp = StampFactory.forInteger(32);
+        IntegerStamp longStamp = StampFactory.forInteger(64);
+        Stamp intEmpty = StampFactory.empty(JavaKind.Int);
+        Stamp longEmpty = StampFactory.empty(JavaKind.Long);
+        assertEquals(intStamp.join(intEmpty), intEmpty);
+        assertEquals(intStamp.meet(intEmpty), intStamp);
+        assertEquals(longStamp.join(longEmpty), longEmpty);
+        assertEquals(longStamp.meet(longEmpty), longStamp);
+    }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/PrimitiveStampBoundaryTest.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/PrimitiveStampBoundaryTest.java	Fri Mar 16 22:59:32 2018 -0700
@@ -35,6 +35,7 @@
 import org.graalvm.compiler.core.common.type.IntegerStamp;
 import org.graalvm.compiler.core.common.type.PrimitiveStamp;
 import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.test.GraalTest;
 import org.junit.Test;
 
@@ -64,6 +65,7 @@
                 shiftStamps.add(IntegerStamp.create(32, Math.min(v1, v2), Math.max(v1, v2)));
             }
         }
+        shiftStamps.add((IntegerStamp) StampFactory.empty(JavaKind.Int));
 
         integerTestStamps = new HashSet<>();
         for (long v1 : longBoundaryValues) {
@@ -74,6 +76,8 @@
                 integerTestStamps.add(IntegerStamp.create(64, Math.min(v1, v2), Math.max(v1, v2)));
             }
         }
+        integerTestStamps.add((PrimitiveStamp) StampFactory.empty(JavaKind.Int));
+        integerTestStamps.add((PrimitiveStamp) StampFactory.empty(JavaKind.Long));
     }
 
     static double[] doubleBoundaryValues = {Double.NEGATIVE_INFINITY, Double.MIN_VALUE, Float.NEGATIVE_INFINITY, Float.MIN_VALUE,
@@ -98,6 +102,8 @@
                 generateFloatingStamps(new FloatStamp(64, Math.min(d1, d2), Math.max(d1, d2), false));
             }
         }
+        floatTestStamps.add((PrimitiveStamp) StampFactory.empty(JavaKind.Float));
+        floatTestStamps.add((PrimitiveStamp) StampFactory.empty(JavaKind.Double));
     }
 
     private static void generateFloatingStamps(FloatStamp floatStamp) {
@@ -130,7 +136,7 @@
 
     private static void checkConvertOperation(IntegerConvertOp<?> op, int inputBits, int resultBits, Stamp result, Stamp v1stamp) {
         Stamp folded = op.foldStamp(inputBits, resultBits, v1stamp);
-        assertTrue(folded.asConstant() != null, "should constant fold %s %s %s", op, v1stamp, folded);
+        assertTrue(folded.isEmpty() || folded.asConstant() != null, "should constant fold %s %s %s", op, v1stamp, folded);
         assertTrue(result.meet(folded).equals(result), "result out of range %s %s %s %s %s", op, v1stamp, folded, result, result.meet(folded));
     }
 
@@ -167,7 +173,7 @@
 
     private static void checkConvertOperation(ArithmeticOpTable.FloatConvertOp op, Stamp result, Stamp v1stamp) {
         Stamp folded = op.foldStamp(v1stamp);
-        assertTrue(folded.asConstant() != null, "should constant fold %s %s %s", op, v1stamp, folded);
+        assertTrue(folded.isEmpty() || folded.asConstant() != null, "should constant fold %s %s %s", op, v1stamp, folded);
         assertTrue(result.meet(folded).equals(result), "result out of range %s %s %s %s %s", op, v1stamp, folded, result, result.meet(folded));
     }
 
@@ -184,6 +190,10 @@
                 IntegerStamp stamp = (IntegerStamp) testStamp;
                 for (IntegerStamp shiftStamp : shifts) {
                     IntegerStamp foldedStamp = (IntegerStamp) shiftOp.foldStamp(stamp, shiftStamp);
+                    if (foldedStamp.isEmpty()) {
+                        assertTrue(stamp.isEmpty() || shiftStamp.isEmpty());
+                        continue;
+                    }
                     checkShiftOperation(stamp.getBits(), shiftOp, foldedStamp, stamp.lowerBound(), shiftStamp.lowerBound());
                     checkShiftOperation(stamp.getBits(), shiftOp, foldedStamp, stamp.lowerBound(), shiftStamp.upperBound());
                     checkShiftOperation(stamp.getBits(), shiftOp, foldedStamp, stamp.upperBound(), shiftStamp.lowerBound());
@@ -205,8 +215,15 @@
 
     private static void checkBinaryOperation(ArithmeticOpTable.BinaryOp<?> op, Stamp result, Stamp v1stamp, Stamp v2stamp) {
         Stamp folded = op.foldStamp(v1stamp, v2stamp);
+        if (v1stamp.isEmpty() || v2stamp.isEmpty()) {
+            assertTrue(folded.isEmpty());
+            assertTrue(v1stamp.asConstant() != null || v1stamp.isEmpty());
+            assertTrue(v2stamp.asConstant() != null || v2stamp.isEmpty());
+            return;
+        }
         Constant constant = op.foldConstant(v1stamp.asConstant(), v2stamp.asConstant());
         if (constant != null) {
+            assertFalse(folded.isEmpty());
             Constant constant2 = folded.asConstant();
             if (constant2 == null && v1stamp instanceof FloatStamp) {
                 JavaConstant c = (JavaConstant) constant;
@@ -239,6 +256,9 @@
     }
 
     private static Stamp boundaryStamp(Stamp v1, boolean upper) {
+        if (v1.isEmpty()) {
+            return v1;
+        }
         if (v1 instanceof IntegerStamp) {
             IntegerStamp istamp = (IntegerStamp) v1;
             long bound = upper ? istamp.upperBound() : istamp.lowerBound();
@@ -319,7 +339,7 @@
                 }
             }
         } else {
-            assert v1stamp instanceof FloatStamp;
+            assertTrue(v1stamp.isEmpty() || v1stamp instanceof FloatStamp);
         }
         assertTrue(result.meet(folded).equals(result), "result out of range %s %s %s %s %s", op, v1stamp, folded, result, result.meet(folded));
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/AbstractFixedGuardNode.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/AbstractFixedGuardNode.java	Fri Mar 16 22:59:32 2018 -0700
@@ -23,6 +23,7 @@
 package org.graalvm.compiler.nodes;
 
 import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.debug.DebugCloseable;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.graph.spi.Simplifiable;
 import org.graalvm.compiler.graph.spi.SimplifierTool;
@@ -41,8 +42,8 @@
 
     public static final NodeClass<AbstractFixedGuardNode> TYPE = NodeClass.create(AbstractFixedGuardNode.class);
     @Input(InputType.Condition) protected LogicNode condition;
-    protected final DeoptimizationReason reason;
-    protected final DeoptimizationAction action;
+    protected DeoptimizationReason reason;
+    protected DeoptimizationAction action;
     protected JavaConstant speculation;
     protected boolean negated;
 
@@ -109,29 +110,42 @@
         }
     }
 
+    @SuppressWarnings("try")
     public DeoptimizeNode lowerToIf() {
-        FixedNode currentNext = next();
-        setNext(null);
-        DeoptimizeNode deopt = graph().add(new DeoptimizeNode(action, reason, speculation));
-        deopt.setStateBefore(stateBefore());
-        IfNode ifNode;
-        AbstractBeginNode noDeoptSuccessor;
-        if (negated) {
-            ifNode = graph().add(new IfNode(condition, deopt, currentNext, 0));
-            noDeoptSuccessor = ifNode.falseSuccessor();
-        } else {
-            ifNode = graph().add(new IfNode(condition, currentNext, deopt, 1));
-            noDeoptSuccessor = ifNode.trueSuccessor();
+        try (DebugCloseable position = this.withNodeSourcePosition()) {
+            FixedNode currentNext = next();
+            setNext(null);
+            DeoptimizeNode deopt = graph().add(new DeoptimizeNode(action, reason, speculation));
+            deopt.setStateBefore(stateBefore());
+            IfNode ifNode;
+            AbstractBeginNode noDeoptSuccessor;
+            if (negated) {
+                ifNode = graph().add(new IfNode(condition, deopt, currentNext, 0));
+                noDeoptSuccessor = ifNode.falseSuccessor();
+            } else {
+                ifNode = graph().add(new IfNode(condition, currentNext, deopt, 1));
+                noDeoptSuccessor = ifNode.trueSuccessor();
+            }
+            ((FixedWithNextNode) predecessor()).setNext(ifNode);
+            this.replaceAtUsages(noDeoptSuccessor);
+            GraphUtil.killWithUnusedFloatingInputs(this);
+
+            return deopt;
         }
-        ((FixedWithNextNode) predecessor()).setNext(ifNode);
-        this.replaceAtUsages(noDeoptSuccessor);
-        GraphUtil.killWithUnusedFloatingInputs(this);
-
-        return deopt;
     }
 
     @Override
     public boolean canDeoptimize() {
         return true;
     }
+
+    @Override
+    public void setAction(DeoptimizationAction action) {
+        this.action = action;
+    }
+
+    @Override
+    public void setReason(DeoptimizationReason reason) {
+        this.reason = reason;
+    }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/BeginNode.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/BeginNode.java	Fri Mar 16 22:59:32 2018 -0700
@@ -27,6 +27,7 @@
 
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.debug.DebugCloseable;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.graph.spi.Simplifiable;
 import org.graalvm.compiler.graph.spi.SimplifierTool;
@@ -71,12 +72,15 @@
         }
     }
 
+    @SuppressWarnings("try")
     public static AbstractBeginNode begin(FixedNode with) {
-        if (with instanceof AbstractBeginNode) {
-            return (AbstractBeginNode) with;
+        try (DebugCloseable position = with.withNodeSourcePosition()) {
+            if (with instanceof AbstractBeginNode) {
+                return (AbstractBeginNode) with;
+            }
+            BeginNode begin = with.graph().add(new BeginNode());
+            begin.setNext(with);
+            return begin;
         }
-        BeginNode begin = with.graph().add(new BeginNode());
-        begin.setNext(with);
-        return begin;
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/DeoptimizeNode.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/DeoptimizeNode.java	Fri Mar 16 22:59:32 2018 -0700
@@ -43,8 +43,8 @@
     public static final int DEFAULT_DEBUG_ID = 0;
 
     public static final NodeClass<DeoptimizeNode> TYPE = NodeClass.create(DeoptimizeNode.class);
-    protected final DeoptimizationAction action;
-    protected final DeoptimizationReason reason;
+    protected DeoptimizationAction action;
+    protected DeoptimizationReason reason;
     protected int debugId;
     protected final JavaConstant speculation;
 
@@ -73,11 +73,21 @@
     }
 
     @Override
+    public void setAction(DeoptimizationAction action) {
+        this.action = action;
+    }
+
+    @Override
     public DeoptimizationReason getReason() {
         return reason;
     }
 
     @Override
+    public void setReason(DeoptimizationReason reason) {
+        this.reason = reason;
+    }
+
+    @Override
     public void lower(LoweringTool tool) {
         tool.getLowerer().lower(this, tool);
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/DynamicPiNode.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/DynamicPiNode.java	Fri Mar 16 22:59:32 2018 -0700
@@ -31,6 +31,8 @@
 import org.graalvm.compiler.nodeinfo.NodeInfo;
 import org.graalvm.compiler.nodes.extended.GuardingNode;
 
+import jdk.vm.ci.meta.Assumptions;
+import jdk.vm.ci.meta.ConstantReflectionProvider;
 import jdk.vm.ci.meta.ResolvedJavaType;
 
 /**
@@ -42,29 +44,55 @@
 
     public static final NodeClass<DynamicPiNode> TYPE = NodeClass.create(DynamicPiNode.class);
     @Input ValueNode typeMirror;
+    private final boolean exact;
 
-    public DynamicPiNode(ValueNode object, GuardingNode guard, ValueNode typeMirror) {
+    protected DynamicPiNode(ValueNode object, GuardingNode guard, ValueNode typeMirror, boolean exact) {
         super(TYPE, object, StampFactory.object(), guard);
         this.typeMirror = typeMirror;
+        this.exact = exact;
+    }
+
+    public static ValueNode create(Assumptions assumptions, ConstantReflectionProvider constantReflection, ValueNode object, GuardingNode guard, ValueNode typeMirror, boolean exact) {
+        ValueNode synonym = findSynonym(assumptions, constantReflection, object, guard, typeMirror, exact);
+        if (synonym != null) {
+            return synonym;
+        }
+        return new DynamicPiNode(object, guard, typeMirror, exact);
     }
 
-    @Override
-    public Node canonical(CanonicalizerTool tool) {
+    public static ValueNode create(Assumptions assumptions, ConstantReflectionProvider constantReflection, ValueNode object, GuardingNode guard, ValueNode typeMirror) {
+        return create(assumptions, constantReflection, object, guard, typeMirror, false);
+    }
+
+    public boolean isExact() {
+        return exact;
+    }
+
+    private static ValueNode findSynonym(Assumptions assumptions, ConstantReflectionProvider constantReflection, ValueNode object, GuardingNode guard, ValueNode typeMirror, boolean exact) {
         if (typeMirror.isConstant()) {
-            ResolvedJavaType t = tool.getConstantReflection().asJavaType(typeMirror.asConstant());
+            ResolvedJavaType t = constantReflection.asJavaType(typeMirror.asConstant());
             if (t != null) {
                 Stamp staticPiStamp;
                 if (t.isPrimitive()) {
                     staticPiStamp = StampFactory.alwaysNull();
                 } else {
-                    TypeReference type = TypeReference.createTrusted(tool.getAssumptions(), t);
+                    TypeReference type = exact ? TypeReference.createExactTrusted(t) : TypeReference.createTrusted(assumptions, t);
                     staticPiStamp = StampFactory.object(type);
                 }
 
-                return new PiNode(object(), staticPiStamp, (ValueNode) getGuard()).canonical(tool);
+                return PiNode.create(object, staticPiStamp, (ValueNode) guard);
             }
         }
 
+        return null;
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        ValueNode synonym = findSynonym(tool.getAssumptions(), tool.getConstantReflection(), object, guard, typeMirror, exact);
+        if (synonym != null) {
+            return synonym;
+        }
         return this;
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/EncodedGraph.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/EncodedGraph.java	Fri Mar 16 22:59:32 2018 -0700
@@ -24,9 +24,11 @@
 
 import java.util.List;
 
+import org.graalvm.collections.EconomicSet;
 import org.graalvm.compiler.graph.NodeClass;
 
 import jdk.vm.ci.meta.Assumptions;
+import jdk.vm.ci.meta.ResolvedJavaField;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 
 /**
@@ -34,7 +36,7 @@
  * {@link GraphEncoder} for a description of the encoding format. Use {@link GraphDecoder} for
  * decoding.
  */
-public class EncodedGraph {
+public final class EncodedGraph {
 
     private final byte[] encoding;
     private final int startOffset;
@@ -42,6 +44,9 @@
     private final NodeClass<?>[] types;
     private final Assumptions assumptions;
     private final List<ResolvedJavaMethod> inlinedMethods;
+    private final boolean trackNodeSourcePosition;
+    private final EconomicSet<ResolvedJavaField> fields;
+    private final boolean hasUnsafeAccess;
 
     /**
      * The "table of contents" of the encoded graph, i.e., the mapping from orderId numbers to the
@@ -49,13 +54,22 @@
      */
     protected int[] nodeStartOffsets;
 
-    public EncodedGraph(byte[] encoding, int startOffset, Object[] objects, NodeClass<?>[] types, Assumptions assumptions, List<ResolvedJavaMethod> inlinedMethods) {
+    public EncodedGraph(byte[] encoding, int startOffset, Object[] objects, NodeClass<?>[] types, StructuredGraph sourceGraph) {
+        this(encoding, startOffset, objects, types, sourceGraph.getAssumptions(), sourceGraph.getMethods(), sourceGraph.getFields(), sourceGraph.hasUnsafeAccess(),
+                        sourceGraph.trackNodeSourcePosition());
+    }
+
+    public EncodedGraph(byte[] encoding, int startOffset, Object[] objects, NodeClass<?>[] types, Assumptions assumptions, List<ResolvedJavaMethod> inlinedMethods,
+                    EconomicSet<ResolvedJavaField> fields, boolean hasUnsafeAccess, boolean trackNodeSourcePosition) {
         this.encoding = encoding;
         this.startOffset = startOffset;
         this.objects = objects;
         this.types = types;
         this.assumptions = assumptions;
         this.inlinedMethods = inlinedMethods;
+        this.trackNodeSourcePosition = trackNodeSourcePosition;
+        this.fields = fields;
+        this.hasUnsafeAccess = hasUnsafeAccess;
     }
 
     public byte[] getEncoding() {
@@ -81,4 +95,16 @@
     public List<ResolvedJavaMethod> getInlinedMethods() {
         return inlinedMethods;
     }
+
+    public boolean trackNodeSourcePosition() {
+        return trackNodeSourcePosition;
+    }
+
+    public EconomicSet<ResolvedJavaField> getFields() {
+        return fields;
+    }
+
+    public boolean hasUnsafeAccess() {
+        return hasUnsafeAccess;
+    }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FixedGuardNode.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FixedGuardNode.java	Fri Mar 16 22:59:32 2018 -0700
@@ -22,6 +22,7 @@
  */
 package org.graalvm.compiler.nodes;
 
+import org.graalvm.compiler.debug.DebugCloseable;
 import static org.graalvm.compiler.nodeinfo.InputType.Guard;
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
@@ -80,16 +81,19 @@
         }
     }
 
+    @SuppressWarnings("try")
     @Override
     public void lower(LoweringTool tool) {
-        if (graph().getGuardsStage().allowsFloatingGuards()) {
-            if (getAction() != DeoptimizationAction.None) {
-                ValueNode guard = tool.createGuard(this, getCondition(), getReason(), getAction(), getSpeculation(), isNegated()).asNode();
-                this.replaceAtUsages(guard);
-                graph().removeFixed(this);
+        try (DebugCloseable position = this.withNodeSourcePosition()) {
+            if (graph().getGuardsStage().allowsFloatingGuards()) {
+                if (getAction() != DeoptimizationAction.None) {
+                    ValueNode guard = tool.createGuard(this, getCondition(), getReason(), getAction(), getSpeculation(), isNegated()).asNode();
+                    this.replaceAtUsages(guard);
+                    graph().removeFixed(this);
+                }
+            } else {
+                lowerToIf().lower(tool);
             }
-        } else {
-            lowerToIf().lower(tool);
         }
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FrameState.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FrameState.java	Fri Mar 16 22:59:32 2018 -0700
@@ -244,7 +244,7 @@
         if (fs == null) {
             return null;
         }
-        return new NodeSourcePosition(null, toSourcePosition(fs.outerFrameState()), fs.code.getMethod(), fs.bci);
+        return new NodeSourcePosition(toSourcePosition(fs.outerFrameState()), fs.code.getMethod(), fs.bci);
     }
 
     /**
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphDecoder.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphDecoder.java	Fri Mar 16 22:59:32 2018 -0700
@@ -146,6 +146,15 @@
         public boolean isInlinedMethod() {
             return false;
         }
+
+        public NodeSourcePosition getCallerBytecodePosition() {
+            return getCallerBytecodePosition(null);
+        }
+
+        public NodeSourcePosition getCallerBytecodePosition(NodeSourcePosition position) {
+            return position;
+        }
+
     }
 
     /** Decoding state maintained for each loop in the encoded graph. */
@@ -1001,7 +1010,7 @@
     }
 
     protected void readProperties(MethodScope methodScope, Node node) {
-        node.setNodeSourcePosition((NodeSourcePosition) readObject(methodScope));
+        NodeSourcePosition position = (NodeSourcePosition) readObject(methodScope);
         Fields fields = node.getNodeClass().getData();
         for (int pos = 0; pos < fields.getCount(); pos++) {
             if (fields.getType(pos).isPrimitive()) {
@@ -1012,6 +1021,9 @@
                 fields.putObject(node, pos, value);
             }
         }
+        if (graph.trackNodeSourcePosition() && position != null) {
+            node.setNodeSourcePosition(methodScope.getCallerBytecodePosition(position));
+        }
     }
 
     /**
@@ -1252,7 +1264,11 @@
         long readerByteIndex = methodScope.reader.getByteIndex();
         methodScope.reader.setByteIndex(methodScope.encodedGraph.nodeStartOffsets[nodeOrderId]);
         NodeClass<?> nodeClass = methodScope.encodedGraph.getNodeClasses()[methodScope.reader.getUVInt()];
-        node = (FixedNode) graph.add(nodeClass.allocateInstance());
+        Node stubNode = nodeClass.allocateInstance();
+        if (graph.trackNodeSourcePosition()) {
+            stubNode.setNodeSourcePosition(NodeSourcePosition.placeholder(graph.method()));
+        }
+        node = (FixedNode) graph.add(stubNode);
         /* Properties and edges are not filled yet, the node remains uninitialized. */
         methodScope.reader.setByteIndex(readerByteIndex);
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphEncoder.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphEncoder.java	Fri Mar 16 22:59:32 2018 -0700
@@ -154,7 +154,7 @@
         encoder.prepare(graph);
         encoder.finishPrepare();
         int startOffset = encoder.encode(graph);
-        return new EncodedGraph(encoder.getEncoding(), startOffset, encoder.getObjects(), encoder.getNodeClasses(), graph.getAssumptions(), graph.getMethods());
+        return new EncodedGraph(encoder.getEncoding(), startOffset, encoder.getObjects(), encoder.getNodeClasses(), graph);
     }
 
     public GraphEncoder(Architecture architecture) {
@@ -288,8 +288,7 @@
         }
 
         /* Check that the decoding of the encode graph is the same as the input. */
-        assert verifyEncoding(graph, new EncodedGraph(getEncoding(), metadataStart, getObjects(), getNodeClasses(), graph.getAssumptions(), graph.getMethods()),
-                        architecture);
+        assert verifyEncoding(graph, new EncodedGraph(getEncoding(), metadataStart, getObjects(), getNodeClasses(), graph), architecture);
 
         return metadataStart;
     }
@@ -436,6 +435,9 @@
     public static boolean verifyEncoding(StructuredGraph originalGraph, EncodedGraph encodedGraph, Architecture architecture) {
         DebugContext debug = originalGraph.getDebug();
         StructuredGraph decodedGraph = new StructuredGraph.Builder(originalGraph.getOptions(), debug, AllowAssumptions.YES).method(originalGraph.method()).build();
+        if (originalGraph.trackNodeSourcePosition()) {
+            decodedGraph.setTrackNodeSourcePosition();
+        }
         GraphDecoder decoder = new GraphDecoder(architecture, decodedGraph);
         decoder.decode(encodedGraph);
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GuardNode.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GuardNode.java	Fri Mar 16 22:59:32 2018 -0700
@@ -59,9 +59,9 @@
 
     public static final NodeClass<GuardNode> TYPE = NodeClass.create(GuardNode.class);
     @Input(Condition) protected LogicNode condition;
-    protected final DeoptimizationReason reason;
+    protected DeoptimizationReason reason;
+    protected DeoptimizationAction action;
     protected JavaConstant speculation;
-    protected DeoptimizationAction action;
     protected boolean negated;
 
     public GuardNode(LogicNode condition, AnchoringNode anchor, DeoptimizationReason reason, DeoptimizationAction action, boolean negated, JavaConstant speculation) {
@@ -149,7 +149,13 @@
         negated = !negated;
     }
 
+    @Override
     public void setAction(DeoptimizationAction invalidaterecompile) {
         this.action = invalidaterecompile;
     }
+
+    @Override
+    public void setReason(DeoptimizationReason reason) {
+        this.reason = reason;
+    }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InliningLog.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InliningLog.java	Fri Mar 16 22:59:32 2018 -0700
@@ -22,13 +22,20 @@
  */
 package org.graalvm.compiler.nodes;
 
-import jdk.vm.ci.code.BytecodePosition;
+import jdk.vm.ci.meta.MetaUtil;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.Equivalence;
+import org.graalvm.collections.MapCursor;
+import org.graalvm.collections.UnmodifiableEconomicMap;
+import org.graalvm.compiler.core.common.GraalOptions;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.options.OptionValues;
 
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
+import java.util.function.BiConsumer;
 
 /**
  * This class contains all inlining decisions performed on a graph during the compilation.
@@ -40,8 +47,6 @@
  * <li>the call target method</li>
  * <li>the reason for the inlining decision</li>
  * <li>the name of the phase in which the inlining decision took place</li>
- * <li>the special {@link BytecodePositionWithId} value that describes the position in the bytecode
- * together with the callsite-specific unique identifier</li>
  * <li>the inlining log of the inlined graph, or {@code null} if the decision was negative</li>
  * </ul>
  *
@@ -49,99 +54,20 @@
  * {@link StructuredGraph} by calling {@link #addDecision} whenever it decides to inline a method.
  * If there are invokes in the graph at the end of the respective phase, then that phase must call
  * {@link #addDecision} to log negative decisions.
- *
- * At the end of the compilation, the contents of the inlining log can be converted into a list of
- * decisions by calling {@link #formatAsList} or into an inlining tree, by calling
- * {@link #formatAsTree}.
  */
 public class InliningLog {
-    /**
-     * A bytecode position with a unique identifier attached.
-     *
-     * The purpose of this class is to disambiguate callsites that are duplicated by a
-     * transformation (such as loop peeling or path duplication).
-     */
-    public static final class BytecodePositionWithId extends BytecodePosition implements Comparable<BytecodePositionWithId> {
-        private final int id;
-
-        public BytecodePositionWithId(BytecodePositionWithId caller, ResolvedJavaMethod method, int bci, int id) {
-            super(caller, method, bci);
-            this.id = id;
-        }
-
-        public BytecodePositionWithId addCallerWithId(BytecodePositionWithId caller) {
-            if (getCaller() == null) {
-                return new BytecodePositionWithId(caller, getMethod(), getBCI(), id);
-            } else {
-                return new BytecodePositionWithId(getCaller().addCallerWithId(caller), getMethod(), getBCI(), id);
-            }
-        }
-
-        public static BytecodePositionWithId create(FrameState state) {
-            return create(state, true);
-        }
-
-        @SuppressWarnings("deprecation")
-        private static BytecodePositionWithId create(FrameState state, boolean topLevel) {
-            if (state == null) {
-                return null;
-            }
-            ResolvedJavaMethod method = state.getMethod();
-            int bci = topLevel ? state.bci - 3 : state.bci;
-            int id = state.getId();
-            return new BytecodePositionWithId(create(state.outerFrameState(), false), method, bci, id);
-        }
-
-        @Override
-        public BytecodePositionWithId getCaller() {
-            return (BytecodePositionWithId) super.getCaller();
-        }
-
-        public BytecodePositionWithId withoutCaller() {
-            return new BytecodePositionWithId(null, getMethod(), getBCI(), id);
-        }
-
-        public long getId() {
-            return id;
-        }
-
-        @Override
-        public boolean equals(Object that) {
-            return super.equals(that) && this.id == ((BytecodePositionWithId) that).id;
-        }
-
-        @Override
-        public int hashCode() {
-            return super.hashCode() ^ (id << 16);
-        }
-
-        @Override
-        public int compareTo(BytecodePositionWithId that) {
-            int diff = this.getBCI() - that.getBCI();
-            if (diff != 0) {
-                return diff;
-            }
-            diff = (int) (this.getId() - that.getId());
-            return diff;
-        }
-    }
 
     public static final class Decision {
         private final boolean positive;
         private final String reason;
         private final String phase;
         private final ResolvedJavaMethod target;
-        private final BytecodePositionWithId position;
-        private final InliningLog childLog;
 
-        private Decision(boolean positive, String reason, String phase, ResolvedJavaMethod target, BytecodePositionWithId position, InliningLog childLog) {
-            assert position != null;
+        private Decision(boolean positive, String reason, String phase, ResolvedJavaMethod target) {
             this.positive = positive;
             this.reason = reason;
             this.phase = phase;
             this.target = target;
-            this.position = position;
-            this.childLog = childLog;
         }
 
         public boolean isPositive() {
@@ -156,123 +82,304 @@
             return phase;
         }
 
-        public BytecodePositionWithId getPosition() {
-            return position;
+        public ResolvedJavaMethod getTarget() {
+            return target;
         }
 
-        public InliningLog getChildLog() {
-            return childLog;
+        @Override
+        public String toString() {
+            return String.format("<%s> %s: %s", phase, target != null ? target.format("%H.%n(%p)") : "", reason);
+        }
+    }
+
+    private class Callsite {
+        public final List<Decision> decisions;
+        public final List<Callsite> children;
+        public Callsite parent;
+        public ResolvedJavaMethod target;
+        public Invokable invoke;
+
+        Callsite(Callsite parent, Invokable originalInvoke) {
+            this.parent = parent;
+            this.decisions = new ArrayList<>();
+            this.children = new ArrayList<>();
+            this.invoke = originalInvoke;
         }
 
-        public ResolvedJavaMethod getTarget() {
-            return target;
+        public Callsite addChild(Invokable childInvoke) {
+            Callsite child = new Callsite(this, childInvoke);
+            children.add(child);
+            return child;
+        }
+
+        public String positionString() {
+            if (parent == null) {
+                return "<root>";
+            }
+            return MetaUtil.appendLocation(new StringBuilder(100), parent.target, getBci()).toString();
+        }
+
+        public int getBci() {
+            return invoke != null ? invoke.bci() : -1;
         }
     }
 
-    private static class Callsite {
-        public final List<String> decisions;
-        public final Map<BytecodePositionWithId, Callsite> children;
-        public final BytecodePositionWithId position;
+    private final Callsite root;
+    private final EconomicMap<Invokable, Callsite> leaves;
+    private final OptionValues options;
+
+    public InliningLog(ResolvedJavaMethod rootMethod, OptionValues options) {
+        this.root = new Callsite(null, null);
+        this.root.target = rootMethod;
+        this.leaves = EconomicMap.create(Equivalence.IDENTITY_WITH_SYSTEM_HASHCODE);
+        this.options = options;
+    }
 
-        Callsite(BytecodePositionWithId position) {
-            this.children = new HashMap<>();
-            this.position = position;
-            this.decisions = new ArrayList<>();
-        }
-
-        public Callsite getOrCreateChild(BytecodePositionWithId fromRootPosition) {
-            Callsite child = children.get(fromRootPosition.withoutCaller());
-            if (child == null) {
-                child = new Callsite(fromRootPosition);
-                children.put(fromRootPosition.withoutCaller(), child);
+    /**
+     * Add an inlining decision for the specified invoke.
+     *
+     * An inlining decision can be either positive or negative. A positive inlining decision must be
+     * logged after replacing an {@link Invoke} with a graph. In this case, the node replacement map
+     * and the {@link InliningLog} of the inlined graph must be provided.
+     */
+    public void addDecision(Invokable invoke, boolean positive, String reason, String phase, EconomicMap<Node, Node> replacements, InliningLog calleeLog) {
+        assert leaves.containsKey(invoke);
+        assert (!positive && replacements == null && calleeLog == null) || (positive && replacements != null && calleeLog != null);
+        Callsite callsite = leaves.get(invoke);
+        callsite.target = callsite.invoke.getTargetMethod();
+        Decision decision = new Decision(positive, reason, phase, invoke.getTargetMethod());
+        callsite.decisions.add(decision);
+        if (positive) {
+            leaves.removeKey(invoke);
+            EconomicMap<Callsite, Callsite> mapping = EconomicMap.create(Equivalence.IDENTITY_WITH_SYSTEM_HASHCODE);
+            for (Callsite calleeChild : calleeLog.root.children) {
+                Callsite child = callsite.addChild(calleeChild.invoke);
+                copyTree(child, calleeChild, replacements, mapping);
             }
-            return child;
-        }
-
-        public Callsite createCallsite(BytecodePositionWithId fromRootPosition, String decision) {
-            Callsite parent = getOrCreateCallsite(fromRootPosition.getCaller());
-            Callsite callsite = parent.getOrCreateChild(fromRootPosition);
-            callsite.decisions.add(decision);
-            return null;
-        }
-
-        private Callsite getOrCreateCallsite(BytecodePositionWithId fromRootPosition) {
-            if (fromRootPosition == null) {
-                return this;
-            } else {
-                Callsite parent = getOrCreateCallsite(fromRootPosition.getCaller());
-                Callsite callsite = parent.getOrCreateChild(fromRootPosition);
-                return callsite;
+            MapCursor<Invokable, Callsite> entries = calleeLog.leaves.getEntries();
+            while (entries.advance()) {
+                Invokable invokeFromCallee = entries.getKey();
+                Callsite callsiteFromCallee = entries.getValue();
+                if (invokeFromCallee.asFixedNode().isDeleted()) {
+                    // Some invoke nodes could have been removed by optimizations.
+                    continue;
+                }
+                Invokable inlinedInvokeFromCallee = (Invokable) replacements.get(invokeFromCallee.asFixedNode());
+                Callsite descendant = mapping.get(callsiteFromCallee);
+                leaves.put(inlinedInvokeFromCallee, descendant);
             }
         }
     }
 
-    private final List<Decision> decisions;
-
-    public InliningLog() {
-        this.decisions = new ArrayList<>();
-    }
-
-    public List<Decision> getDecisions() {
-        return decisions;
-    }
-
-    public void addDecision(boolean positive, String reason, String phase, ResolvedJavaMethod target, BytecodePositionWithId position,
-                    InliningLog calleeLog) {
-        Decision decision = new Decision(positive, reason, phase, target, position, calleeLog);
-        decisions.add(decision);
+    /**
+     * Append the inlining decision tree from the specified log.
+     *
+     * The subtrees of the specified log are appended below the root of this log. This is usually
+     * called when a node in the graph is replaced with its snippet.
+     *
+     * @see InliningLog#addDecision
+     */
+    public void addLog(UnmodifiableEconomicMap<Node, Node> replacements, InliningLog replacementLog) {
+        EconomicMap<Callsite, Callsite> mapping = EconomicMap.create(Equivalence.IDENTITY_WITH_SYSTEM_HASHCODE);
+        for (Callsite calleeChild : replacementLog.root.children) {
+            Callsite child = root.addChild(calleeChild.invoke);
+            copyTree(child, calleeChild, replacements, mapping);
+        }
+        MapCursor<Invokable, Callsite> entries = replacementLog.leaves.getEntries();
+        while (entries.advance()) {
+            Invokable replacementInvoke = entries.getKey();
+            Callsite replacementCallsite = entries.getValue();
+            if (replacementInvoke.asFixedNode().isDeleted()) {
+                // Some invoke nodes could have been removed by optimizations.
+                continue;
+            }
+            Invokable invoke = (Invokable) replacements.get(replacementInvoke.asFixedNode());
+            Callsite callsite = mapping.get(replacementCallsite);
+            leaves.put(invoke, callsite);
+        }
     }
 
-    public String formatAsList() {
-        StringBuilder builder = new StringBuilder();
-        formatAsList("", null, decisions, builder);
-        return builder.toString();
+    /**
+     * Completely replace the current log with the copy of the specified log.
+     *
+     * The precondition is that the current inlining log is completely empty. This is usually called
+     * when copying the entire graph.
+     *
+     * @see InliningLog#addDecision
+     */
+    public void replaceLog(UnmodifiableEconomicMap<Node, Node> replacements, InliningLog replacementLog) {
+        assert root.decisions.isEmpty();
+        assert root.children.isEmpty();
+        assert leaves.isEmpty();
+        EconomicMap<Callsite, Callsite> mapping = EconomicMap.create(Equivalence.IDENTITY_WITH_SYSTEM_HASHCODE);
+        copyTree(root, replacementLog.root, replacements, mapping);
+        MapCursor<Invokable, Callsite> replacementEntries = replacementLog.leaves.getEntries();
+        while (replacementEntries.advance()) {
+            Invokable replacementInvoke = replacementEntries.getKey();
+            Callsite replacementSite = replacementEntries.getValue();
+            Invokable invoke = (Invokable) replacements.get((Node) replacementInvoke);
+            Callsite site = mapping.get(replacementSite);
+            leaves.put(invoke, site);
+        }
     }
 
-    private void formatAsList(String phasePrefix, BytecodePositionWithId caller, List<Decision> subDecisions, StringBuilder builder) {
-        for (Decision decision : subDecisions) {
-            String phaseStack = phasePrefix.equals("") ? decision.getPhase() : phasePrefix + "-" + decision.getPhase();
-            String target = decision.getTarget().format("%H.%n(%p)");
-            String positive = decision.isPositive() ? "inline" : "do not inline";
-            BytecodePositionWithId absolutePosition = decision.getPosition().addCallerWithId(caller);
-            String position = "  " + decision.getPosition().toString().replaceAll("\n", "\n  ");
-            String line = String.format("<%s> %s %s: %s\n%s", phaseStack, positive, target, decision.getReason(), position);
-            builder.append(line).append(System.lineSeparator());
-            if (decision.getChildLog() != null) {
-                formatAsList(phaseStack, absolutePosition, decision.getChildLog().getDecisions(), builder);
-            }
+    private void copyTree(Callsite site, Callsite replacementSite, UnmodifiableEconomicMap<Node, Node> replacements, EconomicMap<Callsite, Callsite> mapping) {
+        mapping.put(replacementSite, site);
+        site.target = replacementSite.target;
+        site.decisions.addAll(replacementSite.decisions);
+        site.invoke = replacementSite.invoke != null && replacementSite.invoke.asFixedNode().isAlive() ? (Invokable) replacements.get(replacementSite.invoke.asFixedNode()) : null;
+        for (Callsite replacementChild : replacementSite.children) {
+            Callsite child = new Callsite(site, null);
+            site.children.add(child);
+            copyTree(child, replacementChild, replacements, mapping);
+        }
+    }
+
+    public void checkInvariants(StructuredGraph graph) {
+        for (Invoke invoke : graph.getInvokes()) {
+            assert leaves.containsKey(invoke) : "Invoke " + invoke + " not contained in the leaves.";
+        }
+        assert root.parent == null;
+        checkTreeInvariants(root);
+    }
+
+    private void checkTreeInvariants(Callsite site) {
+        for (Callsite child : site.children) {
+            assert site == child.parent : "Callsite " + site + " with child " + child + " has an invalid parent pointer " + site;
+            checkTreeInvariants(child);
         }
     }
 
+    private UpdateScope noUpdates = new UpdateScope((oldNode, newNode) -> {
+    });
+
+    private UpdateScope activated = null;
+
+    /**
+     * Used to designate scopes in which {@link Invokable} registration or cloning should be handled
+     * differently.
+     */
+    public final class UpdateScope implements AutoCloseable {
+        private BiConsumer<Invokable, Invokable> updater;
+
+        private UpdateScope(BiConsumer<Invokable, Invokable> updater) {
+            this.updater = updater;
+        }
+
+        public void activate() {
+            if (activated != null) {
+                throw GraalError.shouldNotReachHere("InliningLog updating already set.");
+            }
+            activated = this;
+        }
+
+        @Override
+        public void close() {
+            if (GraalOptions.TraceInlining.getValue(options)) {
+                assert activated != null;
+                activated = null;
+            }
+        }
+
+        public BiConsumer<Invokable, Invokable> getUpdater() {
+            return updater;
+        }
+    }
+
+    public BiConsumer<Invokable, Invokable> getUpdateScope() {
+        if (activated == null) {
+            return null;
+        }
+        return activated.getUpdater();
+    }
+
+    /**
+     * Creates and sets a new update scope for the log.
+     *
+     * The specified {@code updater} is invoked when an {@link Invokable} node is registered or
+     * cloned. If the node is newly registered, then the first argument to the {@code updater} is
+     * {@code null}. If the node is cloned, then the first argument is the node it was cloned from.
+     *
+     * @param updater an operation taking a null (or the original node), and the registered (or
+     *            cloned) {@link Invokable}
+     * @return a bound {@link UpdateScope} object, or a {@code null} if tracing is disabled
+     */
+    public UpdateScope openUpdateScope(BiConsumer<Invokable, Invokable> updater) {
+        if (GraalOptions.TraceInlining.getValue(options)) {
+            UpdateScope scope = new UpdateScope(updater);
+            scope.activate();
+            return scope;
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Creates a new update scope that does not update the log.
+     *
+     * This update scope will not add a newly created {@code Invokable} to the log, nor will it
+     * amend its position if it was cloned. Instead, users need to update the inlining log with the
+     * new {@code Invokable} on their own.
+     *
+     * @see #openUpdateScope
+     */
+    public UpdateScope openDefaultUpdateScope() {
+        if (GraalOptions.TraceInlining.getValue(options)) {
+            noUpdates.activate();
+            return noUpdates;
+        } else {
+            return null;
+        }
+    }
+
+    public boolean containsLeafCallsite(Invokable invokable) {
+        return leaves.containsKey(invokable);
+    }
+
+    public void removeLeafCallsite(Invokable invokable) {
+        leaves.removeKey(invokable);
+    }
+
+    public void trackNewCallsite(Invokable invoke) {
+        assert !leaves.containsKey(invoke);
+        Callsite callsite = new Callsite(root, invoke);
+        root.children.add(callsite);
+        leaves.put(invoke, callsite);
+    }
+
+    public void trackDuplicatedCallsite(Invokable sibling, Invokable newInvoke) {
+        Callsite siblingCallsite = leaves.get(sibling);
+        Callsite parentCallsite = siblingCallsite.parent;
+        Callsite callsite = parentCallsite.addChild(newInvoke);
+        leaves.put(newInvoke, callsite);
+    }
+
+    public void updateExistingCallsite(Invokable previousInvoke, Invokable newInvoke) {
+        Callsite callsite = leaves.get(previousInvoke);
+        leaves.removeKey(previousInvoke);
+        leaves.put(newInvoke, callsite);
+        callsite.invoke = newInvoke;
+    }
+
     public String formatAsTree() {
-        Callsite root = new Callsite(null);
-        createTree("", null, root, decisions);
-        StringBuilder builder = new StringBuilder();
+        StringBuilder builder = new StringBuilder(512);
         formatAsTree(root, "", builder);
         return builder.toString();
     }
 
-    private void createTree(String phasePrefix, BytecodePositionWithId caller, Callsite root, List<Decision> subDecisions) {
-        for (Decision decision : subDecisions) {
-            String phaseStack = phasePrefix.equals("") ? decision.getPhase() : phasePrefix + "-" + decision.getPhase();
-            String target = decision.getTarget().format("%H.%n(%p)");
-            BytecodePositionWithId absolutePosition = decision.getPosition().addCallerWithId(caller);
-            String line = String.format("<%s> %s: %s", phaseStack, target, decision.getReason());
-            root.createCallsite(absolutePosition, line);
-            if (decision.getChildLog() != null) {
-                createTree(phaseStack, absolutePosition, root, decision.getChildLog().getDecisions());
+    private void formatAsTree(Callsite site, String indent, StringBuilder builder) {
+        String position = site.positionString();
+        builder.append(indent).append("at ").append(position).append(": ");
+        if (site.decisions.isEmpty()) {
+            builder.append(System.lineSeparator());
+        } else {
+            for (Decision decision : site.decisions) {
+                builder.append(decision.toString());
+                builder.append(System.lineSeparator());
             }
         }
+        for (Callsite child : site.children) {
+            formatAsTree(child, indent + "  ", builder);
+        }
     }
-
-    private void formatAsTree(Callsite site, String indent, StringBuilder builder) {
-        String position = site.position != null ? site.position.withoutCaller().toString() : "<root>";
-        String decision = String.join("; ", site.decisions);
-        String line = String.format("%s%s; %s", indent, position, decision);
-        builder.append(line).append(System.lineSeparator());
-        String childIndent = indent + "  ";
-        site.children.entrySet().stream().sorted((x, y) -> x.getKey().compareTo(y.getKey())).forEach(e -> {
-            formatAsTree(e.getValue(), childIndent, builder);
-        });
-    }
 }
--- /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/Invokable.java	Fri Mar 16 22:59:32 2018 -0700
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 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.nodes;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import org.graalvm.compiler.core.common.GraalOptions;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Node;
+
+/**
+ * A marker interface for nodes that represent calls to other methods.
+ */
+public interface Invokable {
+    ResolvedJavaMethod getTargetMethod();
+
+    int bci();
+
+    FixedNode asFixedNode();
+
+    /**
+     * Called on a {@link Invokable} node after it is registered with a graph.
+     *
+     * To override the default functionality, code that creates an {@link Invokable} should set the
+     * updating logic by calling {@link InliningLog#openUpdateScope}.
+     */
+    default void updateInliningLogAfterRegister(StructuredGraph newGraph) {
+        InliningLog log = newGraph.getInliningLog();
+        if (log.getUpdateScope() != null) {
+            log.getUpdateScope().accept(null, this);
+        } else {
+            assert !log.containsLeafCallsite(this);
+            log.trackNewCallsite(this);
+        }
+    }
+
+    /**
+     * Called on a {@link Invokable} node after it was cloned from another node.
+     *
+     * This call is always preceded with a call to {@link Invokable#updateInliningLogAfterRegister}.
+     *
+     * To override the default functionality, code that creates an {@link Invokable} should set the
+     * updating logic by calling {@link InliningLog#openUpdateScope}.
+     */
+    default void updateInliningLogAfterClone(Node other) {
+        if (GraalOptions.TraceInlining.getValue(asFixedNode().getOptions())) {
+            // At this point, the invokable node was already added to the inlining log
+            // in the call to updateInliningLogAfterRegister, so we need to remove it.
+            InliningLog log = asFixedNode().graph().getInliningLog();
+            assert other instanceof Invokable;
+            if (log.getUpdateScope() != null) {
+                // InliningLog.UpdateScope determines how to update the log.
+                log.getUpdateScope().accept((Invokable) other, this);
+            } else if (other.graph() == this.asFixedNode().graph()) {
+                // This node was cloned as part of duplication.
+                // We need to add it as a sibling of the node other.
+                assert log.containsLeafCallsite(this) : "Node " + this + " not contained in the log.";
+                assert log.containsLeafCallsite((Invokable) other) : "Sibling " + other + " not contained in the log.";
+                log.removeLeafCallsite(this);
+                log.trackDuplicatedCallsite((Invokable) other, this);
+            } else {
+                // This node was added from a different graph.
+                // The adder is responsible for providing a context.
+                throw GraalError.shouldNotReachHere("No InliningLog.Update scope provided.");
+            }
+        }
+    }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/Invoke.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/Invoke.java	Fri Mar 16 22:59:32 2018 -0700
@@ -31,7 +31,7 @@
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 import jdk.vm.ci.meta.ResolvedJavaType;
 
-public interface Invoke extends StateSplit, Lowerable, DeoptimizingNode.DeoptDuring, FixedNodeInterface {
+public interface Invoke extends StateSplit, Lowerable, DeoptimizingNode.DeoptDuring, FixedNodeInterface, Invokable {
 
     FixedNode next();
 
@@ -39,6 +39,7 @@
 
     CallTargetNode callTarget();
 
+    @Override
     int bci();
 
     Node predecessor();
@@ -60,6 +61,11 @@
 
     void setPolymorphic(boolean value);
 
+    @Override
+    default ResolvedJavaMethod getTargetMethod() {
+        return callTarget() != null ? callTarget().targetMethod() : null;
+    }
+
     /**
      * Returns the {@linkplain ResolvedJavaMethod method} from which this invoke is executed. This
      * is the caller method and in the case of inlining may be different from the method of the
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InvokeNode.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InvokeNode.java	Fri Mar 16 22:59:32 2018 -0700
@@ -93,6 +93,16 @@
     }
 
     @Override
+    protected void afterClone(Node other) {
+        updateInliningLogAfterClone(other);
+    }
+
+    @Override
+    public FixedNode asFixedNode() {
+        return this;
+    }
+
+    @Override
     public CallTargetNode callTarget() {
         return callTarget;
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InvokeWithExceptionNode.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InvokeWithExceptionNode.java	Fri Mar 16 22:59:32 2018 -0700
@@ -74,6 +74,16 @@
         this.exceptionProbability = EXCEPTION_PROBA;
     }
 
+    @Override
+    protected void afterClone(Node other) {
+        updateInliningLogAfterClone(other);
+    }
+
+    @Override
+    public FixedNode asFixedNode() {
+        return this;
+    }
+
     public AbstractBeginNode exceptionEdge() {
         return exceptionEdge;
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/LoopExitNode.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/LoopExitNode.java	Fri Mar 16 22:59:32 2018 -0700
@@ -105,6 +105,9 @@
         Node prev = this.predecessor();
         while (tool.allUsagesAvailable() && prev instanceof BeginNode && prev.hasNoUsages()) {
             AbstractBeginNode begin = (AbstractBeginNode) prev;
+            if (begin.getNodeSourcePosition() != null || this.getNodeSourcePosition() == null || this.getNodeSourcePosition().isPlaceholder()) {
+                this.setNodeSourcePosition(begin.getNodeSourcePosition());
+            }
             prev = prev.predecessor();
             graph().removeFixed(begin);
         }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/PiNode.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/PiNode.java	Fri Mar 16 22:59:32 2018 -0700
@@ -192,7 +192,7 @@
 
         if (guard == null) {
             // Try to merge the pi node with a load node.
-            if (object instanceof ReadNode) {
+            if (object instanceof ReadNode && !object.hasMoreThanOneUsage()) {
                 ReadNode readNode = (ReadNode) object;
                 readNode.setStamp(readNode.stamp(NodeView.DEFAULT).improveWith(stamp));
                 return readNode;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StaticDeoptimizingNode.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StaticDeoptimizingNode.java	Fri Mar 16 22:59:32 2018 -0700
@@ -32,8 +32,12 @@
 
     DeoptimizationReason getReason();
 
+    void setReason(DeoptimizationReason reason);
+
     DeoptimizationAction getAction();
 
+    void setAction(DeoptimizationAction action);
+
     JavaConstant getSpeculation();
 
     /**
@@ -75,4 +79,15 @@
         }
         throw GraalError.shouldNotReachHere();
     }
+
+    static DeoptimizationAction mergeActions(DeoptimizationAction a1, DeoptimizationAction a2) {
+        if (a1 == a2) {
+            return a1;
+        }
+        if (a1 == DeoptimizationAction.InvalidateRecompile && a2 == DeoptimizationAction.InvalidateReprofile ||
+                        a1 == DeoptimizationAction.InvalidateReprofile && a2 == DeoptimizationAction.InvalidateRecompile) {
+            return DeoptimizationAction.InvalidateReprofile;
+        }
+        return null;
+    }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StructuredGraph.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StructuredGraph.java	Fri Mar 16 22:59:32 2018 -0700
@@ -22,6 +22,8 @@
  */
 package org.graalvm.compiler.nodes;
 
+import static org.graalvm.compiler.graph.Graph.SourcePositionTracking.Default;
+
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
@@ -39,6 +41,7 @@
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.debug.DebugContext;
 import org.graalvm.compiler.debug.JavaMethodContext;
+import org.graalvm.compiler.debug.TTY;
 import org.graalvm.compiler.graph.Graph;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.graph.NodeMap;
@@ -167,6 +170,7 @@
         private CompilationIdentifier compilationId = CompilationIdentifier.INVALID_COMPILATION_ID;
         private int entryBCI = JVMCICompiler.INVOCATION_ENTRY_BCI;
         private boolean useProfilingInfo = true;
+        private SourcePositionTracking trackNodeSourcePosition = Default;
         private final OptionValues options;
         private Cancellable cancellable = null;
         private final DebugContext debug;
@@ -179,6 +183,7 @@
             this.options = options;
             this.debug = debug;
             this.assumptions = allowAssumptions == AllowAssumptions.YES ? new Assumptions() : null;
+            this.trackNodeSourcePosition = Graph.trackNodeSourcePositionDefault(options, debug);
         }
 
         /**
@@ -187,7 +192,8 @@
         public Builder(OptionValues options, DebugContext debug) {
             this.options = options;
             this.debug = debug;
-            assumptions = null;
+            this.assumptions = null;
+            this.trackNodeSourcePosition = Graph.trackNodeSourcePositionDefault(options, debug);
         }
 
         public String getName() {
@@ -257,13 +263,25 @@
             return this;
         }
 
+        public Builder trackNodeSourcePosition(SourcePositionTracking tracking) {
+            this.trackNodeSourcePosition = tracking;
+            return this;
+        }
+
+        public Builder trackNodeSourcePosition(boolean flag) {
+            if (flag) {
+                this.trackNodeSourcePosition = SourcePositionTracking.Track;
+            }
+            return this;
+        }
+
         public Builder callerContext(NodeSourcePosition context) {
             this.callerContext = context;
             return this;
         }
 
         public StructuredGraph build() {
-            return new StructuredGraph(name, rootMethod, entryBCI, assumptions, speculationLog, useProfilingInfo, compilationId, options, debug, cancellable, callerContext);
+            return new StructuredGraph(name, rootMethod, entryBCI, assumptions, speculationLog, useProfilingInfo, trackNodeSourcePosition, compilationId, options, debug, cancellable, callerContext);
         }
     }
 
@@ -328,6 +346,7 @@
                     Assumptions assumptions,
                     SpeculationLog speculationLog,
                     boolean useProfilingInfo,
+                    SourcePositionTracking trackNodeSourcePosition,
                     CompilationIdentifier compilationId,
                     OptionValues options,
                     DebugContext debug,
@@ -342,8 +361,10 @@
         this.assumptions = assumptions;
         this.speculationLog = speculationLog;
         this.useProfilingInfo = useProfilingInfo;
+        this.trackNodeSourcePosition = trackNodeSourcePosition;
+        assert trackNodeSourcePosition != null;
         this.cancellable = cancellable;
-        this.inliningLog = new InliningLog();
+        this.inliningLog = new InliningLog(rootMethod, options);
         this.callerContext = context;
     }
 
@@ -457,6 +478,12 @@
         return inliningLog;
     }
 
+    public void logInliningTree() {
+        if (GraalOptions.TraceInlining.getValue(getOptions())) {
+            TTY.println(getInliningLog().formatAsTree());
+        }
+    }
+
     /**
      * Creates a copy of this graph.
      *
@@ -471,6 +498,7 @@
         return copy(newName, duplicationMapCallback, compilationId, debugForCopy);
     }
 
+    @SuppressWarnings("try")
     private StructuredGraph copy(String newName, Consumer<UnmodifiableEconomicMap<Node, Node>> duplicationMapCallback, CompilationIdentifier newCompilationId, DebugContext debugForCopy) {
         AllowAssumptions allowAssumptions = AllowAssumptions.ifNonNull(assumptions);
         StructuredGraph copy = new StructuredGraph(newName,
@@ -479,6 +507,7 @@
                         assumptions == null ? null : new Assumptions(),
                         speculationLog,
                         useProfilingInfo,
+                        trackNodeSourcePosition,
                         newCompilationId,
                         getOptions(), debugForCopy, null, callerContext);
         if (allowAssumptions == AllowAssumptions.YES && assumptions != null) {
@@ -491,7 +520,13 @@
         copy.isAfterExpandLogic = isAfterExpandLogic;
         EconomicMap<Node, Node> replacements = EconomicMap.create(Equivalence.IDENTITY);
         replacements.put(start, copy.start);
-        UnmodifiableEconomicMap<Node, Node> duplicates = copy.addDuplicates(getNodes(), this, this.getNodeCount(), replacements);
+        UnmodifiableEconomicMap<Node, Node> duplicates;
+        try (InliningLog.UpdateScope scope = copy.getInliningLog().openDefaultUpdateScope()) {
+            duplicates = copy.addDuplicates(getNodes(), this, this.getNodeCount(), replacements);
+            if (scope != null) {
+                copy.getInliningLog().replaceLog(duplicates, this.getInliningLog());
+            }
+        }
         if (duplicationMapCallback != null) {
             duplicationMapCallback.accept(duplicates);
         }
@@ -951,6 +986,11 @@
     @Override
     protected void afterRegister(Node node) {
         assert hasValueProxies() || !(node instanceof ValueProxyNode);
+        if (GraalOptions.TraceInlining.getValue(getOptions())) {
+            if (node instanceof Invokable) {
+                ((Invokable) node).updateInliningLogAfterRegister(this);
+            }
+        }
     }
 
     public NodeSourcePosition getCallerContext() {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/CompareNode.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/CompareNode.java	Fri Mar 16 22:59:32 2018 -0700
@@ -25,12 +25,12 @@
 import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_1;
 
+import org.graalvm.compiler.core.common.PermanentBailoutException;
 import org.graalvm.compiler.core.common.calc.CanonicalCondition;
 import org.graalvm.compiler.core.common.calc.Condition;
 import org.graalvm.compiler.core.common.type.AbstractObjectStamp;
 import org.graalvm.compiler.core.common.type.AbstractPointerStamp;
 import org.graalvm.compiler.core.common.type.IntegerStamp;
-import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.graph.spi.Canonicalizable;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
@@ -209,7 +209,7 @@
         @SuppressWarnings("unused")
         protected LogicNode optimizeNormalizeCompare(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth,
                         Constant constant, NormalizeCompareNode normalizeNode, boolean mirrored, NodeView view) {
-            throw new GraalError("NormalizeCompareNode connected to %s (%s %s %s)", this, constant, normalizeNode, mirrored);
+            throw new PermanentBailoutException("NormalizeCompareNode connected to %s (%s %s %s)", this, constant, normalizeNode, mirrored);
         }
 
         private static LogicNode optimizeConditional(Constant constant, ConditionalNode conditionalNode, ConstantReflectionProvider constantReflection, Condition cond, boolean unorderedIsTrue) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ConditionalNode.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ConditionalNode.java	Fri Mar 16 22:59:32 2018 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 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
@@ -170,9 +170,9 @@
                         return trueValue;
                     }
                 } else if (lessThan.getX() == falseValue && lessThan.getY() == trueValue) {
-                    // return "x" for "x < y ? y : x" in case that we know "x <= y"
+                    // return "y" for "x < y ? y : x" in case that we know "x <= y"
                     if (falseValueStamp.upperBound() <= trueValueStamp.lowerBound()) {
-                        return falseValue;
+                        return trueValue;
                     }
                 }
             }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerConvertNode.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerConvertNode.java	Fri Mar 16 22:59:32 2018 -0700
@@ -139,6 +139,15 @@
         return convert(input, stamp, true, view);
     }
 
+    public static ValueNode convertUnsigned(ValueNode input, Stamp stamp, StructuredGraph graph, NodeView view) {
+        ValueNode convert = convert(input, stamp, true, view);
+        if (!convert.isAlive()) {
+            assert !convert.isDeleted();
+            convert = graph.addOrUniqueWithInputs(convert);
+        }
+        return convert;
+    }
+
     public static ValueNode convert(ValueNode input, Stamp stamp, boolean zeroExtend, NodeView view) {
         IntegerStamp fromStamp = (IntegerStamp) input.stamp(view);
         IntegerStamp toStamp = (IntegerStamp) stamp;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerLowerThanNode.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerLowerThanNode.java	Fri Mar 16 22:59:32 2018 -0700
@@ -22,6 +22,8 @@
  */
 package org.graalvm.compiler.nodes.calc;
 
+import static jdk.vm.ci.code.CodeUtil.mask;
+
 import org.graalvm.compiler.core.common.calc.CanonicalCondition;
 import org.graalvm.compiler.core.common.type.IntegerStamp;
 import org.graalvm.compiler.core.common.type.Stamp;
@@ -70,8 +72,8 @@
 
     private Stamp getSucceedingStampForX(boolean mirror, boolean strict, Stamp xStampGeneric, Stamp yStampGeneric, ValueNode forX, ValueNode forY) {
         Stamp s = getSucceedingStampForX(mirror, strict, xStampGeneric, yStampGeneric);
-        if (s != null) {
-            return s;
+        if (s != null && s.isUnrestricted()) {
+            s = null;
         }
         if (forY instanceof AddNode && xStampGeneric instanceof IntegerStamp) {
             IntegerStamp xStamp = (IntegerStamp) xStampGeneric;
@@ -88,11 +90,15 @@
                 IntegerStamp result = getOp().getSucceedingStampForXLowerXPlusA(mirror, strict, aStamp);
                 result = (IntegerStamp) xStamp.tryImproveWith(result);
                 if (result != null) {
-                    return result;
+                    if (s != null) {
+                        s = s.improveWith(result);
+                    } else {
+                        s = result;
+                    }
                 }
             }
         }
-        return null;
+        return s;
     }
 
     private Stamp getSucceedingStampForX(boolean mirror, boolean strict, Stamp xStampGeneric, Stamp yStampGeneric) {
@@ -278,7 +284,7 @@
                     }
                     low += 1;
                 }
-                if (compare(low, lowerBound(xStamp)) > 0) {
+                if (compare(low, lowerBound(xStamp)) > 0 || upperBound(xStamp) != (xStamp.upperBound() & mask(xStamp.getBits()))) {
                     return forInteger(bits, low, upperBound(xStamp));
                 }
             } else {
@@ -290,7 +296,7 @@
                     }
                     low -= 1;
                 }
-                if (compare(low, upperBound(xStamp)) < 0) {
+                if (compare(low, upperBound(xStamp)) < 0 || lowerBound(xStamp) != (xStamp.lowerBound() & mask(xStamp.getBits()))) {
                     return forInteger(bits, lowerBound(xStamp), low);
                 }
             }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/IntegerSwitchNode.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/IntegerSwitchNode.java	Fri Mar 16 22:59:32 2018 -0700
@@ -24,6 +24,7 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Comparator;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -40,7 +41,6 @@
 import org.graalvm.compiler.nodes.AbstractBeginNode;
 import org.graalvm.compiler.nodes.ConstantNode;
 import org.graalvm.compiler.nodes.FixedGuardNode;
-import org.graalvm.compiler.nodes.FixedNode;
 import org.graalvm.compiler.nodes.FixedWithNextNode;
 import org.graalvm.compiler.nodes.LogicNode;
 import org.graalvm.compiler.nodes.NodeView;
@@ -316,7 +316,7 @@
 
     private void doReplace(ValueNode newValue, List<KeyData> newKeyDatas, ArrayList<AbstractBeginNode> newSuccessors, int newDefaultSuccessor, double newDefaultProbability) {
         /* Sort the new keys (invariant of the IntegerSwitchNode). */
-        newKeyDatas.sort((k1, k2) -> k1.key - k2.key);
+        newKeyDatas.sort(Comparator.comparingInt(k -> k.key));
 
         /* Create the final data arrays. */
         int newKeyCount = newKeyDatas.size();
@@ -349,20 +349,27 @@
             }
         }
 
+        /*
+         * Collect dead successors. Successors have to be cleaned before adding the new node to the
+         * graph.
+         */
+        List<AbstractBeginNode> deadSuccessors = successors.filter(s -> !newSuccessors.contains(s)).snapshot();
+        successors.clear();
+
+        /*
+         * Create the new switch node. This is done before removing dead successors as `killCFG`
+         * could edit some of the inputs (e.g., if `newValue` is a loop-phi of the loop that dies
+         * while removing successors).
+         */
+        AbstractBeginNode[] successorsArray = newSuccessors.toArray(new AbstractBeginNode[newSuccessors.size()]);
+        SwitchNode newSwitch = graph().add(new IntegerSwitchNode(newValue, successorsArray, newKeys, newKeyProbabilities, newKeySuccessors));
+
         /* Remove dead successors. */
-        for (int i = 0; i < blockSuccessorCount(); i++) {
-            AbstractBeginNode successor = blockSuccessor(i);
-            if (!newSuccessors.contains(successor)) {
-                FixedNode fixedBranch = successor;
-                fixedBranch.predecessor().replaceFirstSuccessor(fixedBranch, null);
-                GraphUtil.killCFG(fixedBranch);
-            }
-            setBlockSuccessor(i, null);
+        for (AbstractBeginNode successor : deadSuccessors) {
+            GraphUtil.killCFG(successor);
         }
 
-        /* Create the new switch node and replace ourself with it. */
-        AbstractBeginNode[] successorsArray = newSuccessors.toArray(new AbstractBeginNode[newSuccessors.size()]);
-        SwitchNode newSwitch = graph().add(new IntegerSwitchNode(newValue, successorsArray, newKeys, newKeyProbabilities, newKeySuccessors));
+        /* Replace ourselves with the new switch */
         ((FixedWithNextNode) predecessor()).setNext(newSwitch);
         GraphUtil.killWithUnusedFloatingInputs(this);
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/ClassInitializationPlugin.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/ClassInitializationPlugin.java	Fri Mar 16 22:59:32 2018 -0700
@@ -25,10 +25,16 @@
 import org.graalvm.compiler.nodes.FrameState;
 import org.graalvm.compiler.nodes.ValueNode;
 
+import jdk.vm.ci.meta.ConstantPool;
 import jdk.vm.ci.meta.ResolvedJavaType;
 
 public interface ClassInitializationPlugin extends GraphBuilderPlugin {
     boolean shouldApply(GraphBuilderContext builder, ResolvedJavaType type);
 
     ValueNode apply(GraphBuilderContext builder, ResolvedJavaType type, FrameState frameState);
+
+    boolean supportsLazyInitialization(ConstantPool cp);
+
+    void loadReferencedType(GraphBuilderContext builder, ConstantPool cp, int cpi, int bytecode);
+
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderConfiguration.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderConfiguration.java	Fri Mar 16 22:59:32 2018 -0700
@@ -228,8 +228,7 @@
     }
 
     protected GraphBuilderConfiguration(boolean eagerResolving, boolean unresolvedIsError, BytecodeExceptionMode bytecodeExceptionMode, boolean omitAssertions, boolean insertFullInfopoints,
-                    boolean trackNodeSourcePosition, ResolvedJavaType[] skippedExceptionTypes,
-                    Plugins plugins) {
+                    boolean trackNodeSourcePosition, ResolvedJavaType[] skippedExceptionTypes, Plugins plugins) {
         this.eagerResolving = eagerResolving;
         this.unresolvedIsError = unresolvedIsError;
         this.bytecodeExceptionMode = bytecodeExceptionMode;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InlineInvokePlugin.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InlineInvokePlugin.java	Fri Mar 16 22:59:32 2018 -0700
@@ -45,33 +45,35 @@
          * Denotes a call site that must not be inlined and should be implemented by a node that
          * does not speculate on the call not raising an exception.
          */
-        public static final InlineInfo DO_NOT_INLINE_WITH_EXCEPTION = new InlineInfo(null, null);
+        public static final InlineInfo DO_NOT_INLINE_WITH_EXCEPTION = new InlineInfo(null, null, null);
 
         /**
          * Denotes a call site must not be inlined and can be implemented by a node that speculates
          * the call will not throw an exception.
          */
-        public static final InlineInfo DO_NOT_INLINE_NO_EXCEPTION = new InlineInfo(null, null);
+        public static final InlineInfo DO_NOT_INLINE_NO_EXCEPTION = new InlineInfo(null, null, null);
 
         /**
          * Denotes a call site must not be inlined and the execution should be transferred to
          * interpreter in case of an exception.
          */
-        public static final InlineInfo DO_NOT_INLINE_DEOPTIMIZE_ON_EXCEPTION = new InlineInfo(null, null);
+        public static final InlineInfo DO_NOT_INLINE_DEOPTIMIZE_ON_EXCEPTION = new InlineInfo(null, null, null);
 
         private final ResolvedJavaMethod methodToInline;
+        private final ResolvedJavaMethod originalMethod;
         private final BytecodeProvider intrinsicBytecodeProvider;
 
         public static InlineInfo createStandardInlineInfo(ResolvedJavaMethod methodToInline) {
-            return new InlineInfo(methodToInline, null);
+            return new InlineInfo(methodToInline, null, null);
         }
 
-        public static InlineInfo createIntrinsicInlineInfo(ResolvedJavaMethod methodToInline, BytecodeProvider intrinsicBytecodeProvider) {
-            return new InlineInfo(methodToInline, intrinsicBytecodeProvider);
+        public static InlineInfo createIntrinsicInlineInfo(ResolvedJavaMethod methodToInline, ResolvedJavaMethod originalMethod, BytecodeProvider intrinsicBytecodeProvider) {
+            return new InlineInfo(methodToInline, originalMethod, intrinsicBytecodeProvider);
         }
 
-        private InlineInfo(ResolvedJavaMethod methodToInline, BytecodeProvider intrinsicBytecodeProvider) {
+        private InlineInfo(ResolvedJavaMethod methodToInline, ResolvedJavaMethod originalMethod, BytecodeProvider intrinsicBytecodeProvider) {
             this.methodToInline = methodToInline;
+            this.originalMethod = originalMethod;
             this.intrinsicBytecodeProvider = intrinsicBytecodeProvider;
         }
 
@@ -87,6 +89,14 @@
         }
 
         /**
+         * Returns the original method if this is an inline of an intrinsic, or {@code null} if the
+         * call site must not be inlined.
+         */
+        public ResolvedJavaMethod getOriginalMethod() {
+            return originalMethod;
+        }
+
+        /**
          * Gets the provider of bytecode to be parsed for {@link #getMethodToInline()} if is is an
          * intrinsic for the original method (i.e., the {@code method} passed to
          * {@link InlineInvokePlugin#shouldInlineInvoke}). A {@code null} return value indicates
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/IntrinsicContext.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/IntrinsicContext.java	Fri Mar 16 22:59:32 2018 -0700
@@ -29,6 +29,7 @@
 import static org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.INLINE_AFTER_PARSING;
 import static org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.ROOT_COMPILATION;
 
+import org.graalvm.compiler.api.replacements.MethodSubstitution;
 import org.graalvm.compiler.bytecode.BytecodeProvider;
 import org.graalvm.compiler.graph.NodeSourcePosition;
 import org.graalvm.compiler.nodes.AbstractMergeNode;
@@ -54,12 +55,12 @@
     /**
      * Method being intrinsified.
      */
-    final ResolvedJavaMethod method;
+    final ResolvedJavaMethod originalMethod;
 
     /**
      * Method providing the intrinsic implementation.
      */
-    final ResolvedJavaMethod intrinsic;
+    final ResolvedJavaMethod intrinsicMethod;
 
     /**
      * Provider of bytecode to be parsed for a method that is part of an intrinsic.
@@ -76,13 +77,14 @@
 
     public IntrinsicContext(ResolvedJavaMethod method, ResolvedJavaMethod intrinsic, BytecodeProvider bytecodeProvider, CompilationContext compilationContext,
                     boolean allowPartialIntrinsicArgumentMismatch) {
-        this.method = method;
-        this.intrinsic = intrinsic;
+        this.originalMethod = method;
+        this.intrinsicMethod = intrinsic;
         this.bytecodeProvider = bytecodeProvider;
         assert bytecodeProvider != null;
         this.compilationContext = compilationContext;
         this.allowPartialIntrinsicArgumentMismatch = allowPartialIntrinsicArgumentMismatch;
         assert !isCompilationRoot() || method.hasBytecodes() : "Cannot root compile intrinsic for native or abstract method " + method.format("%H.%n(%p)");
+        assert !method.equals(intrinsic) || method.getAnnotation(MethodSubstitution.class) == null : "method and intrinsic must be different: " + method + " " + intrinsic;
     }
 
     /**
@@ -98,14 +100,14 @@
      * Gets the method being intrinsified.
      */
     public ResolvedJavaMethod getOriginalMethod() {
-        return method;
+        return originalMethod;
     }
 
     /**
      * Gets the method providing the intrinsic implementation.
      */
     public ResolvedJavaMethod getIntrinsicMethod() {
-        return intrinsic;
+        return intrinsicMethod;
     }
 
     /**
@@ -121,9 +123,11 @@
      * intrinsification falls back to the original method.
      */
     public boolean isCallToOriginal(ResolvedJavaMethod targetMethod) {
-        return method.equals(targetMethod) || intrinsic.equals(targetMethod);
+        return originalMethod.equals(targetMethod) || intrinsicMethod.equals(targetMethod);
     }
 
+    private NodeSourcePosition nodeSourcePosition;
+
     public boolean isPostParseInlined() {
         return compilationContext.equals(INLINE_AFTER_PARSING);
     }
@@ -132,6 +136,15 @@
         return compilationContext.equals(ROOT_COMPILATION);
     }
 
+    public NodeSourcePosition getNodeSourcePosition() {
+        return nodeSourcePosition;
+    }
+
+    public void setNodeSourcePosition(NodeSourcePosition position) {
+        assert nodeSourcePosition == null : "can only be set once";
+        this.nodeSourcePosition = position;
+    }
+
     /**
      * Denotes the compilation context in which an intrinsic is being parsed.
      */
@@ -182,7 +195,9 @@
                 // Only the last side effect on any execution path in a replacement
                 // can inherit the stateAfter of the replaced node
                 FrameState invalid = graph.add(new FrameState(INVALID_FRAMESTATE_BCI));
-                invalid.setNodeSourcePosition(sourcePosition);
+                if (graph.trackNodeSourcePosition()) {
+                    invalid.setNodeSourcePosition(sourcePosition);
+                }
                 for (StateSplit lastSideEffect : sideEffects.sideEffects()) {
                     lastSideEffect.setStateAfter(invalid);
                 }
@@ -194,7 +209,9 @@
             } else {
                 frameState = graph.add(new FrameState(AFTER_BCI));
             }
-            frameState.setNodeSourcePosition(sourcePosition);
+            if (graph.trackNodeSourcePosition()) {
+                frameState.setNodeSourcePosition(sourcePosition);
+            }
             return frameState;
         } else {
             if (forStateSplit instanceof AbstractMergeNode) {
@@ -202,12 +219,16 @@
                 if (sideEffects.isAfterSideEffect()) {
                     // A merge after one or more side effects
                     FrameState frameState = graph.add(new FrameState(AFTER_BCI));
-                    frameState.setNodeSourcePosition(sourcePosition);
+                    if (graph.trackNodeSourcePosition()) {
+                        frameState.setNodeSourcePosition(sourcePosition);
+                    }
                     return frameState;
                 } else {
                     // A merge before any side effects
                     FrameState frameState = graph.add(new FrameState(BEFORE_BCI));
-                    frameState.setNodeSourcePosition(sourcePosition);
+                    if (graph.trackNodeSourcePosition()) {
+                        frameState.setNodeSourcePosition(sourcePosition);
+                    }
                     return frameState;
                 }
             } else {
@@ -219,6 +240,6 @@
 
     @Override
     public String toString() {
-        return "Intrinsic{original: " + method.format("%H.%n(%p)") + ", intrinsic: " + intrinsic.format("%H.%n(%p)") + ", context: " + compilationContext + "}";
+        return "Intrinsic{original: " + originalMethod.format("%H.%n(%p)") + ", intrinsic: " + intrinsicMethod.format("%H.%n(%p)") + ", context: " + compilationContext + "}";
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/InstanceOfDynamicNode.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/InstanceOfDynamicNode.java	Fri Mar 16 22:59:32 2018 -0700
@@ -55,18 +55,24 @@
     public static final NodeClass<InstanceOfDynamicNode> TYPE = NodeClass.create(InstanceOfDynamicNode.class);
 
     private final boolean allowNull;
+    private final boolean exact;
 
-    public static LogicNode create(Assumptions assumptions, ConstantReflectionProvider constantReflection, ValueNode mirror, ValueNode object, boolean allowNull) {
-        LogicNode synonym = findSynonym(assumptions, constantReflection, mirror, object, allowNull);
+    public static LogicNode create(Assumptions assumptions, ConstantReflectionProvider constantReflection, ValueNode mirror, ValueNode object, boolean allowNull, boolean exact) {
+        LogicNode synonym = findSynonym(assumptions, constantReflection, mirror, object, allowNull, exact);
         if (synonym != null) {
             return synonym;
         }
-        return new InstanceOfDynamicNode(mirror, object, allowNull);
+        return new InstanceOfDynamicNode(mirror, object, allowNull, exact);
     }
 
-    protected InstanceOfDynamicNode(ValueNode mirror, ValueNode object, boolean allowNull) {
+    public static LogicNode create(Assumptions assumptions, ConstantReflectionProvider constantReflection, ValueNode mirror, ValueNode object, boolean allowNull) {
+        return create(assumptions, constantReflection, mirror, object, allowNull, false);
+    }
+
+    protected InstanceOfDynamicNode(ValueNode mirror, ValueNode object, boolean allowNull, boolean exact) {
         super(TYPE, mirror, object);
         this.allowNull = allowNull;
+        this.exact = exact;
         assert mirror.getStackKind() == JavaKind.Object || mirror.getStackKind() == JavaKind.Illegal : mirror.getStackKind();
     }
 
@@ -83,8 +89,7 @@
         tool.getLowerer().lower(this, tool);
     }
 
-    private static LogicNode findSynonym(Assumptions assumptions, ConstantReflectionProvider constantReflection, ValueNode forMirror, ValueNode forObject,
-                    boolean allowNull) {
+    private static LogicNode findSynonym(Assumptions assumptions, ConstantReflectionProvider constantReflection, ValueNode forMirror, ValueNode forObject, boolean allowNull, boolean exact) {
         if (forMirror.isConstant()) {
             ResolvedJavaType t = constantReflection.asJavaType(forMirror.asConstant());
             if (t != null) {
@@ -95,7 +100,7 @@
                         return LogicConstantNode.contradiction();
                     }
                 } else {
-                    TypeReference type = TypeReference.createTrusted(assumptions, t);
+                    TypeReference type = exact ? TypeReference.createExactTrusted(t) : TypeReference.createTrusted(assumptions, t);
                     if (allowNull) {
                         return InstanceOfNode.createAllowNull(type, forObject, null, null);
                     } else {
@@ -117,7 +122,7 @@
 
     @Override
     public LogicNode canonical(CanonicalizerTool tool, ValueNode forMirror, ValueNode forObject) {
-        LogicNode result = findSynonym(tool.getAssumptions(), tool.getConstantReflection(), forMirror, forObject, allowNull);
+        LogicNode result = findSynonym(tool.getAssumptions(), tool.getConstantReflection(), forMirror, forObject, allowNull, exact);
         if (result != null) {
             return result;
         }
@@ -133,6 +138,10 @@
         return allowNull;
     }
 
+    public boolean isExact() {
+        return exact;
+    }
+
     @Override
     public Stamp getSucceedingStampForX(boolean negated, Stamp xStamp, Stamp yStamp) {
         return null;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/Replacements.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/Replacements.java	Fri Mar 16 22:59:32 2018 -0700
@@ -26,6 +26,7 @@
 import org.graalvm.compiler.api.replacements.SnippetTemplateCache;
 import org.graalvm.compiler.bytecode.Bytecode;
 import org.graalvm.compiler.bytecode.BytecodeProvider;
+import org.graalvm.compiler.graph.NodeSourcePosition;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
@@ -50,9 +51,10 @@
      * Gets the snippet graph derived from a given method.
      *
      * @param args arguments to the snippet if available, otherwise {@code null}
+     * @param trackNodeSourcePosition
      * @return the snippet graph, if any, that is derived from {@code method}
      */
-    StructuredGraph getSnippet(ResolvedJavaMethod method, Object[] args);
+    StructuredGraph getSnippet(ResolvedJavaMethod method, Object[] args, boolean trackNodeSourcePosition, NodeSourcePosition replaceePosition);
 
     /**
      * Gets the snippet graph derived from a given method.
@@ -61,23 +63,25 @@
      *            recursive call and won't be processed for {@linkplain MethodSubstitution
      *            substitutions}.
      * @param args arguments to the snippet if available, otherwise {@code null}
+     * @param trackNodeSourcePosition
      * @return the snippet graph, if any, that is derived from {@code method}
      */
-    StructuredGraph getSnippet(ResolvedJavaMethod method, ResolvedJavaMethod recursiveEntry, Object[] args);
+    StructuredGraph getSnippet(ResolvedJavaMethod method, ResolvedJavaMethod recursiveEntry, Object[] args, boolean trackNodeSourcePosition, NodeSourcePosition replaceePosition);
 
     /**
      * Registers a method as snippet.
      */
-    void registerSnippet(ResolvedJavaMethod method);
+    void registerSnippet(ResolvedJavaMethod method, boolean trackNodeSourcePosition);
 
     /**
      * Gets a graph that is a substitution for a given method.
      *
      * @param invokeBci the call site BCI if this request is made for inlining a substitute
      *            otherwise {@code -1}
+     * @param trackNodeSourcePosition
      * @return the graph, if any, that is a substitution for {@code method}
      */
-    StructuredGraph getSubstitution(ResolvedJavaMethod method, int invokeBci);
+    StructuredGraph getSubstitution(ResolvedJavaMethod method, int invokeBci, boolean trackNodeSourcePosition, NodeSourcePosition replaceePosition);
 
     /**
      * Gets the substitute bytecode for a given method.
@@ -88,7 +92,8 @@
     Bytecode getSubstitutionBytecode(ResolvedJavaMethod method);
 
     /**
-     * Determines if there may be a {@linkplain #getSubstitution(ResolvedJavaMethod, int)
+     * Determines if there may be a
+     * {@linkplain #getSubstitution(ResolvedJavaMethod, int, boolean, NodeSourcePosition)
      * substitution graph} for a given method.
      *
      * A call to {@link #getSubstitution} may still return {@code null} for {@code method} and
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ConditionalEliminationPhase.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ConditionalEliminationPhase.java	Fri Mar 16 22:59:32 2018 -0700
@@ -22,6 +22,8 @@
  */
 package org.graalvm.compiler.phases.common;
 
+import static org.graalvm.compiler.nodes.StaticDeoptimizingNode.mergeActions;
+
 import java.util.ArrayDeque;
 import java.util.Deque;
 import java.util.List;
@@ -30,6 +32,7 @@
 import org.graalvm.collections.Equivalence;
 import org.graalvm.collections.MapCursor;
 import org.graalvm.collections.Pair;
+import org.graalvm.compiler.core.common.cfg.AbstractControlFlowGraph;
 import org.graalvm.compiler.core.common.cfg.BlockMap;
 import org.graalvm.compiler.core.common.type.ArithmeticOpTable;
 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp;
@@ -92,6 +95,7 @@
 import org.graalvm.compiler.phases.schedule.SchedulePhase.SchedulingStrategy;
 import org.graalvm.compiler.phases.tiers.PhaseContext;
 
+import jdk.vm.ci.meta.DeoptimizationAction;
 import jdk.vm.ci.meta.JavaConstant;
 import jdk.vm.ci.meta.TriState;
 
@@ -146,8 +150,8 @@
     }
 
     protected ControlFlowGraph.RecursiveVisitor<?> createVisitor(StructuredGraph graph, @SuppressWarnings("unused") ControlFlowGraph cfg, BlockMap<List<Node>> blockToNodes,
-                    @SuppressWarnings("unused") NodeMap<Block> nodeToBlock, PhaseContext context) {
-        return new Instance(graph, blockToNodes, context);
+                    NodeMap<Block> nodeToBlock, PhaseContext context) {
+        return new Instance(graph, blockToNodes, nodeToBlock, context);
     }
 
     public static class MoveGuardsUpwards implements ControlFlowGraph.RecursiveVisitor<Block> {
@@ -244,6 +248,7 @@
     public static class Instance implements ControlFlowGraph.RecursiveVisitor<Integer> {
         protected final NodeMap<InfoElement> map;
         protected final BlockMap<List<Node>> blockToNodes;
+        protected final NodeMap<Block> nodeToBlock;
         protected final CanonicalizerTool tool;
         protected final NodeStack undoOperations;
         protected final StructuredGraph graph;
@@ -255,10 +260,11 @@
          */
         private Deque<DeoptimizingGuard> pendingTests;
 
-        public Instance(StructuredGraph graph, BlockMap<List<Node>> blockToNodes, PhaseContext context) {
+        public Instance(StructuredGraph graph, BlockMap<List<Node>> blockToNodes, NodeMap<Block> nodeToBlock, PhaseContext context) {
             this.graph = graph;
             this.debug = graph.getDebug();
             this.blockToNodes = blockToNodes;
+            this.nodeToBlock = nodeToBlock;
             this.undoOperations = new NodeStack();
             this.map = graph.createNodeMap();
             pendingTests = new ArrayDeque<>();
@@ -614,7 +620,7 @@
          * never be replaced with a pi node via canonicalization).
          */
         private static Stamp getOtherSafeStamp(ValueNode x) {
-            if (x.isConstant()) {
+            if (x.isConstant() || x.graph().isAfterFixedReadPhase()) {
                 return x.stamp(NodeView.DEFAULT);
             }
             return x.stamp(NodeView.DEFAULT).unrestricted();
@@ -633,6 +639,23 @@
             return recursiveFoldStamp(node);
         }
 
+        /**
+         * Look for a preceding guard whose condition is implied by {@code thisGuard}. If we find
+         * one, try to move this guard just above that preceding guard so that we can fold it:
+         *
+         * <pre>
+         *     guard(C1); // preceding guard
+         *     ...
+         *     guard(C2); // thisGuard
+         * </pre>
+         *
+         * If C2 => C1, transform to:
+         *
+         * <pre>
+         *     guard(C2);
+         *     ...
+         * </pre>
+         */
         protected boolean foldPendingTest(DeoptimizingGuard thisGuard, ValueNode original, Stamp newStamp, GuardRewirer rewireGuardFunction) {
             for (DeoptimizingGuard pendingGuard : pendingTests) {
                 LogicNode pendingCondition = pendingGuard.getCondition();
@@ -661,12 +684,9 @@
                 if (result.isKnown()) {
                     /*
                      * The test case be folded using the information available but the test can only
-                     * be moved up if we're sure there's no schedule dependence. For now limit it to
-                     * the original node and constants.
+                     * be moved up if we're sure there's no schedule dependence.
                      */
-                    InputFilter v = new InputFilter(original);
-                    thisGuard.getCondition().applyInputs(v);
-                    if (v.ok && foldGuard(thisGuard, pendingGuard, result.toBoolean(), newStamp, rewireGuardFunction)) {
+                    if (canScheduleAbove(thisGuard.getCondition(), pendingGuard.asNode(), original) && foldGuard(thisGuard, pendingGuard, result.toBoolean(), newStamp, rewireGuardFunction)) {
                         return true;
                     }
                 }
@@ -674,8 +694,30 @@
             return false;
         }
 
+        private boolean canScheduleAbove(Node n, Node target, ValueNode knownToBeAbove) {
+            Block targetBlock = nodeToBlock.get(target);
+            Block testBlock = nodeToBlock.get(n);
+            if (targetBlock != null && testBlock != null) {
+                if (targetBlock == testBlock) {
+                    for (Node fixed : blockToNodes.get(targetBlock)) {
+                        if (fixed == n) {
+                            return true;
+                        } else if (fixed == target) {
+                            break;
+                        }
+                    }
+                } else if (AbstractControlFlowGraph.dominates(testBlock, targetBlock)) {
+                    return true;
+                }
+            }
+            InputFilter v = new InputFilter(knownToBeAbove);
+            n.applyInputs(v);
+            return v.ok;
+        }
+
         protected boolean foldGuard(DeoptimizingGuard thisGuard, DeoptimizingGuard otherGuard, boolean outcome, Stamp guardedValueStamp, GuardRewirer rewireGuardFunction) {
-            if (otherGuard.getAction() == thisGuard.getAction() && otherGuard.getSpeculation() == thisGuard.getSpeculation()) {
+            DeoptimizationAction action = mergeActions(otherGuard.getAction(), thisGuard.getAction());
+            if (action != null && otherGuard.getSpeculation() == thisGuard.getSpeculation()) {
                 LogicNode condition = (LogicNode) thisGuard.getCondition().copyWithInputs();
                 /*
                  * We have ...; guard(C1); guard(C2);...
@@ -688,12 +730,16 @@
                  *
                  * - If C2 => !C1, `mustDeopt` is true and we transform to ..; guard(C1); deopt;
                  */
+                // for the second case, the action of the deopt is copied from there:
+                thisGuard.setAction(action);
                 GuardRewirer rewirer = (guard, result, innerGuardedValueStamp, newInput) -> {
                     // `result` is `outcome`, `guard` is `otherGuard`
                     boolean mustDeopt = result == otherGuard.isNegated();
                     if (rewireGuardFunction.rewire(guard, mustDeopt == thisGuard.isNegated(), innerGuardedValueStamp, newInput)) {
                         if (!mustDeopt) {
                             otherGuard.setCondition(condition, thisGuard.isNegated());
+                            otherGuard.setAction(action);
+                            otherGuard.setReason(thisGuard.getReason());
                         }
                         return true;
                     }
@@ -783,16 +829,6 @@
                 }
             } else if (node instanceof BinaryOpLogicNode) {
                 BinaryOpLogicNode binaryOpLogicNode = (BinaryOpLogicNode) node;
-                infoElement = getInfoElements(binaryOpLogicNode);
-                while (infoElement != null) {
-                    if (infoElement.getStamp().equals(StampFactory.contradiction())) {
-                        return rewireGuards(infoElement.getGuard(), false, infoElement.getProxifiedInput(), null, rewireGuardFunction);
-                    } else if (infoElement.getStamp().equals(StampFactory.tautology())) {
-                        return rewireGuards(infoElement.getGuard(), true, infoElement.getProxifiedInput(), null, rewireGuardFunction);
-                    }
-                    infoElement = nextElement(infoElement);
-                }
-
                 ValueNode x = binaryOpLogicNode.getX();
                 ValueNode y = binaryOpLogicNode.getY();
                 infoElement = getInfoElements(x);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ConvertDeoptimizeToGuardPhase.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ConvertDeoptimizeToGuardPhase.java	Fri Mar 16 22:59:32 2018 -0700
@@ -131,6 +131,7 @@
         }
     }
 
+    @SuppressWarnings("try")
     private void processFixedGuardAndMerge(FixedGuardNode fixedGuard, PhaseContext context, CompareNode compare, ValueNode x, ValuePhiNode xPhi, ValueNode y, ValuePhiNode yPhi,
                     AbstractMergeNode merge) {
         List<EndNode> mergePredecessors = merge.cfgPredecessors().snapshot();
@@ -152,11 +153,14 @@
                 ys = yPhi.valueAt(mergePredecessor).asConstant();
             }
             if (xs != null && ys != null && compare.condition().foldCondition(xs, ys, context.getConstantReflection(), compare.unorderedIsTrue()) == fixedGuard.isNegated()) {
-                propagateFixed(mergePredecessor, fixedGuard, context.getLowerer());
+                try (DebugCloseable position = fixedGuard.withNodeSourcePosition()) {
+                    propagateFixed(mergePredecessor, fixedGuard, context.getLowerer());
+                }
             }
         }
     }
 
+    @SuppressWarnings("try")
     private void propagateFixed(FixedNode from, StaticDeoptimizingNode deopt, LoweringProvider loweringProvider) {
         Node current = from;
         while (current != null) {
@@ -179,32 +183,36 @@
                     return;
                 } else if (current.predecessor() instanceof IfNode) {
                     IfNode ifNode = (IfNode) current.predecessor();
-                    StructuredGraph graph = ifNode.graph();
-                    LogicNode conditionNode = ifNode.condition();
-                    boolean negateGuardCondition = current == ifNode.trueSuccessor();
-                    FixedGuardNode guard = graph.add(new FixedGuardNode(conditionNode, deopt.getReason(), deopt.getAction(), deopt.getSpeculation(), negateGuardCondition));
-                    FixedWithNextNode pred = (FixedWithNextNode) ifNode.predecessor();
-                    AbstractBeginNode survivingSuccessor;
-                    if (negateGuardCondition) {
-                        survivingSuccessor = ifNode.falseSuccessor();
-                    } else {
-                        survivingSuccessor = ifNode.trueSuccessor();
-                    }
-                    graph.removeSplitPropagate(ifNode, survivingSuccessor);
+                    // Prioritize the source position of the IfNode
+                    try (DebugCloseable closable = ifNode.withNodeSourcePosition()) {
+                        StructuredGraph graph = ifNode.graph();
+                        LogicNode conditionNode = ifNode.condition();
+                        boolean negateGuardCondition = current == ifNode.trueSuccessor();
+                        FixedGuardNode guard = graph.add(new FixedGuardNode(conditionNode, deopt.getReason(), deopt.getAction(), deopt.getSpeculation(), negateGuardCondition));
 
-                    Node newGuard = guard;
-                    if (survivingSuccessor instanceof LoopExitNode) {
-                        newGuard = ProxyNode.forGuard(guard, (LoopExitNode) survivingSuccessor, graph);
-                    }
-                    survivingSuccessor.replaceAtUsages(InputType.Guard, newGuard);
+                        FixedWithNextNode pred = (FixedWithNextNode) ifNode.predecessor();
+                        AbstractBeginNode survivingSuccessor;
+                        if (negateGuardCondition) {
+                            survivingSuccessor = ifNode.falseSuccessor();
+                        } else {
+                            survivingSuccessor = ifNode.trueSuccessor();
+                        }
+                        graph.removeSplitPropagate(ifNode, survivingSuccessor);
 
-                    graph.getDebug().log("Converting deopt on %-5s branch of %s to guard for remaining branch %s.", negateGuardCondition, ifNode, survivingSuccessor);
-                    FixedNode next = pred.next();
-                    pred.setNext(guard);
-                    guard.setNext(next);
-                    SimplifierTool simplifierTool = GraphUtil.getDefaultSimplifier(null, null, null, false, graph.getAssumptions(), graph.getOptions(), loweringProvider);
-                    survivingSuccessor.simplify(simplifierTool);
-                    return;
+                        Node newGuard = guard;
+                        if (survivingSuccessor instanceof LoopExitNode) {
+                            newGuard = ProxyNode.forGuard(guard, (LoopExitNode) survivingSuccessor, graph);
+                        }
+                        survivingSuccessor.replaceAtUsages(InputType.Guard, newGuard);
+
+                        graph.getDebug().log("Converting deopt on %-5s branch of %s to guard for remaining branch %s.", negateGuardCondition, ifNode, survivingSuccessor);
+                        FixedNode next = pred.next();
+                        pred.setNext(guard);
+                        guard.setNext(next);
+                        SimplifierTool simplifierTool = GraphUtil.getDefaultSimplifier(null, null, null, false, graph.getAssumptions(), graph.getOptions(), loweringProvider);
+                        survivingSuccessor.simplify(simplifierTool);
+                        return;
+                    }
                 } else if (current.predecessor() == null || current.predecessor() instanceof ControlSplitNode) {
                     assert current.predecessor() != null || (current instanceof StartNode && current == ((AbstractBeginNode) current).graph().start());
                     moveAsDeoptAfter((AbstractBeginNode) current, deopt);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/NodeCounterPhase.java	Fri Mar 16 22:59:32 2018 -0700
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.phases.common;
+
+import org.graalvm.compiler.debug.DebugContext;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionKey;
+import org.graalvm.compiler.options.OptionType;
+import org.graalvm.compiler.phases.BasePhase;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+
+public class NodeCounterPhase extends BasePhase<PhaseContext> {
+
+    public static class Options {
+        // @formatter:off
+        @Option(help = "Counts the number of instances of each node class.", type = OptionType.Debug)
+        public static final OptionKey<Boolean> NodeCounters = new OptionKey<>(false);
+        // @formatter:on
+    }
+
+    @Override
+    protected void run(StructuredGraph graph, PhaseContext context) {
+        for (Node node : graph.getNodes()) {
+            DebugContext.counter("NodeCounter_%s",
+                            node.getNodeClass().getClazz().getSimpleName()).increment(node.getDebug());
+        }
+    }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/InliningUtil.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/InliningUtil.java	Fri Mar 16 22:59:32 2018 -0700
@@ -39,6 +39,7 @@
 import org.graalvm.collections.UnmodifiableEconomicMap;
 import org.graalvm.collections.UnmodifiableMapCursor;
 import org.graalvm.compiler.api.replacements.MethodSubstitution;
+import org.graalvm.compiler.api.replacements.Snippet;
 import org.graalvm.compiler.core.common.GraalOptions;
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.core.common.type.StampFactory;
@@ -47,8 +48,8 @@
 import org.graalvm.compiler.debug.DebugContext;
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.graph.GraalGraphError;
-import org.graalvm.compiler.graph.Graph;
 import org.graalvm.compiler.graph.Graph.DuplicationReplacement;
+import org.graalvm.compiler.graph.Graph.Mark;
 import org.graalvm.compiler.graph.Graph.NodeEventScope;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.graph.NodeInputList;
@@ -68,6 +69,7 @@
 import org.graalvm.compiler.nodes.FixedNode;
 import org.graalvm.compiler.nodes.FixedWithNextNode;
 import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.InliningLog;
 import org.graalvm.compiler.nodes.Invoke;
 import org.graalvm.compiler.nodes.InvokeNode;
 import org.graalvm.compiler.nodes.InvokeWithExceptionNode;
@@ -82,6 +84,7 @@
 import org.graalvm.compiler.nodes.StartNode;
 import org.graalvm.compiler.nodes.StateSplit;
 import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.GuardsStage;
 import org.graalvm.compiler.nodes.UnwindNode;
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.calc.IsNullNode;
@@ -102,7 +105,6 @@
 import jdk.vm.ci.meta.Assumptions;
 import jdk.vm.ci.meta.DeoptimizationAction;
 import jdk.vm.ci.meta.DeoptimizationReason;
-import jdk.vm.ci.meta.JavaConstant;
 import jdk.vm.ci.meta.JavaKind;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 import jdk.vm.ci.meta.ResolvedJavaType;
@@ -118,43 +120,104 @@
         printInlining(info.methodAt(0), info.invoke(), inliningDepth, success, msg, args);
     }
 
+    /**
+     * @see #printInlining
+     */
     private static void printInlining(final ResolvedJavaMethod method, final Invoke invoke, final int inliningDepth, final boolean success, final String msg, final Object... args) {
         if (HotSpotPrintInlining.getValue(invoke.asNode().getOptions())) {
             Util.printInlining(method, invoke.bci(), inliningDepth, success, msg, args);
         }
     }
 
-    public static void logInlinedMethod(InlineInfo info, int inliningDepth, boolean allowLogging, String msg, Object... args) {
-        logInliningDecision(info, inliningDepth, allowLogging, true, msg, args);
+    /**
+     * Trace a decision to inline a method.
+     *
+     * This prints a HotSpot-style inlining message to the console, and it also logs the decision to
+     * the logging stream.
+     *
+     * Phases that perform inlining should use this method to trace the inlining decisions, and use
+     * the {@link #traceNotInlinedMethod} methods only for debugging purposes.
+     */
+    public static void traceInlinedMethod(InlineInfo info, int inliningDepth, boolean allowLogging, String msg, Object... args) {
+        traceMethod(info, inliningDepth, allowLogging, true, msg, args);
+    }
+
+    /**
+     * Trace a decision to inline a method.
+     *
+     * This prints a HotSpot-style inlining message to the console, and it also logs the decision to
+     * the logging stream.
+     *
+     * Phases that perform inlining should use this method to trace the inlining decisions, and use
+     * the {@link #traceNotInlinedMethod} methods only for debugging purposes.
+     */
+    public static void traceInlinedMethod(Invoke invoke, int inliningDepth, boolean allowLogging, ResolvedJavaMethod method, String msg, Object... args) {
+        traceMethod(invoke, inliningDepth, allowLogging, true, method, msg, args);
     }
 
-    public static void logNotInlinedMethod(InlineInfo info, int inliningDepth, String msg, Object... args) {
-        logInliningDecision(info, inliningDepth, true, false, msg, args);
+    /**
+     * Trace a decision to not inline a method.
+     *
+     * This prints a HotSpot-style inlining message to the console, and it also logs the decision to
+     * the logging stream.
+     *
+     * Phases that perform inlining should use this method to trace the inlining decisions, and use
+     * the {@link #traceNotInlinedMethod} methods only for debugging purposes.
+     */
+    public static void traceNotInlinedMethod(InlineInfo info, int inliningDepth, String msg, Object... args) {
+        traceMethod(info, inliningDepth, true, false, msg, args);
     }
 
-    public static void logInliningDecision(InlineInfo info, int inliningDepth, boolean allowLogging, boolean success, String msg, final Object... args) {
+    /**
+     * Trace a decision about not inlining a method.
+     *
+     * This prints a HotSpot-style inlining message to the console, and it also logs the decision to
+     * the logging stream.
+     *
+     * Phases that perform inlining should use this method to trace the inlining decisions, and use
+     * the {@link #traceNotInlinedMethod} methods only for debugging purposes.
+     */
+    public static void traceNotInlinedMethod(Invoke invoke, int inliningDepth, ResolvedJavaMethod method, String msg, Object... args) {
+        traceMethod(invoke, inliningDepth, true, false, method, msg, args);
+    }
+
+    private static void traceMethod(Invoke invoke, int inliningDepth, boolean allowLogging, boolean success, ResolvedJavaMethod method, String msg, Object... args) {
         if (allowLogging) {
-            printInlining(info, inliningDepth, success, msg, args);
-            DebugContext debug = info.graph().getDebug();
-            if (shouldLogInliningDecision(debug)) {
-                logInliningDecision(debug, methodName(info), success, msg, args);
+            DebugContext debug = invoke.asNode().getDebug();
+            printInlining(method, invoke, inliningDepth, success, msg, args);
+            if (shouldLogMethod(debug)) {
+                String methodString = methodName(method, invoke);
+                logMethod(debug, methodString, success, msg, args);
             }
         }
     }
 
-    @SuppressWarnings("try")
-    public static void logInliningDecision(DebugContext debug, final String msg, final Object... args) {
-        try (DebugContext.Scope s = debug.scope(inliningDecisionsScopeString)) {
-            // Can't use log here since we are varargs
-            if (debug.isLogEnabled()) {
-                debug.logv(msg, args);
+    private static void traceMethod(InlineInfo info, int inliningDepth, boolean allowLogging, boolean success, String msg, final Object... args) {
+        if (allowLogging) {
+            printInlining(info, inliningDepth, success, msg, args);
+            DebugContext debug = info.graph().getDebug();
+            if (shouldLogMethod(debug)) {
+                logMethod(debug, methodName(info), success, msg, args);
             }
         }
     }
 
+    /**
+     * Output a generic inlining decision to the logging stream (e.g. inlining termination
+     * condition).
+     *
+     * Used for debugging purposes.
+     */
+    public static void logInliningDecision(DebugContext debug, final String msg, final Object... args) {
+        logInlining(debug, msg, args);
+    }
+
+    /**
+     * Output a decision about not inlining a method to the logging stream, for debugging purposes.
+     */
     public static void logNotInlinedMethod(Invoke invoke, String msg) {
         DebugContext debug = invoke.asNode().getDebug();
-        if (shouldLogInliningDecision(debug)) {
+        if (shouldLogMethod(debug)) {
             String methodString = invoke.toString();
             if (invoke.callTarget() == null) {
                 methodString += " callTarget=null";
@@ -164,33 +227,30 @@
                     methodString += " " + targetName;
                 }
             }
-            logInliningDecision(debug, methodString, false, msg, new Object[0]);
+            logMethod(debug, methodString, false, msg, new Object[0]);
         }
     }
 
-    public static void logNotInlined(Invoke invoke, int inliningDepth, ResolvedJavaMethod method, String msg) {
-        logNotInlinedInvoke(invoke, inliningDepth, method, msg, new Object[0]);
-    }
-
-    public static void logNotInlinedInvoke(Invoke invoke, int inliningDepth, ResolvedJavaMethod method, String msg, Object... args) {
-        DebugContext debug = invoke.asNode().getDebug();
-        printInlining(method, invoke, inliningDepth, false, msg, args);
-        if (shouldLogInliningDecision(debug)) {
-            String methodString = methodName(method, invoke);
-            logInliningDecision(debug, methodString, false, msg, args);
-        }
-    }
-
-    private static void logInliningDecision(DebugContext debug, final String methodString, final boolean success, final String msg, final Object... args) {
+    private static void logMethod(DebugContext debug, final String methodString, final boolean success, final String msg, final Object... args) {
         String inliningMsg = "inlining " + methodString + ": " + msg;
         if (!success) {
             inliningMsg = "not " + inliningMsg;
         }
-        logInliningDecision(debug, inliningMsg, args);
+        logInlining(debug, inliningMsg, args);
     }
 
     @SuppressWarnings("try")
-    public static boolean shouldLogInliningDecision(DebugContext debug) {
+    private static void logInlining(DebugContext debug, final String msg, final Object... args) {
+        try (DebugContext.Scope s = debug.scope(inliningDecisionsScopeString)) {
+            // Can't use log here since we are varargs
+            if (debug.isLogEnabled()) {
+                debug.logv(msg, args);
+            }
+        }
+    }
+
+    @SuppressWarnings("try")
+    private static boolean shouldLogMethod(DebugContext debug) {
         try (DebugContext.Scope s = debug.scope(inliningDecisionsScopeString)) {
             return debug.isLogEnabled();
         }
@@ -269,7 +329,8 @@
     }
 
     /**
-     * Performs an actual inlining, thereby replacing the given invoke with the given inlineGraph.
+     * Performs an actual inlining, thereby replacing the given invoke with the given
+     * {@code inlineGraph}.
      *
      * @param invoke the invoke that will be replaced
      * @param inlineGraph the graph that the invoke will be replaced with
@@ -279,6 +340,23 @@
      */
     @SuppressWarnings("try")
     public static UnmodifiableEconomicMap<Node, Node> inline(Invoke invoke, StructuredGraph inlineGraph, boolean receiverNullCheck, ResolvedJavaMethod inlineeMethod) {
+        return inline(invoke, inlineGraph, receiverNullCheck, inlineeMethod, "", "");
+    }
+
+    /**
+     * Performs an actual inlining, thereby replacing the given invoke with the given
+     * {@code inlineGraph}.
+     *
+     * @param invoke the invoke that will be replaced
+     * @param inlineGraph the graph that the invoke will be replaced with
+     * @param receiverNullCheck true if a null check needs to be generated for non-static inlinings,
+     *            false if no such check is required
+     * @param inlineeMethod the actual method being inlined. Maybe be null for snippets.
+     * @param reason the reason for inlining, used in tracing
+     * @param phase the phase that invoked inlining
+     */
+    @SuppressWarnings("try")
+    public static UnmodifiableEconomicMap<Node, Node> inline(Invoke invoke, StructuredGraph inlineGraph, boolean receiverNullCheck, ResolvedJavaMethod inlineeMethod, String reason, String phase) {
         FixedNode invokeNode = invoke.asNode();
         StructuredGraph graph = invokeNode.graph();
         final NodeInputList<ValueNode> parameters = invoke.callTarget().arguments();
@@ -339,7 +417,15 @@
         assert invokeNode.successors().first() != null : invoke;
         assert invokeNode.predecessor() != null;
 
-        EconomicMap<Node, Node> duplicates = graph.addDuplicates(nodes, inlineGraph, inlineGraph.getNodeCount(), localReplacement);
+        Mark mark = graph.getMark();
+        // Instead, attach the inlining log of the child graph to the current inlining log.
+        EconomicMap<Node, Node> duplicates;
+        try (InliningLog.UpdateScope scope = graph.getInliningLog().openDefaultUpdateScope()) {
+            duplicates = graph.addDuplicates(nodes, inlineGraph, inlineGraph.getNodeCount(), localReplacement);
+            if (scope != null) {
+                graph.getInliningLog().addDecision(invoke, true, reason, phase, duplicates, inlineGraph.getInliningLog());
+            }
+        }
 
         FrameState stateAfter = invoke.stateAfter();
         assert stateAfter == null || stateAfter.isAlive();
@@ -353,7 +439,7 @@
             }
         }
 
-        updateSourcePositions(invoke, inlineGraph, duplicates, !Objects.equals(inlineGraph.method(), inlineeMethod));
+        updateSourcePositions(invoke, inlineGraph, duplicates, !Objects.equals(inlineGraph.method(), inlineeMethod), mark);
         if (stateAfter != null) {
             processFrameStates(invoke, inlineGraph, duplicates, stateAtExceptionEdge, returnNodes.size() > 1);
             int callerLockDepth = stateAfter.nestedLockDepth();
@@ -409,9 +495,14 @@
         return inlineForCanonicalization(invoke, inlineGraph, receiverNullCheck, inlineeMethod, null);
     }
 
+    public static EconomicSet<Node> inlineForCanonicalization(Invoke invoke, StructuredGraph inlineGraph, boolean receiverNullCheck, ResolvedJavaMethod inlineeMethod,
+                    Consumer<UnmodifiableEconomicMap<Node, Node>> duplicatesConsumer) {
+        return inlineForCanonicalization(invoke, inlineGraph, receiverNullCheck, inlineeMethod, duplicatesConsumer, "", "");
+    }
+
     @SuppressWarnings("try")
     public static EconomicSet<Node> inlineForCanonicalization(Invoke invoke, StructuredGraph inlineGraph, boolean receiverNullCheck, ResolvedJavaMethod inlineeMethod,
-                    Consumer<UnmodifiableEconomicMap<Node, Node>> duplicatesConsumer) {
+                    Consumer<UnmodifiableEconomicMap<Node, Node>> duplicatesConsumer, String reason, String phase) {
         HashSetNodeEventListener listener = new HashSetNodeEventListener();
         /*
          * This code relies on the fact that Graph.addDuplicates doesn't trigger the
@@ -419,7 +510,7 @@
          * the graph into the current graph.
          */
         try (NodeEventScope nes = invoke.asNode().graph().trackNodeEvents(listener)) {
-            UnmodifiableEconomicMap<Node, Node> duplicates = InliningUtil.inline(invoke, inlineGraph, receiverNullCheck, inlineeMethod);
+            UnmodifiableEconomicMap<Node, Node> duplicates = InliningUtil.inline(invoke, inlineGraph, receiverNullCheck, inlineeMethod, reason, phase);
             if (duplicatesConsumer != null) {
                 duplicatesConsumer.accept(duplicates);
             }
@@ -462,7 +553,7 @@
             }
         } else {
             if (unwindNode != null && unwindNode.isAlive()) {
-                DeoptimizeNode deoptimizeNode = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler));
+                DeoptimizeNode deoptimizeNode = addDeoptimizeNode(graph, DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler);
                 unwindNode.replaceAndDelete(deoptimizeNode);
             }
         }
@@ -571,27 +662,47 @@
     }
 
     @SuppressWarnings("try")
-    private static void updateSourcePositions(Invoke invoke, StructuredGraph inlineGraph, UnmodifiableEconomicMap<Node, Node> duplicates, boolean isSubstitution) {
-        if (inlineGraph.mayHaveNodeSourcePosition() && invoke.stateAfter() != null) {
-            if (invoke.asNode().getNodeSourcePosition() == null) {
-                // Temporarily ignore the assert below.
-                return;
-            }
-
-            JavaConstant constantReceiver = invoke.getInvokeKind().hasReceiver() && !isSubstitution ? invoke.getReceiver().asJavaConstant() : null;
-            NodeSourcePosition invokePos = invoke.asNode().getNodeSourcePosition();
-            assert invokePos != null : "missing source information";
+    private static void updateSourcePositions(Invoke invoke, StructuredGraph inlineGraph, UnmodifiableEconomicMap<Node, Node> duplicates, boolean isSub, Mark mark) {
+        FixedNode invokeNode = invoke.asNode();
+        boolean isSubstitution = isSub || inlineGraph.method().getAnnotation(MethodSubstitution.class) != null || inlineGraph.method().getAnnotation(Snippet.class) != null;
+        StructuredGraph invokeGraph = invokeNode.graph();
+        assert !invokeGraph.trackNodeSourcePosition() || inlineGraph.trackNodeSourcePosition() ||
+                        isSubstitution : String.format("trackNodeSourcePosition mismatch %s %s != %s %s", invokeGraph, invokeGraph.trackNodeSourcePosition(), inlineGraph,
+                                        inlineGraph.trackNodeSourcePosition());
+        if (invokeGraph.trackNodeSourcePosition() && invoke.stateAfter() != null) {
+            final NodeSourcePosition invokePos = invoke.asNode().getNodeSourcePosition();
+            updateSourcePosition(invokeGraph, duplicates, mark, invokePos, isSubstitution);
+        }
+    }
 
-            EconomicMap<NodeSourcePosition, NodeSourcePosition> posMap = EconomicMap.create(Equivalence.DEFAULT);
-            UnmodifiableMapCursor<Node, Node> cursor = duplicates.getEntries();
-            while (cursor.advance()) {
-                NodeSourcePosition pos = cursor.getKey().getNodeSourcePosition();
-                if (pos != null) {
-                    NodeSourcePosition callerPos = pos.addCaller(constantReceiver, invokePos);
-                    if (!posMap.containsKey(callerPos)) {
-                        posMap.put(callerPos, callerPos);
-                    }
-                    cursor.getValue().setNodeSourcePosition(posMap.get(callerPos));
+    public static void updateSourcePosition(StructuredGraph invokeGraph, UnmodifiableEconomicMap<Node, Node> duplicates, Mark mark, NodeSourcePosition invokePos, boolean isSubstitution) {
+        /*
+         * Not every duplicate node is newly created, so only update the position of the newly
+         * created nodes.
+         */
+        EconomicSet<Node> newNodes = EconomicSet.create(Equivalence.DEFAULT);
+        newNodes.addAll(invokeGraph.getNewNodes(mark));
+        EconomicMap<NodeSourcePosition, NodeSourcePosition> posMap = EconomicMap.create(Equivalence.DEFAULT);
+        UnmodifiableMapCursor<Node, Node> cursor = duplicates.getEntries();
+        while (cursor.advance()) {
+            if (!newNodes.contains(cursor.getValue())) {
+                continue;
+            }
+            NodeSourcePosition pos = cursor.getKey().getNodeSourcePosition();
+            if (pos != null) {
+                NodeSourcePosition callerPos = posMap.get(pos);
+                if (callerPos == null) {
+                    callerPos = pos.addCaller(invokePos, isSubstitution);
+                    posMap.put(pos, callerPos);
+                }
+                cursor.getValue().setNodeSourcePosition(callerPos);
+            } else {
+                if (isSubstitution) {
+                    /*
+                     * If no other position is provided at least attribute the substituted node to
+                     * the original invoke.
+                     */
+                    cursor.getValue().setNodeSourcePosition(invokePos);
                 }
             }
         }
@@ -642,7 +753,15 @@
             }
             frameState.replaceAndDelete(stateAfterException);
             return stateAfterException;
-        } else if (frameState.bci == BytecodeFrame.UNWIND_BCI || frameState.bci == BytecodeFrame.AFTER_EXCEPTION_BCI) {
+        } else if ((frameState.bci == BytecodeFrame.UNWIND_BCI && frameState.graph().getGuardsStage() == GuardsStage.FLOATING_GUARDS) || frameState.bci == BytecodeFrame.AFTER_EXCEPTION_BCI) {
+            /*
+             * This path converts the frame states relevant for exception unwinding to
+             * deoptimization. This is only allowed in configurations when Graal compiles code for
+             * speculative execution (e.g., JIT compilation in HotSpot) but not when compiled code
+             * must be deoptimization free (e.g., AOT compilation for native image generation).
+             * There is currently no global flag in StructuredGraph to distinguish such modes, but
+             * the GuardsStage during inlining indicates the mode in which Graal operates.
+             */
             handleMissingAfterExceptionFrameState(frameState, invoke, replacements, alwaysDuplicateStateAfter);
             return frameState;
         } else if (frameState.bci == BytecodeFrame.BEFORE_BCI) {
@@ -706,7 +825,6 @@
         assert frameState.bci != BytecodeFrame.AFTER_EXCEPTION_BCI : frameState;
         assert frameState.bci != BytecodeFrame.BEFORE_BCI : frameState;
         assert frameState.bci != BytecodeFrame.UNKNOWN_BCI : frameState;
-        assert frameState.bci != BytecodeFrame.UNWIND_BCI : frameState;
         if (frameState.bci != BytecodeFrame.INVALID_FRAMESTATE_BCI) {
             ResolvedJavaMethod method = frameState.getMethod();
             if (method.equals(inlinedMethod)) {
@@ -738,7 +856,7 @@
     }
 
     public static FrameState handleMissingAfterExceptionFrameState(FrameState nonReplaceableFrameState, Invoke invoke, EconomicMap<Node, Node> replacements, boolean alwaysDuplicateStateAfter) {
-        Graph graph = nonReplaceableFrameState.graph();
+        StructuredGraph graph = nonReplaceableFrameState.graph();
         NodeWorkList workList = graph.createNodeWorkList();
         workList.add(nonReplaceableFrameState);
         for (Node node : workList) {
@@ -756,7 +874,7 @@
                         AbstractMergeNode merge = (AbstractMergeNode) fixedStateSplit;
                         while (merge.isAlive()) {
                             AbstractEndNode end = merge.forwardEnds().first();
-                            DeoptimizeNode deoptimizeNode = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler));
+                            DeoptimizeNode deoptimizeNode = addDeoptimizeNode(graph, DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler);
                             end.replaceAtPredecessor(deoptimizeNode);
                             GraphUtil.killCFG(end);
                         }
@@ -775,7 +893,7 @@
                         }
                         handleAfterBciFrameState(newInvoke.stateAfter(), invoke, alwaysDuplicateStateAfter);
                     } else {
-                        FixedNode deoptimizeNode = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler));
+                        FixedNode deoptimizeNode = addDeoptimizeNode(graph, DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler);
                         if (fixedStateSplit instanceof AbstractBeginNode) {
                             deoptimizeNode = BeginNode.begin(deoptimizeNode);
                         }
@@ -788,6 +906,11 @@
         return nonReplaceableFrameState;
     }
 
+    private static DeoptimizeNode addDeoptimizeNode(StructuredGraph graph, DeoptimizationAction action, DeoptimizationReason reason) {
+        GraalError.guarantee(graph.getGuardsStage() == GuardsStage.FLOATING_GUARDS, "Cannot introduce speculative deoptimization when Graal is used with fixed guards");
+        return graph.add(new DeoptimizeNode(action, reason));
+    }
+
     /**
      * Ensure that all states are either {@link BytecodeFrame#INVALID_FRAMESTATE_BCI} or one of
      * {@link BytecodeFrame#AFTER_BCI} or {@link BytecodeFrame#BEFORE_BCI}. Mixing of before and
@@ -856,8 +979,8 @@
         return replacements.hasSubstitution(target, invokeBci);
     }
 
-    public static StructuredGraph getIntrinsicGraph(Replacements replacements, ResolvedJavaMethod target, int invokeBci) {
-        return replacements.getSubstitution(target, invokeBci);
+    public static StructuredGraph getIntrinsicGraph(Replacements replacements, ResolvedJavaMethod target, int invokeBci, boolean trackNodeSourcePosition, NodeSourcePosition replaceePosition) {
+        return replacements.getSubstitution(target, invokeBci, trackNodeSourcePosition, replaceePosition);
     }
 
     public static FixedWithNextNode inlineMacroNode(Invoke invoke, ResolvedJavaMethod concrete, Class<? extends FixedWithNextNode> macroNodeClass) throws GraalError {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/AbstractInlineInfo.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/AbstractInlineInfo.java	Fri Mar 16 22:59:32 2018 -0700
@@ -64,7 +64,7 @@
     @SuppressWarnings("try")
     public final void populateInlinableElements(HighTierContext context, StructuredGraph caller, CanonicalizerPhase canonicalizer, OptionValues options) {
         for (int i = 0; i < numberOfMethods(); i++) {
-            Inlineable elem = Inlineable.getInlineableElement(methodAt(i), invoke, context, canonicalizer);
+            Inlineable elem = Inlineable.getInlineableElement(methodAt(i), invoke, context, canonicalizer, caller.trackNodeSourcePosition());
             setInlinableElement(i, elem);
         }
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/elem/Inlineable.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/elem/Inlineable.java	Fri Mar 16 22:59:32 2018 -0700
@@ -30,10 +30,10 @@
 
 public interface Inlineable {
 
-    static Inlineable getInlineableElement(final ResolvedJavaMethod method, Invoke invoke, HighTierContext context, CanonicalizerPhase canonicalizer) {
+    static Inlineable getInlineableElement(final ResolvedJavaMethod method, Invoke invoke, HighTierContext context, CanonicalizerPhase canonicalizer, boolean trackNodeSourcePosition) {
         assert method != null;
         assert invoke != null;
-        return new InlineableGraph(method, invoke, context, canonicalizer);
+        return new InlineableGraph(method, invoke, context, canonicalizer, trackNodeSourcePosition);
     }
 
     int getNodeCount();
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/elem/InlineableGraph.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/elem/InlineableGraph.java	Fri Mar 16 22:59:32 2018 -0700
@@ -66,8 +66,8 @@
 
     private FixedNodeProbabilityCache probabilites = new FixedNodeProbabilityCache();
 
-    public InlineableGraph(final ResolvedJavaMethod method, final Invoke invoke, final HighTierContext context, CanonicalizerPhase canonicalizer) {
-        StructuredGraph original = getOriginalGraph(method, context, canonicalizer, invoke.asNode().graph(), invoke.bci());
+    public InlineableGraph(final ResolvedJavaMethod method, final Invoke invoke, final HighTierContext context, CanonicalizerPhase canonicalizer, boolean trackNodeSourcePosition) {
+        StructuredGraph original = getOriginalGraph(method, context, canonicalizer, invoke.asNode().graph(), invoke.bci(), trackNodeSourcePosition);
         // TODO copying the graph is only necessary if it is modified or if it contains any invokes
         this.graph = (StructuredGraph) original.copy(invoke.asNode().getDebug());
         specializeGraphToArguments(invoke, context, canonicalizer);
@@ -78,12 +78,13 @@
      * The graph thus obtained is returned, ie the caller is responsible for cloning before
      * modification.
      */
-    private static StructuredGraph getOriginalGraph(final ResolvedJavaMethod method, final HighTierContext context, CanonicalizerPhase canonicalizer, StructuredGraph caller, int callerBci) {
-        StructuredGraph result = InliningUtil.getIntrinsicGraph(context.getReplacements(), method, callerBci);
+    private static StructuredGraph getOriginalGraph(final ResolvedJavaMethod method, final HighTierContext context, CanonicalizerPhase canonicalizer, StructuredGraph caller, int callerBci,
+                    boolean trackNodeSourcePosition) {
+        StructuredGraph result = InliningUtil.getIntrinsicGraph(context.getReplacements(), method, callerBci, trackNodeSourcePosition, null);
         if (result != null) {
             return result;
         }
-        return parseBytecodes(method, context, canonicalizer, caller);
+        return parseBytecodes(method, context, canonicalizer, caller, trackNodeSourcePosition);
     }
 
     /**
@@ -193,9 +194,10 @@
      * </p>
      */
     @SuppressWarnings("try")
-    private static StructuredGraph parseBytecodes(ResolvedJavaMethod method, HighTierContext context, CanonicalizerPhase canonicalizer, StructuredGraph caller) {
+    private static StructuredGraph parseBytecodes(ResolvedJavaMethod method, HighTierContext context, CanonicalizerPhase canonicalizer, StructuredGraph caller, boolean trackNodeSourcePosition) {
         DebugContext debug = caller.getDebug();
-        StructuredGraph newGraph = new StructuredGraph.Builder(caller.getOptions(), debug, AllowAssumptions.ifNonNull(caller.getAssumptions())).method(method).build();
+        StructuredGraph newGraph = new StructuredGraph.Builder(caller.getOptions(), debug, AllowAssumptions.ifNonNull(caller.getAssumptions())).method(method).trackNodeSourcePosition(
+                        trackNodeSourcePosition).build();
         try (DebugContext.Scope s = debug.scope("InlineGraph", newGraph)) {
             if (!caller.isUnsafeAccessTrackingEnabled()) {
                 newGraph.disableUnsafeAccessTracking();
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/policy/GreedyInliningPolicy.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/policy/GreedyInliningPolicy.java	Fri Mar 16 22:59:32 2018 -0700
@@ -69,17 +69,17 @@
         final double relevance = invocation.relevance();
 
         if (InlineEverything.getValue(options)) {
-            InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "inline everything");
+            InliningUtil.traceInlinedMethod(info, inliningDepth, fullyProcessed, "inline everything");
             return true;
         }
 
         if (isIntrinsic(replacements, info)) {
-            InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "intrinsic");
+            InliningUtil.traceInlinedMethod(info, inliningDepth, fullyProcessed, "intrinsic");
             return true;
         }
 
         if (info.shouldInline()) {
-            InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "forced inlining");
+            InliningUtil.traceInlinedMethod(info, inliningDepth, fullyProcessed, "forced inlining");
             return true;
         }
 
@@ -88,13 +88,13 @@
         int lowLevelGraphSize = previousLowLevelGraphSize(info);
 
         if (SmallCompiledLowLevelGraphSize.getValue(options) > 0 && lowLevelGraphSize > SmallCompiledLowLevelGraphSize.getValue(options) * inliningBonus) {
-            InliningUtil.logNotInlinedMethod(info, inliningDepth, "too large previous low-level graph (low-level-nodes: %d, relevance=%f, probability=%f, bonus=%f, nodes=%d)", lowLevelGraphSize,
+            InliningUtil.traceNotInlinedMethod(info, inliningDepth, "too large previous low-level graph (low-level-nodes: %d, relevance=%f, probability=%f, bonus=%f, nodes=%d)", lowLevelGraphSize,
                             relevance, probability, inliningBonus, nodes);
             return false;
         }
 
         if (nodes < TrivialInliningSize.getValue(options) * inliningBonus) {
-            InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "trivial (relevance=%f, probability=%f, bonus=%f, nodes=%d)", relevance, probability, inliningBonus, nodes);
+            InliningUtil.traceInlinedMethod(info, inliningDepth, fullyProcessed, "trivial (relevance=%f, probability=%f, bonus=%f, nodes=%d)", relevance, probability, inliningBonus, nodes);
             return true;
         }
 
@@ -106,19 +106,19 @@
          */
         double invokes = determineInvokeProbability(info);
         if (LimitInlinedInvokes.getValue(options) > 0 && fullyProcessed && invokes > LimitInlinedInvokes.getValue(options) * inliningBonus) {
-            InliningUtil.logNotInlinedMethod(info, inliningDepth, "callee invoke probability is too high (invokeP=%f, relevance=%f, probability=%f, bonus=%f, nodes=%d)", invokes, relevance,
+            InliningUtil.traceNotInlinedMethod(info, inliningDepth, "callee invoke probability is too high (invokeP=%f, relevance=%f, probability=%f, bonus=%f, nodes=%d)", invokes, relevance,
                             probability, inliningBonus, nodes);
             return false;
         }
 
         double maximumNodes = computeMaximumSize(relevance, (int) (MaximumInliningSize.getValue(options) * inliningBonus));
         if (nodes <= maximumNodes) {
-            InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "relevance-based (relevance=%f, probability=%f, bonus=%f, nodes=%d <= %f)", relevance, probability, inliningBonus,
+            InliningUtil.traceInlinedMethod(info, inliningDepth, fullyProcessed, "relevance-based (relevance=%f, probability=%f, bonus=%f, nodes=%d <= %f)", relevance, probability, inliningBonus,
                             nodes, maximumNodes);
             return true;
         }
 
-        InliningUtil.logNotInlinedMethod(info, inliningDepth, "relevance-based (relevance=%f, probability=%f, bonus=%f, nodes=%d > %f)", relevance, probability, inliningBonus, nodes, maximumNodes);
+        InliningUtil.traceNotInlinedMethod(info, inliningDepth, "relevance-based (relevance=%f, probability=%f, bonus=%f, nodes=%d > %f)", relevance, probability, inliningBonus, nodes, maximumNodes);
         return false;
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/policy/InlineMethodSubstitutionsPolicy.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/policy/InlineMethodSubstitutionsPolicy.java	Fri Mar 16 22:59:32 2018 -0700
@@ -39,7 +39,7 @@
         CallTargetNode callTarget = invocation.callee().invoke().callTarget();
         if (callTarget instanceof MethodCallTargetNode) {
             ResolvedJavaMethod calleeMethod = ((MethodCallTargetNode) callTarget).targetMethod();
-            if (replacements.getSubstitution(calleeMethod, invocation.callee().invoke().bci()) != null) {
+            if (replacements.hasSubstitution(calleeMethod, invocation.callee().invoke().bci())) {
                 return true;
             }
         }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/InliningData.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/InliningData.java	Fri Mar 16 22:59:32 2018 -0700
@@ -166,7 +166,7 @@
         if (failureMessage == null) {
             return true;
         } else {
-            InliningUtil.logNotInlined(invoke, inliningDepth(), method, failureMessage);
+            InliningUtil.traceNotInlinedMethod(invoke, inliningDepth(), method, failureMessage);
             return false;
         }
     }
@@ -257,13 +257,13 @@
     private InlineInfo getTypeCheckedInlineInfo(Invoke invoke, ResolvedJavaMethod targetMethod) {
         JavaTypeProfile typeProfile = ((MethodCallTargetNode) invoke.callTarget()).getProfile();
         if (typeProfile == null) {
-            InliningUtil.logNotInlined(invoke, inliningDepth(), targetMethod, "no type profile exists");
+            InliningUtil.traceNotInlinedMethod(invoke, inliningDepth(), targetMethod, "no type profile exists");
             return null;
         }
 
         JavaTypeProfile.ProfiledType[] ptypes = typeProfile.getTypes();
         if (ptypes == null || ptypes.length <= 0) {
-            InliningUtil.logNotInlined(invoke, inliningDepth(), targetMethod, "no types in profile");
+            InliningUtil.traceNotInlinedMethod(invoke, inliningDepth(), targetMethod, "no types in profile");
             return null;
         }
         ResolvedJavaType contextType = invoke.getContextType();
@@ -272,7 +272,7 @@
         OptionValues options = invoke.asNode().getOptions();
         if (ptypes.length == 1 && notRecordedTypeProbability == 0) {
             if (!optimisticOpts.inlineMonomorphicCalls(options)) {
-                InliningUtil.logNotInlined(invoke, inliningDepth(), targetMethod, "inlining monomorphic calls is disabled");
+                InliningUtil.traceNotInlinedMethod(invoke, inliningDepth(), targetMethod, "inlining monomorphic calls is disabled");
                 return null;
             }
 
@@ -287,13 +287,13 @@
             invoke.setPolymorphic(true);
 
             if (!optimisticOpts.inlinePolymorphicCalls(options) && notRecordedTypeProbability == 0) {
-                InliningUtil.logNotInlinedInvoke(invoke, inliningDepth(), targetMethod, "inlining polymorphic calls is disabled (%d types)", ptypes.length);
+                InliningUtil.traceNotInlinedMethod(invoke, inliningDepth(), targetMethod, "inlining polymorphic calls is disabled (%d types)", ptypes.length);
                 return null;
             }
             if (!optimisticOpts.inlineMegamorphicCalls(options) && notRecordedTypeProbability > 0) {
                 // due to filtering impossible types, notRecordedTypeProbability can be > 0 although
                 // the number of types is lower than what can be recorded in a type profile
-                InliningUtil.logNotInlinedInvoke(invoke, inliningDepth(), targetMethod, "inlining megamorphic calls is disabled (%d types, %f %% not recorded types)", ptypes.length,
+                InliningUtil.traceNotInlinedMethod(invoke, inliningDepth(), targetMethod, "inlining megamorphic calls is disabled (%d types, %f %% not recorded types)", ptypes.length,
                                 notRecordedTypeProbability * 100);
                 return null;
             }
@@ -304,7 +304,7 @@
             for (int i = 0; i < ptypes.length; i++) {
                 ResolvedJavaMethod concrete = ptypes[i].getType().resolveConcreteMethod(targetMethod, contextType);
                 if (concrete == null) {
-                    InliningUtil.logNotInlined(invoke, inliningDepth(), targetMethod, "could not resolve method");
+                    InliningUtil.traceNotInlinedMethod(invoke, inliningDepth(), targetMethod, "could not resolve method");
                     return null;
                 }
                 int index = concreteMethods.indexOf(concrete);
@@ -331,7 +331,7 @@
 
                 if (newConcreteMethods.isEmpty()) {
                     // No method left that is worth inlining.
-                    InliningUtil.logNotInlinedInvoke(invoke, inliningDepth(), targetMethod, "no methods remaining after filtering less frequent methods (%d methods previously)",
+                    InliningUtil.traceNotInlinedMethod(invoke, inliningDepth(), targetMethod, "no methods remaining after filtering less frequent methods (%d methods previously)",
                                     concreteMethods.size());
                     return null;
                 }
@@ -341,7 +341,7 @@
             }
 
             if (concreteMethods.size() > maxMethodPerInlining) {
-                InliningUtil.logNotInlinedInvoke(invoke, inliningDepth(), targetMethod, "polymorphic call with more than %d target methods", maxMethodPerInlining);
+                InliningUtil.traceNotInlinedMethod(invoke, inliningDepth(), targetMethod, "polymorphic call with more than %d target methods", maxMethodPerInlining);
                 return null;
             }
 
@@ -362,13 +362,13 @@
 
             if (usedTypes.isEmpty()) {
                 // No type left that is worth checking for.
-                InliningUtil.logNotInlinedInvoke(invoke, inliningDepth(), targetMethod, "no types remaining after filtering less frequent types (%d types previously)", ptypes.length);
+                InliningUtil.traceNotInlinedMethod(invoke, inliningDepth(), targetMethod, "no types remaining after filtering less frequent types (%d types previously)", ptypes.length);
                 return null;
             }
 
             for (ResolvedJavaMethod concrete : concreteMethods) {
                 if (!checkTargetConditions(invoke, concrete)) {
-                    InliningUtil.logNotInlined(invoke, inliningDepth(), targetMethod, "it is a polymorphic method call and at least one invoked method cannot be inlined");
+                    InliningUtil.traceNotInlinedMethod(invoke, inliningDepth(), targetMethod, "it is a polymorphic method call and at least one invoked method cannot be inlined");
                     return null;
                 }
             }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/PhaseSuite.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/PhaseSuite.java	Fri Mar 16 22:59:32 2018 -0700
@@ -96,6 +96,13 @@
     }
 
     /**
+     * Gets an unmodifiable view on the phases in this suite.
+     */
+    public List<BasePhase<? super C>> getPhases() {
+        return Collections.unmodifiableList(phases);
+    }
+
+    /**
      * Returns a {@link ListIterator} at the position of the first phase which is an instance of
      * {@code phaseClass} or null if no such phase can be found.
      *
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/contract/VerifyNodeCosts.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/contract/VerifyNodeCosts.java	Fri Mar 16 22:59:32 2018 -0700
@@ -22,7 +22,6 @@
  */
 package org.graalvm.compiler.phases.contract;
 
-import java.lang.reflect.Field;
 import java.lang.reflect.Modifier;
 import java.util.function.Predicate;
 
@@ -64,13 +63,8 @@
     }
 
     private static NodeClass<?> getType(Class<?> c) {
-        Field f;
         try {
-            f = c.getField("TYPE");
-            f.setAccessible(true);
-            Object val = f.get(null);
-            NodeClass<?> nodeType = (NodeClass<?>) val;
-            return nodeType;
+            return NodeClass.get(c);
         } catch (Throwable t) {
             throw new VerifyPhase.VerificationError("%s.java does not specify a TYPE field.", c.getName());
         }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/BinaryGraphPrinter.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/BinaryGraphPrinter.java	Fri Mar 16 22:59:32 2018 -0700
@@ -46,6 +46,7 @@
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.graph.NodeMap;
 import org.graalvm.compiler.graph.NodeSourcePosition;
+import org.graalvm.compiler.graph.SourceLanguagePosition;
 import org.graalvm.compiler.nodes.AbstractBeginNode;
 import org.graalvm.compiler.nodes.AbstractEndNode;
 import org.graalvm.compiler.nodes.AbstractMergeNode;
@@ -67,9 +68,9 @@
 import org.graalvm.graphio.GraphStructure;
 import org.graalvm.graphio.GraphTypes;
 
+import jdk.vm.ci.meta.JavaType;
 import jdk.vm.ci.meta.ResolvedJavaField;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
-import jdk.vm.ci.meta.ResolvedJavaType;
 import jdk.vm.ci.meta.Signature;
 
 public class BinaryGraphPrinter implements
@@ -265,6 +266,17 @@
             }
             props.put("category", "floating");
         }
+        if (node.getNodeSourcePosition() != null) {
+            NodeSourcePosition pos = node.getNodeSourcePosition();
+            while (pos != null) {
+                SourceLanguagePosition cur = pos.getSourceLanauage();
+                if (cur != null) {
+                    cur.addSourceInformation(props);
+                    break;
+                }
+                pos = pos.getCaller();
+            }
+        }
         if (getSnippetReflectionProvider() != null) {
             for (Map.Entry<String, Object> prop : props.entrySet()) {
                 if (prop.getValue() instanceof JavaConstantFormattable) {
@@ -380,8 +392,8 @@
         if (obj instanceof Class<?>) {
             return ((Class<?>) obj).getName();
         }
-        if (obj instanceof ResolvedJavaType) {
-            return ((ResolvedJavaType) obj).toJavaName();
+        if (obj instanceof JavaType) {
+            return ((JavaType) obj).toJavaName();
         }
         return null;
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraphPrinter.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraphPrinter.java	Fri Mar 16 22:59:32 2018 -0700
@@ -79,7 +79,7 @@
     /**
      * {@code jdk.vm.ci} module.
      */
-    Object JVMCI_MODULE = JDK9Method.JAVA_SPECIFICATION_VERSION < 9 ? null : JDK9Method.getModule.invoke(Services.class);
+    Object JVMCI_MODULE = JDK9Method.JAVA_SPECIFICATION_VERSION < 9 ? null : JDK9Method.getModule(Services.class);
 
     /**
      * Classes whose {@link #toString()} method does not run any untrusted code.
@@ -111,8 +111,8 @@
                 return true;
             }
         } else {
-            Object module = JDK9Method.getModule.invoke(c);
-            if (JVMCI_MODULE == module || (Boolean) JDK9Method.isOpenTo.invoke(JVMCI_MODULE, JVMCI_RUNTIME_PACKAGE, module)) {
+            Object module = JDK9Method.getModule(c);
+            if (JVMCI_MODULE == module || JDK9Method.isOpenTo(JVMCI_MODULE, JVMCI_RUNTIME_PACKAGE, module)) {
                 // Can access non-statically-exported package in JVMCI
                 return true;
             }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraphPrinterDumpHandler.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraphPrinterDumpHandler.java	Fri Mar 16 22:59:32 2018 -0700
@@ -244,7 +244,10 @@
                     lastMethodOrGraph = o;
                 }
             }
-
+            if (result.size() == 2 && result.get(1).startsWith("TruffleGraal")) {
+                result.clear();
+                result.add("Graal Graphs");
+            }
             if (result.isEmpty()) {
                 result.add(graph.toString());
                 graphSeen = true;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64FloatArithmeticSnippets.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64FloatArithmeticSnippets.java	Fri Mar 16 22:59:32 2018 -0700
@@ -75,7 +75,7 @@
         Arguments args = new Arguments(snippet, graph.getGuardsStage(), tool.getLoweringStage());
         args.add("x", node.getX());
         args.add("y", node.getY());
-        template(graph.getDebug(), args).instantiate(providers.getMetaAccess(), node, SnippetTemplate.DEFAULT_REPLACER, tool, args);
+        template(node, args).instantiate(providers.getMetaAccess(), node, SnippetTemplate.DEFAULT_REPLACER, tool, args);
     }
 
     @Snippet
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64IntegerArithmeticSnippets.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64IntegerArithmeticSnippets.java	Fri Mar 16 22:59:32 2018 -0700
@@ -106,7 +106,7 @@
         Arguments args = new Arguments(snippet, graph.getGuardsStage(), tool.getLoweringStage());
         args.add("x", node.getX());
         args.add("y", node.getY());
-        template(graph.getDebug(), args).instantiate(providers.getMetaAccess(), node, SnippetTemplate.DEFAULT_REPLACER, args);
+        template(node, args).instantiate(providers.getMetaAccess(), node, SnippetTemplate.DEFAULT_REPLACER, args);
     }
 
     @Snippet
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64ConvertSnippets.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64ConvertSnippets.java	Fri Mar 16 22:59:32 2018 -0700
@@ -189,7 +189,7 @@
             args.add("input", convert.getValue());
             args.add("result", graph.unique(new AMD64FloatConvertNode(convert.getFloatConvert(), convert.getValue())));
 
-            SnippetTemplate template = template(convert.getDebug(), args);
+            SnippetTemplate template = template(convert, args);
             convert.getDebug().log("Lowering %s in %s: node=%s, template=%s, arguments=%s", convert.getFloatConvert(), graph, convert, template, args);
             template.instantiate(providers.getMetaAccess(), convert, DEFAULT_REPLACER, tool, args);
             convert.safeDelete();
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64GraphBuilderPlugins.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64GraphBuilderPlugins.java	Fri Mar 16 22:59:32 2018 -0700
@@ -29,6 +29,7 @@
 import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.LOG10;
 import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.SIN;
 import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.TAN;
+import static org.graalvm.compiler.serviceprovider.JDK9Method.JAVA_SPECIFICATION_VERSION;
 import static org.graalvm.compiler.serviceprovider.JDK9Method.Java8OrEarlier;
 
 import java.util.Arrays;
@@ -75,6 +76,8 @@
                 registerIntegerLongPlugins(invocationPlugins, LongSubstitutions.class, JavaKind.Long, arch, replacementsBytecodeProvider);
                 registerUnsafePlugins(invocationPlugins, replacementsBytecodeProvider);
                 registerStringPlugins(invocationPlugins, arch, replacementsBytecodeProvider);
+                registerStringLatin1Plugins(invocationPlugins, replacementsBytecodeProvider);
+                registerStringUTF16Plugins(invocationPlugins, replacementsBytecodeProvider);
                 registerMathPlugins(invocationPlugins, arch, arithmeticStubs, replacementsBytecodeProvider);
                 registerArraysEqualsPlugins(invocationPlugins, replacementsBytecodeProvider);
             }
@@ -183,12 +186,34 @@
     }
 
     private static void registerStringPlugins(InvocationPlugins plugins, AMD64 arch, BytecodeProvider replacementsBytecodeProvider) {
-        if (Java8OrEarlier && arch.getFeatures().contains(CPUFeature.SSE4_2)) {
+        if (Java8OrEarlier) {
             Registration r;
             r = new Registration(plugins, String.class, replacementsBytecodeProvider);
             r.setAllowOverwrite(true);
-            r.registerMethodSubstitution(AMD64StringSubstitutions.class, "indexOf", char[].class, int.class,
-                            int.class, char[].class, int.class, int.class, int.class);
+            if (arch.getFeatures().contains(CPUFeature.SSE4_2)) {
+                r.registerMethodSubstitution(AMD64StringSubstitutions.class, "indexOf", char[].class, int.class,
+                                int.class, char[].class, int.class, int.class, int.class);
+            }
+            // r.registerMethodSubstitution(AMD64StringSubstitutions.class, "compareTo",
+            // Receiver.class, String.class);
+        }
+    }
+
+    private static void registerStringLatin1Plugins(InvocationPlugins plugins, BytecodeProvider replacementsBytecodeProvider) {
+        if (JAVA_SPECIFICATION_VERSION >= 9) {
+            Registration r = new Registration(plugins, "java.lang.StringLatin1", replacementsBytecodeProvider);
+            r.setAllowOverwrite(true);
+            r.registerMethodSubstitution(AMD64StringLatin1Substitutions.class, "compareTo", byte[].class, byte[].class);
+            r.registerMethodSubstitution(AMD64StringLatin1Substitutions.class, "compareToUTF16", byte[].class, byte[].class);
+        }
+    }
+
+    private static void registerStringUTF16Plugins(InvocationPlugins plugins, BytecodeProvider replacementsBytecodeProvider) {
+        if (JAVA_SPECIFICATION_VERSION >= 9) {
+            Registration r = new Registration(plugins, "java.lang.StringUTF16", replacementsBytecodeProvider);
+            r.setAllowOverwrite(true);
+            r.registerMethodSubstitution(AMD64StringUTF16Substitutions.class, "compareTo", byte[].class, byte[].class);
+            r.registerMethodSubstitution(AMD64StringUTF16Substitutions.class, "compareToLatin1", byte[].class, byte[].class);
         }
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringLatin1Substitutions.java	Fri Mar 16 22:59:32 2018 -0700
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.amd64;
+
+import org.graalvm.compiler.api.replacements.ClassSubstitution;
+import org.graalvm.compiler.api.replacements.MethodSubstitution;
+import org.graalvm.compiler.replacements.nodes.ArrayCompareToNode;
+
+import jdk.vm.ci.meta.JavaKind;
+
+// JaCoCo Exclude
+
+/**
+ * Substitutions for {@code java.lang.StringLatin1} methods.
+ *
+ * Since JDK 9.
+ */
+@ClassSubstitution(className = "java.lang.StringLatin1", optional = true)
+public class AMD64StringLatin1Substitutions {
+
+    /**
+     * @param value is byte[]
+     * @param other is byte[]
+     */
+    @MethodSubstitution
+    public static int compareTo(byte[] value, byte[] other) {
+        return ArrayCompareToNode.compareTo(value, other, value.length, other.length, JavaKind.Byte, JavaKind.Byte);
+    }
+
+    /**
+     * @param value is byte[]
+     * @param other is char[]
+     */
+    @MethodSubstitution
+    public static int compareToUTF16(byte[] value, byte[] other) {
+        return ArrayCompareToNode.compareTo(value, other, value.length, other.length, JavaKind.Byte, JavaKind.Char);
+    }
+
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringSubstitutions.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringSubstitutions.java	Fri Mar 16 22:59:32 2018 -0700
@@ -26,8 +26,11 @@
 import org.graalvm.compiler.api.replacements.Fold;
 import org.graalvm.compiler.api.replacements.Fold.InjectedParameter;
 import org.graalvm.compiler.api.replacements.MethodSubstitution;
+import org.graalvm.compiler.core.common.SuppressFBWarnings;
 import org.graalvm.compiler.core.common.spi.ArrayOffsetProvider;
 import org.graalvm.compiler.graph.Node.ConstantNodeParameter;
+import org.graalvm.compiler.replacements.StringSubstitutions;
+import org.graalvm.compiler.replacements.nodes.ArrayCompareToNode;
 import org.graalvm.compiler.word.Word;
 import org.graalvm.word.Pointer;
 
@@ -86,4 +89,16 @@
         }
         return result;
     }
+
+    @MethodSubstitution(isStatic = false)
+    @SuppressFBWarnings(value = "ES_COMPARING_PARAMETER_STRING_WITH_EQ", justification = "reference equality on the receiver is what we want")
+    public static int compareTo(String receiver, String anotherString) {
+        if (receiver == anotherString) {
+            return 0;
+        }
+        char[] value = StringSubstitutions.getValue(receiver);
+        char[] other = StringSubstitutions.getValue(anotherString);
+        return ArrayCompareToNode.compareTo(value, other, value.length << 1, other.length << 1, JavaKind.Char, JavaKind.Char);
+    }
+
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringUTF16Substitutions.java	Fri Mar 16 22:59:32 2018 -0700
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.amd64;
+
+import org.graalvm.compiler.api.replacements.ClassSubstitution;
+import org.graalvm.compiler.api.replacements.MethodSubstitution;
+import org.graalvm.compiler.replacements.nodes.ArrayCompareToNode;
+
+import jdk.vm.ci.meta.JavaKind;
+
+// JaCoCo Exclude
+
+/**
+ * Substitutions for {@code java.lang.StringUTF16} methods.
+ *
+ * Since JDK 9.
+ */
+@ClassSubstitution(className = "java.lang.StringUTF16", optional = true)
+public class AMD64StringUTF16Substitutions {
+
+    /**
+     * @param value is char[]
+     * @param other is char[]
+     */
+    @MethodSubstitution
+    public static int compareTo(byte[] value, byte[] other) {
+        return ArrayCompareToNode.compareTo(value, other, value.length, other.length, JavaKind.Char, JavaKind.Char);
+    }
+
+    /**
+     * @param value is char[]
+     * @param other is byte[]
+     */
+    @MethodSubstitution
+    public static int compareToLatin1(byte[] value, byte[] other) {
+        /*
+         * Swapping array arguments because intrinsic expects order to be byte[]/char[] but kind
+         * arguments stay in original order.
+         */
+        return ArrayCompareToNode.compareTo(other, value, other.length, value.length, JavaKind.Char, JavaKind.Byte);
+    }
+
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/MethodSubstitutionTest.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/MethodSubstitutionTest.java	Fri Mar 16 22:59:32 2018 -0700
@@ -109,7 +109,7 @@
         StructuredGraph graph = testGraph(testMethodName);
 
         // Check to see if the resulting graph contains the expected node
-        StructuredGraph replacement = getReplacements().getSubstitution(realMethod, -1);
+        StructuredGraph replacement = getReplacements().getSubstitution(realMethod, -1, false, null);
         if (replacement == null && !optional) {
             assertInGraph(graph, intrinsicClass);
         }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PEGraphDecoderTest.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PEGraphDecoderTest.java	Fri Mar 16 22:59:32 2018 -0700
@@ -136,9 +136,9 @@
             registerPlugins(graphBuilderConfig.getPlugins().getInvocationPlugins());
             targetGraph = new StructuredGraph.Builder(getInitialOptions(), debug, AllowAssumptions.YES).method(testMethod).build();
             CachingPEGraphDecoder decoder = new CachingPEGraphDecoder(getTarget().arch, targetGraph, getProviders(), graphBuilderConfig, OptimisticOptimizations.NONE, AllowAssumptions.YES,
-                            null, null, new InlineInvokePlugin[]{new InlineAll()}, null, null, null);
+                            null, null, new InlineInvokePlugin[]{new InlineAll()}, null, null, null, null);
 
-            decoder.decode(testMethod);
+            decoder.decode(testMethod, false);
             debug.dump(DebugContext.BASIC_LEVEL, targetGraph, "Target Graph");
             targetGraph.verify();
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/SnippetsTest.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/SnippetsTest.java	Fri Mar 16 22:59:32 2018 -0700
@@ -43,6 +43,6 @@
 
     @Override
     protected StructuredGraph parse(Builder builder, PhaseSuite<HighTierContext> graphBuilderSuite) {
-        return installer.makeGraph(getDebugContext(), bytecodeProvider, builder.getMethod(), null, null);
+        return installer.makeGraph(getDebugContext(), bytecodeProvider, builder.getMethod(), null, null, false, null);
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/StandardMethodSubstitutionsTest.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/StandardMethodSubstitutionsTest.java	Fri Mar 16 22:59:32 2018 -0700
@@ -24,8 +24,6 @@
 
 import java.util.HashMap;
 
-import org.junit.Test;
-
 import org.graalvm.compiler.api.replacements.MethodSubstitution;
 import org.graalvm.compiler.nodes.IfNode;
 import org.graalvm.compiler.nodes.StructuredGraph;
@@ -35,6 +33,7 @@
 import org.graalvm.compiler.replacements.nodes.BitScanForwardNode;
 import org.graalvm.compiler.replacements.nodes.BitScanReverseNode;
 import org.graalvm.compiler.replacements.nodes.ReverseBytesNode;
+import org.junit.Test;
 
 import jdk.vm.ci.code.InstalledCode;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
@@ -137,7 +136,7 @@
         StructuredGraph graph = testGraph(testMethodName);
 
         // Check to see if the resulting graph contains the expected node
-        StructuredGraph replacement = getReplacements().getSubstitution(realJavaMethod, -1);
+        StructuredGraph replacement = getReplacements().getSubstitution(realJavaMethod, -1, false, null);
         if (replacement == null && !optional) {
             assertInGraph(graph, intrinsicClass);
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/StringCompareToTest.java	Fri Mar 16 22:59:32 2018 -0700
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 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.test;
+
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.replacements.nodes.ArrayCompareToNode;
+import org.junit.Assert;
+import org.junit.Assume;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import jdk.vm.ci.amd64.AMD64;
+import jdk.vm.ci.code.InstalledCode;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * Tests compareTo method intrinsic.
+ */
+public class StringCompareToTest extends MethodSubstitutionTest {
+
+    private ResolvedJavaMethod realMethod = null;
+    private ResolvedJavaMethod testMethod = null;
+    private InstalledCode testCode = null;
+
+    private final String[] testData = new String[]{
+                    "A", "\uFF21", "AB", "A", "a", "Ab", "AA", "\uFF21",
+                    "A\uFF21", "ABC", "AB", "ABcD", "ABCD\uFF21\uFF21", "ABCD\uFF21", "ABCDEFG\uFF21", "ABCD",
+                    "ABCDEFGH\uFF21\uFF21", "\uFF22", "\uFF21\uFF22", "\uFF21A",
+                    "\uFF21\uFF21",
+                    "\u043c\u0430\u043c\u0430\u0020\u043c\u044b\u043b\u0430\u0020\u0440\u0430\u043c\u0443\u002c\u0020\u0440\u0430\u043c\u0430\u0020\u0441\u044a\u0435\u043b\u0430\u0020\u043c\u0430\u043c\u0443",
+                    "crazy dog jumps over laszy fox",
+                    "XMM-XMM-YMM-YMM-ZMM-ZMM-ZMM-ZMM-",
+                    "XMM-XMM+YMM-YMM-ZMM-ZMM-ZMM-ZMM-",
+                    "XMM-XMM-YMM-YMM+ZMM-ZMM-ZMM-ZMM-",
+                    "XMM-XMM-YMM-YMM-ZMM-ZMM-ZMM-ZMM+",
+                    "XMM-XMM-XMM-XMM-YMM-YMM-YMM-YMM-ZMM-ZMM-ZMM-ZMM-ZMM-ZMM-ZMM-ZMM-",
+                    "XMM-XMM-XMM-XMM+YMM-YMM-YMM-YMM-ZMM-ZMM-ZMM-ZMM-ZMM-ZMM-ZMM-ZMM-",
+                    "XMM-XMM-XMM-XMM-YMM-YMM-YMM-YMM+ZMM-ZMM-ZMM-ZMM-ZMM-ZMM-ZMM-ZMM-",
+                    "XMM-XMM-XMM-XMM-YMM-YMM-YMM-YMM-ZMM-ZMM-ZMM-ZMM-ZMM-ZMM-ZMM-ZMM+",
+                    ""
+    };
+
+    public StringCompareToTest() {
+        Assume.assumeTrue(getTarget().arch instanceof AMD64);
+
+        realMethod = getResolvedJavaMethod(String.class, "compareTo", String.class);
+        testMethod = getResolvedJavaMethod("stringCompareTo");
+        StructuredGraph graph = testGraph("stringCompareTo");
+
+        // Check to see if the resulting graph contains the expected node
+        StructuredGraph replacement = getReplacements().getSubstitution(realMethod, -1, false, null);
+        if (replacement == null) {
+            assertInGraph(graph, ArrayCompareToNode.class);
+        }
+
+        // Force compilation
+        testCode = getCode(testMethod);
+        Assert.assertNotNull(testCode);
+    }
+
+    private void executeStringCompareTo(String s0, String s1) {
+        Object expected = invokeSafe(realMethod, s0, s1);
+        // Verify that the original method and the substitution produce the same value
+        assertDeepEquals(expected, invokeSafe(testMethod, null, s0, s1));
+        // Verify that the generated code and the original produce the same value
+        assertDeepEquals(expected, executeVarargsSafe(testCode, s0, s1));
+    }
+
+    public static int stringCompareTo(String a, String b) {
+        return a.compareTo(b);
+    }
+
+    @Test
+    @Ignore("GR-8748")
+    public void testEqualString() {
+        String s = "equal-string";
+        executeStringCompareTo(s, new String(s.toCharArray()));
+    }
+
+    @Test
+    @Ignore("GR-8748")
+    public void testDifferentString() {
+        executeStringCompareTo("some-string", "different-string");
+    }
+
+    @Test
+    @Ignore("GR-8748")
+    public void testAllStrings() {
+        for (String s0 : testData) {
+            for (String s1 : testData) {
+                executeStringCompareTo(s0, s1);
+            }
+        }
+    }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/StringSubstitutionsTest.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/StringSubstitutionsTest.java	Fri Mar 16 22:59:32 2018 -0700
@@ -22,11 +22,10 @@
  */
 package org.graalvm.compiler.replacements.test;
 
-import org.junit.Test;
-
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.replacements.StringSubstitutions;
 import org.graalvm.compiler.replacements.nodes.ArrayEqualsNode;
+import org.junit.Test;
 
 import jdk.vm.ci.code.InstalledCode;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
@@ -42,7 +41,7 @@
         StructuredGraph graph = testGraph(testMethodName);
 
         // Check to see if the resulting graph contains the expected node
-        StructuredGraph replacement = getReplacements().getSubstitution(realMethod, -1);
+        StructuredGraph replacement = getReplacements().getSubstitution(realMethod, -1, false, null);
         if (replacement == null && !optional) {
             assertInGraph(graph, intrinsicClass);
         }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/WordTest.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/WordTest.java	Fri Mar 16 22:59:32 2018 -0700
@@ -44,7 +44,7 @@
     protected StructuredGraph parse(Builder builder, PhaseSuite<HighTierContext> graphBuilderSuite) {
         // create a copy to assign a valid compilation id
         DebugContext debug = getDebugContext();
-        StructuredGraph originalGraph = installer.makeGraph(debug, bytecodeProvider, builder.getMethod(), null, null);
+        StructuredGraph originalGraph = installer.makeGraph(debug, bytecodeProvider, builder.getMethod(), null, null, false, null);
         return originalGraph.copyWithIdentifier(builder.getCompilationId(), debug);
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/BoxingSnippets.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/BoxingSnippets.java	Fri Mar 16 22:59:32 2018 -0700
@@ -29,8 +29,8 @@
 
 import org.graalvm.compiler.api.replacements.Snippet;
 import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter;
+import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
 import org.graalvm.compiler.debug.DebugHandlersFactory;
-import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
 import org.graalvm.compiler.nodes.ConstantNode;
 import org.graalvm.compiler.nodes.PiNode;
 import org.graalvm.compiler.nodes.ValueNode;
@@ -207,7 +207,7 @@
                 args.add("value", box.getValue());
                 args.addConst("valueOfCounter", valueOfCounter);
 
-                SnippetTemplate template = template(box.getDebug(), args);
+                SnippetTemplate template = template(box, args);
                 box.getDebug().log("Lowering integerValueOf in %s: node=%s, template=%s, arguments=%s", box.graph(), box, template, args);
                 template.instantiate(providers.getMetaAccess(), box, DEFAULT_REPLACER, args);
             }
@@ -218,7 +218,7 @@
             args.add("value", unbox.getValue());
             args.addConst("valueCounter", valueCounter);
 
-            SnippetTemplate template = template(unbox.getDebug(), args);
+            SnippetTemplate template = template(unbox, args);
             unbox.getDebug().log("Lowering integerValueOf in %s: node=%s, template=%s, arguments=%s", unbox.graph(), unbox, template, args);
             template.instantiate(providers.getMetaAccess(), unbox, DEFAULT_REPLACER, args);
         }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/CachingPEGraphDecoder.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/CachingPEGraphDecoder.java	Fri Mar 16 22:59:32 2018 -0700
@@ -27,6 +27,7 @@
 import org.graalvm.collections.EconomicMap;
 import org.graalvm.compiler.bytecode.BytecodeProvider;
 import org.graalvm.compiler.debug.DebugContext;
+import org.graalvm.compiler.graph.SourceLanguagePositionProvider;
 import org.graalvm.compiler.java.GraphBuilderPhase;
 import org.graalvm.compiler.nodes.EncodedGraph;
 import org.graalvm.compiler.nodes.GraphEncoder;
@@ -63,9 +64,9 @@
     public CachingPEGraphDecoder(Architecture architecture, StructuredGraph graph, Providers providers, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts,
                     AllowAssumptions allowAssumptions, LoopExplosionPlugin loopExplosionPlugin, InvocationPlugins invocationPlugins, InlineInvokePlugin[] inlineInvokePlugins,
                     ParameterPlugin parameterPlugin,
-                    NodePlugin[] nodePlugins, ResolvedJavaMethod callInlinedMethod) {
+                    NodePlugin[] nodePlugins, ResolvedJavaMethod callInlinedMethod, SourceLanguagePositionProvider sourceLanguagePositionProvider) {
         super(architecture, graph, providers.getMetaAccess(), providers.getConstantReflection(), providers.getConstantFieldProvider(), providers.getStampProvider(), loopExplosionPlugin,
-                        invocationPlugins, inlineInvokePlugins, parameterPlugin, nodePlugins, callInlinedMethod);
+                        invocationPlugins, inlineInvokePlugins, parameterPlugin, nodePlugins, callInlinedMethod, sourceLanguagePositionProvider);
 
         this.providers = providers;
         this.graphBuilderConfig = graphBuilderConfig;
@@ -80,10 +81,11 @@
     }
 
     @SuppressWarnings("try")
-    private EncodedGraph createGraph(ResolvedJavaMethod method, BytecodeProvider intrinsicBytecodeProvider) {
-        StructuredGraph graphToEncode = new StructuredGraph.Builder(options, debug, allowAssumptions).useProfilingInfo(false).method(method).build();
+    private EncodedGraph createGraph(ResolvedJavaMethod method, ResolvedJavaMethod originalMethod, BytecodeProvider intrinsicBytecodeProvider) {
+        StructuredGraph graphToEncode = new StructuredGraph.Builder(options, debug, allowAssumptions).useProfilingInfo(false).trackNodeSourcePosition(
+                        graphBuilderConfig.trackNodeSourcePosition()).method(method).build();
         try (DebugContext.Scope scope = debug.scope("createGraph", graphToEncode)) {
-            IntrinsicContext initialIntrinsicContext = intrinsicBytecodeProvider != null ? new IntrinsicContext(method, method, intrinsicBytecodeProvider, INLINE_AFTER_PARSING) : null;
+            IntrinsicContext initialIntrinsicContext = intrinsicBytecodeProvider != null ? new IntrinsicContext(originalMethod, method, intrinsicBytecodeProvider, INLINE_AFTER_PARSING) : null;
             GraphBuilderPhase.Instance graphBuilderPhaseInstance = createGraphBuilderPhaseInstance(initialIntrinsicContext);
             graphBuilderPhaseInstance.apply(graphToEncode);
 
@@ -106,10 +108,10 @@
     }
 
     @Override
-    protected EncodedGraph lookupEncodedGraph(ResolvedJavaMethod method, BytecodeProvider intrinsicBytecodeProvider) {
+    protected EncodedGraph lookupEncodedGraph(ResolvedJavaMethod method, ResolvedJavaMethod originalMethod, BytecodeProvider intrinsicBytecodeProvider, boolean trackNodeSourcePosition) {
         EncodedGraph result = graphCache.get(method);
         if (result == null && method.hasBytecodes()) {
-            result = createGraph(method, intrinsicBytecodeProvider);
+            result = createGraph(method, originalMethod, intrinsicBytecodeProvider);
         }
         return result;
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ConstantStringIndexOfSnippets.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ConstantStringIndexOfSnippets.java	Fri Mar 16 22:59:32 2018 -0700
@@ -65,7 +65,7 @@
             char[] targetCharArray = snippetReflection.asObject(char[].class, stringIndexOf.getArgument(3).asJavaConstant());
             args.addConst("md2", md2(targetCharArray));
             args.addConst("cache", computeCache(targetCharArray));
-            template(graph.getDebug(), args).instantiate(providers.getMetaAccess(), stringIndexOf, DEFAULT_REPLACER, args);
+            template(stringIndexOf, args).instantiate(providers.getMetaAccess(), stringIndexOf, DEFAULT_REPLACER, args);
         }
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/GraphKit.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/GraphKit.java	Fri Mar 16 22:59:32 2018 -0700
@@ -32,9 +32,11 @@
 import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.core.common.type.StampPair;
+import org.graalvm.compiler.debug.DebugCloseable;
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.graph.Graph;
 import org.graalvm.compiler.graph.Node.ValueNumberable;
+import org.graalvm.compiler.graph.NodeSourcePosition;
 import org.graalvm.compiler.java.FrameStateBuilder;
 import org.graalvm.compiler.java.GraphBuilderPhase;
 import org.graalvm.compiler.nodes.AbstractBeginNode;
@@ -52,6 +54,7 @@
 import org.graalvm.compiler.nodes.MergeNode;
 import org.graalvm.compiler.nodes.NodeView;
 import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.UnwindNode;
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.calc.FloatingNode;
 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
@@ -224,28 +227,42 @@
      * Creates and appends an {@link InvokeNode} for a call to a given method with a given set of
      * arguments.
      */
+    @SuppressWarnings("try")
     public InvokeNode createInvoke(ResolvedJavaMethod method, InvokeKind invokeKind, FrameStateBuilder frameStateBuilder, int bci, ValueNode... args) {
-        assert method.isStatic() == (invokeKind == InvokeKind.Static);
-        Signature signature = method.getSignature();
-        JavaType returnType = signature.getReturnType(null);
-        assert checkArgs(method, args);
-        StampPair returnStamp = graphBuilderPlugins.getOverridingStamp(this, returnType, false);
-        if (returnStamp == null) {
-            returnStamp = StampFactory.forDeclaredType(graph.getAssumptions(), returnType, false);
+        try (DebugCloseable context = graph.withNodeSourcePosition(NodeSourcePosition.placeholder(method))) {
+            assert method.isStatic() == (invokeKind == InvokeKind.Static);
+            Signature signature = method.getSignature();
+            JavaType returnType = signature.getReturnType(null);
+            assert checkArgs(method, args);
+            StampPair returnStamp = graphBuilderPlugins.getOverridingStamp(this, returnType, false);
+            if (returnStamp == null) {
+                returnStamp = StampFactory.forDeclaredType(graph.getAssumptions(), returnType, false);
+            }
+            MethodCallTargetNode callTarget = graph.add(createMethodCallTarget(invokeKind, method, args, returnStamp, bci));
+            InvokeNode invoke = append(new InvokeNode(callTarget, bci));
+
+            if (frameStateBuilder != null) {
+                if (invoke.getStackKind() != JavaKind.Void) {
+                    frameStateBuilder.push(invoke.getStackKind(), invoke);
+                }
+                invoke.setStateAfter(frameStateBuilder.create(bci, invoke));
+                if (invoke.getStackKind() != JavaKind.Void) {
+                    frameStateBuilder.pop(invoke.getStackKind());
+                }
+            }
+            return invoke;
         }
-        MethodCallTargetNode callTarget = graph.add(createMethodCallTarget(invokeKind, method, args, returnStamp, bci));
-        InvokeNode invoke = append(new InvokeNode(callTarget, bci));
+    }
+
+    public InvokeWithExceptionNode createInvokeWithExceptionAndUnwind(ResolvedJavaMethod method, InvokeKind invokeKind,
+                    FrameStateBuilder frameStateBuilder, int invokeBci, int exceptionEdgeBci, ValueNode... args) {
 
-        if (frameStateBuilder != null) {
-            if (invoke.getStackKind() != JavaKind.Void) {
-                frameStateBuilder.push(invoke.getStackKind(), invoke);
-            }
-            invoke.setStateAfter(frameStateBuilder.create(bci, invoke));
-            if (invoke.getStackKind() != JavaKind.Void) {
-                frameStateBuilder.pop(invoke.getStackKind());
-            }
-        }
-        return invoke;
+        InvokeWithExceptionNode result = startInvokeWithException(method, invokeKind, frameStateBuilder, invokeBci, exceptionEdgeBci, args);
+        exceptionPart();
+        ExceptionObjectNode exception = exceptionObject();
+        append(new UnwindNode(exception));
+        endInvokeWithException();
+        return result;
     }
 
     protected MethodCallTargetNode createMethodCallTarget(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args, StampPair returnStamp, @SuppressWarnings("unused") int bci) {
@@ -311,6 +328,9 @@
         GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault(plugins);
 
         StructuredGraph calleeGraph = new StructuredGraph.Builder(invoke.getOptions(), invoke.getDebug()).method(method).build();
+        if (invoke.graph().trackNodeSourcePosition()) {
+            calleeGraph.setTrackNodeSourcePosition();
+        }
         IntrinsicContext initialReplacementContext = new IntrinsicContext(method, method, providers.getReplacements().getDefaultReplacementBytecodeProvider(), INLINE_AFTER_PARSING);
         GraphBuilderPhase.Instance instance = new GraphBuilderPhase.Instance(metaAccess, providers.getStampProvider(), providers.getConstantReflection(), providers.getConstantFieldProvider(), config,
                         OptimisticOptimizations.NONE,
@@ -357,11 +377,12 @@
      *
      * @param condition The condition for the if-block
      * @param trueProbability The estimated probability the condition is true
+     * @return the created {@link IfNode}.
      */
-    public void startIf(LogicNode condition, double trueProbability) {
+    public IfNode startIf(LogicNode condition, double trueProbability) {
         AbstractBeginNode thenSuccessor = graph.add(new BeginNode());
         AbstractBeginNode elseSuccessor = graph.add(new BeginNode());
-        append(new IfNode(condition, thenSuccessor, elseSuccessor, trueProbability));
+        IfNode node = append(new IfNode(condition, thenSuccessor, elseSuccessor, trueProbability));
         lastFixedNode = null;
 
         IfStructure s = new IfStructure();
@@ -369,6 +390,7 @@
         s.thenPart = thenSuccessor;
         s.elsePart = elseSuccessor;
         pushStructure(s);
+        return node;
     }
 
     private IfStructure saveLastIfNode() {
@@ -403,11 +425,18 @@
         s.state = IfState.ELSE_PART;
     }
 
-    public void endIf() {
+    /**
+     * Ends an if block started with {@link #startIf(LogicNode, double)}.
+     *
+     * @return the created merge node, or {@code null} if no merge node was required (for example,
+     *         when one part ended with a control sink).
+     */
+    public AbstractMergeNode endIf() {
         IfStructure s = saveLastIfNode();
 
         FixedWithNextNode thenPart = s.thenPart instanceof FixedWithNextNode ? (FixedWithNextNode) s.thenPart : null;
         FixedWithNextNode elsePart = s.elsePart instanceof FixedWithNextNode ? (FixedWithNextNode) s.elsePart : null;
+        AbstractMergeNode merge = null;
 
         if (thenPart != null && elsePart != null) {
             /* Both parts are alive, we need a real merge. */
@@ -416,7 +445,7 @@
             EndNode elseEnd = graph.add(new EndNode());
             graph.addAfterFixed(elsePart, elseEnd);
 
-            AbstractMergeNode merge = graph.add(new MergeNode());
+            merge = graph.add(new MergeNode());
             merge.addForwardEnd(thenEnd);
             merge.addForwardEnd(elseEnd);
 
@@ -436,6 +465,7 @@
         }
         s.state = IfState.FINISHED;
         popStructure();
+        return merge;
     }
 
     static class InvokeWithExceptionStructure extends Structure {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/InlineDuringParsingPlugin.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/InlineDuringParsingPlugin.java	Fri Mar 16 22:59:32 2018 -0700
@@ -26,6 +26,7 @@
 import static org.graalvm.compiler.java.BytecodeParserOptions.InlineDuringParsingMaxDepth;
 import static org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin.InlineInfo.createStandardInlineInfo;
 
+import org.graalvm.compiler.java.BytecodeParserOptions;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
@@ -35,6 +36,15 @@
 
 public final class InlineDuringParsingPlugin implements InlineInvokePlugin {
 
+    /**
+     * 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 MaxDepthAfterBudgetExceeded = Integer.getInteger("InlineDuringParsingPlugin.MaxDepthAfterBudgetExceeded", 3);
+
     @Override
     public InlineInfo shouldInlineInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) {
         // @formatter:off
@@ -49,7 +59,7 @@
 
             if (!method.isSynchronized() &&
                 checkSize(method, args, b.getGraph()) &&
-                b.getDepth() < InlineDuringParsingMaxDepth.getValue(b.getOptions())) {
+                checkInliningDepth(b)) {
                 return createStandardInlineInfo(method);
             }
         }
@@ -57,6 +67,15 @@
         return null;
     }
 
+    private static boolean checkInliningDepth(GraphBuilderContext b) {
+        int nodeCount = b.getGraph().getNodeCount();
+        int maxDepth = InlineDuringParsingMaxDepth.getValue(b.getOptions());
+        if (nodeCount > NodeBudget && MaxDepthAfterBudgetExceeded < maxDepth) {
+            maxDepth = MaxDepthAfterBudgetExceeded;
+        }
+        return b.getDepth() < maxDepth;
+    }
+
     private static boolean checkSize(ResolvedJavaMethod method, ValueNode[] args, StructuredGraph graph) {
         int bonus = 1;
         for (ValueNode v : args) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/InstanceOfSnippetsTemplates.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/InstanceOfSnippetsTemplates.java	Fri Mar 16 22:59:32 2018 -0700
@@ -96,7 +96,7 @@
                 replacer.replaceUsingInstantiation();
             } else {
                 Arguments args = makeArguments(replacer, tool);
-                template(instanceOf.getDebug(), args).instantiate(providers.getMetaAccess(), instanceOf, replacer, tool, args);
+                template(instanceOf, args).instantiate(providers.getMetaAccess(), instanceOf, replacer, tool, args);
             }
         }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/IntrinsicGraphBuilder.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/IntrinsicGraphBuilder.java	Fri Mar 16 22:59:32 2018 -0700
@@ -31,6 +31,8 @@
 import org.graalvm.compiler.core.common.type.TypeReference;
 import org.graalvm.compiler.debug.DebugContext;
 import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.debug.DebugCloseable;
+import org.graalvm.compiler.graph.NodeSourcePosition;
 import org.graalvm.compiler.nodes.CallTargetNode;
 import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind;
 import org.graalvm.compiler.nodes.FixedNode;
@@ -91,6 +93,7 @@
         this.code = code;
         this.method = code.getMethod();
         this.graph = new StructuredGraph.Builder(options, debug, allowAssumptions).method(method).build();
+        this.graph.setTrackNodeSourcePosition();
         this.invokeBci = invokeBci;
         this.lastInstr = graph.start();
 
@@ -255,14 +258,18 @@
         return arguments[0];
     }
 
+    @SuppressWarnings("try")
     public StructuredGraph buildGraph(InvocationPlugin plugin) {
-        Receiver receiver = method.isStatic() ? null : this;
-        if (plugin.execute(this, method, receiver, arguments)) {
-            assert (returnValue != null) == (method.getSignature().getReturnKind() != JavaKind.Void) : method;
-            append(new ReturnNode(returnValue));
-            return graph;
+        NodeSourcePosition position = graph.trackNodeSourcePosition() ? NodeSourcePosition.placeholder(method) : null;
+        try (DebugCloseable context = graph.withNodeSourcePosition(position)) {
+            Receiver receiver = method.isStatic() ? null : this;
+            if (plugin.execute(this, method, receiver, arguments)) {
+                assert (returnValue != null) == (method.getSignature().getReturnKind() != JavaKind.Void) : method;
+                append(new ReturnNode(returnValue));
+                return graph;
+            }
+            return null;
         }
-        return null;
     }
 
     @Override
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.java	Fri Mar 16 22:59:32 2018 -0700
@@ -48,6 +48,8 @@
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.graph.NodeSourcePosition;
+import org.graalvm.compiler.graph.SourceLanguagePosition;
+import org.graalvm.compiler.graph.SourceLanguagePositionProvider;
 import org.graalvm.compiler.graph.spi.Canonicalizable;
 import org.graalvm.compiler.java.GraphBuilderPhase;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
@@ -108,6 +110,7 @@
 import jdk.vm.ci.code.Architecture;
 import jdk.vm.ci.code.BailoutException;
 import jdk.vm.ci.code.BytecodeFrame;
+import jdk.vm.ci.meta.Assumptions;
 import jdk.vm.ci.meta.ConstantReflectionProvider;
 import jdk.vm.ci.meta.DeoptimizationAction;
 import jdk.vm.ci.meta.DeoptimizationReason;
@@ -142,7 +145,7 @@
         @Option(help = "Max number of loop explosions per method.", type = OptionType.Debug)//
         public static final OptionKey<Integer> MaximumLoopExplosionCount = new OptionKey<>(10000);
 
-        @Option(help = "Do not bail out but throw an exception on failed loop explosion.", type = OptionType.Debug) //
+        @Option(help = "Do not bail out but throw an exception on failed loop explosion.", type = OptionType.Debug)//
         public static final OptionKey<Boolean> FailedLoopExplosionIsFatal = new OptionKey<>(false);
     }
 
@@ -154,6 +157,7 @@
         protected final int inliningDepth;
 
         protected final ValueNode[] arguments;
+        private final SourceLanguagePosition sourceLanguagePosition;
 
         protected FrameState outerState;
         protected FrameState exceptionState;
@@ -169,6 +173,13 @@
             this.invokeData = invokeData;
             this.inliningDepth = inliningDepth;
             this.arguments = arguments;
+            SourceLanguagePosition position = null;
+            if (arguments != null && method.hasReceiver() && arguments.length > 0 && arguments[0].isJavaConstant()) {
+                JavaConstant constantArgument = arguments[0].asJavaConstant();
+                position = sourceLanguagePositionProvider.getPosition(constantArgument);
+            }
+            this.sourceLanguagePosition = position;
+
         }
 
         @Override
@@ -176,15 +187,24 @@
             return caller != null;
         }
 
-        public NodeSourcePosition getCallerBytecodePosition() {
+        @Override
+        public NodeSourcePosition getCallerBytecodePosition(NodeSourcePosition position) {
             if (caller == null) {
-                return null;
+                return position;
             }
             if (callerBytecodePosition == null) {
-                JavaConstant constantReceiver = caller.invokeData == null ? null : caller.invokeData.constantReceiver;
-                NodeSourcePosition callerPosition = caller.getCallerBytecodePosition();
                 NodeSourcePosition invokePosition = invokeData.invoke.asNode().getNodeSourcePosition();
-                callerBytecodePosition = invokePosition != null ? invokePosition.addCaller(constantReceiver, callerPosition) : callerPosition;
+                if (invokePosition == null) {
+                    assert position == null : "should only happen when tracking is disabled";
+                    return null;
+                }
+                callerBytecodePosition = invokePosition;
+            }
+            if (position != null) {
+                return position.addCaller(caller.sourceLanguagePosition, callerBytecodePosition);
+            }
+            if (caller.sourceLanguagePosition != null && callerBytecodePosition != null) {
+                return new NodeSourcePosition(caller.sourceLanguagePosition, callerBytecodePosition.getCaller(), callerBytecodePosition.getMethod(), callerBytecodePosition.getBCI());
             }
             return callerBytecodePosition;
         }
@@ -361,8 +381,11 @@
         }
 
         private DebugCloseable withNodeSoucePosition() {
-            if (getGraph().mayHaveNodeSourcePosition()) {
-                return getGraph().withNodeSourcePosition(methodScope.getCallerBytecodePosition());
+            if (getGraph().trackNodeSourcePosition()) {
+                NodeSourcePosition callerBytecodePosition = methodScope.getCallerBytecodePosition();
+                if (callerBytecodePosition != null) {
+                    return getGraph().withNodeSourcePosition(callerBytecodePosition);
+                }
             }
             return null;
         }
@@ -440,11 +463,12 @@
     private final EconomicMap<SpecialCallTargetCacheKey, Object> specialCallTargetCache;
     private final EconomicMap<ResolvedJavaMethod, Object> invocationPluginCache;
     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,
                     ParameterPlugin parameterPlugin,
-                    NodePlugin[] nodePlugins, ResolvedJavaMethod callInlinedMethod) {
+                    NodePlugin[] nodePlugins, ResolvedJavaMethod callInlinedMethod, SourceLanguagePositionProvider sourceLanguagePositionProvider) {
         super(architecture, graph, metaAccess, constantReflection, constantFieldProvider, stampProvider, true);
         this.loopExplosionPlugin = loopExplosionPlugin;
         this.invocationPlugins = invocationPlugins;
@@ -454,6 +478,7 @@
         this.specialCallTargetCache = EconomicMap.create(Equivalence.DEFAULT);
         this.invocationPluginCache = EconomicMap.create(Equivalence.DEFAULT);
         this.callInlinedMethod = callInlinedMethod;
+        this.sourceLanguagePositionProvider = sourceLanguagePositionProvider;
     }
 
     protected static LoopExplosionKind loopExplosionKind(ResolvedJavaMethod method, LoopExplosionPlugin loopExplosionPlugin) {
@@ -464,8 +489,8 @@
         }
     }
 
-    public void decode(ResolvedJavaMethod method) {
-        PEMethodScope methodScope = new PEMethodScope(graph, null, null, lookupEncodedGraph(method, null), method, null, 0, loopExplosionPlugin, null);
+    public void decode(ResolvedJavaMethod method, boolean trackNodeSourcePosition) {
+        PEMethodScope methodScope = new PEMethodScope(graph, null, null, lookupEncodedGraph(method, null, null, trackNodeSourcePosition), method, null, 0, loopExplosionPlugin, null);
         decode(createInitialLoopScope(methodScope, null));
         cleanupGraph(methodScope);
 
@@ -533,6 +558,12 @@
             MethodCallTargetNode methodCall = (MethodCallTargetNode) callTarget;
             if (methodCall.invokeKind().hasReceiver()) {
                 invokeData.constantReceiver = methodCall.arguments().get(0).asJavaConstant();
+                NodeSourcePosition invokePosition = invokeData.invoke.asNode().getNodeSourcePosition();
+                if (invokeData.constantReceiver != null && invokePosition != null) {
+                    // new NodeSourcePosition(invokeData.constantReceiver,
+                    // invokePosition.getCaller(), invokePosition.getMethod(),
+                    // invokePosition.getBCI());
+                }
             }
             LoopScope inlineLoopScope = trySimplifyInvoke(methodScope, loopScope, invokeData, (MethodCallTargetNode) callTarget);
             if (inlineLoopScope != null) {
@@ -687,11 +718,12 @@
 
     protected LoopScope doInline(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData, InlineInfo inlineInfo, ValueNode[] arguments) {
         ResolvedJavaMethod inlineMethod = inlineInfo.getMethodToInline();
-        EncodedGraph graphToInline = lookupEncodedGraph(inlineMethod, inlineInfo.getIntrinsicBytecodeProvider());
+        EncodedGraph graphToInline = lookupEncodedGraph(inlineMethod, inlineInfo.getOriginalMethod(), inlineInfo.getIntrinsicBytecodeProvider(), graph.trackNodeSourcePosition());
         if (graphToInline == null) {
             return null;
         }
 
+        assert !graph.trackNodeSourcePosition() || graphToInline.trackNodeSourcePosition() : graph + " " + graphToInline;
         if (methodScope.inliningDepth > Options.InliningDepthError.getValue(options)) {
             throw tooDeepInlining(methodScope);
         }
@@ -740,6 +772,32 @@
             inlineLoopScope.createdNodes[firstArgumentNodeId + i] = arguments[i];
         }
 
+        // Copy assumptions from inlinee to caller
+        Assumptions assumptions = graph.getAssumptions();
+        Assumptions inlinedAssumptions = graphToInline.getAssumptions();
+        if (assumptions != null) {
+            if (inlinedAssumptions != null) {
+                assumptions.record(inlinedAssumptions);
+            }
+        } else {
+            assert inlinedAssumptions == null : String.format("cannot inline graph (%s) which makes assumptions into a graph (%s) that doesn't", inlineMethod, graph);
+        }
+
+        // Copy inlined methods from inlinee to caller
+        List<ResolvedJavaMethod> inlinedMethods = graphToInline.getInlinedMethods();
+        if (inlinedMethods != null) {
+            graph.getMethods().addAll(inlinedMethods);
+        }
+
+        if (graphToInline.getFields() != null) {
+            for (ResolvedJavaField field : graphToInline.getFields()) {
+                graph.recordField(field);
+            }
+        }
+        if (graphToInline.hasUnsafeAccess()) {
+            graph.markUnsafeAccess();
+        }
+
         /*
          * Do the actual inlining by returning the initial loop scope for the inlined method scope.
          */
@@ -927,7 +985,7 @@
         }
     }
 
-    protected abstract EncodedGraph lookupEncodedGraph(ResolvedJavaMethod method, BytecodeProvider intrinsicBytecodeProvider);
+    protected abstract EncodedGraph lookupEncodedGraph(ResolvedJavaMethod method, ResolvedJavaMethod originalMethod, BytecodeProvider intrinsicBytecodeProvider, boolean trackNodeSourcePosition);
 
     @Override
     protected void handleFixedNode(MethodScope s, LoopScope loopScope, int nodeOrderId, FixedNode node) {
@@ -1124,20 +1182,6 @@
     }
 
     @Override
-    protected Node addFloatingNode(MethodScope s, Node node) {
-        Node addedNode = super.addFloatingNode(s, node);
-        PEMethodScope methodScope = (PEMethodScope) s;
-        NodeSourcePosition pos = node.getNodeSourcePosition();
-        if (methodScope.isInlinedMethod()) {
-            if (pos != null) {
-                NodeSourcePosition bytecodePosition = methodScope.getCallerBytecodePosition();
-                node.setNodeSourcePosition(pos.addCaller(bytecodePosition));
-            }
-        }
-        return addedNode;
-    }
-
-    @Override
     protected Node handleFloatingNodeAfterAdd(MethodScope s, LoopScope loopScope, Node node) {
         PEMethodScope methodScope = (PEMethodScope) s;
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ReplacementsImpl.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ReplacementsImpl.java	Fri Mar 16 22:59:32 2018 -0700
@@ -55,6 +55,7 @@
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.debug.TimerKey;
 import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeSourcePosition;
 import org.graalvm.compiler.graph.Node.NodeIntrinsic;
 import org.graalvm.compiler.java.GraphBuilderPhase;
 import org.graalvm.compiler.java.GraphBuilderPhase.Instance;
@@ -148,7 +149,7 @@
         if (subst != null) {
             if (b.parsingIntrinsic() || InlineDuringParsing.getValue(b.getOptions()) || InlineIntrinsicsDuringParsing.getValue(b.getOptions())) {
                 // Forced inlining of intrinsics
-                return createIntrinsicInlineInfo(subst.getMethod(), subst.getOrigin());
+                return createIntrinsicInlineInfo(subst.getMethod(), method, subst.getOrigin());
             }
             return null;
         }
@@ -156,7 +157,7 @@
             assert b.getDepth() < MAX_GRAPH_INLINING_DEPTH : "inlining limit exceeded";
 
             // Force inlining when parsing replacements
-            return createIntrinsicInlineInfo(method, defaultBytecodeProvider);
+            return createIntrinsicInlineInfo(method, null, defaultBytecodeProvider);
         } else {
             assert method.getAnnotation(NodeIntrinsic.class) == null : String.format("@%s method %s must only be called from within a replacement%n%s", NodeIntrinsic.class.getSimpleName(),
                             method.format("%h.%n"), b);
@@ -202,8 +203,8 @@
     private static final TimerKey SnippetPreparationTime = DebugContext.timer("SnippetPreparationTime");
 
     @Override
-    public StructuredGraph getSnippet(ResolvedJavaMethod method, Object[] args) {
-        return getSnippet(method, null, args);
+    public StructuredGraph getSnippet(ResolvedJavaMethod method, Object[] args, boolean trackNodeSourcePosition, NodeSourcePosition replaceePosition) {
+        return getSnippet(method, null, args, trackNodeSourcePosition, replaceePosition);
     }
 
     private static final AtomicInteger nextDebugContextId = new AtomicInteger();
@@ -217,29 +218,34 @@
 
     @Override
     @SuppressWarnings("try")
-    public StructuredGraph getSnippet(ResolvedJavaMethod method, ResolvedJavaMethod recursiveEntry, Object[] args) {
+    public StructuredGraph getSnippet(ResolvedJavaMethod method, ResolvedJavaMethod recursiveEntry, Object[] args, boolean trackNodeSourcePosition, NodeSourcePosition replaceePosition) {
         assert method.getAnnotation(Snippet.class) != null : "Snippet must be annotated with @" + Snippet.class.getSimpleName();
         assert method.hasBytecodes() : "Snippet must not be abstract or native";
 
         StructuredGraph graph = UseSnippetGraphCache.getValue(options) ? graphs.get(method) : null;
-        if (graph == null) {
+        if (graph == null || (trackNodeSourcePosition && !graph.trackNodeSourcePosition())) {
             try (DebugContext debug = openDebugContext("Snippet_", method);
                             DebugCloseable a = SnippetPreparationTime.start(debug)) {
-                StructuredGraph newGraph = makeGraph(debug, defaultBytecodeProvider, method, args, recursiveEntry);
+                StructuredGraph newGraph = makeGraph(debug, defaultBytecodeProvider, method, args, recursiveEntry, trackNodeSourcePosition, replaceePosition);
                 DebugContext.counter("SnippetNodeCount[%#s]", method).add(newGraph.getDebug(), newGraph.getNodeCount());
                 if (!UseSnippetGraphCache.getValue(options) || args != null) {
                     return newGraph;
                 }
                 newGraph.freeze();
-                graphs.putIfAbsent(method, newGraph);
+                if (graph != null) {
+                    graphs.replace(method, graph, newGraph);
+                } else {
+                    graphs.putIfAbsent(method, newGraph);
+                }
                 graph = graphs.get(method);
             }
         }
+        assert !trackNodeSourcePosition || graph.trackNodeSourcePosition();
         return graph;
     }
 
     @Override
-    public void registerSnippet(ResolvedJavaMethod method) {
+    public void registerSnippet(ResolvedJavaMethod method, boolean trackNodeSourcePosition) {
         // No initialization needed as snippet graphs are created on demand in getSnippet
     }
 
@@ -266,7 +272,7 @@
     }
 
     @Override
-    public StructuredGraph getSubstitution(ResolvedJavaMethod method, int invokeBci) {
+    public StructuredGraph getSubstitution(ResolvedJavaMethod method, int invokeBci, boolean trackNodeSourcePosition, NodeSourcePosition replaceePosition) {
         StructuredGraph result;
         InvocationPlugin plugin = graphBuilderPlugins.getInvocationPlugins().lookupInvocation(method);
         if (plugin != null && (!plugin.inlineOnly() || invokeBci >= 0)) {
@@ -275,9 +281,9 @@
                 MethodSubstitutionPlugin msPlugin = (MethodSubstitutionPlugin) plugin;
                 ResolvedJavaMethod substitute = msPlugin.getSubstitute(metaAccess);
                 StructuredGraph graph = UseSnippetGraphCache.getValue(options) ? graphs.get(substitute) : null;
-                if (graph == null) {
+                if (graph == null || graph.trackNodeSourcePosition() != trackNodeSourcePosition) {
                     try (DebugContext debug = openDebugContext("Substitution_", method)) {
-                        graph = makeGraph(debug, msPlugin.getBytecodeProvider(), substitute, null, method);
+                        graph = makeGraph(debug, msPlugin.getBytecodeProvider(), substitute, null, method, trackNodeSourcePosition, replaceePosition);
                         if (!UseSnippetGraphCache.getValue(options)) {
                             return graph;
                         }
@@ -311,9 +317,11 @@
      * @param args
      * @param original the original method if {@code method} is a {@linkplain MethodSubstitution
      *            substitution} otherwise null
+     * @param trackNodeSourcePosition
      */
-    public StructuredGraph makeGraph(DebugContext debug, BytecodeProvider bytecodeProvider, ResolvedJavaMethod method, Object[] args, ResolvedJavaMethod original) {
-        return createGraphMaker(method, original).makeGraph(debug, bytecodeProvider, args);
+    public StructuredGraph makeGraph(DebugContext debug, BytecodeProvider bytecodeProvider, ResolvedJavaMethod method, Object[] args, ResolvedJavaMethod original, boolean trackNodeSourcePosition,
+                    NodeSourcePosition replaceePosition) {
+        return createGraphMaker(method, original).makeGraph(debug, bytecodeProvider, args, trackNodeSourcePosition, replaceePosition);
     }
 
     /**
@@ -350,10 +358,10 @@
         }
 
         @SuppressWarnings("try")
-        public StructuredGraph makeGraph(DebugContext debug, BytecodeProvider bytecodeProvider, Object[] args) {
+        public StructuredGraph makeGraph(DebugContext debug, BytecodeProvider bytecodeProvider, Object[] args, boolean trackNodeSourcePosition, NodeSourcePosition replaceePosition) {
             try (DebugContext.Scope s = debug.scope("BuildSnippetGraph", method)) {
                 assert method.hasBytecodes() : method;
-                StructuredGraph graph = buildInitialGraph(debug, bytecodeProvider, method, args);
+                StructuredGraph graph = buildInitialGraph(debug, bytecodeProvider, method, args, trackNodeSourcePosition, replaceePosition);
 
                 finalizeGraph(graph);
 
@@ -417,10 +425,12 @@
          * Builds the initial graph for a replacement.
          */
         @SuppressWarnings("try")
-        protected StructuredGraph buildInitialGraph(DebugContext debug, BytecodeProvider bytecodeProvider, final ResolvedJavaMethod methodToParse, Object[] args) {
+        protected StructuredGraph buildInitialGraph(DebugContext debug, BytecodeProvider bytecodeProvider, final ResolvedJavaMethod methodToParse, Object[] args, boolean trackNodeSourcePosition,
+                        NodeSourcePosition replaceePosition) {
             // Replacements cannot have optimistic assumptions since they have
             // to be valid for the entire run of the VM.
-            final StructuredGraph graph = new StructuredGraph.Builder(replacements.options, debug).method(methodToParse).build();
+            final StructuredGraph graph = new StructuredGraph.Builder(replacements.options, debug).method(methodToParse).trackNodeSourcePosition(trackNodeSourcePosition).callerContext(
+                            replaceePosition).build();
 
             // Replacements are not user code so they do not participate in unsafe access
             // tracking
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetCounterNode.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetCounterNode.java	Fri Mar 16 22:59:32 2018 -0700
@@ -156,7 +156,7 @@
                 args.addConst("counter", counter.getCounter());
                 args.add("increment", counter.getIncrement());
 
-                template(counter.getDebug(), args).instantiate(providers.getMetaAccess(), counter, DEFAULT_REPLACER, args);
+                template(counter, args).instantiate(providers.getMetaAccess(), counter, DEFAULT_REPLACER, args);
             }
         }
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetTemplate.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetTemplate.java	Fri Mar 16 22:59:32 2018 -0700
@@ -47,27 +47,15 @@
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.function.Predicate;
 
-import jdk.vm.ci.code.TargetDescription;
-import jdk.vm.ci.meta.Constant;
-import jdk.vm.ci.meta.JavaConstant;
-import jdk.vm.ci.meta.JavaKind;
-import jdk.vm.ci.meta.Local;
-import jdk.vm.ci.meta.LocalVariableTable;
-import jdk.vm.ci.meta.MetaAccessProvider;
-import jdk.vm.ci.meta.ResolvedJavaMethod;
-import jdk.vm.ci.meta.ResolvedJavaType;
-import jdk.vm.ci.meta.Signature;
-import jdk.vm.ci.meta.ResolvedJavaMethod.Parameter;
-
 import org.graalvm.collections.EconomicMap;
 import org.graalvm.collections.EconomicSet;
 import org.graalvm.collections.Equivalence;
 import org.graalvm.collections.UnmodifiableEconomicMap;
 import org.graalvm.compiler.api.replacements.Snippet;
-import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
 import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter;
 import org.graalvm.compiler.api.replacements.Snippet.NonNullParameter;
 import org.graalvm.compiler.api.replacements.Snippet.VarargsParameter;
+import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
 import org.graalvm.compiler.core.common.GraalOptions;
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.core.common.type.StampFactory;
@@ -76,14 +64,15 @@
 import org.graalvm.compiler.debug.CounterKey;
 import org.graalvm.compiler.debug.DebugCloseable;
 import org.graalvm.compiler.debug.DebugContext;
+import org.graalvm.compiler.debug.DebugContext.Description;
 import org.graalvm.compiler.debug.DebugHandlersFactory;
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.debug.TimerKey;
-import org.graalvm.compiler.debug.DebugContext.Description;
+import org.graalvm.compiler.graph.Graph.Mark;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.NodeSourcePosition;
 import org.graalvm.compiler.graph.Position;
-import org.graalvm.compiler.graph.Graph.Mark;
 import org.graalvm.compiler.loop.LoopEx;
 import org.graalvm.compiler.loop.LoopsData;
 import org.graalvm.compiler.loop.phases.LoopTransformations;
@@ -97,20 +86,21 @@
 import org.graalvm.compiler.nodes.FixedNode;
 import org.graalvm.compiler.nodes.FixedWithNextNode;
 import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.InliningLog;
 import org.graalvm.compiler.nodes.LoopBeginNode;
 import org.graalvm.compiler.nodes.MergeNode;
 import org.graalvm.compiler.nodes.NodeView;
 import org.graalvm.compiler.nodes.ParameterNode;
 import org.graalvm.compiler.nodes.PhiNode;
+import org.graalvm.compiler.nodes.PiNode.Placeholder;
+import org.graalvm.compiler.nodes.PiNode.PlaceholderStamp;
 import org.graalvm.compiler.nodes.ReturnNode;
 import org.graalvm.compiler.nodes.StartNode;
 import org.graalvm.compiler.nodes.StateSplit;
 import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.GuardsStage;
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.ValueNodeUtil;
-import org.graalvm.compiler.nodes.PiNode.Placeholder;
-import org.graalvm.compiler.nodes.PiNode.PlaceholderStamp;
-import org.graalvm.compiler.nodes.StructuredGraph.GuardsStage;
 import org.graalvm.compiler.nodes.calc.FloatingNode;
 import org.graalvm.compiler.nodes.java.LoadIndexedNode;
 import org.graalvm.compiler.nodes.java.StoreIndexedNode;
@@ -131,10 +121,10 @@
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
 import org.graalvm.compiler.phases.common.FloatingReadPhase;
+import org.graalvm.compiler.phases.common.FloatingReadPhase.MemoryMapImpl;
 import org.graalvm.compiler.phases.common.GuardLoweringPhase;
 import org.graalvm.compiler.phases.common.LoweringPhase;
 import org.graalvm.compiler.phases.common.RemoveValueProxyPhase;
-import org.graalvm.compiler.phases.common.FloatingReadPhase.MemoryMapImpl;
 import org.graalvm.compiler.phases.common.inlining.InliningUtil;
 import org.graalvm.compiler.phases.tiers.PhaseContext;
 import org.graalvm.compiler.phases.util.Providers;
@@ -144,6 +134,18 @@
 import org.graalvm.word.LocationIdentity;
 import org.graalvm.word.WordBase;
 
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.Local;
+import jdk.vm.ci.meta.LocalVariableTable;
+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;
+import jdk.vm.ci.meta.Signature;
+
 /**
  * A snippet template is a graph created by parsing a snippet method and then specialized by binding
  * constants to the snippet's {@link ConstantParameter} parameters.
@@ -565,7 +567,7 @@
 
     static class Options {
         @Option(help = "Use a LRU cache for snippet templates.")//
-        static final OptionKey<Boolean> UseSnippetTemplateCache = new OptionKey<>(true);
+        public static final OptionKey<Boolean> UseSnippetTemplateCache = new OptionKey<>(true);
 
         @Option(help = "")//
         static final OptionKey<Integer> MaxTemplatesPerSnippet = new OptionKey<>(50);
@@ -618,7 +620,7 @@
             assert method.getAnnotation(Snippet.class) != null : method + " must be annotated with @" + Snippet.class.getSimpleName();
             assert findMethod(declaringClass, methodName, method) == null : "found more than one method named " + methodName + " in " + declaringClass;
             ResolvedJavaMethod javaMethod = providers.getMetaAccess().lookupJavaMethod(method);
-            providers.getReplacements().registerSnippet(javaMethod);
+            providers.getReplacements().registerSnippet(javaMethod, GraalOptions.TrackNodeSourcePosition.getValue(options));
             LocationIdentity[] privateLocations = GraalOptions.SnippetCounters.getValue(options) ? SnippetCounterNode.addSnippetCounters(initialPrivateLocations) : initialPrivateLocations;
             if (GraalOptions.EagerSnippets.getValue(options)) {
                 return new EagerSnippetInfo(javaMethod, privateLocations);
@@ -641,13 +643,15 @@
          * Gets a template for a given key, creating it first if necessary.
          */
         @SuppressWarnings("try")
-        protected SnippetTemplate template(DebugContext outer, final Arguments args) {
+        protected SnippetTemplate template(ValueNode replacee, final Arguments args) {
+            StructuredGraph graph = replacee.graph();
+            DebugContext outer = graph.getDebug();
             SnippetTemplate template = Options.UseSnippetTemplateCache.getValue(options) && args.cacheable ? templates.get(args.cacheKey) : null;
-            if (template == null) {
+            if (template == null || (graph.trackNodeSourcePosition() && !template.snippet.trackNodeSourcePosition())) {
                 try (DebugContext debug = openDebugContext(outer, args)) {
                     try (DebugCloseable a = SnippetTemplateCreationTime.start(debug); DebugContext.Scope s = debug.scope("SnippetSpecialization", args.info.method)) {
                         SnippetTemplates.increment(debug);
-                        template = new SnippetTemplate(options, debug, providers, snippetReflection, args);
+                        template = new SnippetTemplate(options, debug, providers, snippetReflection, args, graph.trackNodeSourcePosition(), replacee);
                         if (Options.UseSnippetTemplateCache.getValue(options) && args.cacheable) {
                             templates.put(args.cacheKey, template);
                         }
@@ -697,12 +701,13 @@
      * Creates a snippet template.
      */
     @SuppressWarnings("try")
-    protected SnippetTemplate(OptionValues options, DebugContext debug, final Providers providers, SnippetReflectionProvider snippetReflection, Arguments args) {
+    protected SnippetTemplate(OptionValues options, DebugContext debug, final Providers providers, SnippetReflectionProvider snippetReflection, Arguments args, boolean trackNodeSourcePosition,
+                    Node replacee) {
         this.snippetReflection = snippetReflection;
         this.info = args.info;
 
         Object[] constantArgs = getConstantArgs(args);
-        StructuredGraph snippetGraph = providers.getReplacements().getSnippet(args.info.method, args.info.original, constantArgs);
+        StructuredGraph snippetGraph = providers.getReplacements().getSnippet(args.info.method, args.info.original, constantArgs, trackNodeSourcePosition, replacee.getNodeSourcePosition());
 
         ResolvedJavaMethod method = snippetGraph.method();
         Signature signature = method.getSignature();
@@ -710,8 +715,12 @@
         PhaseContext phaseContext = new PhaseContext(providers);
 
         // Copy snippet graph, replacing constant parameters with given arguments
-        final StructuredGraph snippetCopy = new StructuredGraph.Builder(options, debug).name(snippetGraph.name).method(snippetGraph.method()).build();
-
+        final StructuredGraph snippetCopy = new StructuredGraph.Builder(options, debug).name(snippetGraph.name).method(snippetGraph.method()).trackNodeSourcePosition(
+                        snippetGraph.trackNodeSourcePosition()).build();
+        assert !GraalOptions.TrackNodeSourcePosition.getValue(options) || snippetCopy.trackNodeSourcePosition();
+        if (providers.getCodeCache() != null && providers.getCodeCache().shouldDebugNonSafepoints()) {
+            snippetCopy.setTrackNodeSourcePosition();
+        }
         try (DebugContext.Scope scope = debug.scope("SpecializeSnippet", snippetCopy)) {
             if (!snippetGraph.isUnsafeAccessTrackingEnabled()) {
                 snippetCopy.disableUnsafeAccessTracking();
@@ -755,7 +764,12 @@
                     }
                 }
             }
-            snippetCopy.addDuplicates(snippetGraph.getNodes(), snippetGraph, snippetGraph.getNodeCount(), nodeReplacements);
+            try (InliningLog.UpdateScope updateScope = snippetCopy.getInliningLog().openDefaultUpdateScope()) {
+                UnmodifiableEconomicMap<Node, Node> duplicates = snippetCopy.addDuplicates(snippetGraph.getNodes(), snippetGraph, snippetGraph.getNodeCount(), nodeReplacements);
+                if (updateScope != null) {
+                    snippetCopy.getInliningLog().replaceLog(duplicates, snippetGraph.getInliningLog());
+                }
+            }
 
             debug.dump(DebugContext.INFO_LEVEL, snippetCopy, "Before specialization");
 
@@ -1396,8 +1410,7 @@
             StructuredGraph replaceeGraph = replacee.graph();
             EconomicMap<Node, Node> replacements = bind(replaceeGraph, metaAccess, args);
             replacements.put(entryPointNode, AbstractBeginNode.prevBegin(replacee));
-            UnmodifiableEconomicMap<Node, Node> duplicates = replaceeGraph.addDuplicates(nodes, snippet, snippet.getNodeCount(), replacements);
-            debug.dump(DebugContext.DETAILED_LEVEL, replaceeGraph, "After inlining snippet %s", snippet.method());
+            UnmodifiableEconomicMap<Node, Node> duplicates = inlineSnippet(replacee, debug, replaceeGraph, replacements);
 
             // Re-wire the control flow graph around the replacee
             FixedNode firstCFGNodeDuplicate = (FixedNode) duplicates.get(firstCFGNode);
@@ -1490,6 +1503,27 @@
         }
     }
 
+    private UnmodifiableEconomicMap<Node, Node> inlineSnippet(Node replacee, DebugContext debug, StructuredGraph replaceeGraph, EconomicMap<Node, Node> replacements) {
+        Mark mark = replaceeGraph.getMark();
+        try (InliningLog.UpdateScope scope = replaceeGraph.getInliningLog().openUpdateScope((oldNode, newNode) -> {
+            InliningLog log = replaceeGraph.getInliningLog();
+            if (oldNode == null) {
+                log.trackNewCallsite(newNode);
+            }
+        })) {
+            UnmodifiableEconomicMap<Node, Node> duplicates = replaceeGraph.addDuplicates(nodes, snippet, snippet.getNodeCount(), replacements);
+            if (scope != null) {
+                replaceeGraph.getInliningLog().addLog(duplicates, snippet.getInliningLog());
+            }
+            NodeSourcePosition position = replacee.getNodeSourcePosition();
+            if (position != null) {
+                InliningUtil.updateSourcePosition(replaceeGraph, duplicates, mark, position, true);
+            }
+            debug.dump(DebugContext.DETAILED_LEVEL, replaceeGraph, "After inlining snippet %s", snippet.method());
+            return duplicates;
+        }
+    }
+
     private void propagateStamp(Node node) {
         if (node instanceof PhiNode) {
             PhiNode phi = (PhiNode) node;
@@ -1549,8 +1583,7 @@
             StructuredGraph replaceeGraph = replacee.graph();
             EconomicMap<Node, Node> replacements = bind(replaceeGraph, metaAccess, args);
             replacements.put(entryPointNode, tool.getCurrentGuardAnchor().asNode());
-            UnmodifiableEconomicMap<Node, Node> duplicates = replaceeGraph.addDuplicates(nodes, snippet, snippet.getNodeCount(), replacements);
-            debug.dump(DebugContext.DETAILED_LEVEL, replaceeGraph, "After inlining snippet %s", snippet.method());
+            UnmodifiableEconomicMap<Node, Node> duplicates = inlineSnippet(replacee, debug, replaceeGraph, replacements);
 
             FixedWithNextNode lastFixedNode = tool.lastFixedNode();
             assert lastFixedNode != null && lastFixedNode.isAlive() : replaceeGraph + " lastFixed=" + lastFixedNode;
@@ -1611,8 +1644,7 @@
                     floatingNodes.add(n);
                 }
             }
-            UnmodifiableEconomicMap<Node, Node> duplicates = replaceeGraph.addDuplicates(floatingNodes, snippet, floatingNodes.size(), replacements);
-            debug.dump(DebugContext.DETAILED_LEVEL, replaceeGraph, "After inlining snippet %s", snippet.method());
+            UnmodifiableEconomicMap<Node, Node> duplicates = inlineSnippet(replacee, debug, replaceeGraph, replacements);
 
             rewireFrameStates(replacee, duplicates);
             updateStamps(replacee, duplicates);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java	Fri Mar 16 22:59:32 2018 -0700
@@ -385,6 +385,23 @@
         if (allowDeoptimization) {
             for (JavaKind kind : new JavaKind[]{JavaKind.Int, JavaKind.Long}) {
                 Class<?> type = kind.toJavaClass();
+
+                r.register1("decrementExact", type, new InvocationPlugin() {
+                    @Override
+                    public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x) {
+                        b.addPush(kind, new IntegerSubExactNode(x, ConstantNode.forIntegerKind(kind, 1)));
+                        return true;
+                    }
+                });
+
+                r.register1("incrementExact", type, new InvocationPlugin() {
+                    @Override
+                    public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x) {
+                        b.addPush(kind, new IntegerAddExactNode(x, ConstantNode.forIntegerKind(kind, 1)));
+                        return true;
+                    }
+                });
+
                 r.register2("addExact", type, type, new InvocationPlugin() {
                     @Override
                     public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) {
@@ -392,6 +409,7 @@
                         return true;
                     }
                 });
+
                 r.register2("subtractExact", type, type, new InvocationPlugin() {
                     @Override
                     public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) {
@@ -399,6 +417,7 @@
                         return true;
                     }
                 });
+
                 r.register2("multiplyExact", type, type, new InvocationPlugin() {
                     @Override
                     public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StringSubstitutions.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StringSubstitutions.java	Fri Mar 16 22:59:32 2018 -0700
@@ -63,5 +63,5 @@
     /**
      * Will be intrinsified with an {@link InvocationPlugin} to a {@link LoadFieldNode}.
      */
-    private static native char[] getValue(String s);
+    public static native char[] getValue(String s);
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileBytecodeProvider.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileBytecodeProvider.java	Fri Mar 16 22:59:32 2018 -0700
@@ -101,8 +101,8 @@
     private static InputStream getClassfileAsStream(Class<?> c) {
         String classfilePath = c.getName().replace('.', '/') + ".class";
         if (JDK9Method.JAVA_SPECIFICATION_VERSION >= 9) {
-            Object module = getModule.invoke(c);
-            return getResourceAsStream.invoke(module, classfilePath);
+            Object module = getModule(c);
+            return getResourceAsStream(module, classfilePath);
         } else {
             ClassLoader cl = c.getClassLoader();
             if (cl == null) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ArrayCompareToNode.java	Fri Mar 16 22:59:32 2018 -0700
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.nodes;
+
+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.type.StampFactory;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.NamedLocationIdentity;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.ValueNodeUtil;
+import org.graalvm.compiler.nodes.memory.MemoryAccess;
+import org.graalvm.compiler.nodes.memory.MemoryNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.nodes.spi.Virtualizable;
+import org.graalvm.compiler.nodes.spi.VirtualizerTool;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+import org.graalvm.word.LocationIdentity;
+
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.Value;
+
+// JaCoCo Exclude
+
+/**
+ * Compares two arrays lexicographically.
+ */
+@NodeInfo(cycles = CYCLES_1024, size = SIZE_1024)
+public final class ArrayCompareToNode extends FixedWithNextNode implements LIRLowerable, Canonicalizable, Virtualizable, MemoryAccess {
+
+    public static final NodeClass<ArrayCompareToNode> TYPE = NodeClass.create(ArrayCompareToNode.class);
+
+    /** {@link JavaKind} of one array to compare. */
+    protected final JavaKind kind1;
+
+    /** {@link JavaKind} of the other array to compare. */
+    protected final JavaKind kind2;
+
+    /** One array to be tested for equality. */
+    @Input ValueNode array1;
+
+    /** The other array to be tested for equality. */
+    @Input ValueNode array2;
+
+    /** Length of one array. */
+    @Input ValueNode length1;
+
+    /** Length of the other array. */
+    @Input ValueNode length2;
+
+    @OptionalInput(Memory) MemoryNode lastLocationAccess;
+
+    public ArrayCompareToNode(ValueNode array1, ValueNode array2, ValueNode length1, ValueNode length2, @ConstantNodeParameter JavaKind kind1, @ConstantNodeParameter JavaKind kind2) {
+        super(TYPE, StampFactory.forKind(JavaKind.Int));
+        this.kind1 = kind1;
+        this.kind2 = kind2;
+        this.array1 = array1;
+        this.array2 = array2;
+        this.length1 = length1;
+        this.length2 = length2;
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        if (tool.allUsagesAvailable() && hasNoUsages()) {
+            return null;
+        }
+        ValueNode a1 = GraphUtil.unproxify(array1);
+        ValueNode a2 = GraphUtil.unproxify(array2);
+        if (a1 == a2) {
+            return ConstantNode.forInt(0);
+        }
+        return this;
+    }
+
+    @Override
+    public void virtualize(VirtualizerTool tool) {
+        ValueNode alias1 = tool.getAlias(array1);
+        ValueNode alias2 = tool.getAlias(array2);
+        if (alias1 == alias2) {
+            // the same virtual objects will always have the same contents
+            tool.replaceWithValue(ConstantNode.forInt(0, graph()));
+        }
+    }
+
+    @NodeIntrinsic
+    public static native int compareTo(Object array1, Object array2, int length1, int length2, @ConstantNodeParameter JavaKind kind1, @ConstantNodeParameter JavaKind kind2);
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        Value result = gen.getLIRGeneratorTool().emitArrayCompareTo(kind1, kind2, gen.operand(array1), gen.operand(array2), gen.operand(length1), gen.operand(length2));
+        gen.setResult(this, result);
+    }
+
+    @Override
+    public LocationIdentity getLocationIdentity() {
+        return NamedLocationIdentity.getArrayLocation(kind1);
+    }
+
+    @Override
+    public MemoryNode getLastLocationAccess() {
+        return lastLocationAccess;
+    }
+
+    @Override
+    public void setLastLocationAccess(MemoryNode lla) {
+        updateUsages(ValueNodeUtil.asNode(lastLocationAccess), ValueNodeUtil.asNode(lla));
+        lastLocationAccess = lla;
+    }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroNode.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroNode.java	Fri Mar 16 22:59:32 2018 -0700
@@ -29,12 +29,16 @@
 import org.graalvm.compiler.api.replacements.MethodSubstitution;
 import org.graalvm.compiler.api.replacements.Snippet;
 import org.graalvm.compiler.core.common.type.StampPair;
+import org.graalvm.compiler.debug.DebugCloseable;
 import org.graalvm.compiler.debug.DebugContext;
 import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.graph.NodeInputList;
 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.InvokeNode;
@@ -75,7 +79,7 @@
           size = SIZE_UNKNOWN,
           sizeRationale = "If this node is not optimized away it will be lowered to a call, which we cannot estimate")
 //@formatter:on
-public abstract class MacroNode extends FixedWithNextNode implements Lowerable {
+public abstract class MacroNode extends FixedWithNextNode implements Lowerable, Invokable {
 
     public static final NodeClass<MacroNode> TYPE = NodeClass.create(MacroNode.class);
     @Input protected NodeInputList<ValueNode> arguments;
@@ -108,10 +112,12 @@
         return arguments.toArray(new ValueNode[0]);
     }
 
-    public int getBci() {
+    @Override
+    public int bci() {
         return bci;
     }
 
+    @Override
     public ResolvedJavaMethod getTargetMethod() {
         return targetMethod;
     }
@@ -120,6 +126,16 @@
         return null;
     }
 
+    @Override
+    protected void afterClone(Node other) {
+        updateInliningLogAfterClone(other);
+    }
+
+    @Override
+    public FixedNode asFixedNode() {
+        return this;
+    }
+
     /**
      * Gets a snippet to be used for lowering this macro node. The returned graph (if non-null) must
      * have been {@linkplain #lowerReplacement(StructuredGraph, LoweringTool) lowered}.
@@ -196,10 +212,13 @@
         }
     }
 
+    @SuppressWarnings("try")
     public InvokeNode replaceWithInvoke() {
-        InvokeNode invoke = createInvoke();
-        graph().replaceFixedWithFixed(this, invoke);
-        return invoke;
+        try (DebugCloseable context = withNodeSourcePosition()) {
+            InvokeNode invoke = createInvoke();
+            graph().replaceFixedWithFixed(this, invoke);
+            return invoke;
+        }
     }
 
     protected InvokeNode createInvoke() {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroStateSplitNode.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroStateSplitNode.java	Fri Mar 16 22:59:32 2018 -0700
@@ -85,7 +85,7 @@
             }
             assert invoke.stateAfter().bci == BytecodeFrame.AFTER_BCI;
             // Here we need to fix the bci of the invoke
-            InvokeNode newInvoke = snippetGraph.add(new InvokeNode(invoke.callTarget(), getBci()));
+            InvokeNode newInvoke = snippetGraph.add(new InvokeNode(invoke.callTarget(), bci()));
             newInvoke.setStateAfter(invoke.stateAfter());
             snippetGraph.replaceFixedWithFixed((InvokeNode) invoke.asNode(), newInvoke);
         }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/GraalServices.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/GraalServices.java	Fri Mar 16 22:59:32 2018 -0700
@@ -54,14 +54,18 @@
      * @param other all JVMCI packages will be opened to the module defining this class
      */
     public static void openJVMCITo(Class<?> other) {
-        Object jvmci = getModule.invoke(Services.class);
-        Object otherModule = getModule.invoke(other);
+        Object jvmci = getModule(Services.class);
+        Object otherModule = getModule(other);
         if (jvmci != otherModule) {
-            Set<String> packages = getPackages.invoke(jvmci);
+            Set<String> packages = getPackages(jvmci);
             for (String pkg : packages) {
-                boolean opened = isOpenTo.invoke(jvmci, pkg, otherModule);
+                boolean opened = isOpenTo(jvmci, pkg, otherModule);
                 if (!opened) {
-                    addOpens.invoke(jvmci, pkg, otherModule);
+                    try {
+                        addOpens.invoke(jvmci, pkg, otherModule);
+                    } catch (Throwable throwable) {
+                        throw new InternalError(throwable);
+                    }
                 }
             }
         }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/JDK9Method.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/JDK9Method.java	Fri Mar 16 22:59:32 2018 -0700
@@ -22,9 +22,11 @@
  */
 package org.graalvm.compiler.serviceprovider;
 
-import java.lang.reflect.InvocationTargetException;
+import java.io.InputStream;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
 import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
+import java.util.Set;
 
 /**
  * Reflection based access to API introduced by JDK 9. This allows the API to be used in code that
@@ -46,9 +48,17 @@
      */
     public static final int JAVA_SPECIFICATION_VERSION = getJavaSpecificationVersion();
 
-    public JDK9Method(Class<?> declaringClass, String name, Class<?>... parameterTypes) {
+    public static MethodHandle lookupMethodHandle(Class<?> declaringClass, String name, Class<?>... parameterTypes) {
         try {
-            this.method = declaringClass.getMethod(name, parameterTypes);
+            return MethodHandles.lookup().unreflect(declaringClass.getMethod(name, parameterTypes));
+        } catch (Exception e) {
+            throw new InternalError(e);
+        }
+    }
+
+    private static Method lookupMethod(Class<?> declaringClass, String name, Class<?>... parameterTypes) {
+        try {
+            return declaringClass.getMethod(name, parameterTypes);
         } catch (Exception e) {
             throw new InternalError(e);
         }
@@ -59,90 +69,85 @@
      */
     public static final boolean Java8OrEarlier = JAVA_SPECIFICATION_VERSION <= 8;
 
-    public final Method method;
-
-    public Class<?> getReturnType() {
-        return method.getReturnType();
-    }
-
     /**
      * {@code Class.getModule()}.
      */
-    public static final JDK9Method getModule;
+    private static final MethodHandle getModuleHandle;
+
+    public static Object getModule(Class<?> clazz) {
+        try {
+            return getModuleHandle.invoke(clazz);
+        } catch (Throwable throwable) {
+            throw new InternalError(throwable);
+        }
+    }
 
     /**
      * {@code java.lang.Module.getPackages()}.
      */
-    public static final JDK9Method getPackages;
+    private static final MethodHandle getPackages;
+
+    public static Set<String> getPackages(Object module) {
+        try {
+            return (Set<String>) getPackages.invoke(module);
+        } catch (Throwable throwable) {
+            throw new InternalError(throwable);
+        }
+    }
 
     /**
      * {@code java.lang.Module.getResourceAsStream(String)}.
      */
-    public static final JDK9Method getResourceAsStream;
+    private static final MethodHandle getResourceAsStream;
+
+    public static InputStream getResourceAsStream(Object module, String resource) {
+        try {
+            return (InputStream) getResourceAsStream.invoke(module, resource);
+        } catch (Throwable throwable) {
+            throw new InternalError(throwable);
+        }
+    }
 
     /**
-     * {@code java.lang.Module.addOpens(String, Module)}.
+     * {@code java.lang.Module.addOpens(String, Module)}. This only seems to work correctly when
+     * invoked through reflection.
      */
-    public static final JDK9Method addOpens;
+    public static final Method addOpens;
 
     /**
      * {@code java.lang.Module.isOpen(String, Module)}.
      */
-    public static final JDK9Method isOpenTo;
+    private static final MethodHandle isOpenTo;
 
-    /**
-     * Invokes the static Module API method represented by this object.
-     */
-    @SuppressWarnings("unchecked")
-    public <T> T invokeStatic(Object... args) {
-        checkAvailability();
-        assert Modifier.isStatic(method.getModifiers());
+    public static boolean isOpenTo(Object module1, String pkg, Object module2) {
         try {
-            return (T) method.invoke(null, args);
-        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
-            throw new InternalError(e);
+            return (boolean) isOpenTo.invoke(module1, pkg, module2);
+        } catch (Throwable throwable) {
+            throw new InternalError(throwable);
         }
     }
 
-    /**
-     * Invokes the non-static Module API method represented by this object.
-     */
-    @SuppressWarnings("unchecked")
-    public <T> T invoke(Object receiver, Object... args) {
-        checkAvailability();
-        assert !Modifier.isStatic(method.getModifiers());
-        try {
-            return (T) method.invoke(receiver, args);
-        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
-            throw new InternalError(e);
-        }
-    }
-
-    private void checkAvailability() throws InternalError {
-        if (method == null) {
-            throw new InternalError("Cannot use Module API on JDK " + JAVA_SPECIFICATION_VERSION);
-        }
-    }
+    public static final Class<?> MODULE_CLASS;
 
     static {
         if (JAVA_SPECIFICATION_VERSION >= 9) {
-            getModule = new JDK9Method(Class.class, "getModule");
-            Class<?> moduleClass = getModule.getReturnType();
-            getPackages = new JDK9Method(moduleClass, "getPackages");
-            addOpens = new JDK9Method(moduleClass, "addOpens", String.class, moduleClass);
-            getResourceAsStream = new JDK9Method(moduleClass, "getResourceAsStream", String.class);
-            isOpenTo = new JDK9Method(moduleClass, "isOpen", String.class, moduleClass);
+            try {
+                MODULE_CLASS = Class.class.getMethod("getModule").getReturnType();
+                getModuleHandle = lookupMethodHandle(Class.class, "getModule");
+                getPackages = lookupMethodHandle(MODULE_CLASS, "getPackages");
+                addOpens = lookupMethod(MODULE_CLASS, "addOpens", String.class, MODULE_CLASS);
+                getResourceAsStream = lookupMethodHandle(MODULE_CLASS, "getResourceAsStream", String.class);
+                isOpenTo = lookupMethodHandle(MODULE_CLASS, "isOpen", String.class, MODULE_CLASS);
+            } catch (NoSuchMethodException e) {
+                throw new InternalError(e);
+            }
         } else {
-            JDK9Method unavailable = new JDK9Method();
-            getModule = unavailable;
-            getPackages = unavailable;
-            addOpens = unavailable;
-            getResourceAsStream = unavailable;
-            isOpenTo = unavailable;
+            MODULE_CLASS = null;
+            getModuleHandle = null;
+            getPackages = null;
+            addOpens = null;
+            getResourceAsStream = null;
+            isOpenTo = null;
         }
     }
-
-    private JDK9Method() {
-        method = null;
-    }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/ProtocolImpl.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/ProtocolImpl.java	Fri Mar 16 22:59:32 2018 -0700
@@ -128,7 +128,11 @@
 
     @Override
     protected Object findType(Port edges, int i) {
-        return structure.edgeType(edges, i);
+        Object type = structure.edgeType(edges, i);
+        if (findEnumOrdinal(type) < 0) {
+            throw new IllegalStateException("edgeType method shall return an enum! Was: " + type);
+        }
+        return type;
     }
 
     @Override
@@ -138,7 +142,11 @@
 
     @Override
     protected Object findJavaClass(NodeClass clazz) {
-        return structure.nodeClassType(clazz);
+        final Object type = structure.nodeClassType(clazz);
+        if (!(type instanceof Class<?>) && findJavaTypeName(type) == null) {
+            throw new IllegalStateException("nodeClassType method shall return a Java class (instance of Class)! Was: " + type);
+        }
+        return type;
     }
 
     @Override
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.micro.benchmarks/src/micro/benchmarks/StringBenchmark.java	Fri Mar 16 11:26:05 2018 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.micro.benchmarks/src/micro/benchmarks/StringBenchmark.java	Fri Mar 16 22:59:32 2018 -0700
@@ -45,6 +45,7 @@
 
         // Checkstyle: stop
         String lorem = "Lorem ipsum dolor sit amet, consectetur adipisici elit, sed eiusmod tempor incidunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquid ex ea commodi consequat. Quis aute iure reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint obcaecat cupiditat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
+        String loremLastChar = "Lorem ipsum dolor sit amet, consectetur adipisici elit, sed eiusmod tempor incidunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquid ex ea commodi consequat. Quis aute iure reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint obcaecat cupiditat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum?";
         // Checkstyle: resume
     }
 
@@ -71,4 +72,10 @@
     public int indexOfStringNotFound(BenchState state) {
         return state.lorem.indexOf(state.s2);
     }
+
+    @Benchmark
+    @Warmup(iterations = 5)
+    public int compareTo(BenchState state) {
+        return state.lorem.compareTo(state.loremLastChar);
+    }
 }