8180267: Update Graal
authorkvn
Fri, 12 May 2017 13:56:13 -0700
changeset 46459 7d4e637d3f21
parent 46458 3c12af929e7d
child 46460 d25a320cd821
8180267: Update Graal Reviewed-by: iveresov
hotspot/make/CompileTools.gmk
hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/GraalFilters.java
hotspot/src/jdk.internal.vm.compiler/share/classes/module-info.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.api.word/src/org/graalvm/api/word/AtomicUnsigned.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.api.word/src/org/graalvm/api/word/AtomicWord.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.api.word/src/org/graalvm/api/word/ComparableWord.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.api.word/src/org/graalvm/api/word/LocationIdentity.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.api.word/src/org/graalvm/api/word/Pointer.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.api.word/src/org/graalvm/api/word/PointerBase.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.api.word/src/org/graalvm/api/word/PointerUtils.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.api.word/src/org/graalvm/api/word/Signed.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.api.word/src/org/graalvm/api/word/Unsigned.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.api.word/src/org/graalvm/api/word/UnsignedUtils.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.api.word/src/org/graalvm/api/word/WordBase.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.api.word/src/org/graalvm/api/word/WordFactory.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.test/src/org/graalvm/compiler/api/test/Graal.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64.test/src/org/graalvm/compiler/asm/amd64/test/SimpleAssemblerTest.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.test/src/org/graalvm/compiler/asm/test/AssemblerTest.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/Bytecode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/ResolvedJavaMethodBytecode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/ResolvedJavaMethodBytecodeProvider.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64LIRKindTool.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64LIRKindTool.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/LIRKind.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/LocationIdentity.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/RegisterAllocationConfig.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/ForeignCallsProvider.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/LIRKindTool.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/ObjectStamp.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/PrimitiveStamp.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/Stamp.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/ModuleAPI.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/Util.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCLIRKindTool.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CheckGraalInvariants.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionTest.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationMulTest.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest1.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest10.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest11.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest2.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest3.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest4.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest5.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest6.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest7.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest8.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest9.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTestBase.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CountedLoopTest.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GuardedIntrinsicTest.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/IfCanonicalizerTest.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/LoopFullUnrollTest.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MethodHandleEagerResolution.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/NarrowingReadTest.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ReferenceGetLoopTest.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StampMemoryAccessTest.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StaticInterfaceFieldTest.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/TypeSystemTest.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnbalancedMonitorsTest.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnusedArray.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyBailoutUsageTest.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyDebugUsageTest.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyVirtualizableTest.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/backend/AllocatorTest.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/debug/VerifyMethodMetricsTest.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/tutorial/StaticAnalysis.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompiler.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalDebugInitializationParticipant.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/LIRGenerationPhase.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/NodeLIRBuilder.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/Debug.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/GraalDebugConfig.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/DebugScope.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/.checkstyle_checks.xml
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackendFactory.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotForeignCallsProvider.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotLIRGenerator.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotLIRKindTool.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64.test/src/org/graalvm/compiler/hotspot/amd64/test/DataPatchInConstantsTest.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotAddressLowering.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackendFactory.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotForeignCallsProvider.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRGenerator.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRKindTool.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotBackendFactory.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotForeignCallsProvider.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLIRGenerator.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLIRKindTool.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CheckGraalIntrinsics.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorld.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ConstantPoolSubstitutionsTests.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/DataPatchTest.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/EliminateRedundantInitializationPhaseTest.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ForeignCallDeoptimizeTest.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotGraalMBeanTest.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotStampMemoryAccessTest.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/OptionsInFileTest.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/RetryableCompilationTest.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/TestIntrinsicCompiles.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/WriteBarrierVerificationTest.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationTask.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackend.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotForeignCallLinkage.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotForeignCallLinkageImpl.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompiler.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompilerFactory.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalJVMCIServiceLocator.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalMBean.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalOptionValues.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntimeProvider.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotLIRGenerator.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotNodeLIRBuilder.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotReferenceMapBuilder.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotRetryableCompilation.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/JVMCIVersionCheck.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotForeignCallsProviderImpl.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotInvocationPlugins.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotNodePlugin.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotWordOperationPlugin.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/BeginLockScopeNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/CompressionNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/EndLockScopeNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/HotSpotCompressionNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/StubForeignCallNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/InitializeKlassStubCall.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/type/HotSpotLIRKindTool.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/type/HotSpotNarrowOopStamp.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/type/KlassPointerStamp.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/type/NarrowOopStamp.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/LoadJavaMirrorWithKlassPhase.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/EliminateRedundantInitializationPhase.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/AESCryptSubstitutions.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/CRC32Substitutions.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/CipherBlockChainingSubstitutions.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ClassGetHubNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HashCodeSnippets.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotReplacementsUtil.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/IdentityHashCodeNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/LoadExceptionObjectSnippets.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/MonitorSnippets.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/NewObjectSnippets.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/SHA2Substitutions.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/SHA5Substitutions.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/SHASubstitutions.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/StringToBytesSnippets.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ThreadSubstitutions.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/WriteBarrierSnippets.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopyCallNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopyNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopySlowPathNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopySnippets.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopyUnrollNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/CheckcastArrayCopyCallNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/UnsafeArrayCopyNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/UnsafeArrayCopySnippets.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/CreateExceptionStub.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/ExceptionHandlerStub.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/ForeignCallStub.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/NewArrayStub.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/NewInstanceStub.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/SnippetStub.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/StubUtil.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/UnwindExceptionToCallerStub.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/word/KlassPointer.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/word/MetaspacePointer.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/word/MethodPointer.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParserOptions.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_newarray_02.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotspot/Test6959129.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Monitor_contended01.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Monitor_notowner01.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Monitorenter01.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Monitorenter02.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Object_wait01.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Object_wait02.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Object_wait03.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Object_wait04.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/SynchronizedLoopExit01.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_isInterrupted02.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_isInterrupted03.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_isInterrupted05.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_join01.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_join02.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_join03.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_sleep01.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_yield01.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.jtt/src/org/graalvm/compiler/lir/jtt/LIRTest.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.jtt/src/org/graalvm/compiler/lir/jtt/SPARCBranchBailoutTest.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/EdgeMoveOptimizer.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/FullInfopointOp.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/LIRInstruction.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/LIRInstructionClass.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/RedundantMoveElimination.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/StandardOp.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanAssignLocationsPhase.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanEliminateSpillMovePhase.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanLifetimeAnalysisPhase.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanWalker.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/MoveResolver.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceGlobalMoveResolutionPhase.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceGlobalMoveResolver.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/bu/BottomUpAllocator.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanAssignLocationsPhase.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanEliminateSpillMovePhase.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanLifetimeAnalysisPhase.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanWalker.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLocalMoveResolver.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/constopt/ConstantLoadOptimization.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/constopt/DefUseTree.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/LIRGeneratorTool.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/VerifyingMoveFactory.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/profiling/MoveProfiler.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/profiling/MoveType.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/stackslotalloc/FixPointIntervalBuilder.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/CountedLoopInfo.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/ConditionalEliminationBenchmark.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/util/GraalUtil.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/lir/GraalCompilerState.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/lir/RegisterAllocationTimeBenchmark.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/NegateNodeCanonicalizationTest.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/ShortCircuitOrNodeTest.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/CompressionNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FieldLocationIdentity.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FrameState.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/IfNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InvokeNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InvokeWithExceptionNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/KillingBeginNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/NamedLocationIdentity.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StartNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StructuredGraph.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/NormalizeCompareNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/RemNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/Block.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/ControlFlowGraph.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/HIRLoop.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/LocationSet.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/StringToBytesNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/BytecodeExceptionNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/ForeignCallNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/GuardedUnsafeLoadNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/JavaReadNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/JavaWriteNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/MembarNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawLoadNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawStoreNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnsafeAccessNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnsafeCopyNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnsafeMemoryLoadNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnsafeMemoryStoreNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/IntrinsicContext.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InvocationPlugin.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InvocationPlugins.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/MethodSubstitutionPlugin.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AbstractCompareAndSwapNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AtomicReadAndAddNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AtomicReadAndWriteNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/ExceptionObjectNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LogicCompareAndSwapNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LoweredAtomicReadAndWriteNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/MonitorEnterNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/MonitorExitNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/RawMonitorEnterNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/UnsafeCompareAndSwapNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/ValueCompareAndSwapNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/AbstractWriteNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/Access.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/FixedAccessNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/FloatableAccessNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/FloatingAccessNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/FloatingReadNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryAccess.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryCheckpoint.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryMap.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryMapNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryPhiNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/ReadNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/WriteNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/MemoryProxy.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/Replacements.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/type/NarrowOopStamp.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/util/GraphUtil.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/CommitAllocationNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionKey.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/CanonicalizerPhase.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ConditionalEliminationPhase.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/DominatorConditionalEliminationPhase.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ExpandLogicPhase.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/FloatingReadPhase.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/IterativeConditionalEliminationPhase.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/LoweringPhase.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/NewConditionalEliminationPhase.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/InliningUtil.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/BasePhase.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/MemoryScheduleVerification.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/SchedulePhase.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/verify/VerifyCallerSensitiveMethods.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/verify/VerifyDebugUsage.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/verify/VerifyInstanceOfUsage.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraphPrinter.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraphPrinterDumpHandler.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64GraphBuilderPlugins.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringIndexOfNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringSubstitutions.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ArrayStoreBytecodeExceptionTest.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/BytecodeExceptionTest.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ClassCastBytecodeExceptionTest.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/DerivedOopTest.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/FoldTest.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/IndexOobBytecodeExceptionTest.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/NullBytecodeExceptionTest.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ObjectAccessTest.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PEGraphDecoderTest.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PointerTest.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PointerTrackingTest.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ReplacementsParseTest.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/SnippetsTest.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/SubstitutionsTest.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/WordTest.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/classfile/RedefineIntrinsicTest.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/DefaultJavaLoweringProvider.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/GraphKit.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ReplacementsImpl.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetCounterNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetLowerableMemoryNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetTemplate.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/WordOperationPlugin.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileBytecode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileBytecodeProvider.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ArrayEqualsNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BasicArrayCopyNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroStateSplitNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/GraalServices.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/JDK9Method.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/GraalTest.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/JLModule.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/SubprocessUtil.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsClosure.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationBlockState.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationClosure.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/ReadEliminationBlockState.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/ReadEliminationClosure.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/AtomicUnsigned.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/AtomicWord.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/BarrieredAccess.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/ComparableWord.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/ObjectAccess.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/Pointer.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/PointerBase.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/PointerUtils.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/Signed.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/Unsigned.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/UnsignedUtils.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/Word.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/WordBase.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/WordCastNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/WordOperationPlugin.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/WordTypes.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/nodes/WordCastNode.java
hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/impl/EconomicMapImpl.java
hotspot/test/ProblemList.txt
--- a/hotspot/make/CompileTools.gmk	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/make/CompileTools.gmk	Fri May 12 13:56:13 2017 -0700
@@ -47,6 +47,7 @@
   $(eval $(call SetupJavaCompilation, BUILD_VM_COMPILER_MATCH_PROCESSOR, \
       SETUP := GENERATE_OLDBYTECODE, \
       SRC := \
+          $(SRC_DIR)/org.graalvm.api.word/src \
           $(SRC_DIR)/org.graalvm.compiler.core/src \
           $(SRC_DIR)/org.graalvm.compiler.core.common/src \
           $(SRC_DIR)/org.graalvm.compiler.core.match.processor/src \
@@ -114,6 +115,7 @@
   $(eval $(call SetupJavaCompilation, BUILD_VM_COMPILER_REPLACEMENTS_VERIFIER, \
       SETUP := GENERATE_OLDBYTECODE, \
       SRC := \
+          $(SRC_DIR)/org.graalvm.api.word/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/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/GraalFilters.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/GraalFilters.java	Fri May 12 13:56:13 2017 -0700
@@ -34,6 +34,7 @@
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 import jdk.vm.ci.meta.ResolvedJavaType;
 
+import org.graalvm.api.word.WordBase;
 import org.graalvm.compiler.api.directives.GraalDirectives;
 import org.graalvm.compiler.api.replacements.ClassSubstitution;
 import org.graalvm.compiler.api.replacements.MethodSubstitution;
@@ -43,7 +44,6 @@
 import org.graalvm.compiler.hotspot.replacements.HotSpotClassSubstitutions;
 import org.graalvm.compiler.hotspot.word.MetaspacePointer;
 import org.graalvm.compiler.replacements.Snippets;
-import org.graalvm.compiler.word.WordBase;
 
 public class GraalFilters {
     private List<ResolvedJavaType> specialClasses;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/module-info.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/module-info.java	Fri May 12 13:56:13 2017 -0700
@@ -42,6 +42,7 @@
     uses org.graalvm.compiler.options.OptionValuesAccess;
     uses org.graalvm.compiler.nodes.graphbuilderconf.NodeIntrinsicPluginFactory;
 
+    exports org.graalvm.api.word                        to jdk.aot;
     exports org.graalvm.compiler.api.directives         to jdk.aot;
     exports org.graalvm.compiler.api.runtime            to jdk.aot;
     exports org.graalvm.compiler.api.replacements       to jdk.aot;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.api.word/src/org/graalvm/api/word/AtomicUnsigned.java	Fri May 12 13:56:13 2017 -0700
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2015, 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
+ * 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.api.word;
+
+/**
+ * A {@link Unsigned} value that may be updated atomically. See the
+ * {@link java.util.concurrent.atomic} package specification for description of the properties of
+ * atomic variables.
+ */
+public class AtomicUnsigned extends AtomicWord<Unsigned> {
+
+    /**
+     * Atomically adds the given value to the current value.
+     *
+     * @param delta the value to add
+     * @return the previous value
+     */
+    public final Unsigned getAndAdd(Unsigned delta) {
+        return WordFactory.unsigned(value.getAndAdd(delta.rawValue()));
+    }
+
+    /**
+     * Atomically adds the given value to the current value.
+     *
+     * @param delta the value to add
+     * @return the updated value
+     */
+    public final Unsigned addAndGet(Unsigned delta) {
+        return WordFactory.unsigned(value.addAndGet(delta.rawValue()));
+    }
+
+    /**
+     * Atomically subtracts the given value from the current value.
+     *
+     * @param delta the value to add
+     * @return the previous value
+     */
+    public final Unsigned getAndSubtract(Unsigned delta) {
+        return WordFactory.unsigned(value.getAndAdd(-delta.rawValue()));
+    }
+
+    /**
+     * Atomically subtracts the given value from the current value.
+     *
+     * @param delta the value to add
+     * @return the updated value
+     */
+    public final Unsigned subtractAndGet(Unsigned delta) {
+        return WordFactory.unsigned(value.addAndGet(-delta.rawValue()));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.api.word/src/org/graalvm/api/word/AtomicWord.java	Fri May 12 13:56:13 2017 -0700
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2015, 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
+ * 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.api.word;
+
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * A {@link WordBase word} value that may be updated atomically. See the
+ * {@link java.util.concurrent.atomic} package specification for description of the properties of
+ * atomic variables.
+ *
+ * Similar to {@link AtomicReference}, but for {@link WordBase word} types. A dedicated
+ * implementation is necessary because Object and word types cannot be mixed.
+ */
+public class AtomicWord<T extends WordBase> {
+
+    /**
+     * For simplicity, we convert the word value to a long and delegate to existing atomic
+     * operations.
+     */
+    protected final AtomicLong value;
+
+    /**
+     * Creates a new AtomicWord with initial value {@link WordFactory#zero}.
+     */
+    public AtomicWord() {
+        value = new AtomicLong();
+    }
+
+    /**
+     * Gets the current value.
+     *
+     * @return the current value
+     */
+    public final T get() {
+        return WordFactory.unsigned(value.get());
+    }
+
+    /**
+     * Sets to the given value.
+     *
+     * @param newValue the new value
+     */
+    public final void set(T newValue) {
+        value.set(newValue.rawValue());
+    }
+
+    /**
+     * Atomically sets to the given value and returns the old value.
+     *
+     * @param newValue the new value
+     * @return the previous value
+     */
+    public final T getAndSet(T newValue) {
+        return WordFactory.unsigned(value.getAndSet(newValue.rawValue()));
+    }
+
+    /**
+     * Atomically sets the value to the given updated value if the current value {@code ==} the
+     * expected value.
+     *
+     * @param expect the expected value
+     * @param update the new value
+     * @return {@code true} if successful. False return indicates that the actual value was not
+     *         equal to the expected value.
+     */
+    public final boolean compareAndSet(T expect, T update) {
+        return value.compareAndSet(expect.rawValue(), update.rawValue());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.api.word/src/org/graalvm/api/word/ComparableWord.java	Fri May 12 13:56:13 2017 -0700
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2012, 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.api.word;
+
+public interface ComparableWord extends WordBase {
+
+    /**
+     * Compares this word with the specified value.
+     *
+     * @param val value to which this word is to be compared.
+     * @return {@code this == val}
+     */
+    boolean equal(ComparableWord val);
+
+    /**
+     * Compares this word with the specified value.
+     *
+     * @param val value to which this word is to be compared.
+     * @return {@code this != val}
+     */
+    boolean notEqual(ComparableWord val);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.api.word/src/org/graalvm/api/word/LocationIdentity.java	Fri May 12 13:56:13 2017 -0700
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2011, 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.api.word;
+
+// JaCoCo Exclude
+
+/**
+ * Marker interface for location identities. A different location identity of two memory accesses
+ * guarantees that the two accesses do not interfere.
+ *
+ * Clients of {@link LocationIdentity} must use {@link #equals(Object)}, not {@code ==}, when
+ * comparing two {@link LocationIdentity} values for equality. Likewise, they must not use
+ * {@link java.util.IdentityHashMap}s with {@link LocationIdentity} values as keys.
+ */
+public abstract class LocationIdentity {
+
+    private static final class AnyLocationIdentity extends LocationIdentity {
+        @Override
+        public boolean isImmutable() {
+            return false;
+        }
+
+        @Override
+        public String toString() {
+            return "ANY_LOCATION";
+        }
+    }
+
+    private static final class InitLocationIdentity extends LocationIdentity {
+        @Override
+        public boolean isImmutable() {
+            return true;
+        }
+
+        @Override
+        public String toString() {
+            return "INIT_LOCATION";
+        }
+    }
+
+    public static final LocationIdentity ANY_LOCATION = new AnyLocationIdentity();
+    public static final LocationIdentity INIT_LOCATION = new InitLocationIdentity();
+
+    /**
+     * Indicates that the given location is the union of all possible mutable locations. A write to
+     * such a location kill all reads from mutable locations and a read from this location is killed
+     * by any write (except for initialization writes).
+     */
+    public static LocationIdentity any() {
+        return ANY_LOCATION;
+    }
+
+    /**
+     * Location only allowed to be used for writes. Indicates that a completely new memory location
+     * is written. Kills no read. The previous value at the given location must be either
+     * uninitialized or null. Writes to this location do not need a GC pre-barrier.
+     */
+    public static LocationIdentity init() {
+        return INIT_LOCATION;
+    }
+
+    /**
+     * Denotes a location is unchanging in all cases. Not that this is different than the Java
+     * notion of final which only requires definite assignment.
+     */
+    public abstract boolean isImmutable();
+
+    public final boolean isMutable() {
+        return !isImmutable();
+    }
+
+    public final boolean isAny() {
+        return this == ANY_LOCATION;
+    }
+
+    public final boolean isInit() {
+        return this == INIT_LOCATION;
+    }
+
+    public final boolean isSingle() {
+        return this != ANY_LOCATION;
+    }
+
+    public final boolean overlaps(LocationIdentity other) {
+        return isAny() || other.isAny() || this.equals(other);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.api.word/src/org/graalvm/api/word/Pointer.java	Fri May 12 13:56:13 2017 -0700
@@ -0,0 +1,963 @@
+/*
+ * Copyright (c) 2012, 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.api.word;
+
+/**
+ * Lowest-level memory access of native C memory.
+ * <p>
+ * Do not use these methods to access Java objects. These methods access the raw memory without any
+ * null checks, read- or write barriers. Even when the VM uses compressed pointers, then readObject
+ * and writeObject methods access uncompressed pointers.
+ */
+public interface Pointer extends Unsigned, PointerBase {
+
+    /**
+     * Unsafe conversion of this Pointer to a Java language object. No correctness checks or type
+     * checks are performed. The caller must ensure that the Pointer contains a valid Java object
+     * that can i.e., processed by the garbage collector.
+     *
+     * @return this Pointer cast to Object.
+     */
+    Object toObject();
+
+    /**
+     * Unsafe conversion of this Pointer to a Java language object. No correctness checks or type
+     * checks are performed. The caller must ensure that the Pointer contains a valid Java object
+     * that can i.e., processed by the garbage collector and the Pointer does not contain 0.
+     *
+     * @return this Pointer cast to non-null Object.
+     */
+    Object toObjectNonNull();
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    byte readByte(WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    char readChar(WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    short readShort(WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    int readInt(WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    long readLong(WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    float readFloat(WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    double readDouble(WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    <T extends WordBase> T readWord(WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    Object readObject(WordBase offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    byte readByte(int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    char readChar(int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    short readShort(int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    int readInt(int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    long readLong(int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    float readFloat(int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    double readDouble(int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    <T extends WordBase> T readWord(int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the read
+     * @return the result of the memory access
+     */
+    Object readObject(int offset, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    void writeByte(WordBase offset, byte val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    void writeChar(WordBase offset, char val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    void writeShort(WordBase offset, short val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    void writeInt(WordBase offset, int val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    void writeLong(WordBase offset, long val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    void writeFloat(WordBase offset, float val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    void writeDouble(WordBase offset, double val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    void writeWord(WordBase offset, WordBase val, LocationIdentity locationIdentity);
+
+    /**
+     * Initializes the memory at address {@code (this + offset)}. Both the base address and offset
+     * are in bytes. The memory must be uninitialized or zero prior to this operation.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    void initializeLong(WordBase offset, long val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    void writeObject(WordBase offset, Object val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    void writeByte(int offset, byte val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    void writeChar(int offset, char val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    void writeShort(int offset, short val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    void writeInt(int offset, int val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    void writeLong(int offset, long val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    void writeFloat(int offset, float val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    void writeDouble(int offset, double val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    void writeWord(int offset, WordBase val, LocationIdentity locationIdentity);
+
+    /**
+     * Initializes the memory at address {@code (this + offset)}. Both the base address and offset
+     * are in bytes. The memory must be uninitialized or zero prior to this operation.
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    void initializeLong(int offset, long val, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param locationIdentity the identity of the write
+     * @param val the value to be written to memory
+     */
+    void writeObject(int offset, Object val, LocationIdentity locationIdentity);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    byte readByte(WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    char readChar(WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    short readShort(WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    int readInt(WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    long readLong(WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    float readFloat(WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    double readDouble(WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    <T extends WordBase> T readWord(WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    Object readObject(WordBase offset);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    byte readByte(int offset);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    char readChar(int offset);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    short readShort(int offset);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    int readInt(int offset);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    long readLong(int offset);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    float readFloat(int offset);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    double readDouble(int offset);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    <T extends WordBase> T readWord(int offset);
+
+    /**
+     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @return the result of the memory access
+     */
+    Object readObject(int offset);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    void writeByte(WordBase offset, byte val);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    void writeChar(WordBase offset, char val);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    void writeShort(WordBase offset, short val);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    void writeInt(WordBase offset, int val);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    void writeLong(WordBase offset, long val);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    void writeFloat(WordBase offset, float val);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    void writeDouble(WordBase offset, double val);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    void writeWord(WordBase offset, WordBase val);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     * <p>
+     * The offset is always treated as a {@link Signed} value. However, the static type is
+     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
+     * knows that the highest-order bit of the unsigned value is never used).
+     *
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    void writeObject(WordBase offset, Object val);
+
+    int compareAndSwapInt(WordBase offset, int expectedValue, int newValue, LocationIdentity locationIdentity);
+
+    long compareAndSwapLong(WordBase offset, long expectedValue, long newValue, LocationIdentity locationIdentity);
+
+    <T extends WordBase> T compareAndSwapWord(WordBase offset, T expectedValue, T newValue, LocationIdentity locationIdentity);
+
+    Object compareAndSwapObject(WordBase offset, Object expectedValue, Object newValue, LocationIdentity locationIdentity);
+
+    boolean logicCompareAndSwapInt(WordBase offset, int expectedValue, int newValue, LocationIdentity locationIdentity);
+
+    boolean logicCompareAndSwapLong(WordBase offset, long expectedValue, long newValue, LocationIdentity locationIdentity);
+
+    boolean logicCompareAndSwapWord(WordBase offset, WordBase expectedValue, WordBase newValue, LocationIdentity locationIdentity);
+
+    boolean logicCompareAndSwapObject(WordBase offset, Object expectedValue, Object newValue, LocationIdentity locationIdentity);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    void writeByte(int offset, byte val);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    void writeChar(int offset, char val);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    void writeShort(int offset, short val);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    void writeInt(int offset, int val);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    void writeLong(int offset, long val);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    void writeFloat(int offset, float val);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    void writeDouble(int offset, double val);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    void writeWord(int offset, WordBase val);
+
+    /**
+     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
+     * bytes.
+     *
+     * @param offset the signed offset for the memory access
+     * @param val the value to be written to memory
+     */
+    void writeObject(int offset, Object val);
+
+    int compareAndSwapInt(int offset, int expectedValue, int newValue, LocationIdentity locationIdentity);
+
+    long compareAndSwapLong(int offset, long expectedValue, long newValue, LocationIdentity locationIdentity);
+
+    <T extends WordBase> T compareAndSwapWord(int offset, T expectedValue, T newValue, LocationIdentity locationIdentity);
+
+    Object compareAndSwapObject(int offset, Object expectedValue, Object newValue, LocationIdentity locationIdentity);
+
+    boolean logicCompareAndSwapInt(int offset, int expectedValue, int newValue, LocationIdentity locationIdentity);
+
+    boolean logicCompareAndSwapLong(int offset, long expectedValue, long newValue, LocationIdentity locationIdentity);
+
+    boolean logicCompareAndSwapWord(int offset, WordBase expectedValue, WordBase newValue, LocationIdentity locationIdentity);
+
+    boolean logicCompareAndSwapObject(int offset, Object expectedValue, Object newValue, LocationIdentity locationIdentity);
+
+    // Math functions that are defined in Unsigned, but known to preserve the
+    // pointer-characteristics.
+    // It is therefore safe that they return a static type of Pointer instead of Unsigned.
+
+    @Override
+    Pointer add(Unsigned val);
+
+    @Override
+    Pointer add(int val);
+
+    @Override
+    Pointer subtract(Unsigned val);
+
+    @Override
+    Pointer subtract(int val);
+
+    @Override
+    Pointer and(Unsigned val);
+
+    @Override
+    Pointer and(int val);
+
+    @Override
+    Pointer or(Unsigned val);
+
+    @Override
+    Pointer or(int val);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.api.word/src/org/graalvm/api/word/PointerBase.java	Fri May 12 13:56:13 2017 -0700
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2013, 2013, 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.api.word;
+
+/**
+ * Marker interface for all {@link WordBase word types} that have the semantic of a pointer (but not
+ * necessarily all the memory access methods defined in {@link Pointer}).
+ */
+public interface PointerBase extends ComparableWord {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.api.word/src/org/graalvm/api/word/PointerUtils.java	Fri May 12 13:56:13 2017 -0700
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2015, 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
+ * 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.api.word;
+
+/**
+ * Utility methods on Pointers.
+ */
+public final class PointerUtils {
+
+    private PointerUtils() {
+        // This is a class of static methods, so no need for any instances.
+    }
+
+    /**
+     * The value of a null Pointer.
+     *
+     * @return A null Pointer value.
+     */
+    @SuppressWarnings("unchecked")
+    public static <T extends PointerBase> T nullPointer() {
+        return (T) WordFactory.zero();
+    }
+
+    /**
+     * Predicate to check for the null Pointer value.
+     *
+     * @return Whether that Pointer is the null Pointer.
+     */
+    public static boolean isNull(ComparableWord that) {
+        return that.equal(nullPointer());
+    }
+
+    /**
+     * Predicate to check for a non-null Pointer value.
+     *
+     * @return Whether that Pointer is not the null Pointer.
+     */
+    public static boolean isNonNull(ComparableWord that) {
+        return that.notEqual(nullPointer());
+    }
+
+    /**
+     * Round a Pointer down to the nearest smaller multiple.
+     *
+     * @param that The Pointer to be rounded up.
+     * @param multiple The multiple to which that Pointer should be decreased.
+     * @return That Pointer, but rounded down.
+     */
+    public static Pointer roundDown(PointerBase that, Unsigned multiple) {
+        return (Pointer) UnsignedUtils.roundDown((Unsigned) that, multiple);
+    }
+
+    /**
+     * Round a Pointer up to the nearest larger multiple.
+     *
+     * @param that The Pointer to be rounded up.
+     * @param multiple The multiple to which that Pointer should be increased.
+     * @return That Pointer, but rounded up.
+     */
+    public static Pointer roundUp(PointerBase that, Unsigned multiple) {
+        return (Pointer) UnsignedUtils.roundUp((Unsigned) that, multiple);
+    }
+
+    /**
+     * Check that a Pointer is an even multiple.
+     *
+     * @param that The Pointer to be verified as a multiple.
+     * @param multiple The multiple against which the Pointer should be verified.
+     * @return true if that Pointer is a multiple, false otherwise.
+     */
+    public static boolean isAMultiple(PointerBase that, Unsigned multiple) {
+        return that.equal(PointerUtils.roundDown(that, multiple));
+    }
+
+    /**
+     * Return the distance between two Pointers.
+     *
+     * @param pointer1 A first Pointer.
+     * @param pointer2 A second Pointer.
+     * @return The distance in bytes between the two Pointers.
+     */
+    public static Unsigned absoluteDifference(PointerBase pointer1, PointerBase pointer2) {
+        Pointer p1 = (Pointer) pointer1;
+        Pointer p2 = (Pointer) pointer2;
+        final Unsigned result;
+        if (p1.aboveOrEqual(p2)) {
+            result = p1.subtract(p2);
+        } else {
+            result = p2.subtract(p1);
+        }
+        return result;
+    }
+
+    /**
+     * The minimum of two Pointers.
+     *
+     * @param x A Pointer.
+     * @param y Another Pointer.
+     * @return The whichever Pointer is smaller.
+     */
+    public static <T extends PointerBase> T min(T x, T y) {
+        return (((Pointer) x).belowOrEqual((Pointer) y)) ? x : y;
+    }
+
+    /**
+     * The maximum of two Pointers.
+     *
+     * @param x A Pointer.
+     * @param y Another Pointer.
+     * @return The whichever Pointer is larger.
+     */
+    public static <T extends PointerBase> T max(T x, T y) {
+        return (((Pointer) x).aboveOrEqual((Pointer) y)) ? x : y;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.api.word/src/org/graalvm/api/word/Signed.java	Fri May 12 13:56:13 2017 -0700
@@ -0,0 +1,296 @@
+/*
+ * Copyright (c) 2012, 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.api.word;
+
+public interface Signed extends ComparableWord {
+
+    /**
+     * Returns a Signed whose value is {@code (this + val)}.
+     *
+     * @param val value to be added to this Signed.
+     * @return {@code this + val}
+     */
+    Signed add(Signed val);
+
+    /**
+     * Returns a Signed whose value is {@code (this - val)}.
+     *
+     * @param val value to be subtracted from this Signed.
+     * @return {@code this - val}
+     */
+    Signed subtract(Signed val);
+
+    /**
+     * Returns a Signed whose value is {@code (this * val)}.
+     *
+     * @param val value to be multiplied by this Signed.
+     * @return {@code this * val}
+     */
+    Signed multiply(Signed val);
+
+    /**
+     * Returns a Signed whose value is {@code (this / val)}.
+     *
+     * @param val value by which this Signed is to be divided.
+     * @return {@code this / val}
+     */
+    Signed signedDivide(Signed val);
+
+    /**
+     * Returns a Signed whose value is {@code (this % val)}.
+     *
+     * @param val value by which this Signed is to be divided, and the remainder computed.
+     * @return {@code this % val}
+     */
+    Signed signedRemainder(Signed val);
+
+    /**
+     * Returns a Signed whose value is {@code (this << n)}.
+     *
+     * @param n shift distance, in bits.
+     * @return {@code this << n}
+     */
+    Signed shiftLeft(Unsigned n);
+
+    /**
+     * Returns a Signed whose value is {@code (this >> n)}. Sign extension is performed.
+     *
+     * @param n shift distance, in bits.
+     * @return {@code this >> n}
+     */
+    Signed signedShiftRight(Unsigned n);
+
+    /**
+     * Returns a Signed whose value is {@code (this & val)}. (This method returns a negative Signed
+     * if and only if this and val are both negative.)
+     *
+     * @param val value to be AND'ed with this Signed.
+     * @return {@code this & val}
+     */
+    Signed and(Signed val);
+
+    /**
+     * Returns a Signed whose value is {@code (this | val)}. (This method returns a negative Signed
+     * if and only if either this or val is negative.)
+     *
+     * @param val value to be OR'ed with this Signed.
+     * @return {@code this | val}
+     */
+    Signed or(Signed val);
+
+    /**
+     * Returns a Signed whose value is {@code (this ^ val)}. (This method returns a negative Signed
+     * if and only if exactly one of this and val are negative.)
+     *
+     * @param val value to be XOR'ed with this Signed.
+     * @return {@code this ^ val}
+     */
+    Signed xor(Signed val);
+
+    /**
+     * Returns a Signed whose value is {@code (~this)}. (This method returns a negative value if and
+     * only if this Signed is non-negative.)
+     *
+     * @return {@code ~this}
+     */
+    Signed not();
+
+    /**
+     * Compares this Signed with the specified value.
+     *
+     * @param val value to which this Signed is to be compared.
+     * @return {@code this == val}
+     */
+    boolean equal(Signed val);
+
+    /**
+     * Compares this Signed with the specified value.
+     *
+     * @param val value to which this Signed is to be compared.
+     * @return {@code this != val}
+     */
+    boolean notEqual(Signed val);
+
+    /**
+     * Compares this Signed with the specified value.
+     *
+     * @param val value to which this Signed is to be compared.
+     * @return {@code this < val}
+     */
+    boolean lessThan(Signed val);
+
+    /**
+     * Compares this Signed with the specified value.
+     *
+     * @param val value to which this Signed is to be compared.
+     * @return {@code this <= val}
+     */
+    boolean lessOrEqual(Signed val);
+
+    /**
+     * Compares this Signed with the specified value.
+     *
+     * @param val value to which this Signed is to be compared.
+     * @return {@code this > val}
+     */
+    boolean greaterThan(Signed val);
+
+    /**
+     * Compares this Signed with the specified value.
+     *
+     * @param val value to which this Signed is to be compared.
+     * @return {@code this >= val}
+     */
+    boolean greaterOrEqual(Signed val);
+
+    /**
+     * Returns a Signed whose value is {@code (this + val)}.
+     *
+     * @param val value to be added to this Signed.
+     * @return {@code this + val}
+     */
+    Signed add(int val);
+
+    /**
+     * Returns a Signed whose value is {@code (this - val)}.
+     *
+     * @param val value to be subtracted from this Signed.
+     * @return {@code this - val}
+     */
+    Signed subtract(int val);
+
+    /**
+     * Returns a Signed whose value is {@code (this * val)}.
+     *
+     * @param val value to be multiplied by this Signed.
+     * @return {@code this * val}
+     */
+    Signed multiply(int val);
+
+    /**
+     * Returns a Signed whose value is {@code (this / val)}.
+     *
+     * @param val value by which this Signed is to be divided.
+     * @return {@code this / val}
+     */
+    Signed signedDivide(int val);
+
+    /**
+     * Returns a Signed whose value is {@code (this % val)}.
+     *
+     * @param val value by which this Signed is to be divided, and the remainder computed.
+     * @return {@code this % val}
+     */
+    Signed signedRemainder(int val);
+
+    /**
+     * Returns a Signed whose value is {@code (this << n)}.
+     *
+     * @param n shift distance, in bits.
+     * @return {@code this << n}
+     */
+    Signed shiftLeft(int n);
+
+    /**
+     * Returns a Signed whose value is {@code (this >> n)}. Sign extension is performed.
+     *
+     * @param n shift distance, in bits.
+     * @return {@code this >> n}
+     */
+    Signed signedShiftRight(int n);
+
+    /**
+     * Returns a Signed whose value is {@code (this & val)}. (This method returns a negative Signed
+     * if and only if this and val are both negative.)
+     *
+     * @param val value to be AND'ed with this Signed.
+     * @return {@code this & val}
+     */
+    Signed and(int val);
+
+    /**
+     * Returns a Signed whose value is {@code (this | val)}. (This method returns a negative Signed
+     * if and only if either this or val is negative.)
+     *
+     * @param val value to be OR'ed with this Signed.
+     * @return {@code this | val}
+     */
+    Signed or(int val);
+
+    /**
+     * Returns a Signed whose value is {@code (this ^ val)}. (This method returns a negative Signed
+     * if and only if exactly one of this and val are negative.)
+     *
+     * @param val value to be XOR'ed with this Signed.
+     * @return {@code this ^ val}
+     */
+    Signed xor(int val);
+
+    /**
+     * Compares this Signed with the specified value.
+     *
+     * @param val value to which this Signed is to be compared.
+     * @return {@code this == val}
+     */
+    boolean equal(int val);
+
+    /**
+     * Compares this Signed with the specified value.
+     *
+     * @param val value to which this Signed is to be compared.
+     * @return {@code this != val}
+     */
+    boolean notEqual(int val);
+
+    /**
+     * Compares this Signed with the specified value.
+     *
+     * @param val value to which this Signed is to be compared.
+     * @return {@code this < val}
+     */
+    boolean lessThan(int val);
+
+    /**
+     * Compares this Signed with the specified value.
+     *
+     * @param val value to which this Signed is to be compared.
+     * @return {@code this <= val}
+     */
+    boolean lessOrEqual(int val);
+
+    /**
+     * Compares this Signed with the specified value.
+     *
+     * @param val value to which this Signed is to be compared.
+     * @return {@code this > val}
+     */
+    boolean greaterThan(int val);
+
+    /**
+     * Compares this Signed with the specified value.
+     *
+     * @param val value to which this Signed is to be compared.
+     * @return {@code this >= val}
+     */
+    boolean greaterOrEqual(int val);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.api.word/src/org/graalvm/api/word/Unsigned.java	Fri May 12 13:56:13 2017 -0700
@@ -0,0 +1,337 @@
+/*
+ * Copyright (c) 2012, 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.api.word;
+
+public interface Unsigned extends ComparableWord {
+
+    /**
+     * Returns a Unsigned whose value is {@code (this + val)}.
+     *
+     * @param val value to be added to this Unsigned.
+     * @return {@code this + val}
+     */
+    Unsigned add(Unsigned val);
+
+    /**
+     * Returns a Unsigned whose value is {@code (this - val)}.
+     *
+     * @param val value to be subtracted from this Unsigned.
+     * @return {@code this - val}
+     */
+    Unsigned subtract(Unsigned val);
+
+    /**
+     * Returns a Unsigned whose value is {@code (this * val)}.
+     *
+     * @param val value to be multiplied by this Unsigned.
+     * @return {@code this * val}
+     */
+    Unsigned multiply(Unsigned val);
+
+    /**
+     * Returns a Unsigned whose value is {@code (this / val)}.
+     *
+     * @param val value by which this Unsigned is to be divided.
+     * @return {@code this / val}
+     */
+    Unsigned unsignedDivide(Unsigned val);
+
+    /**
+     * Returns a Unsigned whose value is {@code (this % val)}.
+     *
+     * @param val value by which this Unsigned is to be divided, and the remainder computed.
+     * @return {@code this % val}
+     */
+    Unsigned unsignedRemainder(Unsigned val);
+
+    /**
+     * Returns a Unsigned whose value is {@code (this << n)}.
+     *
+     * @param n shift distance, in bits.
+     * @return {@code this << n}
+     */
+    Unsigned shiftLeft(Unsigned n);
+
+    /**
+     * Returns a Unsigned whose value is {@code (this >>> n)}. No sign extension is performed.
+     *
+     * @param n shift distance, in bits.
+     * @return {@code this >> n}
+     */
+    Unsigned unsignedShiftRight(Unsigned n);
+
+    /**
+     * Returns a Unsigned whose value is {@code (this & val)}.
+     *
+     * @param val value to be AND'ed with this Unsigned.
+     * @return {@code this & val}
+     */
+    Unsigned and(Unsigned val);
+
+    /**
+     * Returns a Unsigned whose value is {@code (this | val)}.
+     *
+     * @param val value to be OR'ed with this Unsigned.
+     * @return {@code this | val}
+     */
+    Unsigned or(Unsigned val);
+
+    /**
+     * Returns a Unsigned whose value is {@code (this ^ val)}.
+     *
+     * @param val value to be XOR'ed with this Unsigned.
+     * @return {@code this ^ val}
+     */
+    Unsigned xor(Unsigned val);
+
+    /**
+     * Returns a Unsigned whose value is {@code (~this)}.
+     *
+     * @return {@code ~this}
+     */
+    Unsigned not();
+
+    /**
+     * Compares this Unsigned with the specified value.
+     *
+     * @param val value to which this Unsigned is to be compared.
+     * @return {@code this == val}
+     */
+    boolean equal(Unsigned val);
+
+    /**
+     * Compares this Unsigned with the specified value.
+     *
+     * @param val value to which this Unsigned is to be compared.
+     * @return {@code this != val}
+     */
+    boolean notEqual(Unsigned val);
+
+    /**
+     * Compares this Unsigned with the specified value.
+     *
+     * @param val value to which this Unsigned is to be compared.
+     * @return {@code this < val}
+     */
+    boolean belowThan(Unsigned val);
+
+    /**
+     * Compares this Unsigned with the specified value.
+     *
+     * @param val value to which this Unsigned is to be compared.
+     * @return {@code this <= val}
+     */
+    boolean belowOrEqual(Unsigned val);
+
+    /**
+     * Compares this Unsigned with the specified value.
+     *
+     * @param val value to which this Unsigned is to be compared.
+     * @return {@code this > val}
+     */
+    boolean aboveThan(Unsigned val);
+
+    /**
+     * Compares this Unsigned with the specified value.
+     *
+     * @param val value to which this Unsigned is to be compared.
+     * @return {@code this >= val}
+     */
+    boolean aboveOrEqual(Unsigned val);
+
+    /**
+     * Returns a Unsigned whose value is {@code (this + val)}.
+     * <p>
+     * Note that the right operand is a signed value, while the operation is performed unsigned.
+     * Therefore, the result is only well-defined for positive right operands.
+     *
+     * @param val value to be added to this Unsigned.
+     * @return {@code this + val}
+     */
+    Unsigned add(int val);
+
+    /**
+     * Returns a Unsigned whose value is {@code (this - val)}.
+     * <p>
+     * Note that the right operand is a signed value, while the operation is performed unsigned.
+     * Therefore, the result is only well-defined for positive right operands.
+     *
+     * @param val value to be subtracted from this Unsigned.
+     * @return {@code this - val}
+     */
+    Unsigned subtract(int val);
+
+    /**
+     * Returns a Unsigned whose value is {@code (this * val)}.
+     * <p>
+     * Note that the right operand is a signed value, while the operation is performed unsigned.
+     * Therefore, the result is only well-defined for positive right operands.
+     *
+     * @param val value to be multiplied by this Unsigned.
+     * @return {@code this * val}
+     */
+    Unsigned multiply(int val);
+
+    /**
+     * Returns a Unsigned whose value is {@code (this / val)}.
+     * <p>
+     * Note that the right operand is a signed value, while the operation is performed unsigned.
+     * Therefore, the result is only well-defined for positive right operands.
+     *
+     * @param val value by which this Unsigned is to be divided.
+     * @return {@code this / val}
+     */
+    Unsigned unsignedDivide(int val);
+
+    /**
+     * Returns a Unsigned whose value is {@code (this % val)}.
+     * <p>
+     * Note that the right operand is a signed value, while the operation is performed unsigned.
+     * Therefore, the result is only well-defined for positive right operands.
+     *
+     * @param val value by which this Unsigned is to be divided, and the remainder computed.
+     * @return {@code this % val}
+     */
+    Unsigned unsignedRemainder(int val);
+
+    /**
+     * Returns a Unsigned whose value is {@code (this << n)}.
+     * <p>
+     * Note that the right operand is a signed value, while the operation is performed unsigned.
+     * Therefore, the result is only well-defined for positive right operands.
+     *
+     * @param n shift distance, in bits.
+     * @return {@code this << n}
+     */
+    Unsigned shiftLeft(int n);
+
+    /**
+     * Returns a Unsigned whose value is {@code (this >>> n)}. No sign extension is performed.
+     * <p>
+     * Note that the right operand is a signed value, while the operation is performed unsigned.
+     * Therefore, the result is only well-defined for positive right operands.
+     *
+     * @param n shift distance, in bits.
+     * @return {@code this >> n}
+     */
+    Unsigned unsignedShiftRight(int n);
+
+    /**
+     * Returns a Unsigned whose value is {@code (this & val)}.
+     * <p>
+     * Note that the right operand is a signed value, while the operation is performed unsigned.
+     * Therefore, the result is only well-defined for positive right operands.
+     *
+     * @param val value to be AND'ed with this Unsigned.
+     * @return {@code this & val}
+     */
+    Unsigned and(int val);
+
+    /**
+     * Returns a Unsigned whose value is {@code (this | val)}.
+     * <p>
+     * Note that the right operand is a signed value, while the operation is performed unsigned.
+     * Therefore, the result is only well-defined for positive right operands.
+     *
+     * @param val value to be OR'ed with this Unsigned.
+     * @return {@code this | val}
+     */
+    Unsigned or(int val);
+
+    /**
+     * Returns a Unsigned whose value is {@code (this ^ val)}.
+     * <p>
+     * Note that the right operand is a signed value, while the operation is performed unsigned.
+     * Therefore, the result is only well-defined for positive right operands.
+     *
+     * @param val value to be XOR'ed with this Unsigned.
+     * @return {@code this ^ val}
+     */
+    Unsigned xor(int val);
+
+    /**
+     * Compares this Unsigned with the specified value.
+     * <p>
+     * Note that the right operand is a signed value, while the operation is performed unsigned.
+     * Therefore, the result is only well-defined for positive right operands.
+     *
+     * @param val value to which this Unsigned is to be compared.
+     * @return {@code this == val}
+     */
+    boolean equal(int val);
+
+    /**
+     * Compares this Unsigned with the specified value.
+     * <p>
+     * Note that the right operand is a signed value, while the operation is performed unsigned.
+     * Therefore, the result is only well-defined for positive right operands.
+     *
+     * @param val value to which this Unsigned is to be compared.
+     * @return {@code this != val}
+     */
+    boolean notEqual(int val);
+
+    /**
+     * Compares this Unsigned with the specified value.
+     * <p>
+     * Note that the right operand is a signed value, while the operation is performed unsigned.
+     * Therefore, the result is only well-defined for positive right operands.
+     *
+     * @param val value to which this Unsigned is to be compared.
+     * @return {@code this < val}
+     */
+    boolean belowThan(int val);
+
+    /**
+     * Compares this Unsigned with the specified value.
+     * <p>
+     * Note that the right operand is a signed value, while the operation is performed unsigned.
+     * Therefore, the result is only well-defined for positive right operands.
+     *
+     * @param val value to which this Unsigned is to be compared.
+     * @return {@code this <= val}
+     */
+    boolean belowOrEqual(int val);
+
+    /**
+     * Compares this Unsigned with the specified value.
+     * <p>
+     * Note that the right operand is a signed value, while the operation is performed unsigned.
+     * Therefore, the result is only well-defined for positive right operands.
+     *
+     * @param val value to which this Unsigned is to be compared.
+     * @return {@code this > val}
+     */
+    boolean aboveThan(int val);
+
+    /**
+     * Compares this Unsigned with the specified value.
+     * <p>
+     * Note that the right operand is a signed value, while the operation is performed unsigned.
+     * Therefore, the result is only well-defined for positive right operands.
+     *
+     * @param val value to which this Unsigned is to be compared.
+     * @return {@code this >= val}
+     */
+    boolean aboveOrEqual(int val);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.api.word/src/org/graalvm/api/word/UnsignedUtils.java	Fri May 12 13:56:13 2017 -0700
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2015, 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
+ * 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.api.word;
+
+/**
+ * Utility methods on Unsigned values.
+ */
+public final class UnsignedUtils {
+
+    private UnsignedUtils() {
+        // This is a class of static methods, so no need for any instances.
+    }
+
+    /**
+     * Round an Unsigned down to the nearest smaller multiple.
+     *
+     * @param that The Unsigned to be rounded down.
+     * @param multiple The multiple to which that Unsigned should be decreased.
+     * @return That Unsigned, but rounded down.
+     */
+    public static Unsigned roundDown(Unsigned that, Unsigned multiple) {
+        return that.unsignedDivide(multiple).multiply(multiple);
+    }
+
+    /**
+     * Round an Unsigned up to the nearest larger multiple.
+     *
+     * @param that The Unsigned to be rounded up.
+     * @param multiple The multiple to which that Unsigned should be increased.
+     * @return That Unsigned, but rounded up.
+     */
+    public static Unsigned roundUp(Unsigned that, Unsigned multiple) {
+        return UnsignedUtils.roundDown(that.add(multiple.subtract(1)), multiple);
+    }
+
+    /**
+     * Check that an Unsigned is an even multiple.
+     *
+     * @param that The Unsigned to be verified as a multiple.
+     * @param multiple The multiple against which the Unsigned should be verified.
+     * @return true if that Unsigned is a multiple, false otherwise.
+     */
+    public static boolean isAMultiple(Unsigned that, Unsigned multiple) {
+        return that.equal(UnsignedUtils.roundDown(that, multiple));
+    }
+
+    /**
+     * The minimum of two Unsigneds.
+     *
+     * @param x An Unsigned.
+     * @param y Another Unsigned.
+     * @return The whichever Unsigned is smaller.
+     */
+    public static Unsigned min(Unsigned x, Unsigned y) {
+        return (x.belowOrEqual(y)) ? x : y;
+    }
+
+    /**
+     * The maximum of two Unsigneds.
+     *
+     * @param x An Unsigned.
+     * @param y Another Unsigned.
+     * @return The whichever Unsigned is larger.
+     */
+    public static Unsigned max(Unsigned x, Unsigned y) {
+        return (x.aboveOrEqual(y)) ? x : y;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.api.word/src/org/graalvm/api/word/WordBase.java	Fri May 12 13:56:13 2017 -0700
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2012, 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.api.word;
+
+public interface WordBase {
+
+    long rawValue();
+
+    /**
+     * This is deprecated because of the easy to mistype name collision between {@link #equals} and
+     * the other word based equality routines. In general you should never be statically calling
+     * this method anyway.
+     */
+    @Override
+    @Deprecated
+    boolean equals(Object o);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.api.word/src/org/graalvm/api/word/WordFactory.java	Fri May 12 13:56:13 2017 -0700
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2012, 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.api.word;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.reflect.InvocationTargetException;
+
+public abstract class WordFactory {
+
+    /**
+     * Links a method to a canonical operation represented by an {@link FactoryOpcode} val.
+     */
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.METHOD)
+    protected @interface FactoryOperation {
+        FactoryOpcode opcode();
+    }
+
+    /**
+     * The canonical {@link FactoryOperation} represented by a method in a word type.
+     */
+    protected enum FactoryOpcode {
+        ZERO,
+        FROM_UNSIGNED,
+        FROM_SIGNED,
+    }
+
+    protected interface BoxFactory {
+        <T extends WordBase> T box(long val);
+    }
+
+    protected static final BoxFactory boxFactory;
+
+    static {
+        try {
+            /*
+             * We know the implementation class, but cannot reference it statically because we need
+             * to break the dependency between the interface and the implementation.
+             */
+            boxFactory = (BoxFactory) Class.forName("org.graalvm.compiler.word.Word$BoxFactoryImpl").getConstructor().newInstance();
+        } catch (ClassNotFoundException | NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
+            throw new ExceptionInInitializerError("Could not find and initialize the word type factory. The Graal compiler needs to be on the class path to use the word type.");
+        }
+    }
+
+    /**
+     * We allow subclassing, because only subclasses can access the protected inner classes that we
+     * use to mark the operations.
+     */
+    protected WordFactory() {
+    }
+
+    /**
+     * The constant 0, i.e., the word with no bits set. There is no difference between a signed and
+     * unsigned zero.
+     *
+     * @return the constant 0.
+     */
+    @FactoryOperation(opcode = FactoryOpcode.ZERO)
+    public static <T extends WordBase> T zero() {
+        return boxFactory.box(0L);
+    }
+
+    /**
+     * Unsafe conversion from a Java long value to a Word. The parameter is treated as an unsigned
+     * 64-bit value (in contrast to the semantics of a Java long).
+     *
+     * @param val a 64 bit unsigned value
+     * @return the value cast to Word
+     */
+    @FactoryOperation(opcode = FactoryOpcode.FROM_UNSIGNED)
+    public static <T extends Unsigned> T unsigned(long val) {
+        return boxFactory.box(val);
+    }
+
+    /**
+     * Unsafe conversion from a Java long value to a {@link PointerBase pointer}. The parameter is
+     * treated as an unsigned 64-bit value (in contrast to the semantics of a Java long).
+     *
+     * @param val a 64 bit unsigned value
+     * @return the value cast to PointerBase
+     */
+    @FactoryOperation(opcode = FactoryOpcode.FROM_UNSIGNED)
+    public static <T extends PointerBase> T pointer(long val) {
+        return boxFactory.box(val);
+    }
+
+    /**
+     * Unsafe conversion from a Java int value to a Word. The parameter is treated as an unsigned
+     * 32-bit value (in contrast to the semantics of a Java int).
+     *
+     * @param val a 32 bit unsigned value
+     * @return the value cast to Word
+     */
+    @FactoryOperation(opcode = FactoryOpcode.FROM_UNSIGNED)
+    public static <T extends Unsigned> T unsigned(int val) {
+        return boxFactory.box(val & 0xffffffffL);
+    }
+
+    /**
+     * Unsafe conversion from a Java long value to a Word. The parameter is treated as a signed
+     * 64-bit value (unchanged semantics of a Java long).
+     *
+     * @param val a 64 bit signed value
+     * @return the value cast to Word
+     */
+    @FactoryOperation(opcode = FactoryOpcode.FROM_SIGNED)
+    public static <T extends Signed> T signed(long val) {
+        return boxFactory.box(val);
+    }
+
+    /**
+     * Unsafe conversion from a Java int value to a Word. The parameter is treated as a signed
+     * 32-bit value (unchanged semantics of a Java int).
+     *
+     * @param val a 32 bit signed value
+     * @return the value cast to Word
+     */
+    @FactoryOperation(opcode = FactoryOpcode.FROM_SIGNED)
+    public static <T extends Signed> T signed(int val) {
+        return boxFactory.box(val);
+    }
+}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.test/src/org/graalvm/compiler/api/test/Graal.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.test/src/org/graalvm/compiler/api/test/Graal.java	Fri May 12 13:56:13 2017 -0700
@@ -24,13 +24,13 @@
 
 import java.util.Formatter;
 
+import org.graalvm.compiler.api.runtime.GraalJVMCICompiler;
+import org.graalvm.compiler.api.runtime.GraalRuntime;
+
 import jdk.vm.ci.runtime.JVMCI;
 import jdk.vm.ci.runtime.JVMCICompiler;
 import jdk.vm.ci.services.Services;
 
-import org.graalvm.compiler.api.runtime.GraalJVMCICompiler;
-import org.graalvm.compiler.api.runtime.GraalRuntime;
-
 /**
  * Access point for {@linkplain #getRuntime() retrieving} the {@link GraalRuntime} instance of the
  * system compiler from unit tests.
@@ -40,7 +40,7 @@
     private static final GraalRuntime runtime = initializeRuntime();
 
     private static GraalRuntime initializeRuntime() {
-        Services.exportJVMCITo(Graal.class);
+        Services.initializeJVMCI();
         JVMCICompiler compiler = JVMCI.getRuntime().getCompiler();
         if (compiler instanceof GraalJVMCICompiler) {
             GraalJVMCICompiler graal = (GraalJVMCICompiler) compiler;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64.test/src/org/graalvm/compiler/asm/amd64/test/SimpleAssemblerTest.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64.test/src/org/graalvm/compiler/asm/amd64/test/SimpleAssemblerTest.java	Fri May 12 13:56:13 2017 -0700
@@ -27,6 +27,16 @@
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 
+import org.graalvm.compiler.asm.amd64.AMD64Assembler;
+import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.asm.test.AssemblerTest;
+import org.graalvm.compiler.code.CompilationResult;
+import org.graalvm.compiler.code.DataSection.Data;
+import org.graalvm.compiler.code.DataSection.RawData;
+import org.graalvm.compiler.code.DataSection.SerializableData;
+import org.junit.Before;
+import org.junit.Test;
+
 import jdk.vm.ci.amd64.AMD64;
 import jdk.vm.ci.code.CallingConvention;
 import jdk.vm.ci.code.Register;
@@ -36,17 +46,6 @@
 import jdk.vm.ci.meta.JavaConstant;
 import jdk.vm.ci.meta.JavaKind;
 
-import org.junit.Before;
-import org.junit.Test;
-
-import org.graalvm.compiler.asm.amd64.AMD64Assembler;
-import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
-import org.graalvm.compiler.asm.test.AssemblerTest;
-import org.graalvm.compiler.code.CompilationResult;
-import org.graalvm.compiler.code.DataSection.Data;
-import org.graalvm.compiler.code.DataSection.RawData;
-import org.graalvm.compiler.code.DataSection.SerializableData;
-
 public class SimpleAssemblerTest extends AssemblerTest {
 
     @Before
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.test/src/org/graalvm/compiler/asm/test/AssemblerTest.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.test/src/org/graalvm/compiler/asm/test/AssemblerTest.java	Fri May 12 13:56:13 2017 -0700
@@ -37,7 +37,6 @@
 import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.runtime.RuntimeProvider;
 import org.graalvm.compiler.serviceprovider.GraalServices;
-import org.graalvm.compiler.test.AddExports;
 import org.graalvm.compiler.test.GraalTest;
 import org.junit.Assert;
 
@@ -52,7 +51,6 @@
 import jdk.vm.ci.runtime.JVMCI;
 import jdk.vm.ci.runtime.JVMCIBackend;
 
-@AddExports("jdk.internal.vm.ci/jdk.vm.ci.runtime")
 public abstract class AssemblerTest extends GraalTest {
 
     private final MetaAccessProvider metaAccess;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/Bytecode.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/Bytecode.java	Fri May 12 13:56:13 2017 -0700
@@ -63,6 +63,11 @@
 
     ExceptionHandler[] getExceptionHandlers();
 
+    /**
+     * Gets the {@link BytecodeProvider} from which this object was acquired.
+     */
+    BytecodeProvider getOrigin();
+
     static String toLocation(Bytecode bytecode, int bci) {
         return appendLocation(new StringBuilder(), bytecode, bci).toString();
     }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/ResolvedJavaMethodBytecode.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/ResolvedJavaMethodBytecode.java	Fri May 12 13:56:13 2017 -0700
@@ -36,9 +36,20 @@
 public class ResolvedJavaMethodBytecode implements Bytecode {
 
     private final ResolvedJavaMethod method;
+    private final BytecodeProvider origin;
 
     public ResolvedJavaMethodBytecode(ResolvedJavaMethod method) {
+        this(method, ResolvedJavaMethodBytecodeProvider.INSTANCE);
+    }
+
+    public ResolvedJavaMethodBytecode(ResolvedJavaMethod method, BytecodeProvider origin) {
         this.method = method;
+        this.origin = origin;
+    }
+
+    @Override
+    public BytecodeProvider getOrigin() {
+        return origin;
     }
 
     @Override
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/ResolvedJavaMethodBytecodeProvider.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/ResolvedJavaMethodBytecodeProvider.java	Fri May 12 13:56:13 2017 -0700
@@ -29,9 +29,14 @@
  */
 public class ResolvedJavaMethodBytecodeProvider implements BytecodeProvider {
 
+    /**
+     * A state-less, shared {@link ResolvedJavaMethodBytecodeProvider} instance.
+     */
+    public static final ResolvedJavaMethodBytecodeProvider INSTANCE = new ResolvedJavaMethodBytecodeProvider();
+
     @Override
     public Bytecode getBytecode(ResolvedJavaMethod method) {
-        return new ResolvedJavaMethodBytecode(method);
+        return new ResolvedJavaMethodBytecode(method, this);
     }
 
     @Override
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64LIRKindTool.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64LIRKindTool.java	Fri May 12 13:56:13 2017 -0700
@@ -66,4 +66,13 @@
         return LIRKind.value(AArch64Kind.QWORD);
     }
 
+    @Override
+    public LIRKind getNarrowOopKind() {
+        return LIRKind.reference(AArch64Kind.DWORD);
+    }
+
+    @Override
+    public LIRKind getNarrowPointerKind() {
+        return LIRKind.value(AArch64Kind.DWORD);
+    }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64LIRKindTool.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64LIRKindTool.java	Fri May 12 13:56:13 2017 -0700
@@ -66,4 +66,13 @@
         return LIRKind.value(AMD64Kind.QWORD);
     }
 
+    @Override
+    public LIRKind getNarrowOopKind() {
+        return LIRKind.reference(AMD64Kind.DWORD);
+    }
+
+    @Override
+    public LIRKind getNarrowPointerKind() {
+        return LIRKind.value(AMD64Kind.DWORD);
+    }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/LIRKind.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/LIRKind.java	Fri May 12 13:56:13 2017 -0700
@@ -22,7 +22,7 @@
  */
 package org.graalvm.compiler.core.common;
 
-import java.util.ArrayList;
+import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig;
 
 import jdk.vm.ci.code.Architecture;
 import jdk.vm.ci.meta.AllocatableValue;
@@ -170,23 +170,6 @@
     }
 
     /**
-     * Merge the types of the inputs. The result will have the {@link PlatformKind} of one of the
-     * inputs. If all inputs are values (references), the result is a value (reference). Otherwise,
-     * the result is an unknown reference.
-     *
-     * This method should be used to construct the result {@link LIRKind} of merge operation that
-     * does not modify values (e.g. phis).
-     */
-    public static LIRKind merge(Value... inputs) {
-        assert inputs.length > 0;
-        ArrayList<LIRKind> kinds = new ArrayList<>(inputs.length);
-        for (int i = 0; i < inputs.length; i++) {
-            kinds.add(inputs[i].getValueKind(LIRKind.class));
-        }
-        return merge(kinds);
-    }
-
-    /**
      * Helper method to construct derived reference kinds. Returns the base value of a reference or
      * derived reference. For values it returns {@code null}, and for unknown references it returns
      * {@link Value#ILLEGAL}.
@@ -228,62 +211,62 @@
     }
 
     /**
-     * @see #merge(Value...)
+     * Merges the reference information of the inputs. The result will have the {@link PlatformKind}
+     * of {@code mergeKind}. If all inputs are values (references), the result is a value
+     * (reference). Otherwise, the result is an unknown reference.
+     *
+     * The correctness of the {@link PlatformKind} is not verified.
      */
-    public static LIRKind merge(Iterable<LIRKind> kinds) {
-        LIRKind mergeKind = null;
-
-        for (LIRKind kind : kinds) {
+    public static LIRKind mergeReferenceInformation(LIRKind mergeKind, LIRKind inputKind) {
+        assert mergeKind != null;
+        assert inputKind != null;
 
-            if (kind.isUnknownReference()) {
-                /**
-                 * Kind is an unknown reference, therefore the result can only be also an unknown
-                 * reference.
-                 */
-                mergeKind = kind;
-                break;
-            }
-            if (mergeKind == null) {
-                mergeKind = kind;
-                continue;
-            }
+        if (mergeKind.isUnknownReference()) {
+            /**
+             * {@code mergeKind} is an unknown reference, therefore the result can only be also an
+             * unknown reference.
+             */
+            return mergeKind;
+        }
 
-            if (kind.isValue()) {
-                /* Kind is a value. */
-                if (mergeKind.referenceMask != 0) {
-                    /*
-                     * Inputs consists of values and references. Make the result an unknown
-                     * reference.
-                     */
-                    mergeKind = mergeKind.makeUnknownReference();
-                    break;
-                }
-                /* Check that other inputs are also values. */
-            } else {
-                /* Kind is a reference. */
-                if (mergeKind.referenceMask != kind.referenceMask) {
-                    /*
-                     * Reference maps do not match so the result can only be an unknown reference.
-                     */
-                    mergeKind = mergeKind.makeUnknownReference();
-                    break;
-                }
+        if (mergeKind.isValue()) {
+            /* {@code mergeKind} is a value. */
+            if (!inputKind.isValue()) {
+                /*
+                 * Inputs consists of values and references. Make the result an unknown reference.
+                 */
+                return mergeKind.makeUnknownReference();
             }
-
+            return mergeKind;
+        }
+        /* {@code mergeKind} is a reference. */
+        if (mergeKind.referenceMask != inputKind.referenceMask) {
+            /*
+             * Reference masks do not match so the result can only be an unknown reference.
+             */
+            return mergeKind.makeUnknownReference();
         }
-        assert mergeKind != null && verifyMerge(mergeKind, kinds);
 
-        // all inputs are values or references, just return one of them
+        /* Both are references. */
+        if (mergeKind.isDerivedReference()) {
+            if (inputKind.isDerivedReference() && mergeKind.getDerivedReferenceBase().equals(inputKind.getDerivedReferenceBase())) {
+                /* Same reference base so they must be equal. */
+                return mergeKind;
+            }
+            /* Base pointers differ. Make the result an unknown reference. */
+            return mergeKind.makeUnknownReference();
+        }
+        if (inputKind.isDerivedReference()) {
+            /*
+             * {@code mergeKind} is not derived but {@code inputKind} is. Make the result an unknown
+             * reference.
+             */
+            return mergeKind.makeUnknownReference();
+        }
+        /* Both are not derived references so they must be equal. */
         return mergeKind;
     }
 
-    private static boolean verifyMerge(LIRKind mergeKind, Iterable<LIRKind> kinds) {
-        for (LIRKind kind : kinds) {
-            assert mergeKind == null || verifyMoveKinds(mergeKind, kind) : String.format("Input kinds do not match %s vs. %s", mergeKind, kind);
-        }
-        return true;
-    }
-
     /**
      * Create a new {@link LIRKind} with the same reference information and a new
      * {@linkplain #getPlatformKind platform kind}. If the new kind is a longer vector than this,
@@ -447,6 +430,7 @@
         final int prime = 31;
         int result = 1;
         result = prime * result + ((getPlatformKind() == null) ? 0 : getPlatformKind().hashCode());
+        result = prime * result + ((getDerivedReferenceBase() == null) ? 0 : getDerivedReferenceBase().hashCode());
         result = prime * result + referenceMask;
         return result;
     }
@@ -461,16 +445,37 @@
         }
 
         LIRKind other = (LIRKind) obj;
-        return getPlatformKind() == other.getPlatformKind() && referenceMask == other.referenceMask;
+        if (getPlatformKind() != other.getPlatformKind() || referenceMask != other.referenceMask) {
+            return false;
+        }
+        if (isDerivedReference()) {
+            if (!other.isDerivedReference()) {
+                return false;
+            }
+            return getDerivedReferenceBase().equals(other.getDerivedReferenceBase());
+        }
+        // `this` is not a derived reference
+        if (other.isDerivedReference()) {
+            return false;
+        }
+        return true;
     }
 
-    public static boolean verifyMoveKinds(ValueKind<?> dst, ValueKind<?> src) {
+    public static boolean verifyMoveKinds(ValueKind<?> dst, ValueKind<?> src, RegisterAllocationConfig config) {
         if (src.equals(dst)) {
             return true;
         }
-        if (src.getPlatformKind().equals(dst.getPlatformKind())) {
-            return !isUnknownReference(src) || isUnknownReference(dst);
+        if (isUnknownReference(dst) || isValue(dst) && isValue(src)) {
+            PlatformKind srcPlatformKind = src.getPlatformKind();
+            PlatformKind dstPlatformKind = dst.getPlatformKind();
+            if (srcPlatformKind.equals(dstPlatformKind)) {
+                return true;
+            }
+            // if the register category matches it should be fine, although the kind is different
+            return config.getRegisterCategory(srcPlatformKind).equals(config.getRegisterCategory(dstPlatformKind));
         }
+        // reference information mismatch
         return false;
     }
+
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/LocationIdentity.java	Fri May 12 13:14:25 2017 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,107 +0,0 @@
-/*
- * Copyright (c) 2011, 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.core.common;
-
-// JaCoCo Exclude
-
-/**
- * Marker interface for location identities. A different location identity of two memory accesses
- * guarantees that the two accesses do not interfere.
- *
- * Clients of {@link LocationIdentity} must use {@link #equals(Object)}, not {@code ==}, when
- * comparing two {@link LocationIdentity} values for equality. Likewise, they must not use
- * {@link java.util.IdentityHashMap}s with {@link LocationIdentity} values as keys.
- */
-public abstract class LocationIdentity {
-
-    private static final class AnyLocationIdentity extends LocationIdentity {
-        @Override
-        public boolean isImmutable() {
-            return false;
-        }
-
-        @Override
-        public String toString() {
-            return "ANY_LOCATION";
-        }
-    }
-
-    private static final class InitLocationIdentity extends LocationIdentity {
-        @Override
-        public boolean isImmutable() {
-            return true;
-        }
-
-        @Override
-        public String toString() {
-            return "INIT_LOCATION";
-        }
-    }
-
-    public static final LocationIdentity ANY_LOCATION = new AnyLocationIdentity();
-    public static final LocationIdentity INIT_LOCATION = new InitLocationIdentity();
-
-    /**
-     * Indicates that the given location is the union of all possible mutable locations. A write to
-     * such a location kill all reads from mutable locations and a read from this location is killed
-     * by any write (except for initialization writes).
-     */
-    public static LocationIdentity any() {
-        return ANY_LOCATION;
-    }
-
-    /**
-     * Location only allowed to be used for writes. Indicates that a completely new memory location
-     * is written. Kills no read. The previous value at the given location must be either
-     * uninitialized or null. Writes to this location do not need a GC pre-barrier.
-     */
-    public static LocationIdentity init() {
-        return INIT_LOCATION;
-    }
-
-    /**
-     * Denotes a location is unchanging in all cases. Not that this is different than the Java
-     * notion of final which only requires definite assignment.
-     */
-    public abstract boolean isImmutable();
-
-    public final boolean isMutable() {
-        return !isImmutable();
-    }
-
-    public final boolean isAny() {
-        return this == ANY_LOCATION;
-    }
-
-    public final boolean isInit() {
-        return this == INIT_LOCATION;
-    }
-
-    public final boolean isSingle() {
-        return this != ANY_LOCATION;
-    }
-
-    public final boolean overlaps(LocationIdentity other) {
-        return isAny() || other.isAny() || this.equals(other);
-    }
-}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/RegisterAllocationConfig.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/RegisterAllocationConfig.java	Fri May 12 13:56:13 2017 -0700
@@ -27,6 +27,7 @@
 import org.graalvm.util.Equivalence;
 
 import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.Register.RegisterCategory;
 import jdk.vm.ci.code.RegisterArray;
 import jdk.vm.ci.code.RegisterConfig;
 import jdk.vm.ci.meta.PlatformKind;
@@ -120,6 +121,13 @@
         return ret;
     }
 
+    /**
+     * Gets the {@link RegisterCategory} for the given {@link PlatformKind}.
+     */
+    public RegisterCategory getRegisterCategory(PlatformKind kind) {
+        return getAllocatableRegisters(kind).allocatableRegisters[0].getRegisterCategory();
+    }
+
     protected AllocatableRegisters createAllocatableRegisters(RegisterArray registers) {
         int min = Integer.MAX_VALUE;
         int max = Integer.MIN_VALUE;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/ForeignCallsProvider.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/ForeignCallsProvider.java	Fri May 12 13:56:13 2017 -0700
@@ -22,8 +22,8 @@
  */
 package org.graalvm.compiler.core.common.spi;
 
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.core.common.LIRKind;
-import org.graalvm.compiler.core.common.LocationIdentity;
 
 import jdk.vm.ci.code.ValueKindFactory;
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/LIRKindTool.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/LIRKindTool.java	Fri May 12 13:56:13 2017 -0700
@@ -48,4 +48,14 @@
      * Get the architecture specific kind pointer-sized integer kind.
      */
     LIRKind getWordKind();
+
+    /**
+     * Get the platform specific kind used to represent compressed oops.
+     */
+    LIRKind getNarrowOopKind();
+
+    /**
+     * Gets the platform specific kind used to represent compressed metaspace pointers.
+     */
+    LIRKind getNarrowPointerKind();
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/ObjectStamp.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/ObjectStamp.java	Fri May 12 13:56:13 2017 -0700
@@ -80,6 +80,14 @@
 
     @Override
     public Constant readConstant(MemoryAccessProvider provider, Constant base, long displacement) {
-        return provider.readObjectConstant(base, displacement);
+        try {
+            return provider.readObjectConstant(base, displacement);
+        } catch (IllegalArgumentException e) {
+            /*
+             * It's possible that the base and displacement aren't valid together so simply return
+             * null.
+             */
+            return null;
+        }
     }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/PrimitiveStamp.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/PrimitiveStamp.java	Fri May 12 13:56:13 2017 -0700
@@ -54,7 +54,15 @@
 
     @Override
     public Constant readConstant(MemoryAccessProvider provider, Constant base, long displacement) {
-        return provider.readPrimitiveConstant(getStackKind(), base, displacement, getBits());
+        try {
+            return provider.readPrimitiveConstant(getStackKind(), base, displacement, getBits());
+        } catch (IllegalArgumentException e) {
+            /*
+             * It's possible that the base and displacement aren't valid together so simply return
+             * null.
+             */
+            return null;
+        }
     }
 
     @Override
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/Stamp.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/Stamp.java	Fri May 12 13:56:13 2017 -0700
@@ -145,6 +145,8 @@
 
     /**
      * Read a value of this stamp from memory.
+     *
+     * @return the value read or null if the value can't be read for some reason.
      */
     public abstract Constant readConstant(MemoryAccessProvider provider, Constant base, long displacement);
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/ModuleAPI.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/ModuleAPI.java	Fri May 12 13:56:13 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -22,13 +22,14 @@
  */
 package org.graalvm.compiler.core.common.util;
 
-import static org.graalvm.compiler.core.common.util.Util.JAVA_SPECIFICATION_VERSION;
+import static org.graalvm.compiler.serviceprovider.JDK9Method.JAVA_SPECIFICATION_VERSION;
 
-import java.lang.reflect.AccessibleObject;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 
+import org.graalvm.compiler.debug.GraalError;
+
 /**
  * Reflection based access to the Module API introduced by JDK 9. This allows the API to be used in
  * code that must be compiled on a JDK prior to 9. Use of this class must be guarded by a test for
@@ -42,11 +43,19 @@
  */
 public final class ModuleAPI {
 
-    private ModuleAPI(Method method) {
-        this.method = method;
+    public ModuleAPI(Class<?> declaringClass, String name, Class<?>... parameterTypes) {
+        try {
+            this.method = declaringClass.getMethod(name, parameterTypes);
+        } catch (Exception e) {
+            throw new GraalError(e);
+        }
     }
 
-    private final Method method;
+    public final Method method;
+
+    public Class<?> getReturnType() {
+        return method.getReturnType();
+    }
 
     /**
      * {@code Class.getModule()}.
@@ -54,36 +63,11 @@
     public static final ModuleAPI getModule;
 
     /**
-     * {@code jdk.internal.module.Modules.addExports(Module, String, Module)}.
-     */
-    public static final ModuleAPI addExports;
-
-    /**
-     * {@code jdk.internal.module.Modules.addOpens(Module, String, Module)}.
-     */
-    public static final ModuleAPI addOpens;
-
-    /**
      * {@code java.lang.Module.getResourceAsStream(String)}.
      */
     public static final ModuleAPI getResourceAsStream;
 
     /**
-     * {@code java.lang.Module.getPackages()}.
-     */
-    public static final ModuleAPI getPackages;
-
-    /**
-     * {@code java.lang.Module.canRead(Module)}.
-     */
-    public static final ModuleAPI canRead;
-
-    /**
-     * {@code java.lang.Module.isExported(String)}.
-     */
-    public static final ModuleAPI isExported;
-
-    /**
      * {@code java.lang.Module.isExported(String, Module)}.
      */
     public static final ModuleAPI isExportedTo;
@@ -98,7 +82,7 @@
         try {
             return (T) method.invoke(null, args);
         } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
-            throw new InternalError(e);
+            throw new GraalError(e);
         }
     }
 
@@ -112,84 +96,31 @@
         try {
             return (T) method.invoke(receiver, args);
         } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
-            throw new InternalError(e);
-        }
-    }
-
-    /**
-     * Opens all packages in {@code moduleMember}'s module for deep reflection (i.e., allow
-     * {@link AccessibleObject#setAccessible(boolean)} to be called for any class/method/field) by
-     * {@code requestor}'s module.
-     */
-    public static void openAllPackagesForReflectionTo(Class<?> moduleMember, Class<?> requestor) {
-        Object moduleToOpen = getModule.invoke(moduleMember);
-        Object requestorModule = getModule.invoke(requestor);
-        if (moduleToOpen != requestorModule) {
-            String[] packages = getPackages.invoke(moduleToOpen);
-            for (String pkg : packages) {
-                addOpens.invokeStatic(moduleToOpen, pkg, requestorModule);
-            }
+            throw new GraalError(e);
         }
     }
 
-    /**
-     * Opens {@code declaringClass}'s package to allow a method declared in {@code accessor} to call
-     * {@link AccessibleObject#setAccessible(boolean)} on an {@link AccessibleObject} representing a
-     * field or method declared by {@code declaringClass}.
-     */
-    public static void openForReflectionTo(Class<?> declaringClass, Class<?> accessor) {
-        Object moduleToOpen = getModule.invoke(declaringClass);
-        Object accessorModule = getModule.invoke(accessor);
-        if (moduleToOpen != accessorModule) {
-            addOpens.invokeStatic(moduleToOpen, declaringClass.getPackage().getName(), accessorModule);
-        }
-    }
-
-    /**
-     * Exports the package named {@code packageName} declared in {@code moduleMember}'s module to
-     * {@code requestor}'s module.
-     */
-    public static void exportPackageTo(Class<?> moduleMember, String packageName, Class<?> requestor) {
-        Object moduleToExport = getModule.invoke(moduleMember);
-        Object requestorModule = getModule.invoke(requestor);
-        if (moduleToExport != requestorModule) {
-            addExports.invokeStatic(moduleToExport, packageName, requestorModule);
-        }
-    }
-
-    private void checkAvailability() throws InternalError {
+    private void checkAvailability() throws GraalError {
         if (method == null) {
-            throw new InternalError("Cannot use Module API on JDK " + JAVA_SPECIFICATION_VERSION);
+            throw new GraalError("Cannot use Module API on JDK " + JAVA_SPECIFICATION_VERSION);
         }
     }
 
     static {
         if (JAVA_SPECIFICATION_VERSION >= 9) {
-            try {
-                getModule = new ModuleAPI(Class.class.getMethod("getModule"));
-                Class<?> moduleClass = getModule.method.getReturnType();
-                Class<?> modulesClass = Class.forName("jdk.internal.module.Modules");
-                getResourceAsStream = new ModuleAPI(moduleClass.getMethod("getResourceAsStream", String.class));
-                getPackages = new ModuleAPI(moduleClass.getMethod("getPackages"));
-                canRead = new ModuleAPI(moduleClass.getMethod("canRead", moduleClass));
-                isExported = new ModuleAPI(moduleClass.getMethod("isExported", String.class));
-                isExportedTo = new ModuleAPI(moduleClass.getMethod("isExported", String.class, moduleClass));
-                addExports = new ModuleAPI(modulesClass.getDeclaredMethod("addExports", moduleClass, String.class, moduleClass));
-                addOpens = new ModuleAPI(modulesClass.getDeclaredMethod("addOpens", moduleClass, String.class, moduleClass));
-            } catch (NoSuchMethodException | SecurityException | ClassNotFoundException e) {
-                throw new InternalError(e);
-            }
+            getModule = new ModuleAPI(Class.class, "getModule");
+            Class<?> moduleClass = getModule.getReturnType();
+            getResourceAsStream = new ModuleAPI(moduleClass, "getResourceAsStream", String.class);
+            isExportedTo = new ModuleAPI(moduleClass, "isExported", String.class, moduleClass);
         } else {
-            ModuleAPI unavailable = new ModuleAPI(null);
+            ModuleAPI unavailable = new ModuleAPI();
             getModule = unavailable;
             getResourceAsStream = unavailable;
-            getPackages = unavailable;
-            canRead = unavailable;
-            isExported = unavailable;
             isExportedTo = unavailable;
-            addExports = unavailable;
-            addOpens = unavailable;
         }
+    }
 
+    private ModuleAPI() {
+        method = null;
     }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/Util.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/Util.java	Fri May 12 13:56:13 2017 -0700
@@ -39,25 +39,6 @@
  */
 public class Util {
 
-    private static int getJavaSpecificationVersion() {
-        String value = System.getProperty("java.specification.version");
-        if (value.startsWith("1.")) {
-            value = value.substring(2);
-        }
-        return Integer.parseInt(value);
-    }
-
-    /**
-     * The integer value corresponding to the value of the {@code java.specification.version} system
-     * property after any leading {@code "1."} has been stripped.
-     */
-    public static final int JAVA_SPECIFICATION_VERSION = getJavaSpecificationVersion();
-
-    /**
-     * Determines if the Java runtime is version 8 or earlier.
-     */
-    public static final boolean Java8OrEarlier = JAVA_SPECIFICATION_VERSION <= 8;
-
     /**
      * Statically cast an object to an arbitrary Object type. Dynamically checked.
      */
@@ -193,9 +174,6 @@
      * {@code flag}.
      */
     public static void setAccessible(Field field, boolean flag) {
-        if (!Java8OrEarlier) {
-            ModuleAPI.openForReflectionTo(field.getDeclaringClass(), Util.class);
-        }
         field.setAccessible(flag);
     }
 
@@ -204,9 +182,6 @@
      * {@code flag}.
      */
     public static void setAccessible(Executable executable, boolean flag) {
-        if (!Java8OrEarlier) {
-            ModuleAPI.openForReflectionTo(executable.getDeclaringClass(), Util.class);
-        }
         executable.setAccessible(flag);
     }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCLIRKindTool.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCLIRKindTool.java	Fri May 12 13:56:13 2017 -0700
@@ -65,4 +65,14 @@
     public LIRKind getWordKind() {
         return LIRKind.value(SPARCKind.XWORD);
     }
+
+    @Override
+    public LIRKind getNarrowOopKind() {
+        return LIRKind.reference(SPARCKind.WORD);
+    }
+
+    @Override
+    public LIRKind getNarrowPointerKind() {
+        return LIRKind.value(SPARCKind.WORD);
+    }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CheckGraalInvariants.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CheckGraalInvariants.java	Fri May 12 13:56:13 2017 -0700
@@ -41,6 +41,7 @@
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
 
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.api.replacements.Snippet;
 import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter;
 import org.graalvm.compiler.api.replacements.Snippet.NonNullParameter;
@@ -50,7 +51,6 @@
 import org.graalvm.compiler.core.CompilerThreadFactory;
 import org.graalvm.compiler.core.CompilerThreadFactory.DebugConfigAccess;
 import org.graalvm.compiler.core.common.LIRKind;
-import org.graalvm.compiler.core.common.LocationIdentity;
 import org.graalvm.compiler.core.common.type.ArithmeticOpTable;
 import org.graalvm.compiler.debug.Debug;
 import org.graalvm.compiler.debug.DebugConfigScope;
@@ -79,6 +79,7 @@
 import org.graalvm.compiler.phases.verify.VerifyBailoutUsage;
 import org.graalvm.compiler.phases.verify.VerifyCallerSensitiveMethods;
 import org.graalvm.compiler.phases.verify.VerifyDebugUsage;
+import org.graalvm.compiler.phases.verify.VerifyInstanceOfUsage;
 import org.graalvm.compiler.phases.verify.VerifyUpdateUsages;
 import org.graalvm.compiler.phases.verify.VerifyUsageWithEquals;
 import org.graalvm.compiler.phases.verify.VerifyVirtualizableUsage;
@@ -167,7 +168,7 @@
         MetaAccessProvider metaAccess = providers.getMetaAccess();
 
         PhaseSuite<HighTierContext> graphBuilderSuite = new PhaseSuite<>();
-        Plugins plugins = new Plugins(new InvocationPlugins(metaAccess));
+        Plugins plugins = new Plugins(new InvocationPlugins());
         GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true);
         graphBuilderSuite.appendPhase(new GraphBuilderPhase(config));
         HighTierContext context = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.NONE);
@@ -365,6 +366,7 @@
         new VerifyVirtualizableUsage().apply(graph, context);
         new VerifyUpdateUsages().apply(graph, context);
         new VerifyBailoutUsage().apply(graph, context);
+        new VerifyInstanceOfUsage().apply(graph, context);
         if (graph.method().isBridge()) {
             BridgeMethodUtils.getBridgedMethod(graph.method());
         }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionTest.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionTest.java	Fri May 12 13:56:13 2017 -0700
@@ -28,14 +28,11 @@
 
 import java.util.Random;
 
-import jdk.vm.ci.meta.JavaConstant;
-
+import org.graalvm.compiler.core.common.calc.Condition;
 import org.junit.Test;
 
-import org.graalvm.compiler.core.common.calc.Condition;
-import org.graalvm.compiler.test.AddExports;
+import jdk.vm.ci.meta.JavaConstant;
 
-@AddExports("jdk.internal.vm.ci/jdk.vm.ci.meta")
 public class ConditionTest {
 
     @Test
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationMulTest.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationMulTest.java	Fri May 12 13:56:13 2017 -0700
@@ -25,7 +25,7 @@
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
-import org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase;
+import org.graalvm.compiler.phases.common.ConditionalEliminationPhase;
 import org.graalvm.compiler.phases.tiers.HighTierContext;
 import org.junit.Test;
 
@@ -75,9 +75,11 @@
     private StructuredGraph prepareGraph(String snippet) {
         StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO);
         HighTierContext context = getDefaultHighTierContext();
-        DominatorConditionalEliminationPhase.create(false).apply(graph, context);
+        new ConditionalEliminationPhase(false).apply(graph, context);
         CanonicalizerPhase c = new CanonicalizerPhase();
         c.apply(graph, context);
+        new ConditionalEliminationPhase(false).apply(graph, context);
+        c.apply(graph, context);
         return graph;
     }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest1.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest1.java	Fri May 12 13:56:13 2017 -0700
@@ -26,9 +26,8 @@
 import org.junit.Test;
 
 /**
- * Collection of tests for
- * {@link org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase} including those
- * that triggered bugs in this phase.
+ * Collection of tests for {@link org.graalvm.compiler.phases.common.ConditionalEliminationPhase}
+ * including those that triggered bugs in this phase.
  */
 public class ConditionalEliminationTest1 extends ConditionalEliminationTestBase {
     protected static int sink3;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest10.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest10.java	Fri May 12 13:56:13 2017 -0700
@@ -22,22 +22,21 @@
  */
 package org.graalvm.compiler.core.test;
 
-import org.junit.Assert;
-import org.junit.Test;
-
 import org.graalvm.compiler.api.directives.GraalDirectives;
 import org.graalvm.compiler.nodes.GuardNode;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
 import org.graalvm.compiler.nodes.spi.LoweringTool;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
-import org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase;
 import org.graalvm.compiler.phases.common.LoweringPhase;
+import org.graalvm.compiler.phases.common.ConditionalEliminationPhase;
 import org.graalvm.compiler.phases.tiers.PhaseContext;
+import org.junit.Assert;
+import org.junit.Test;
 
 /**
  * This test checks the combined action of
- * {@link org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase} and
+ * {@link org.graalvm.compiler.phases.common.ConditionalEliminationPhase} and
  * {@link org.graalvm.compiler.phases.common.LoweringPhase}. The lowering phase needs to introduce
  * the null checks at the correct places for the dominator conditional elimination phase to pick
  * them up.
@@ -95,7 +94,7 @@
         StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
         PhaseContext context = new PhaseContext(getProviders());
         new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
-        DominatorConditionalEliminationPhase.create(true).apply(graph, context);
+        new ConditionalEliminationPhase(true).apply(graph, context);
         Assert.assertEquals(guardCount, graph.getNodes().filter(GuardNode.class).count());
     }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest11.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest11.java	Fri May 12 13:56:13 2017 -0700
@@ -27,9 +27,8 @@
 import org.junit.Test;
 
 /**
- * Collection of tests for
- * {@link org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase} including those
- * that triggered bugs in this phase.
+ * Collection of tests for {@link org.graalvm.compiler.phases.common.ConditionalEliminationPhase}
+ * including those that triggered bugs in this phase.
  */
 public class ConditionalEliminationTest11 extends ConditionalEliminationTestBase {
     @SuppressWarnings("all")
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest2.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest2.java	Fri May 12 13:56:13 2017 -0700
@@ -22,22 +22,20 @@
  */
 package org.graalvm.compiler.core.test;
 
-import org.junit.Test;
-
 import org.graalvm.compiler.nodes.GuardNode;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
 import org.graalvm.compiler.nodes.spi.LoweringTool;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
-import org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase;
 import org.graalvm.compiler.phases.common.FloatingReadPhase;
 import org.graalvm.compiler.phases.common.LoweringPhase;
+import org.graalvm.compiler.phases.common.ConditionalEliminationPhase;
 import org.graalvm.compiler.phases.tiers.PhaseContext;
+import org.junit.Test;
 
 /**
- * Collection of tests for
- * {@link org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase} including those
- * that triggered bugs in this phase.
+ * Collection of tests for {@link org.graalvm.compiler.phases.common.ConditionalEliminationPhase}
+ * including those that triggered bugs in this phase.
  */
 public class ConditionalEliminationTest2 extends ConditionalEliminationTestBase {
 
@@ -103,7 +101,7 @@
         new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
         canonicalizer.apply(graph, context);
         new FloatingReadPhase().apply(graph);
-        DominatorConditionalEliminationPhase.create(true).apply(graph, context);
+        new ConditionalEliminationPhase(true).apply(graph, context);
         canonicalizer.apply(graph, context);
 
         assertDeepEquals(1, graph.getNodes().filter(GuardNode.class).count());
@@ -125,7 +123,7 @@
 
         new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
         canonicalizer.apply(graph, context);
-        DominatorConditionalEliminationPhase.create(true).apply(graph, context);
+        new ConditionalEliminationPhase(true).apply(graph, context);
         canonicalizer.apply(graph, context);
 
         assertDeepEquals(0, graph.getNodes().filter(GuardNode.class).count());
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest3.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest3.java	Fri May 12 13:56:13 2017 -0700
@@ -26,9 +26,8 @@
 import org.junit.Test;
 
 /**
- * Collection of tests for
- * {@link org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase} including those
- * that triggered bugs in this phase.
+ * Collection of tests for {@link org.graalvm.compiler.phases.common.ConditionalEliminationPhase}
+ * including those that triggered bugs in this phase.
  */
 @Ignore
 public class ConditionalEliminationTest3 extends ConditionalEliminationTestBase {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest4.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest4.java	Fri May 12 13:56:13 2017 -0700
@@ -25,9 +25,8 @@
 import org.junit.Test;
 
 /**
- * Collection of tests for
- * {@link org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase} including those
- * that triggered bugs in this phase.
+ * Collection of tests for {@link org.graalvm.compiler.phases.common.ConditionalEliminationPhase}
+ * including those that triggered bugs in this phase.
  */
 public class ConditionalEliminationTest4 extends ConditionalEliminationTestBase {
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest5.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest5.java	Fri May 12 13:56:13 2017 -0700
@@ -27,9 +27,8 @@
 import org.junit.Test;
 
 /**
- * Collection of tests for
- * {@link org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase} including those
- * that triggered bugs in this phase.
+ * Collection of tests for {@link org.graalvm.compiler.phases.common.ConditionalEliminationPhase}
+ * including those that triggered bugs in this phase.
  */
 public class ConditionalEliminationTest5 extends ConditionalEliminationTestBase {
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest6.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest6.java	Fri May 12 13:56:13 2017 -0700
@@ -25,9 +25,8 @@
 import org.junit.Test;
 
 /**
- * Collection of tests for
- * {@link org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase} including those
- * that triggered bugs in this phase.
+ * Collection of tests for {@link org.graalvm.compiler.phases.common.ConditionalEliminationPhase}
+ * including those that triggered bugs in this phase.
  */
 public class ConditionalEliminationTest6 extends ConditionalEliminationTestBase {
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest7.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest7.java	Fri May 12 13:56:13 2017 -0700
@@ -26,9 +26,8 @@
 import org.junit.Test;
 
 /**
- * Collection of tests for
- * {@link org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase} including those
- * that triggered bugs in this phase.
+ * Collection of tests for {@link org.graalvm.compiler.phases.common.ConditionalEliminationPhase}
+ * including those that triggered bugs in this phase.
  */
 @Ignore
 public class ConditionalEliminationTest7 extends ConditionalEliminationTestBase {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest8.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest8.java	Fri May 12 13:56:13 2017 -0700
@@ -25,9 +25,8 @@
 import org.junit.Test;
 
 /**
- * Collection of tests for
- * {@link org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase} including those
- * that triggered bugs in this phase.
+ * Collection of tests for {@link org.graalvm.compiler.phases.common.ConditionalEliminationPhase}
+ * including those that triggered bugs in this phase.
  */
 public class ConditionalEliminationTest8 extends ConditionalEliminationTestBase {
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest9.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest9.java	Fri May 12 13:56:13 2017 -0700
@@ -27,9 +27,8 @@
 import org.graalvm.compiler.api.directives.GraalDirectives;
 
 /**
- * Collection of tests for
- * {@link org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase} including those
- * that triggered bugs in this phase.
+ * Collection of tests for {@link org.graalvm.compiler.phases.common.ConditionalEliminationPhase}
+ * including those that triggered bugs in this phase.
  */
 public class ConditionalEliminationTest9 extends ConditionalEliminationTestBase {
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTestBase.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTestBase.java	Fri May 12 13:56:13 2017 -0700
@@ -29,17 +29,16 @@
 import org.graalvm.compiler.nodes.spi.LoweringTool;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.common.ConvertDeoptimizeToGuardPhase;
-import org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase;
 import org.graalvm.compiler.phases.common.IterativeConditionalEliminationPhase;
 import org.graalvm.compiler.phases.common.LoweringPhase;
+import org.graalvm.compiler.phases.common.ConditionalEliminationPhase;
 import org.graalvm.compiler.phases.schedule.SchedulePhase;
 import org.graalvm.compiler.phases.tiers.PhaseContext;
 import org.junit.Assert;
 
 /**
- * Collection of tests for
- * {@link org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase} including those
- * that triggered bugs in this phase.
+ * Collection of tests for {@link org.graalvm.compiler.phases.common.ConditionalEliminationPhase}
+ * including those that triggered bugs in this phase.
  */
 public class ConditionalEliminationTestBase extends GraalCompilerTest {
     protected static int sink0;
@@ -70,7 +69,7 @@
         try (Debug.Scope scope = Debug.scope("ConditionalEliminationTest.ReferenceGraph", referenceGraph)) {
             prepareGraph(referenceGraph, canonicalizer, context, applyLowering);
             if (applyConditionalEliminationOnReference) {
-                DominatorConditionalEliminationPhase.create(true).apply(referenceGraph, context);
+                new ConditionalEliminationPhase(true).apply(referenceGraph, context);
             }
             canonicalizer.apply(referenceGraph, context);
             canonicalizer.apply(referenceGraph, context);
@@ -102,7 +101,7 @@
         canonicalizer.apply(graph, context);
 
         int baseProxyCount = graph.getNodes().filter(ProxyNode.class).count();
-        DominatorConditionalEliminationPhase.create(true).apply(graph, context);
+        new ConditionalEliminationPhase(true).apply(graph, context);
         canonicalizer.apply(graph, context);
         new SchedulePhase(graph.getOptions()).apply(graph, context);
         int actualProxiesCreated = graph.getNodes().filter(ProxyNode.class).count() - baseProxyCount;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CountedLoopTest.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CountedLoopTest.java	Fri May 12 13:56:13 2017 -0700
@@ -35,9 +35,9 @@
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.calc.FloatingNode;
-import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration;
 import org.graalvm.compiler.nodes.spi.LIRLowerable;
 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
@@ -242,10 +242,8 @@
     }
 
     @Override
-    protected Plugins getDefaultGraphBuilderPlugins() {
-        Plugins plugins = super.getDefaultGraphBuilderPlugins();
-        Registration r = new Registration(plugins.getInvocationPlugins(), CountedLoopTest.class);
-
+    protected void registerInvocationPlugins(InvocationPlugins invocationPlugins) {
+        Registration r = new Registration(invocationPlugins, CountedLoopTest.class);
         r.register2("get", IVProperty.class, int.class, new InvocationPlugin() {
             @Override
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg1, ValueNode arg2) {
@@ -261,8 +259,7 @@
                 }
             }
         });
-
-        return plugins;
+        super.registerInvocationPlugins(invocationPlugins);
     }
 
     @Override
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java	Fri May 12 13:56:13 2017 -0700
@@ -52,7 +52,6 @@
 import org.graalvm.compiler.core.GraalCompiler.Request;
 import org.graalvm.compiler.core.common.CompilationIdentifier;
 import org.graalvm.compiler.core.common.type.StampFactory;
-import org.graalvm.compiler.core.common.util.ModuleAPI;
 import org.graalvm.compiler.core.target.Backend;
 import org.graalvm.compiler.debug.Debug;
 import org.graalvm.compiler.debug.Debug.Scope;
@@ -72,6 +71,7 @@
 import org.graalvm.compiler.nodeinfo.NodeSize;
 import org.graalvm.compiler.nodeinfo.Verbosity;
 import org.graalvm.compiler.nodes.BreakpointNode;
+import org.graalvm.compiler.nodes.Cancellable;
 import org.graalvm.compiler.nodes.ConstantNode;
 import org.graalvm.compiler.nodes.FixedWithNextNode;
 import org.graalvm.compiler.nodes.FrameState;
@@ -112,6 +112,7 @@
 import org.graalvm.compiler.runtime.RuntimeProvider;
 import org.graalvm.compiler.test.AddExports;
 import org.graalvm.compiler.test.GraalTest;
+import org.graalvm.compiler.test.JLModule;
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
@@ -133,7 +134,6 @@
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 import jdk.vm.ci.meta.ResolvedJavaType;
 import jdk.vm.ci.meta.SpeculationLog;
-import jdk.vm.ci.services.Services;
 
 /**
  * Base class for Graal compiler unit tests.
@@ -154,12 +154,7 @@
  * <p>
  * These tests will be run by the {@code mx unittest} command.
  */
-@AddExports({"jdk.internal.vm.ci/jdk.vm.ci.meta",
-                "jdk.internal.vm.ci/jdk.vm.ci.services",
-                "jdk.internal.vm.ci/jdk.vm.ci.code",
-                "jdk.internal.vm.ci/jdk.vm.ci.services",
-                "java.base/jdk.internal.org.objectweb.asm",
-                "java.base/jdk.internal.org.objectweb.asm.tree"})
+@AddExports({"java.base/jdk.internal.org.objectweb.asm", "java.base/jdk.internal.org.objectweb.asm.tree"})
 public abstract class GraalCompilerTest extends GraalTest {
 
     /**
@@ -180,18 +175,13 @@
     public static final Class<?> JAVA_BASE = Class.class;
 
     /**
-     * Representative class for the {@code jdk.vm.ci} module.
-     */
-    public static final Class<?> JDK_VM_CI = Services.class;
-
-    /**
      * Exports the package named {@code packageName} declared in {@code moduleMember}'s module to
      * this object's module. This must be called before accessing packages that are no longer public
      * as of JDK 9.
      */
     protected final void exportPackage(Class<?> moduleMember, String packageName) {
         if (!Java8OrEarlier) {
-            ModuleAPI.exportPackageTo(moduleMember, packageName, getClass());
+            JLModule.exportPackageTo(moduleMember, packageName, getClass());
         }
     }
 
@@ -382,6 +372,15 @@
 
     @After
     public void afterTest() {
+        if (invocationPluginExtensions != null) {
+            synchronized (this) {
+                if (invocationPluginExtensions != null) {
+                    extendedInvocationPlugins.removeTestPlugins(invocationPluginExtensions);
+                    extendedInvocationPlugins = null;
+                    invocationPluginExtensions = null;
+                }
+            }
+        }
         if (debugScope != null) {
             debugScope.close();
         }
@@ -1191,8 +1190,15 @@
     private StructuredGraph parse1(ResolvedJavaMethod javaMethod, PhaseSuite<HighTierContext> graphBuilderSuite, AllowAssumptions allowAssumptions, CompilationIdentifier compilationId,
                     OptionValues options) {
         assert javaMethod.getAnnotation(Test.class) == null : "shouldn't parse method with @Test annotation: " + javaMethod;
-        StructuredGraph graph = new StructuredGraph.Builder(options, allowAssumptions).method(javaMethod).speculationLog(getSpeculationLog()).useProfilingInfo(true).compilationId(
-                        compilationId).build();
+        // @formatter:off
+        StructuredGraph graph = new StructuredGraph.Builder(options, allowAssumptions).
+                        method(javaMethod).
+                        speculationLog(getSpeculationLog()).
+                        useProfilingInfo(true).
+                        compilationId(compilationId).
+                        cancellable(getCancellable(javaMethod)).
+                        build();
+        // @formatter:on
         try (Scope ds = Debug.scope("Parsing", javaMethod, graph)) {
             graphBuilderSuite.apply(graph, getDefaultHighTierContext());
             return graph;
@@ -1201,6 +1207,16 @@
         }
     }
 
+    /**
+     * Gets the cancellable that should be associated with a graph being created by any of the
+     * {@code parse...()} methods.
+     *
+     * @param method the method being parsed into a graph
+     */
+    protected Cancellable getCancellable(ResolvedJavaMethod method) {
+        return null;
+    }
+
     protected Plugins getDefaultGraphBuilderPlugins() {
         PhaseSuite<HighTierContext> suite = backend.getSuites().getDefaultGraphBuilderSuite();
         Plugins defaultPlugins = ((GraphBuilderPhase) suite.findPhase(GraphBuilderPhase.class).previous()).getGraphBuilderConfig().getPlugins();
@@ -1213,17 +1229,16 @@
         return backend.getSuites().getDefaultGraphBuilderSuite().copy();
     }
 
-    protected PhaseSuite<HighTierContext> getCustomGraphBuilderSuite(GraphBuilderConfiguration gbConf) {
-        PhaseSuite<HighTierContext> suite = getDefaultGraphBuilderSuite();
-        ListIterator<BasePhase<? super HighTierContext>> iterator = suite.findPhase(GraphBuilderPhase.class);
-        GraphBuilderConfiguration gbConfCopy = editGraphBuilderConfiguration(gbConf.copy());
-        iterator.remove();
-        iterator.add(new GraphBuilderPhase(gbConfCopy));
-        return suite;
-    }
-
-    protected GraphBuilderConfiguration editGraphBuilderConfiguration(GraphBuilderConfiguration conf) {
-        InvocationPlugins invocationPlugins = conf.getPlugins().getInvocationPlugins();
+    /**
+     * Registers extra invocation plugins for this test. The extra plugins are removed in the
+     * {@link #afterTest()} method.
+     *
+     * Subclasses overriding this method should always call the same method on the super class in
+     * case it wants to register plugins.
+     *
+     * @param invocationPlugins
+     */
+    protected void registerInvocationPlugins(InvocationPlugins invocationPlugins) {
         invocationPlugins.register(new InvocationPlugin() {
             @Override
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
@@ -1245,7 +1260,41 @@
                 return true;
             }
         }, GraalCompilerTest.class, "shouldBeOptimizedAway");
+    }
 
+    /**
+     * The {@link #testN(int, String, Object...)} method means multiple threads trying to initialize
+     * this field.
+     */
+    private volatile InvocationPlugins invocationPluginExtensions;
+
+    private InvocationPlugins extendedInvocationPlugins;
+
+    protected PhaseSuite<HighTierContext> getCustomGraphBuilderSuite(GraphBuilderConfiguration gbConf) {
+        PhaseSuite<HighTierContext> suite = getDefaultGraphBuilderSuite();
+        ListIterator<BasePhase<? super HighTierContext>> iterator = suite.findPhase(GraphBuilderPhase.class);
+        initializeInvocationPluginExtensions();
+        GraphBuilderConfiguration gbConfCopy = editGraphBuilderConfiguration(gbConf.copy());
+        iterator.remove();
+        iterator.add(new GraphBuilderPhase(gbConfCopy));
+        return suite;
+    }
+
+    private void initializeInvocationPluginExtensions() {
+        if (invocationPluginExtensions == null) {
+            synchronized (this) {
+                if (invocationPluginExtensions == null) {
+                    InvocationPlugins invocationPlugins = new InvocationPlugins();
+                    registerInvocationPlugins(invocationPlugins);
+                    extendedInvocationPlugins = getReplacements().getGraphBuilderPlugins().getInvocationPlugins();
+                    extendedInvocationPlugins.addTestPlugins(invocationPlugins, null);
+                    invocationPluginExtensions = invocationPlugins;
+                }
+            }
+        }
+    }
+
+    protected GraphBuilderConfiguration editGraphBuilderConfiguration(GraphBuilderConfiguration conf) {
         conf.getPlugins().prependInlineInvokePlugin(new InlineInvokePlugin() {
 
             @Override
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GuardedIntrinsicTest.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GuardedIntrinsicTest.java	Fri May 12 13:56:13 2017 -0700
@@ -35,7 +35,6 @@
 import org.graalvm.compiler.nodes.debug.OpaqueNode;
 import org.graalvm.compiler.nodes.extended.LoadHubNode;
 import org.graalvm.compiler.nodes.extended.LoadMethodNode;
-import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin.Receiver;
@@ -118,8 +117,7 @@
     }
 
     @Override
-    protected GraphBuilderConfiguration editGraphBuilderConfiguration(GraphBuilderConfiguration conf) {
-        InvocationPlugins invocationPlugins = conf.getPlugins().getInvocationPlugins();
+    protected void registerInvocationPlugins(InvocationPlugins invocationPlugins) {
         Registration r = new Registration(invocationPlugins, Super.class);
 
         r.register1("getAge", Receiver.class, new InvocationPlugin() {
@@ -131,7 +129,7 @@
                 return true;
             }
         });
-        return super.editGraphBuilderConfiguration(conf);
+        super.registerInvocationPlugins(invocationPlugins);
     }
 
     public static int referenceMakeSuperAge() {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/IfCanonicalizerTest.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/IfCanonicalizerTest.java	Fri May 12 13:56:13 2017 -0700
@@ -196,6 +196,33 @@
         return (n < 0) ? 1 : (n >= 1024) ? 1024 : n + 1;
     }
 
+    @Test
+    public void test10() {
+        // Exercise NormalizeCompareNode with long values
+        test("test10Snippet", 0, 1);
+    }
+
+    public static long test10Snippet(int x, int y) {
+        return (x < y) ? -1L : ((x == y) ? 0L : 1L);
+    }
+
+    @Test
+    public void test11() {
+        test("test11Snippet", 0, 1);
+    }
+
+    public static long test11Snippet(int x, int y) {
+        long normalizeCompare = normalizeCompareLong(x, y);
+        if (normalizeCompare == 0) {
+            return 5;
+        }
+        return 1;
+    }
+
+    private static Long normalizeCompareLong(int x, int y) {
+        return (x < y) ? -1L : ((x == y) ? 0L : 1L);
+    }
+
     private void testCombinedIf(String snippet, int count) {
         StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
         PhaseContext context = new PhaseContext(getProviders());
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/LoopFullUnrollTest.java	Fri May 12 13:56:13 2017 -0700
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.Debug.Scope;
+import org.graalvm.compiler.debug.DebugDumpScope;
+import org.graalvm.compiler.loop.DefaultLoopPolicies;
+import org.graalvm.compiler.loop.phases.LoopFullUnrollPhase;
+import org.graalvm.compiler.nodes.LoopBeginNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+import org.junit.Test;
+
+public class LoopFullUnrollTest extends GraalCompilerTest {
+
+    public static int testMinToMax(int input) {
+        int ret = 2;
+        int current = input;
+        for (long i = Long.MIN_VALUE; i < Long.MAX_VALUE; i++) {
+            ret *= 2 + current;
+            current /= 50;
+        }
+        return ret;
+    }
+
+    @Test
+    public void runMinToMax() throws Throwable {
+        test("testMinToMax", 1);
+    }
+
+    public static int testMinTo0(int input) {
+        int ret = 2;
+        int current = input;
+        for (long i = Long.MIN_VALUE; i <= 0; i++) {
+            ret *= 2 + current;
+            current /= 50;
+        }
+        return ret;
+    }
+
+    @Test
+    public void runMinTo0() throws Throwable {
+        test("testMinTo0", 1);
+    }
+
+    public static int testNegativeTripCount(int input) {
+        int ret = 2;
+        int current = input;
+        for (long i = 0; i <= -20; i++) {
+            ret *= 2 + current;
+            current /= 50;
+        }
+        return ret;
+    }
+
+    @Test
+    public void runNegativeTripCount() throws Throwable {
+        test("testNegativeTripCount", 0);
+    }
+
+    @SuppressWarnings("try")
+    private void test(String snippet, int loopCount) {
+        try (Scope s = Debug.scope(getClass().getSimpleName(), new DebugDumpScope(snippet))) {
+            final StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO);
+
+            PhaseContext context = new PhaseContext(getProviders());
+            new LoopFullUnrollPhase(new CanonicalizerPhase(), new DefaultLoopPolicies()).apply(graph, context);
+
+            assertTrue(graph.getNodes().filter(LoopBeginNode.class).count() == loopCount);
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+    }
+}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MethodHandleEagerResolution.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MethodHandleEagerResolution.java	Fri May 12 13:56:13 2017 -0700
@@ -33,6 +33,7 @@
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
 import org.graalvm.compiler.test.AddExports;
 
+// Export needed to open String.value field to reflection by this test
 @AddExports("java.base/java.lang")
 public final class MethodHandleEagerResolution extends GraalCompilerTest {
     private static final MethodHandle FIELD_HANDLE;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/NarrowingReadTest.java	Fri May 12 13:56:13 2017 -0700
@@ -0,0 +1,68 @@
+/*
+ * 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.core.test;
+
+import org.junit.Test;
+
+/**
+ * Sometimes it's possible to emit a smaller read from a larger memory location instead reading the
+ * whole thing and truncating it. Make sure it returns the right value.
+ */
+public class NarrowingReadTest extends GraalCompilerTest {
+
+    public byte testNarrowReadSnippetByte(Long l) {
+        return (byte) l.longValue();
+    }
+
+    @Test
+    public void testNarrowReadByte() {
+        test("testNarrowReadSnippetByte", Long.valueOf(Byte.MAX_VALUE));
+    }
+
+    public short testNarrowReadSnippetShort(Long l) {
+        return (short) l.longValue();
+    }
+
+    @Test
+    public void testNarrowReadShort() {
+        test("testNarrowReadSnippetShort", Long.valueOf(Short.MAX_VALUE));
+    }
+
+    public int testNarrowReadSnippetInt(Long l) {
+        return (int) l.longValue();
+    }
+
+    @Test
+    public void testNarrowReadInt() {
+        test("testNarrowReadSnippetInt", Long.valueOf(Integer.MAX_VALUE));
+    }
+
+    public long testNarrowReadSnippetIntToLong(Long l) {
+        return (int) l.longValue();
+    }
+
+    @Test
+    public void testNarrowReadIntToLong() {
+        test("testNarrowReadSnippetIntToLong", Long.valueOf(Integer.MAX_VALUE));
+    }
+}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ReferenceGetLoopTest.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ReferenceGetLoopTest.java	Fri May 12 13:56:13 2017 -0700
@@ -27,8 +27,7 @@
 import java.lang.ref.WeakReference;
 
 import org.junit.Test;
-
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.loop.LoopEx;
 import org.graalvm.compiler.loop.LoopsData;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StampMemoryAccessTest.java	Fri May 12 13:56:13 2017 -0700
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.MemoryAccessProvider;
+
+/**
+ *
+ */
+public class StampMemoryAccessTest extends GraalCompilerTest {
+
+    @Ignore("not all JVMCI versions are safe yet")
+    @Test
+    public void testReadPrimitive() {
+        MemoryAccessProvider memory = getConstantReflection().getMemoryAccessProvider();
+        JavaConstant base = getSnippetReflection().forObject("");
+        Stamp stamp = StampFactory.forKind(JavaKind.Long);
+        assertTrue(stamp.readConstant(memory, base, 128) == null);
+    }
+
+    @Ignore("not all JVMCI versions are safe yet")
+    @Test
+    public void testReadObject() {
+        MemoryAccessProvider memory = getConstantReflection().getMemoryAccessProvider();
+        JavaConstant base = getSnippetReflection().forObject("");
+        Stamp stamp = StampFactory.forKind(JavaKind.Object);
+        assertTrue(stamp.readConstant(memory, base, 128) == null);
+    }
+}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StaticInterfaceFieldTest.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StaticInterfaceFieldTest.java	Fri May 12 13:56:13 2017 -0700
@@ -81,7 +81,7 @@
         MetaAccessProvider metaAccess = providers.getMetaAccess();
 
         PhaseSuite<HighTierContext> graphBuilderSuite = new PhaseSuite<>();
-        Plugins plugins = new Plugins(new InvocationPlugins(metaAccess));
+        Plugins plugins = new Plugins(new InvocationPlugins());
         GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true);
         graphBuilderSuite.appendPhase(new GraphBuilderPhase(config));
         HighTierContext context = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.NONE);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/TypeSystemTest.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/TypeSystemTest.java	Fri May 12 13:56:13 2017 -0700
@@ -28,10 +28,6 @@
 import java.io.IOException;
 import java.io.InputStream;
 
-import org.junit.Assert;
-import org.junit.Ignore;
-import org.junit.Test;
-
 import org.graalvm.compiler.debug.Debug;
 import org.graalvm.compiler.debug.TTY;
 import org.graalvm.compiler.graph.Node;
@@ -44,9 +40,12 @@
 import org.graalvm.compiler.nodes.cfg.Block;
 import org.graalvm.compiler.nodes.java.InstanceOfNode;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
-import org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase;
+import org.graalvm.compiler.phases.common.ConditionalEliminationPhase;
 import org.graalvm.compiler.phases.schedule.SchedulePhase;
 import org.graalvm.compiler.phases.tiers.PhaseContext;
+import org.junit.Assert;
+import org.junit.Ignore;
+import org.junit.Test;
 
 /**
  * In the following tests, the scalar type system of the compiler should be complete enough to see
@@ -186,12 +185,12 @@
          * tail-duplication gets activated thus resulting in a graph with more nodes than the
          * reference graph.
          */
-        DominatorConditionalEliminationPhase.create(false).apply(graph, new PhaseContext(getProviders()));
+        new ConditionalEliminationPhase(false).apply(graph, new PhaseContext(getProviders()));
         new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
         // a second canonicalizer is needed to process nested MaterializeNodes
         new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
         StructuredGraph referenceGraph = parseEager(referenceSnippet, AllowAssumptions.NO);
-        DominatorConditionalEliminationPhase.create(false).apply(referenceGraph, new PhaseContext(getProviders()));
+        new ConditionalEliminationPhase(false).apply(referenceGraph, new PhaseContext(getProviders()));
         new CanonicalizerPhase().apply(referenceGraph, new PhaseContext(getProviders()));
         new CanonicalizerPhase().apply(referenceGraph, new PhaseContext(getProviders()));
         assertEquals(referenceGraph, graph);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnbalancedMonitorsTest.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnbalancedMonitorsTest.java	Fri May 12 13:56:13 2017 -0700
@@ -86,7 +86,7 @@
         ResolvedJavaMethod method = getResolvedJavaMethod(LOADER.findClass(INNER_CLASS_NAME), name);
         try {
             StructuredGraph graph = new StructuredGraph.Builder(getInitialOptions()).method(method).build();
-            Plugins plugins = new Plugins(new InvocationPlugins(getMetaAccess()));
+            Plugins plugins = new Plugins(new InvocationPlugins());
             GraphBuilderConfiguration graphBuilderConfig = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true);
             OptimisticOptimizations optimisticOpts = OptimisticOptimizations.NONE;
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnusedArray.java	Fri May 12 13:56:13 2017 -0700
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2016, 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.core.test;
+
+import static org.graalvm.compiler.graph.test.matchers.NodeIterableIsEmpty.isEmpty;
+import static org.junit.Assert.assertThat;
+
+import org.graalvm.compiler.graph.iterators.NodeIterable;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.java.NewArrayNode;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+import org.junit.Test;
+
+public class UnusedArray extends GraalCompilerTest {
+    @SuppressWarnings("unused")
+    public void smallArray() {
+        byte[] array = new byte[3];
+    }
+
+    @SuppressWarnings("unused")
+    public void largeArray() {
+        byte[] array = new byte[10 * 1024 * 1024];
+    }
+
+    @SuppressWarnings("unused")
+    public void unknownArray(int l) {
+        byte[] array = new byte[l];
+    }
+
+    @Test
+    public void testSmall() {
+        test("smallArray");
+    }
+
+    @Test
+    public void testLarge() {
+        test("largeArray");
+    }
+
+    @Test
+    public void testUnknown() {
+        test("unknownArray");
+    }
+
+    public void test(String method) {
+        StructuredGraph graph = parseEager(method, StructuredGraph.AllowAssumptions.YES);
+        new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders()));
+        NodeIterable<NewArrayNode> newArrayNodes = graph.getNodes().filter(NewArrayNode.class);
+        assertThat(newArrayNodes, isEmpty());
+    }
+}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyBailoutUsageTest.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyBailoutUsageTest.java	Fri May 12 13:56:13 2017 -0700
@@ -121,7 +121,7 @@
         Providers providers = rt.getHostBackend().getProviders();
         MetaAccessProvider metaAccess = providers.getMetaAccess();
         PhaseSuite<HighTierContext> graphBuilderSuite = new PhaseSuite<>();
-        Plugins plugins = new Plugins(new InvocationPlugins(metaAccess));
+        Plugins plugins = new Plugins(new InvocationPlugins());
         GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true);
         graphBuilderSuite.appendPhase(new GraphBuilderPhase(config));
         HighTierContext context = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.NONE);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyDebugUsageTest.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyDebugUsageTest.java	Fri May 12 13:56:13 2017 -0700
@@ -328,7 +328,7 @@
         Providers providers = rt.getHostBackend().getProviders();
         MetaAccessProvider metaAccess = providers.getMetaAccess();
         PhaseSuite<HighTierContext> graphBuilderSuite = new PhaseSuite<>();
-        Plugins plugins = new Plugins(new InvocationPlugins(metaAccess));
+        Plugins plugins = new Plugins(new InvocationPlugins());
         GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true);
         graphBuilderSuite.appendPhase(new GraphBuilderPhase(config));
         HighTierContext context = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.NONE);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyVirtualizableTest.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyVirtualizableTest.java	Fri May 12 13:56:13 2017 -0700
@@ -266,7 +266,7 @@
         Providers providers = rt.getHostBackend().getProviders();
         MetaAccessProvider metaAccess = providers.getMetaAccess();
         PhaseSuite<HighTierContext> graphBuilderSuite = new PhaseSuite<>();
-        Plugins plugins = new Plugins(new InvocationPlugins(metaAccess));
+        Plugins plugins = new Plugins(new InvocationPlugins());
         GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true);
         graphBuilderSuite.appendPhase(new GraphBuilderPhase(config));
         HighTierContext context = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.NONE);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/backend/AllocatorTest.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/backend/AllocatorTest.java	Fri May 12 13:56:13 2017 -0700
@@ -91,8 +91,8 @@
         private void collectStats(final LIRInstruction instr) {
             instr.forEachOutput(collectStatsProc);
 
-            if (instr instanceof ValueMoveOp) {
-                ValueMoveOp move = (ValueMoveOp) instr;
+            if (ValueMoveOp.isValueMoveOp(instr)) {
+                ValueMoveOp move = ValueMoveOp.asValueMoveOp(instr);
                 Value def = move.getResult();
                 Value use = move.getInput();
                 if (ValueUtil.isRegister(def)) {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/debug/VerifyMethodMetricsTest.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/debug/VerifyMethodMetricsTest.java	Fri May 12 13:56:13 2017 -0700
@@ -247,7 +247,7 @@
         Providers providers = rt.getHostBackend().getProviders();
         MetaAccessProvider metaAccess = providers.getMetaAccess();
         PhaseSuite<HighTierContext> graphBuilderSuite = new PhaseSuite<>();
-        Plugins plugins = new Plugins(new InvocationPlugins(metaAccess));
+        Plugins plugins = new Plugins(new InvocationPlugins());
         GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true);
         graphBuilderSuite.appendPhase(new GraphBuilderPhase(config));
         HighTierContext context = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.NONE);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/tutorial/StaticAnalysis.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/tutorial/StaticAnalysis.java	Fri May 12 13:56:13 2017 -0700
@@ -252,7 +252,7 @@
                      * the code before static analysis, the classes would otherwise be not loaded
                      * yet and the bytecode parser would only create a graph.
                      */
-                    Plugins plugins = new Plugins(new InvocationPlugins(metaAccess));
+                    Plugins plugins = new Plugins(new InvocationPlugins());
                     GraphBuilderConfiguration graphBuilderConfig = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true);
                     /*
                      * For simplicity, we ignore all exception handling during the static analysis.
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompiler.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompiler.java	Fri May 12 13:56:13 2017 -0700
@@ -193,12 +193,11 @@
         String methodPattern = GraalCompilerOptions.CrashAt.getValue(graph.getOptions());
         if (methodPattern != null) {
             String crashLabel = null;
-            ResolvedJavaMethod method = graph.method();
-            if (method == null) {
-                if (graph.name.contains(methodPattern)) {
-                    crashLabel = graph.name;
-                }
-            } else {
+            if (graph.name != null && graph.name.contains(methodPattern)) {
+                crashLabel = graph.name;
+            }
+            if (crashLabel == null) {
+                ResolvedJavaMethod method = graph.method();
                 MethodFilter[] filters = MethodFilter.parse(methodPattern);
                 for (MethodFilter filter : filters) {
                     if (filter.matches(method)) {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalDebugInitializationParticipant.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalDebugInitializationParticipant.java	Fri May 12 13:56:13 2017 -0700
@@ -66,6 +66,10 @@
             params.enableMethodFilter = true;
         }
 
+        if (!params.enable && GraalDebugConfig.Options.DumpOnPhaseChange.getValue(options) != null) {
+            params.enable = true;
+        }
+
         if (!params.enableUnscopedMethodMetrics && GraalDebugConfig.Options.MethodMeter.getValue(options) != null) {
             // mm requires full debugging support
             params.enable = true;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/LIRGenerationPhase.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/LIRGenerationPhase.java	Fri May 12 13:56:13 2017 -0700
@@ -57,6 +57,7 @@
     }
 
     private static final DebugCounter instructionCounter = Debug.counter("GeneratedLIRInstructions");
+    private static final DebugCounter nodeCount = Debug.counter("FinalNodeCount");
 
     @Override
     protected final void run(TargetDescription target, LIRGenerationResult lirGenRes, LIRGenerationPhase.LIRGenerationContext context) {
@@ -68,6 +69,9 @@
         }
         context.lirGen.beforeRegisterAllocation();
         assert SSAUtil.verifySSAForm(lirGenRes.getLIR());
+        if (nodeCount.isEnabled()) {
+            nodeCount.add(graph.getNodeCount());
+        }
     }
 
     private static void emitBlock(NodeLIRBuilderTool nodeLirGen, LIRGenerationResult lirGenRes, Block b, StructuredGraph graph, BlockMap<List<Node>> blockMap) {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/NodeLIRBuilder.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/NodeLIRBuilder.java	Fri May 12 13:56:13 2017 -0700
@@ -243,32 +243,27 @@
     }
 
     protected LIRKind getExactPhiKind(PhiNode phi) {
-        // TODO (je): maybe turn this into generator-style instead of allocating an ArrayList.
-        ArrayList<LIRKind> values = new ArrayList<>(phi.valueCount());
-        for (int i = 0; i < phi.valueCount(); i++) {
+        LIRKind derivedKind = gen.toRegisterKind(gen.getLIRKind(phi.stamp()));
+        /* Collect reference information. */
+        for (int i = 0; i < phi.valueCount() && !derivedKind.isUnknownReference(); i++) {
             ValueNode node = phi.valueAt(i);
             Value value = getOperand(node);
+
+            // get ValueKind for input
+            final LIRKind valueKind;
             if (value != null) {
-                values.add(value.getValueKind(LIRKind.class));
+                valueKind = value.getValueKind(LIRKind.class);
             } else {
                 assert isPhiInputFromBackedge(phi, i) : String.format("Input %s to phi node %s is not yet available although it is not coming from a loop back edge", node, phi);
-                // non-java constant -> get LIRKind from stamp.
                 LIRKind kind = gen.getLIRKind(node.stamp());
-                values.add(gen.toRegisterKind(kind));
+                valueKind = gen.toRegisterKind(kind);
             }
+            /* Merge the reference information of the derived kind and the input. */
+            derivedKind = LIRKind.mergeReferenceInformation(derivedKind, valueKind);
         }
-        LIRKind derivedKind = LIRKind.merge(values);
-        assert verifyPHIKind(derivedKind, gen.getLIRKind(phi.stamp()));
         return derivedKind;
     }
 
-    private boolean verifyPHIKind(LIRKind derivedKind, LIRKind phiKind) {
-        PlatformKind derivedPlatformKind = derivedKind.getPlatformKind();
-        PlatformKind phiPlatformKind = gen.toRegisterKind(phiKind).getPlatformKind();
-        assert derivedPlatformKind.equals(phiPlatformKind) : "kinds don't match: " + derivedPlatformKind + " vs " + phiPlatformKind;
-        return true;
-    }
-
     private static boolean isPhiInputFromBackedge(PhiNode phi, int index) {
         AbstractMergeNode merge = phi.merge();
         AbstractEndNode end = merge.phiPredecessorAt(index);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/Debug.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/Debug.java	Fri May 12 13:56:13 2017 -0700
@@ -123,6 +123,12 @@
     }
 
     /**
+     * A special dump level that indicates the dumping machinery is enabled but no dumps will be
+     * produced except through other options.
+     */
+    public static final int ENABLED_LEVEL = 0;
+
+    /**
      * Basic debug level.
      *
      * For HIR dumping, only ~5 graphs per method: after parsing, after inlining, after high tier,
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/GraalDebugConfig.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/GraalDebugConfig.java	Fri May 12 13:56:13 2017 -0700
@@ -63,6 +63,9 @@
         public static final OptionKey<String> MethodFilter = new OptionKey<>(null);
         @Option(help = "Only check MethodFilter against the root method in the context if true, otherwise check all methods", type = OptionType.Debug)
         public static final OptionKey<Boolean> MethodFilterRootOnly = new OptionKey<>(false);
+        @Option(help = "Dump a before and after graph if the named phase changes the graph.%n" +
+                       "The argument is substring matched against the simple name of the phase class", type = OptionType.Debug)
+        public static final OptionKey<String> DumpOnPhaseChange = new OptionKey<>(null);
 
         @Option(help = "How to print counters and timing values:%n" +
                        "Name - aggregate by unqualified name%n" +
@@ -320,8 +323,8 @@
         } else {
             level = filter.matchLevel(Debug.currentScope());
         }
-        if (level > 0 && !checkMethodFilter()) {
-            level = 0;
+        if (level >= 0 && !checkMethodFilter()) {
+            level = -1;
         }
         return level;
     }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/DebugScope.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/DebugScope.java	Fri May 12 13:56:13 2017 -0700
@@ -235,7 +235,7 @@
     }
 
     public boolean isDumpEnabled(int dumpLevel) {
-        assert dumpLevel > 0;
+        assert dumpLevel >= 0;
         return currentDumpLevel >= dumpLevel;
     }
 
@@ -441,7 +441,7 @@
             memUseTrackingEnabled = false;
             timeEnabled = false;
             verifyEnabled = false;
-            currentDumpLevel = 0;
+            currentDumpLevel = -1;
             methodMetricsEnabled = false;
             // Be pragmatic: provide a default log stream to prevent a crash if the stream is not
             // set while logging
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/.checkstyle_checks.xml	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/.checkstyle_checks.xml	Fri May 12 13:56:13 2017 -0700
@@ -135,6 +135,30 @@
       <property name="format" value="new (Hashtable|Vector|Stack|StringBuffer)[^\w]"/>
       <property name="message" value="Don't use old synchronized collection classes"/>
     </module>
+    <module name="RegexpSinglelineJava">
+      <property name="format" value="instanceof MoveOp"/>
+      <property name="message" value="Do not use `op instanceof MoveOp`. Use `MoveOp.isMoveOp(op)` instead!"/>
+    </module>
+    <module name="RegexpSinglelineJava">
+      <property name="format" value="instanceof ValueMoveOp"/>
+      <property name="message" value="Do not use `op instanceof ValueMoveOp`. Use `ValueMoveOp.isValueMoveOp(op)` instead!"/>
+    </module>
+    <module name="RegexpSinglelineJava">
+      <property name="format" value="instanceof LoadConstantOp"/>
+      <property name="message" value="Do not use `op instanceof LoadConstantOp`. Use `LoadConstantOp.isLoadConstantOp(op)` instead!"/>
+    </module>
+    <module name="RegexpSinglelineJava">
+      <property name="format" value="\(MoveOp\)"/>
+      <property name="message" value="Do not cast directly to `MoveOp`. Use `MoveOp.asMoveOp(op)` instead!"/>
+    </module>
+    <module name="RegexpSinglelineJava">
+      <property name="format" value="\(ValueMoveOp\)"/>
+      <property name="message" value="Do not cast directly to `ValueMoveOp`. Use `ValueMoveOp.asValueMoveOp(op)` instead!"/>
+    </module>
+    <module name="RegexpSinglelineJava">
+      <property name="format" value="\(LoadConstantOp\)"/>
+      <property name="message" value="Do not cast directly to `LoadConstantOp`. Use `LoadConstantOp.asLoadConstantOp(op)` instead!"/>
+    </module>
   </module>
   <module name="RegexpHeader">
     <property name="header" value="/\*\n \* Copyright \(c\) (20[0-9][0-9], )?20[0-9][0-9], Oracle and/or its affiliates. All rights reserved.\n \* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n \*\n \* This code is free software; you can redistribute it and/or modify it\n \* under the terms of the GNU General Public License version 2 only, as\n \* published by the Free Software Foundation.\n \*\n \* This code is distributed in the hope that it will be useful, but WITHOUT\n \* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n \* FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License\n \* version 2 for more details \(a copy is included in the LICENSE file that\n \* accompanied this code\).\n \*\n \* You should have received a copy of the GNU General Public License version\n \* 2 along with this work; if not, write to the Free Software Foundation,\n \* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n \*\n \* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n \* or visit www.oracle.com if you need additional information or have any\n \* questions.\n \*/\n"/>
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackendFactory.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackendFactory.java	Fri May 12 13:56:13 2017 -0700
@@ -135,7 +135,7 @@
                 replacements = createReplacements(graalRuntime.getOptions(), p, snippetReflection, bytecodeProvider);
             }
             try (InitTimer rt = timer("create GraphBuilderPhase plugins")) {
-                plugins = createGraphBuilderPlugins(config, constantReflection, foreignCalls, metaAccess, snippetReflection, replacements, wordTypes, stampProvider);
+                plugins = createGraphBuilderPlugins(compilerConfiguration, config, constantReflection, foreignCalls, metaAccess, snippetReflection, replacements, wordTypes, stampProvider);
                 replacements.setGraphBuilderPlugins(plugins);
             }
             try (InitTimer rt = timer("create Suites provider")) {
@@ -150,11 +150,11 @@
         }
     }
 
-    protected Plugins createGraphBuilderPlugins(GraalHotSpotVMConfig config, HotSpotConstantReflectionProvider constantReflection, HotSpotHostForeignCallsProvider foreignCalls,
-                    HotSpotMetaAccessProvider metaAccess, HotSpotSnippetReflectionProvider snippetReflection, HotSpotReplacementsImpl replacements, HotSpotWordTypes wordTypes,
-                    HotSpotStampProvider stampProvider) {
-        Plugins plugins = HotSpotGraphBuilderPlugins.create(config, wordTypes, metaAccess, constantReflection, snippetReflection, foreignCalls, stampProvider, replacements);
-        AArch64GraphBuilderPlugins.register(plugins, replacements.getReplacementBytecodeProvider());
+    protected Plugins createGraphBuilderPlugins(CompilerConfiguration compilerConfiguration, GraalHotSpotVMConfig config, HotSpotConstantReflectionProvider constantReflection,
+                    HotSpotHostForeignCallsProvider foreignCalls, HotSpotMetaAccessProvider metaAccess, HotSpotSnippetReflectionProvider snippetReflection, HotSpotReplacementsImpl replacements,
+                    HotSpotWordTypes wordTypes, HotSpotStampProvider stampProvider) {
+        Plugins plugins = HotSpotGraphBuilderPlugins.create(compilerConfiguration, config, wordTypes, metaAccess, constantReflection, snippetReflection, foreignCalls, stampProvider, replacements);
+        AArch64GraphBuilderPlugins.register(plugins, replacements.getDefaultReplacementBytecodeProvider());
         return plugins;
     }
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotForeignCallsProvider.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotForeignCallsProvider.java	Fri May 12 13:56:13 2017 -0700
@@ -26,7 +26,7 @@
 import static jdk.vm.ci.aarch64.AArch64.r3;
 import static jdk.vm.ci.hotspot.HotSpotCallingConventionType.NativeCall;
 import static jdk.vm.ci.meta.Value.ILLEGAL;
-import static org.graalvm.compiler.core.common.LocationIdentity.any;
+import static org.graalvm.api.word.LocationIdentity.any;
 import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.JUMP_ADDRESS;
 import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.RegisterEffect.PRESERVES_REGISTERS;
 import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.Transition.LEAF;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotLIRGenerator.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotLIRGenerator.java	Fri May 12 13:56:13 2017 -0700
@@ -29,13 +29,14 @@
 import java.util.function.Function;
 
 import org.graalvm.compiler.asm.Label;
-import org.graalvm.compiler.core.common.NumUtil;
 import org.graalvm.compiler.asm.aarch64.AArch64Address.AddressingMode;
 import org.graalvm.compiler.asm.aarch64.AArch64Assembler.ConditionFlag;
 import org.graalvm.compiler.core.aarch64.AArch64ArithmeticLIRGenerator;
 import org.graalvm.compiler.core.aarch64.AArch64LIRGenerator;
+import org.graalvm.compiler.core.aarch64.AArch64LIRKindTool;
 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.calc.Condition;
 import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
 import org.graalvm.compiler.core.common.spi.LIRKindTool;
@@ -93,7 +94,7 @@
     private HotSpotDebugInfoBuilder debugInfoBuilder;
 
     protected AArch64HotSpotLIRGenerator(HotSpotProviders providers, GraalHotSpotVMConfig config, LIRGenerationResult lirGenRes) {
-        this(new AArch64HotSpotLIRKindTool(), new AArch64ArithmeticLIRGenerator(), new AArch64HotSpotMoveFactory(), providers, config, lirGenRes);
+        this(new AArch64LIRKindTool(), new AArch64ArithmeticLIRGenerator(), new AArch64HotSpotMoveFactory(), providers, config, lirGenRes);
     }
 
     protected AArch64HotSpotLIRGenerator(LIRKindTool lirKindTool, AArch64ArithmeticLIRGenerator arithmeticLIRGen, MoveFactory moveFactory, HotSpotProviders providers, GraalHotSpotVMConfig config,
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotLIRKindTool.java	Fri May 12 13:14:25 2017 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 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
- * 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.aarch64;
-
-import org.graalvm.compiler.core.aarch64.AArch64LIRKindTool;
-import org.graalvm.compiler.core.common.LIRKind;
-import org.graalvm.compiler.hotspot.nodes.type.HotSpotLIRKindTool;
-
-import jdk.vm.ci.aarch64.AArch64Kind;
-
-public class AArch64HotSpotLIRKindTool extends AArch64LIRKindTool implements HotSpotLIRKindTool {
-
-    @Override
-    public LIRKind getNarrowOopKind() {
-        return LIRKind.reference(AArch64Kind.DWORD);
-    }
-
-    @Override
-    public LIRKind getNarrowPointerKind() {
-        return LIRKind.value(AArch64Kind.DWORD);
-    }
-}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64.test/src/org/graalvm/compiler/hotspot/amd64/test/DataPatchInConstantsTest.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64.test/src/org/graalvm/compiler/hotspot/amd64/test/DataPatchInConstantsTest.java	Fri May 12 13:56:13 2017 -0700
@@ -23,20 +23,15 @@
 
 package org.graalvm.compiler.hotspot.amd64.test;
 
+import static jdk.vm.ci.code.ValueUtil.asRegister;
 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
-import static jdk.vm.ci.code.ValueUtil.asRegister;
-
-import org.junit.Assume;
-import org.junit.Before;
-import org.junit.Test;
 
 import org.graalvm.compiler.asm.amd64.AMD64Address;
 import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
 import org.graalvm.compiler.graph.NodeClass;
-import org.graalvm.compiler.hotspot.nodes.CompressionNode;
-import org.graalvm.compiler.hotspot.nodes.type.NarrowOopStamp;
+import org.graalvm.compiler.hotspot.nodes.HotSpotCompressionNode;
 import org.graalvm.compiler.hotspot.test.HotSpotGraalCompilerTest;
 import org.graalvm.compiler.lir.LIRInstruction;
 import org.graalvm.compiler.lir.LIRInstructionClass;
@@ -46,12 +41,16 @@
 import org.graalvm.compiler.nodeinfo.NodeInfo;
 import org.graalvm.compiler.nodes.FixedWithNextNode;
 import org.graalvm.compiler.nodes.ValueNode;
-import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration;
 import org.graalvm.compiler.nodes.spi.LIRLowerable;
 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.nodes.type.NarrowOopStamp;
+import org.junit.Assume;
+import org.junit.Before;
+import org.junit.Test;
 
 import jdk.vm.ci.amd64.AMD64;
 import jdk.vm.ci.meta.AllocatableValue;
@@ -141,9 +140,8 @@
     }
 
     @Override
-    protected Plugins getDefaultGraphBuilderPlugins() {
-        Plugins plugins = super.getDefaultGraphBuilderPlugins();
-        Registration r = new Registration(plugins.getInvocationPlugins(), DataPatchInConstantsTest.class);
+    protected void registerInvocationPlugins(InvocationPlugins invocationPlugins) {
+        Registration r = new Registration(invocationPlugins, DataPatchInConstantsTest.class);
 
         r.register1("loadThroughPatch", Object.class, new InvocationPlugin() {
             @Override
@@ -156,14 +154,13 @@
         r.register1("loadThroughCompressedPatch", Object.class, new InvocationPlugin() {
             @Override
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg) {
-                ValueNode compressed = b.add(CompressionNode.compress(arg, runtime().getVMConfig().getOopEncoding()));
+                ValueNode compressed = b.add(HotSpotCompressionNode.compress(arg, runtime().getVMConfig().getOopEncoding()));
                 ValueNode patch = b.add(new LoadThroughPatchNode(compressed));
-                b.addPush(JavaKind.Object, CompressionNode.uncompress(patch, runtime().getVMConfig().getOopEncoding()));
+                b.addPush(JavaKind.Object, HotSpotCompressionNode.uncompress(patch, runtime().getVMConfig().getOopEncoding()));
                 return true;
             }
         });
-
-        return plugins;
+        super.registerInvocationPlugins(invocationPlugins);
     }
 
     @NodeInfo(cycles = CYCLES_2, size = SIZE_1)
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotAddressLowering.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotAddressLowering.java	Fri May 12 13:56:13 2017 -0700
@@ -39,11 +39,11 @@
 import org.graalvm.compiler.debug.DebugCounter;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
-import org.graalvm.compiler.hotspot.nodes.CompressionNode;
-import org.graalvm.compiler.hotspot.nodes.CompressionNode.CompressionOp;
 import org.graalvm.compiler.hotspot.nodes.GraalHotSpotVMConfigNode;
 import org.graalvm.compiler.hotspot.nodes.type.KlassPointerStamp;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.CompressionNode;
+import org.graalvm.compiler.nodes.CompressionNode.CompressionOp;
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.calc.FloatingNode;
 import org.graalvm.compiler.nodes.spi.LIRLowerable;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackendFactory.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackendFactory.java	Fri May 12 13:56:13 2017 -0700
@@ -136,7 +136,8 @@
                 replacements = createReplacements(options, p, snippetReflection, bytecodeProvider);
             }
             try (InitTimer rt = timer("create GraphBuilderPhase plugins")) {
-                plugins = createGraphBuilderPlugins(config, options, target, constantReflection, foreignCalls, metaAccess, snippetReflection, replacements, wordTypes, stampProvider);
+                plugins = createGraphBuilderPlugins(compilerConfiguration, config, options, target, constantReflection, foreignCalls, metaAccess, snippetReflection, replacements, wordTypes,
+                                stampProvider);
                 replacements.setGraphBuilderPlugins(plugins);
             }
             try (InitTimer rt = timer("create Suites provider")) {
@@ -151,12 +152,11 @@
         }
     }
 
-    protected Plugins createGraphBuilderPlugins(GraalHotSpotVMConfig config, OptionValues options, TargetDescription target, HotSpotConstantReflectionProvider constantReflection,
-                    HotSpotHostForeignCallsProvider foreignCalls,
-                    HotSpotMetaAccessProvider metaAccess, HotSpotSnippetReflectionProvider snippetReflection, HotSpotReplacementsImpl replacements, HotSpotWordTypes wordTypes,
-                    HotSpotStampProvider stampProvider) {
-        Plugins plugins = HotSpotGraphBuilderPlugins.create(config, wordTypes, metaAccess, constantReflection, snippetReflection, foreignCalls, stampProvider, replacements);
-        AMD64GraphBuilderPlugins.register(plugins, replacements.getReplacementBytecodeProvider(), (AMD64) target.arch, GraalArithmeticStubs.getValue(options));
+    protected Plugins createGraphBuilderPlugins(CompilerConfiguration compilerConfiguration, GraalHotSpotVMConfig config, OptionValues options, TargetDescription target,
+                    HotSpotConstantReflectionProvider constantReflection, HotSpotHostForeignCallsProvider foreignCalls, HotSpotMetaAccessProvider metaAccess,
+                    HotSpotSnippetReflectionProvider snippetReflection, HotSpotReplacementsImpl replacements, HotSpotWordTypes wordTypes, HotSpotStampProvider stampProvider) {
+        Plugins plugins = HotSpotGraphBuilderPlugins.create(compilerConfiguration, config, wordTypes, metaAccess, constantReflection, snippetReflection, foreignCalls, stampProvider, replacements);
+        AMD64GraphBuilderPlugins.register(plugins, replacements.getDefaultReplacementBytecodeProvider(), (AMD64) target.arch, GraalArithmeticStubs.getValue(options));
         return plugins;
     }
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotForeignCallsProvider.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotForeignCallsProvider.java	Fri May 12 13:56:13 2017 -0700
@@ -26,7 +26,7 @@
 import static jdk.vm.ci.amd64.AMD64.rdx;
 import static jdk.vm.ci.hotspot.HotSpotCallingConventionType.NativeCall;
 import static jdk.vm.ci.meta.Value.ILLEGAL;
-import static org.graalvm.compiler.core.common.LocationIdentity.any;
+import static org.graalvm.api.word.LocationIdentity.any;
 import static org.graalvm.compiler.hotspot.HotSpotBackend.EXCEPTION_HANDLER;
 import static org.graalvm.compiler.hotspot.HotSpotBackend.EXCEPTION_HANDLER_IN_CALLER;
 import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.JUMP_ADDRESS;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Fri May 12 13:56:13 2017 -0700
@@ -35,6 +35,7 @@
 import org.graalvm.compiler.asm.amd64.AMD64Address.Scale;
 import org.graalvm.compiler.core.amd64.AMD64ArithmeticLIRGenerator;
 import org.graalvm.compiler.core.amd64.AMD64LIRGenerator;
+import org.graalvm.compiler.core.amd64.AMD64LIRKindTool;
 import org.graalvm.compiler.core.amd64.AMD64MoveFactoryBase.BackupSlotProvider;
 import org.graalvm.compiler.core.common.CompressEncoding;
 import org.graalvm.compiler.core.common.LIRKind;
@@ -52,7 +53,6 @@
 import org.graalvm.compiler.hotspot.debug.BenchmarkCounters;
 import org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction;
 import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
-import org.graalvm.compiler.hotspot.nodes.type.HotSpotLIRKindTool;
 import org.graalvm.compiler.hotspot.stubs.Stub;
 import org.graalvm.compiler.lir.LIR;
 import org.graalvm.compiler.lir.LIRFrameState;
@@ -111,7 +111,7 @@
     }
 
     private AMD64HotSpotLIRGenerator(HotSpotProviders providers, GraalHotSpotVMConfig config, LIRGenerationResult lirGenRes, BackupSlotProvider backupSlotProvider) {
-        this(new AMD64HotSpotLIRKindTool(), new AMD64HotSpotArithmeticLIRGenerator(), new AMD64HotSpotMoveFactory(backupSlotProvider), providers, config, lirGenRes);
+        this(new AMD64LIRKindTool(), new AMD64HotSpotArithmeticLIRGenerator(), new AMD64HotSpotMoveFactory(backupSlotProvider), providers, config, lirGenRes);
     }
 
     protected AMD64HotSpotLIRGenerator(LIRKindTool lirKindTool, AMD64ArithmeticLIRGenerator arithmeticLIRGen, MoveFactory moveFactory, HotSpotProviders providers, GraalHotSpotVMConfig config,
@@ -400,8 +400,7 @@
     @Override
     public Value emitLoadObjectAddress(Constant constant) {
         HotSpotObjectConstant objectConstant = (HotSpotObjectConstant) constant;
-        HotSpotLIRKindTool kindTool = (HotSpotLIRKindTool) getLIRKindTool();
-        LIRKind kind = objectConstant.isCompressed() ? kindTool.getNarrowOopKind() : kindTool.getObjectKind();
+        LIRKind kind = objectConstant.isCompressed() ? getLIRKindTool().getNarrowOopKind() : getLIRKindTool().getObjectKind();
         Variable result = newVariable(kind);
         append(new AMD64HotSpotLoadAddressOp(result, constant, HotSpotConstantLoadAction.RESOLVE));
         return result;
@@ -410,8 +409,7 @@
     @Override
     public Value emitLoadMetaspaceAddress(Constant constant, HotSpotConstantLoadAction action) {
         HotSpotMetaspaceConstant metaspaceConstant = (HotSpotMetaspaceConstant) constant;
-        HotSpotLIRKindTool kindTool = (HotSpotLIRKindTool) getLIRKindTool();
-        LIRKind kind = metaspaceConstant.isCompressed() ? kindTool.getNarrowPointerKind() : kindTool.getWordKind();
+        LIRKind kind = metaspaceConstant.isCompressed() ? getLIRKindTool().getNarrowPointerKind() : getLIRKindTool().getWordKind();
         Variable result = newVariable(kind);
         append(new AMD64HotSpotLoadAddressOp(result, constant, action));
         return result;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRKindTool.java	Fri May 12 13:14:25 2017 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2015, 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
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package org.graalvm.compiler.hotspot.amd64;
-
-import org.graalvm.compiler.core.amd64.AMD64LIRKindTool;
-import org.graalvm.compiler.core.common.LIRKind;
-import org.graalvm.compiler.hotspot.nodes.type.HotSpotLIRKindTool;
-
-import jdk.vm.ci.amd64.AMD64Kind;
-
-public class AMD64HotSpotLIRKindTool extends AMD64LIRKindTool implements HotSpotLIRKindTool {
-
-    @Override
-    public LIRKind getNarrowOopKind() {
-        return LIRKind.reference(AMD64Kind.DWORD);
-    }
-
-    @Override
-    public LIRKind getNarrowPointerKind() {
-        return LIRKind.value(AMD64Kind.DWORD);
-    }
-}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotBackendFactory.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotBackendFactory.java	Fri May 12 13:56:13 2017 -0700
@@ -100,7 +100,7 @@
         HotSpotSnippetReflectionProvider snippetReflection = new HotSpotSnippetReflectionProvider(runtime, constantReflection, wordTypes);
         BytecodeProvider bytecodeProvider = new ClassfileBytecodeProvider(metaAccess, snippetReflection);
         HotSpotReplacementsImpl replacements = new HotSpotReplacementsImpl(runtime.getOptions(), p, snippetReflection, bytecodeProvider, target);
-        Plugins plugins = createGraphBuilderPlugins(config, metaAccess, constantReflection, foreignCalls, stampProvider, snippetReflection, replacements, wordTypes);
+        Plugins plugins = createGraphBuilderPlugins(compilerConfiguration, config, metaAccess, constantReflection, foreignCalls, stampProvider, snippetReflection, replacements, wordTypes);
         replacements.setGraphBuilderPlugins(plugins);
         HotSpotSuitesProvider suites = createSuites(config, runtime, compilerConfiguration, plugins, replacements);
         HotSpotProviders providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, replacements, suites, registers,
@@ -110,11 +110,11 @@
         return createBackend(config, runtime, providers);
     }
 
-    protected Plugins createGraphBuilderPlugins(GraalHotSpotVMConfig config, HotSpotMetaAccessProvider metaAccess, HotSpotConstantReflectionProvider constantReflection,
-                    HotSpotForeignCallsProvider foreignCalls, HotSpotStampProvider stampProvider, HotSpotSnippetReflectionProvider snippetReflection, HotSpotReplacementsImpl replacements,
-                    HotSpotWordTypes wordTypes) {
-        Plugins plugins = HotSpotGraphBuilderPlugins.create(config, wordTypes, metaAccess, constantReflection, snippetReflection, foreignCalls, stampProvider, replacements);
-        SPARCGraphBuilderPlugins.register(plugins, replacements.getReplacementBytecodeProvider());
+    protected Plugins createGraphBuilderPlugins(CompilerConfiguration compilerConfiguration, GraalHotSpotVMConfig config, HotSpotMetaAccessProvider metaAccess,
+                    HotSpotConstantReflectionProvider constantReflection, HotSpotForeignCallsProvider foreignCalls, HotSpotStampProvider stampProvider,
+                    HotSpotSnippetReflectionProvider snippetReflection, HotSpotReplacementsImpl replacements, HotSpotWordTypes wordTypes) {
+        Plugins plugins = HotSpotGraphBuilderPlugins.create(compilerConfiguration, config, wordTypes, metaAccess, constantReflection, snippetReflection, foreignCalls, stampProvider, replacements);
+        SPARCGraphBuilderPlugins.register(plugins, replacements.getDefaultReplacementBytecodeProvider());
         return plugins;
     }
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotForeignCallsProvider.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotForeignCallsProvider.java	Fri May 12 13:56:13 2017 -0700
@@ -28,7 +28,7 @@
 import static jdk.vm.ci.sparc.SPARC.i1;
 import static jdk.vm.ci.sparc.SPARC.o0;
 import static jdk.vm.ci.sparc.SPARC.o1;
-import static org.graalvm.compiler.core.common.LocationIdentity.any;
+import static org.graalvm.api.word.LocationIdentity.any;
 import static org.graalvm.compiler.hotspot.HotSpotBackend.EXCEPTION_HANDLER;
 import static org.graalvm.compiler.hotspot.HotSpotBackend.EXCEPTION_HANDLER_IN_CALLER;
 import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.JUMP_ADDRESS;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLIRGenerator.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLIRGenerator.java	Fri May 12 13:56:13 2017 -0700
@@ -22,10 +22,10 @@
  */
 package org.graalvm.compiler.hotspot.sparc;
 
+import static jdk.vm.ci.sparc.SPARCKind.WORD;
+import static jdk.vm.ci.sparc.SPARCKind.XWORD;
 import static org.graalvm.compiler.lir.LIRValueUtil.asConstant;
 import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue;
-import static jdk.vm.ci.sparc.SPARCKind.WORD;
-import static jdk.vm.ci.sparc.SPARCKind.XWORD;
 
 import org.graalvm.compiler.core.common.CompressEncoding;
 import org.graalvm.compiler.core.common.LIRKind;
@@ -34,14 +34,15 @@
 import org.graalvm.compiler.core.common.spi.LIRKindTool;
 import org.graalvm.compiler.core.sparc.SPARCArithmeticLIRGenerator;
 import org.graalvm.compiler.core.sparc.SPARCLIRGenerator;
+import org.graalvm.compiler.core.sparc.SPARCLIRKindTool;
 import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
 import org.graalvm.compiler.hotspot.HotSpotBackend;
 import org.graalvm.compiler.hotspot.HotSpotDebugInfoBuilder;
 import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage;
 import org.graalvm.compiler.hotspot.HotSpotLIRGenerationResult;
 import org.graalvm.compiler.hotspot.HotSpotLIRGenerator;
 import org.graalvm.compiler.hotspot.HotSpotLockStack;
-import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
 import org.graalvm.compiler.hotspot.debug.BenchmarkCounters;
 import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
 import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider;
@@ -92,7 +93,7 @@
     }
 
     private SPARCHotSpotLIRGenerator(HotSpotProviders providers, GraalHotSpotVMConfig config, LIRGenerationResult lirGenRes, ConstantTableBaseProvider constantTableBaseProvider) {
-        this(new SPARCHotSpotLIRKindTool(), new SPARCArithmeticLIRGenerator(), new SPARCHotSpotMoveFactory(constantTableBaseProvider), providers, config, lirGenRes, constantTableBaseProvider);
+        this(new SPARCLIRKindTool(), new SPARCArithmeticLIRGenerator(), new SPARCHotSpotMoveFactory(constantTableBaseProvider), providers, config, lirGenRes, constantTableBaseProvider);
     }
 
     public SPARCHotSpotLIRGenerator(LIRKindTool lirKindTool, SPARCArithmeticLIRGenerator arithmeticLIRGen, MoveFactory moveFactory, HotSpotProviders providers, GraalHotSpotVMConfig config,
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLIRKindTool.java	Fri May 12 13:14:25 2017 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2015, 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
- * 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.sparc;
-
-import org.graalvm.compiler.core.common.LIRKind;
-import org.graalvm.compiler.core.sparc.SPARCLIRKindTool;
-import org.graalvm.compiler.hotspot.nodes.type.HotSpotLIRKindTool;
-
-import jdk.vm.ci.sparc.SPARCKind;
-
-public class SPARCHotSpotLIRKindTool extends SPARCLIRKindTool implements HotSpotLIRKindTool {
-
-    @Override
-    public LIRKind getNarrowOopKind() {
-        return LIRKind.reference(SPARCKind.WORD);
-    }
-
-    @Override
-    public LIRKind getNarrowPointerKind() {
-        return LIRKind.value(SPARCKind.WORD);
-    }
-}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CheckGraalIntrinsics.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CheckGraalIntrinsics.java	Fri May 12 13:56:13 2017 -0700
@@ -22,22 +22,16 @@
  */
 package org.graalvm.compiler.hotspot.test;
 
-import static org.graalvm.compiler.core.common.util.Util.JAVA_SPECIFICATION_VERSION;
-
 import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 import java.util.Set;
 import java.util.TreeSet;
 import java.util.stream.Collectors;
 
-import org.junit.Test;
-
 import org.graalvm.compiler.api.test.Graal;
 import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
 import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
@@ -45,30 +39,33 @@
 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Binding;
 import org.graalvm.compiler.runtime.RuntimeProvider;
+import org.graalvm.compiler.serviceprovider.JDK9Method;
 import org.graalvm.compiler.test.GraalTest;
-import org.graalvm.util.EconomicSet;
+import org.graalvm.util.EconomicMap;
+import org.graalvm.util.MapCursor;
+import org.junit.Test;
 
 import jdk.vm.ci.hotspot.HotSpotVMConfigStore;
 import jdk.vm.ci.hotspot.VMIntrinsicMethod;
 import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.MetaUtil;
 import jdk.vm.ci.meta.MethodHandleAccessProvider.IntrinsicMethod;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 
 /**
- * Checks the set of intrinsics implemented by Graal against the set of intrinsics declared by
- * HotSpot. The purpose of this test is to detect when new intrinsics are added to HotSpot and
- * process them appropriately in Graal. This will be achieved by working through
- * {@link #TO_BE_INVESTIGATED} and either implementing the intrinsic or moving it to {@link #IGNORE}
- * .
+ * Checks the intrinsics implemented by Graal against the set of intrinsics declared by HotSpot. The
+ * purpose of this test is to detect when new intrinsics are added to HotSpot and process them
+ * appropriately in Graal. This will be achieved by working through {@link #TO_BE_INVESTIGATED} and
+ * either implementing the intrinsic or moving it to {@link #IGNORE} .
  */
 public class CheckGraalIntrinsics extends GraalTest {
 
-    public static boolean match(ResolvedJavaMethod method, VMIntrinsicMethod intrinsic) {
-        if (intrinsic.name.equals(method.getName())) {
-            if (intrinsic.descriptor.equals(method.getSignature().toMethodDescriptor())) {
-                String declaringClass = method.getDeclaringClass().toClassName().replace('.', '/');
-                if (declaringClass.equals(intrinsic.declaringClass)) {
+    public static boolean match(String type, Binding binding, VMIntrinsicMethod intrinsic) {
+        if (intrinsic.name.equals(binding.name)) {
+            if (intrinsic.descriptor.startsWith(binding.argumentsDescriptor)) {
+                if (type.equals(intrinsic.declaringClass)) {
                     return true;
                 }
             }
@@ -76,16 +73,21 @@
         return false;
     }
 
-    private static ResolvedJavaMethod findMethod(EconomicSet<ResolvedJavaMethod> methods, VMIntrinsicMethod intrinsic) {
-        for (ResolvedJavaMethod method : methods) {
-            if (match(method, intrinsic)) {
-                return method;
+    public static InvocationPlugin findPlugin(EconomicMap<String, List<Binding>> bindings, VMIntrinsicMethod intrinsic) {
+        MapCursor<String, List<Binding>> cursor = bindings.getEntries();
+        while (cursor.advance()) {
+            // Match format of VMIntrinsicMethod.declaringClass
+            String type = MetaUtil.internalNameToJava(cursor.getKey(), true, false).replace('.', '/');
+            for (Binding binding : cursor.getValue()) {
+                if (match(type, binding, intrinsic)) {
+                    return binding.plugin;
+                }
             }
         }
         return null;
     }
 
-    private static ResolvedJavaMethod resolveIntrinsic(MetaAccessProvider metaAccess, VMIntrinsicMethod intrinsic) throws ClassNotFoundException {
+    public static ResolvedJavaMethod resolveIntrinsic(MetaAccessProvider metaAccess, VMIntrinsicMethod intrinsic) throws ClassNotFoundException {
         Class<?> c = Class.forName(intrinsic.declaringClass.replace('/', '.'), false, CheckGraalIntrinsics.class.getClassLoader());
         for (Method javaMethod : c.getDeclaredMethods()) {
             if (javaMethod.getName().equals(intrinsic.name)) {
@@ -366,7 +368,7 @@
         if (!config.useCRC32Intrinsics) {
             // Registration of the CRC32 plugins is guarded by UseCRC32Intrinsics
             add(IGNORE, "java/util/zip/CRC32.update(II)I");
-            if (JAVA_SPECIFICATION_VERSION < 9) {
+            if (JDK9Method.JAVA_SPECIFICATION_VERSION < 9) {
                 add(IGNORE,
                                 "java/util/zip/CRC32.updateByteBuffer(IJII)I",
                                 "java/util/zip/CRC32.updateBytes(I[BII)I");
@@ -378,7 +380,7 @@
                                 "java/util/zip/CRC32C.updateDirectByteBuffer(IJII)I");
             }
         } else {
-            if (JAVA_SPECIFICATION_VERSION >= 9) {
+            if (JDK9Method.JAVA_SPECIFICATION_VERSION >= 9) {
                 add(TO_BE_INVESTIGATED,
                                 "java/util/zip/CRC32C.updateBytes(I[BII)I",
                                 "java/util/zip/CRC32C.updateDirectByteBuffer(IJII)I");
@@ -387,7 +389,7 @@
 
         if (!config.useAESIntrinsics) {
             // Registration of the AES plugins is guarded by UseAESIntrinsics
-            if (JAVA_SPECIFICATION_VERSION < 9) {
+            if (JDK9Method.JAVA_SPECIFICATION_VERSION < 9) {
                 add(IGNORE,
                                 "com/sun/crypto/provider/AESCrypt.decryptBlock([BI[BI)V",
                                 "com/sun/crypto/provider/AESCrypt.encryptBlock([BI[BI)V",
@@ -403,7 +405,7 @@
         }
         if (!config.useMultiplyToLenIntrinsic()) {
             // Registration of the AES plugins is guarded by UseAESIntrinsics
-            if (JAVA_SPECIFICATION_VERSION < 9) {
+            if (JDK9Method.JAVA_SPECIFICATION_VERSION < 9) {
                 add(IGNORE, "java/math/BigInteger.multiplyToLen([II[II[I)[I");
             } else {
                 add(IGNORE, "java/math/BigInteger.implMultiplyToLen([II[II[I)[I");
@@ -426,28 +428,20 @@
     public void test() throws ClassNotFoundException {
         HotSpotGraalRuntimeProvider rt = (HotSpotGraalRuntimeProvider) Graal.getRequiredCapability(RuntimeProvider.class);
         HotSpotProviders providers = rt.getHostBackend().getProviders();
-        Map<ResolvedJavaMethod, Object> impl = new HashMap<>();
         Plugins graphBuilderPlugins = providers.getGraphBuilderPlugins();
         InvocationPlugins invocationPlugins = graphBuilderPlugins.getInvocationPlugins();
-        for (ResolvedJavaMethod method : invocationPlugins.getMethods()) {
-            InvocationPlugin plugin = invocationPlugins.lookupInvocation(method);
-            assert plugin != null;
-            impl.put(method, plugin);
-        }
 
-        EconomicSet<ResolvedJavaMethod> methods = invocationPlugins.getMethods();
         HotSpotVMConfigStore store = rt.getVMConfig().getStore();
         List<VMIntrinsicMethod> intrinsics = store.getIntrinsics();
 
         List<String> missing = new ArrayList<>();
+        EconomicMap<String, List<Binding>> bindings = invocationPlugins.getBindings(true);
         for (VMIntrinsicMethod intrinsic : intrinsics) {
-            ResolvedJavaMethod method = findMethod(methods, intrinsic);
-            if (method == null) {
-                method = resolveIntrinsic(providers.getMetaAccess(), intrinsic);
-
-                IntrinsicMethod intrinsicMethod = null;
+            InvocationPlugin plugin = findPlugin(bindings, intrinsic);
+            if (plugin == null) {
+                ResolvedJavaMethod method = resolveIntrinsic(providers.getMetaAccess(), intrinsic);
                 if (method != null) {
-                    intrinsicMethod = providers.getConstantReflection().getMethodHandleAccess().lookupMethodHandleIntrinsic(method);
+                    IntrinsicMethod intrinsicMethod = providers.getConstantReflection().getMethodHandleAccess().lookupMethodHandleIntrinsic(method);
                     if (intrinsicMethod != null) {
                         continue;
                     }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorld.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorld.java	Fri May 12 13:56:13 2017 -0700
@@ -26,9 +26,9 @@
 import static org.graalvm.compiler.core.GraalCompilerOptions.ExitVMOnException;
 import static org.graalvm.compiler.core.GraalCompilerOptions.PrintBailout;
 import static org.graalvm.compiler.core.GraalCompilerOptions.PrintStackTraceOnException;
-import static org.graalvm.compiler.core.common.util.Util.Java8OrEarlier;
 import static org.graalvm.compiler.core.test.ReflectionOptionDescriptors.extractEntries;
 import static org.graalvm.compiler.hotspot.test.CompileTheWorld.Options.DESCRIPTORS;
+import static org.graalvm.compiler.serviceprovider.JDK9Method.Java8OrEarlier;
 
 import java.io.Closeable;
 import java.io.File;
@@ -69,7 +69,6 @@
 import org.graalvm.compiler.bytecode.Bytecodes;
 import org.graalvm.compiler.core.CompilerThreadFactory;
 import org.graalvm.compiler.core.CompilerThreadFactory.DebugConfigAccess;
-import org.graalvm.compiler.core.common.util.Util;
 import org.graalvm.compiler.core.test.ReflectionOptionDescriptors;
 import org.graalvm.compiler.debug.DebugEnvironment;
 import org.graalvm.compiler.debug.GraalDebugConfig;
@@ -85,7 +84,9 @@
 import org.graalvm.compiler.options.OptionKey;
 import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.options.OptionsParser;
+import org.graalvm.compiler.serviceprovider.JDK9Method;
 import org.graalvm.util.EconomicMap;
+import org.graalvm.util.UnmodifiableEconomicMap;
 
 import jdk.vm.ci.hotspot.HotSpotCodeCacheProvider;
 import jdk.vm.ci.hotspot.HotSpotCompilationRequest;
@@ -98,7 +99,6 @@
 import jdk.vm.ci.meta.MetaAccessProvider;
 import jdk.vm.ci.runtime.JVMCI;
 import jdk.vm.ci.runtime.JVMCICompiler;
-import jdk.vm.ci.services.Services;
 
 /**
  * This class implements compile-the-world functionality with JVMCI.
@@ -106,9 +106,9 @@
 public final class CompileTheWorld {
 
     /**
-     * Magic token to denote that JDK classes are to be compiled. If {@link Util#Java8OrEarlier},
-     * then the classes in {@code rt.jar} are compiled. Otherwise the classes in the Java runtime
-     * image are compiled.
+     * Magic token to denote that JDK classes are to be compiled. If
+     * {@link JDK9Method#Java8OrEarlier}, then the classes in {@code rt.jar} are compiled. Otherwise
+     * the classes in the Java runtime image are compiled.
      */
     public static final String SUN_BOOT_CLASS_PATH = "sun.boot.class.path";
 
@@ -184,7 +184,7 @@
     private ThreadPoolExecutor threadPool;
 
     private OptionValues currentOptions;
-    private final EconomicMap<OptionKey<?>, Object> compilationOptions;
+    private final UnmodifiableEconomicMap<OptionKey<?>, Object> compilationOptions;
 
     /**
      * Creates a compile-the-world instance.
@@ -205,21 +205,22 @@
         this.methodFilters = methodFilters == null || methodFilters.isEmpty() ? null : MethodFilter.parse(methodFilters);
         this.excludeMethodFilters = excludeMethodFilters == null || excludeMethodFilters.isEmpty() ? null : MethodFilter.parse(excludeMethodFilters);
         this.verbose = verbose;
-        EconomicMap<OptionKey<?>, Object> compilationOptionsCopy = EconomicMap.create(compilationOptions);
         this.currentOptions = initialOptions;
 
+        // Copy the initial options and add in any extra options
+        EconomicMap<OptionKey<?>, Object> compilationOptionsCopy = EconomicMap.create(initialOptions.getMap());
+        compilationOptionsCopy.putAll(compilationOptions);
+
         // We don't want the VM to exit when a method fails to compile...
-        ExitVMOnException.update(compilationOptionsCopy, false);
+        ExitVMOnException.putIfAbsent(compilationOptionsCopy, false);
 
         // ...but we want to see exceptions.
-        PrintBailout.update(compilationOptionsCopy, true);
-        PrintStackTraceOnException.update(compilationOptionsCopy, true);
+        PrintBailout.putIfAbsent(compilationOptionsCopy, true);
+        PrintStackTraceOnException.putIfAbsent(compilationOptionsCopy, true);
 
         // By default only report statistics for the CTW threads themselves
-        if (!GraalDebugConfig.Options.DebugValueThreadFilter.hasBeenSet(initialOptions)) {
-            GraalDebugConfig.Options.DebugValueThreadFilter.update(compilationOptionsCopy, "^CompileTheWorld");
-        }
-        this.compilationOptions = EconomicMap.create(compilationOptionsCopy);
+        GraalDebugConfig.Options.DebugValueThreadFilter.putIfAbsent(compilationOptionsCopy, "^CompileTheWorld");
+        this.compilationOptions = compilationOptionsCopy;
     }
 
     public CompileTheWorld(HotSpotJVMCIRuntimeProvider jvmciRuntime, HotSpotGraalCompiler compiler, OptionValues options) {
@@ -509,7 +510,7 @@
         }
 
         OptionValues savedOptions = currentOptions;
-        currentOptions = new OptionValues(savedOptions, compilationOptions);
+        currentOptions = new OptionValues(compilationOptions);
         threadPool = new ThreadPoolExecutor(threadCount, threadCount, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(),
                         new CompilerThreadFactory("CompileTheWorld", new DebugConfigAccess() {
                             @Override
@@ -683,7 +684,7 @@
             public void run() {
                 waitToRun();
                 OptionValues savedOptions = currentOptions;
-                currentOptions = new OptionValues(savedOptions, compilationOptions);
+                currentOptions = new OptionValues(compilationOptions);
                 try {
                     compileMethod(method, classFileCounter);
                 } finally {
@@ -808,7 +809,6 @@
     }
 
     public static void main(String[] args) throws Throwable {
-        Services.exportJVMCITo(CompileTheWorld.class);
         HotSpotJVMCIRuntime jvmciRuntime = HotSpotJVMCIRuntime.runtime();
         HotSpotGraalCompiler compiler = (HotSpotGraalCompiler) jvmciRuntime.getCompiler();
         HotSpotGraalRuntimeProvider graalRuntime = compiler.getGraalRuntime();
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ConstantPoolSubstitutionsTests.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ConstantPoolSubstitutionsTests.java	Fri May 12 13:56:13 2017 -0700
@@ -23,12 +23,10 @@
 
 package org.graalvm.compiler.hotspot.test;
 
-import static org.graalvm.compiler.core.common.util.ModuleAPI.addExports;
-import static org.graalvm.compiler.core.common.util.ModuleAPI.getModule;
+import static org.graalvm.compiler.test.JLModule.uncheckedAddExports;
 
 import java.lang.reflect.Method;
 
-import org.graalvm.compiler.core.common.util.Util;
 import org.graalvm.compiler.core.test.GraalCompilerTest;
 import org.graalvm.compiler.debug.Debug;
 import org.graalvm.compiler.debug.Debug.Scope;
@@ -36,6 +34,7 @@
 import org.graalvm.compiler.nodes.Invoke;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.test.JLModule;
 import org.junit.BeforeClass;
 import org.junit.Test;
 import org.objectweb.asm.ClassWriter;
@@ -109,11 +108,11 @@
      * This test uses some API hidden by the JDK9 module system.
      */
     private static void addExports(Class<?> c) {
-        if (!Util.Java8OrEarlier) {
-            Object javaBaseModule = getModule.invoke(String.class);
-            Object cModule = getModule.invoke(c);
-            addExports.invokeStatic(javaBaseModule, "jdk.internal.reflect", cModule);
-            addExports.invokeStatic(javaBaseModule, "jdk.internal.misc", cModule);
+        if (!Java8OrEarlier) {
+            Object javaBaseModule = JLModule.fromClass(String.class);
+            Object cModule = JLModule.fromClass(c);
+            uncheckedAddExports(javaBaseModule, "jdk.internal.reflect", cModule);
+            uncheckedAddExports(javaBaseModule, "jdk.internal.misc", cModule);
         }
     }
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/DataPatchTest.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/DataPatchTest.java	Fri May 12 13:56:13 2017 -0700
@@ -23,17 +23,16 @@
 
 package org.graalvm.compiler.hotspot.test;
 
-import org.junit.Assume;
-import org.junit.Test;
 import org.graalvm.compiler.core.common.CompressEncoding;
-import org.graalvm.compiler.hotspot.nodes.CompressionNode;
+import org.graalvm.compiler.hotspot.nodes.HotSpotCompressionNode;
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.debug.OpaqueNode;
-import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration;
+import org.junit.Assume;
+import org.junit.Test;
 
 import jdk.vm.ci.meta.JavaKind;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
@@ -73,19 +72,18 @@
     }
 
     @Override
-    protected GraphBuilderConfiguration editGraphBuilderConfiguration(GraphBuilderConfiguration conf) {
-        InvocationPlugins invocationPlugins = conf.getPlugins().getInvocationPlugins();
+    protected void registerInvocationPlugins(InvocationPlugins invocationPlugins) {
         Registration r = new Registration(invocationPlugins, DataPatchTest.class);
         r.register1("compressUncompress", Object.class, new InvocationPlugin() {
             @Override
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg) {
                 CompressEncoding encoding = runtime().getVMConfig().getOopEncoding();
-                ValueNode compressed = b.add(CompressionNode.compress(arg, encoding));
+                ValueNode compressed = b.add(HotSpotCompressionNode.compress(arg, encoding));
                 ValueNode proxy = b.add(new OpaqueNode(compressed));
-                b.addPush(JavaKind.Object, CompressionNode.uncompress(proxy, encoding));
+                b.addPush(JavaKind.Object, HotSpotCompressionNode.uncompress(proxy, encoding));
                 return true;
             }
         });
-        return super.editGraphBuilderConfiguration(conf);
+        super.registerInvocationPlugins(invocationPlugins);
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/EliminateRedundantInitializationPhaseTest.java	Fri May 12 13:56:13 2017 -0700
@@ -0,0 +1,194 @@
+/*
+ * 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.hotspot.test;
+
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.hotspot.meta.HotSpotClassInitializationPlugin;
+import org.graalvm.compiler.hotspot.nodes.aot.InitializeKlassNode;
+import org.graalvm.compiler.hotspot.phases.aot.EliminateRedundantInitializationPhase;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class EliminateRedundantInitializationPhaseTest extends GraalCompilerTest {
+    @Override
+    protected Plugins getDefaultGraphBuilderPlugins() {
+        Plugins plugins = super.getDefaultGraphBuilderPlugins();
+        plugins.setClassInitializationPlugin(new HotSpotClassInitializationPlugin());
+        return plugins;
+    }
+
+    public static class X {
+        public static int x;
+        public static int y;
+        public static int z;
+    }
+
+    public static class Y extends X {
+        public static int a;
+        public static int b;
+    }
+
+    public static void assignFields() {
+        X.x = 1;
+        X.y = 2;
+        X.z = 3;
+    }
+
+    public static void assignFieldsConditionally(boolean choice) {
+        X.x = 1;
+        if (choice) {
+            X.y = 2;
+        } else {
+            X.z = 3;
+        }
+    }
+
+    public static void assignFieldsSubclassDominates() {
+        Y.a = 1;
+        X.x = 2;
+        X.y = 3;
+        X.z = 4;
+    }
+
+    public static void assignFieldsConditionallySubclassDominates(boolean choice) {
+        Y.a = 1;
+        if (choice) {
+            X.x = 2;
+        } else {
+            X.y = 3;
+        }
+        Y.z = 4;
+    }
+
+    public static void assignFieldsSubclassPostdominates() {
+        X.x = 1;
+        Y.a = 2;
+    }
+
+    public static void assignFieldsConditionallySubclassPostdominates(boolean choice) {
+        X.x = 1;
+        if (choice) {
+            X.y = 2;
+        } else {
+            X.z = 3;
+        }
+        Y.a = 4;
+    }
+
+    public static void assignFieldsConditionallyMixed(boolean choice) {
+        X.x = 1;
+        if (choice) {
+            Y.a = 2;
+        } else {
+            X.z = 3;
+        }
+        Y.b = 4;
+    }
+
+    public static void assignFieldsInLoop() {
+        X.x = 1;
+        for (int i = 0; i < 10; i++) {
+            X.y += X.z;
+        }
+    }
+
+    public static void assignFieldsInBranches(boolean choice) {
+        if (choice) {
+            X.x = 1;
+        } else {
+            X.y = 2;
+        }
+        X.z = 3;
+    }
+
+    public static void assignFieldsInBranchesMixed(boolean choice) {
+        if (choice) {
+            X.x = 1;
+        } else {
+            Y.a = 2;
+        }
+        X.z = 3;
+    }
+
+    private void test(String name, int initNodesAfterParse, int initNodesAfterOpt) {
+        StructuredGraph graph = parseEager(name, AllowAssumptions.NO);
+        Assert.assertEquals(initNodesAfterParse, graph.getNodes().filter(InitializeKlassNode.class).count());
+        HighTierContext highTierContext = getDefaultHighTierContext();
+        new EliminateRedundantInitializationPhase().apply(graph, highTierContext);
+        Assert.assertEquals(initNodesAfterOpt, graph.getNodes().filter(InitializeKlassNode.class).count());
+    }
+
+    @Test
+    public void test1() {
+        test("assignFields", 3, 1);
+    }
+
+    @Test
+    public void test2() {
+        test("assignFieldsConditionally", 3, 1);
+    }
+
+    @Test
+    public void test3() {
+        test("assignFieldsSubclassDominates", 4, 1);
+    }
+
+    @Test
+    public void test4() {
+        test("assignFieldsConditionallySubclassDominates", 4, 1);
+    }
+
+    @Test
+    public void test5() {
+        test("assignFieldsSubclassPostdominates", 2, 2);
+    }
+
+    @Test
+    public void test6() {
+        test("assignFieldsConditionallySubclassPostdominates", 4, 2);
+    }
+
+    @Test
+    public void test7() {
+        test("assignFieldsConditionallyMixed", 4, 3);
+    }
+
+    @Test
+    public void test8() {
+        test("assignFieldsInLoop", 4, 1);
+    }
+
+    @Test
+    public void test9() {
+        test("assignFieldsInBranches", 3, 2);
+    }
+
+    @Test
+    public void test10() {
+        test("assignFieldsInBranchesMixed", 3, 2);
+    }
+}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ForeignCallDeoptimizeTest.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ForeignCallDeoptimizeTest.java	Fri May 12 13:56:13 2017 -0700
@@ -30,9 +30,9 @@
 import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.extended.ForeignCallNode;
-import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
 
 import jdk.vm.ci.meta.JavaKind;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
@@ -43,11 +43,9 @@
 public class ForeignCallDeoptimizeTest extends GraalCompilerTest {
 
     @Override
-    protected Plugins getDefaultGraphBuilderPlugins() {
+    protected void registerInvocationPlugins(InvocationPlugins invocationPlugins) {
         ForeignCallsProvider foreignCalls = ((HotSpotProviders) getProviders()).getForeignCalls();
-
-        Plugins ret = super.getDefaultGraphBuilderPlugins();
-        ret.getInvocationPlugins().register(new InvocationPlugin() {
+        invocationPlugins.register(new InvocationPlugin() {
 
             @Override
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg) {
@@ -56,7 +54,7 @@
                 return true;
             }
         }, ForeignCallDeoptimizeTest.class, "testCallInt", int.class);
-        return ret;
+        super.registerInvocationPlugins(invocationPlugins);
     }
 
     public static int testCallInt(int value) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotGraalMBeanTest.java	Fri May 12 13:56:13 2017 -0700
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2013, 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.hotspot.test;
+
+import java.lang.management.ManagementFactory;
+import java.lang.reflect.Field;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanInfo;
+import javax.management.MBeanServer;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import org.graalvm.compiler.hotspot.HotSpotGraalMBean;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import org.junit.Test;
+
+public class HotSpotGraalMBeanTest {
+    @Test
+    public void registration() throws Exception {
+        ObjectName name;
+
+        Field field = null;
+        try {
+            field = stopMBeanServer();
+        } catch (Exception ex) {
+            if (ex.getClass().getName().equals("java.lang.reflect.InaccessibleObjectException")) {
+                // skip on JDK9
+                return;
+            }
+        }
+        assertNull("The platformMBeanServer isn't initialized now", field.get(null));
+
+        HotSpotGraalMBean bean = HotSpotGraalMBean.create();
+        assertNotNull("Bean created", bean);
+
+        assertNull("It is not registered yet", bean.ensureRegistered(true));
+
+        MBeanServer server = ManagementFactory.getPlatformMBeanServer();
+
+        assertNotNull("Now the bean thinks it is registered", name = bean.ensureRegistered(true));
+
+        assertNotNull("And the bean is found", server.getObjectInstance(name));
+    }
+
+    private static Field stopMBeanServer() throws NoSuchFieldException, SecurityException, IllegalAccessException, IllegalArgumentException {
+        final Field field = ManagementFactory.class.getDeclaredField("platformMBeanServer");
+        field.setAccessible(true);
+        field.set(null, null);
+        return field;
+    }
+
+    @Test
+    public void readBeanInfo() throws Exception {
+        ObjectName name;
+
+        assertNotNull("Server is started", ManagementFactory.getPlatformMBeanServer());
+
+        HotSpotGraalMBean realBean = HotSpotGraalMBean.create();
+        assertNotNull("Bean is registered", name = realBean.ensureRegistered(false));
+
+        ObjectInstance bean = ManagementFactory.getPlatformMBeanServer().getObjectInstance(name);
+        assertNotNull("Bean is registered", bean);
+        MBeanInfo info = ManagementFactory.getPlatformMBeanServer().getMBeanInfo(name);
+        assertNotNull("Info is found", info);
+        for (MBeanAttributeInfo attr : info.getAttributes()) {
+            if (attr.getName().equals("Dump")) {
+                assertFalse("Read only now", attr.isWritable());
+                assertTrue("Readable", attr.isReadable());
+                return;
+            }
+        }
+        fail("No Dump attribute found");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotStampMemoryAccessTest.java	Fri May 12 13:56:13 2017 -0700
@@ -0,0 +1,51 @@
+/*
+ * 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.hotspot.test;
+
+import org.graalvm.compiler.core.common.CompressEncoding;
+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.hotspot.nodes.type.HotSpotNarrowOopStamp;
+import org.junit.Assume;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.MemoryAccessProvider;
+
+public class HotSpotStampMemoryAccessTest extends HotSpotGraalCompilerTest {
+
+    @Ignore("not all versions are safe yet")
+    @Test
+    public void testReadNarrowObject() {
+        CompressEncoding oopEncoding = runtime().getVMConfig().getOopEncoding();
+        Assume.assumeTrue("Compressed oops must be enabled", runtime().getVMConfig().useCompressedOops);
+        MemoryAccessProvider memory = getConstantReflection().getMemoryAccessProvider();
+        JavaConstant base = getSnippetReflection().forObject("");
+        ObjectStamp stamp = (ObjectStamp) StampFactory.forKind(JavaKind.Object);
+        Stamp narrowStamp = HotSpotNarrowOopStamp.compressed(stamp, oopEncoding);
+        assertTrue(narrowStamp.readConstant(memory, base, 128) == null);
+    }
+}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/OptionsInFileTest.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/OptionsInFileTest.java	Fri May 12 13:56:13 2017 -0700
@@ -25,20 +25,18 @@
 import static org.graalvm.compiler.debug.GraalDebugConfig.Options.Dump;
 import static org.graalvm.compiler.debug.GraalDebugConfig.Options.MethodFilter;
 import static org.graalvm.compiler.debug.GraalDebugConfig.Options.PrintGraph;
-import static org.graalvm.compiler.test.SubprocessUtil.formatExecutedCommand;
 import static org.graalvm.compiler.test.SubprocessUtil.getVMCommandLine;
 import static org.graalvm.compiler.test.SubprocessUtil.withoutDebuggerArguments;
 
-import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
-import java.io.InputStreamReader;
 import java.io.PrintStream;
-import java.util.ArrayList;
 import java.util.List;
 
 import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.test.SubprocessUtil;
+import org.graalvm.compiler.test.SubprocessUtil.Subprocess;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -47,9 +45,7 @@
  */
 public class OptionsInFileTest extends GraalCompilerTest {
     @Test
-    public void test() throws IOException {
-        List<String> args = withoutDebuggerArguments(getVMCommandLine());
-
+    public void test() throws IOException, InterruptedException {
         String methodFilterValue = "a very unlikely method name";
         String debugFilterValue = "a very unlikely debug scope";
         File optionsFile = File.createTempFile("options", ".properties").getAbsoluteFile();
@@ -64,34 +60,25 @@
                 out.println(PrintGraph.getName() + " = false");
             }
 
-            args.add("-Dgraal.options.file=" + optionsFile);
-            args.add("-XX:+JVMCIPrintProperties");
-
-            ProcessBuilder processBuilder = new ProcessBuilder(args);
-            processBuilder.redirectErrorStream(true);
-            Process process = processBuilder.start();
-            BufferedReader stdout = new BufferedReader(new InputStreamReader(process.getInputStream()));
-
+            List<String> vmArgs = withoutDebuggerArguments(getVMCommandLine());
+            vmArgs.add("-Dgraal.options.file=" + optionsFile);
+            vmArgs.add("-XX:+JVMCIPrintProperties");
+            Subprocess proc = SubprocessUtil.java(vmArgs);
             String[] expected = {
                             "graal.MethodFilter := \"a very unlikely method name\"",
                             "graal.Dump := \"a very unlikely debug scope\"",
                             "graal.PrintGraph := false"};
-
-            List<String> outputLines = new ArrayList<>();
-
-            String line;
-            while ((line = stdout.readLine()) != null) {
-                outputLines.add(line);
+            for (String line : proc.output) {
                 for (int i = 0; i < expected.length; i++) {
                     if (expected[i] != null && line.contains(expected[i])) {
                         expected[i] = null;
                     }
                 }
             }
-            String dashes = "-------------------------------------------------------";
+
             for (int i = 0; i < expected.length; i++) {
                 if (expected[i] != null) {
-                    Assert.fail(String.format("Did not find '%s' in output of command:%n%s", expected[i], formatExecutedCommand(args, outputLines, dashes, dashes)));
+                    Assert.fail(String.format("Did not find '%s' in output of command:%n%s", expected[i], proc));
                 }
             }
         } finally {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/RetryableCompilationTest.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/RetryableCompilationTest.java	Fri May 12 13:56:13 2017 -0700
@@ -22,43 +22,50 @@
  */
 package org.graalvm.compiler.hotspot.test;
 
-import static org.graalvm.compiler.test.SubprocessUtil.formatExecutedCommand;
 import static org.graalvm.compiler.test.SubprocessUtil.getVMCommandLine;
 import static org.graalvm.compiler.test.SubprocessUtil.withoutDebuggerArguments;
 
-import java.io.BufferedReader;
 import java.io.File;
 import java.io.IOException;
-import java.io.InputStreamReader;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Enumeration;
 import java.util.List;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
 
 import org.graalvm.compiler.core.test.GraalCompilerTest;
-import org.graalvm.compiler.hotspot.CompilationTask;
+import org.graalvm.compiler.test.SubprocessUtil;
+import org.graalvm.compiler.test.SubprocessUtil.Subprocess;
 import org.junit.Assert;
 import org.junit.Test;
 
 /**
- * Tests {@link CompilationTask} support for dumping graphs and other info useful for debugging a
- * compiler crash.
+ * Tests support for dumping graphs and other info useful for debugging a compiler crash.
  */
 public class RetryableCompilationTest extends GraalCompilerTest {
+
+    /**
+     * Tests compilation requested by the VM.
+     */
     @Test
-    public void test() throws IOException {
-        List<String> args = withoutDebuggerArguments(getVMCommandLine());
+    public void testVMCompilation() throws IOException, InterruptedException {
+        testHelper(Arrays.asList("-XX:+BootstrapJVMCI", "-XX:+UseJVMCICompiler", "-Dgraal.CrashAt=Object.*,String.*", "-version"));
+    }
 
-        args.add("-XX:+BootstrapJVMCI");
-        args.add("-XX:+UseJVMCICompiler");
-        args.add("-Dgraal.CrashAt=Object.*,String.*");
-        args.add("-version");
+    /**
+     * Tests compilation requested by Truffle.
+     */
+    @Test
+    public void testTruffleCompilation() throws IOException, InterruptedException {
+        testHelper(Arrays.asList("-Dgraal.CrashAt=root test1"), "org.graalvm.compiler.truffle.test.SLTruffleGraalTestSuite", "test");
+    }
 
-        ProcessBuilder processBuilder = new ProcessBuilder(args);
-        processBuilder.redirectErrorStream(true);
-        Process process = processBuilder.start();
-        BufferedReader stdout = new BufferedReader(new InputStreamReader(process.getInputStream()));
+    private static void testHelper(List<String> extraVmArgs, String... mainClassAndArgs) throws IOException, InterruptedException {
+        List<String> vmArgs = withoutDebuggerArguments(getVMCommandLine());
+        vmArgs.addAll(extraVmArgs);
+
+        Subprocess proc = SubprocessUtil.java(vmArgs, mainClassAndArgs);
 
         String forcedCrashString = "Forced crash after compiling";
         String diagnosticOutputFilePrefix = "Graal diagnostic output saved in ";
@@ -66,11 +73,7 @@
         boolean seenForcedCrashString = false;
         String diagnosticOutputZip = null;
 
-        List<String> outputLines = new ArrayList<>();
-
-        String line;
-        while ((line = stdout.readLine()) != null) {
-            outputLines.add(line);
+        for (String line : proc.output) {
             if (line.contains(forcedCrashString)) {
                 seenForcedCrashString = true;
             } else if (diagnosticOutputZip == null) {
@@ -80,12 +83,11 @@
                 }
             }
         }
-        String dashes = "-------------------------------------------------------";
         if (!seenForcedCrashString) {
-            Assert.fail(String.format("Did not find '%s' in output of command:%n%s", forcedCrashString, formatExecutedCommand(args, outputLines, dashes, dashes)));
+            Assert.fail(String.format("Did not find '%s' in output of command:%n%s", forcedCrashString, proc));
         }
         if (diagnosticOutputZip == null) {
-            Assert.fail(String.format("Did not find '%s' in output of command:%n%s", diagnosticOutputFilePrefix, formatExecutedCommand(args, outputLines, dashes, dashes)));
+            Assert.fail(String.format("Did not find '%s' in output of command:%n%s", diagnosticOutputFilePrefix, proc));
         }
 
         File zip = new File(diagnosticOutputZip).getAbsoluteFile();
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/TestIntrinsicCompiles.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/TestIntrinsicCompiles.java	Fri May 12 13:56:13 2017 -0700
@@ -35,9 +35,10 @@
 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Binding;
 import org.graalvm.compiler.nodes.graphbuilderconf.MethodSubstitutionPlugin;
 import org.graalvm.compiler.runtime.RuntimeProvider;
-import org.graalvm.util.EconomicSet;
+import org.graalvm.util.EconomicMap;
 import org.junit.Test;
 
 import jdk.vm.ci.hotspot.HotSpotVMConfigStore;
@@ -50,46 +51,27 @@
  */
 public class TestIntrinsicCompiles extends GraalCompilerTest {
 
-    private static boolean match(ResolvedJavaMethod method, VMIntrinsicMethod intrinsic) {
-        if (intrinsic.name.equals(method.getName())) {
-            if (intrinsic.descriptor.equals(method.getSignature().toMethodDescriptor())) {
-                String declaringClass = method.getDeclaringClass().toClassName().replace('.', '/');
-                if (declaringClass.equals(intrinsic.declaringClass)) {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
-    private static ResolvedJavaMethod findMethod(EconomicSet<ResolvedJavaMethod> methods, VMIntrinsicMethod intrinsic) {
-        for (ResolvedJavaMethod method : methods) {
-            if (match(method, intrinsic)) {
-                return method;
-            }
-        }
-        return null;
-    }
-
     @Test
     @SuppressWarnings("try")
-    public void test() {
+    public void test() throws ClassNotFoundException {
         HotSpotGraalCompiler compiler = (HotSpotGraalCompiler) JVMCI.getRuntime().getCompiler();
         HotSpotGraalRuntimeProvider rt = (HotSpotGraalRuntimeProvider) Graal.getRequiredCapability(RuntimeProvider.class);
         HotSpotProviders providers = rt.getHostBackend().getProviders();
         Plugins graphBuilderPlugins = providers.getGraphBuilderPlugins();
         InvocationPlugins invocationPlugins = graphBuilderPlugins.getInvocationPlugins();
 
-        EconomicSet<ResolvedJavaMethod> pluginMethods = invocationPlugins.getMethods();
+        EconomicMap<String, List<Binding>> bindings = invocationPlugins.getBindings(true);
         HotSpotVMConfigStore store = rt.getVMConfig().getStore();
         List<VMIntrinsicMethod> intrinsics = store.getIntrinsics();
         for (VMIntrinsicMethod intrinsic : intrinsics) {
-            ResolvedJavaMethod method = findMethod(pluginMethods, intrinsic);
-            if (method != null) {
-                InvocationPlugin plugin = invocationPlugins.lookupInvocation(method);
-                if (plugin instanceof MethodSubstitutionPlugin && !method.isNative()) {
-                    StructuredGraph graph = compiler.getIntrinsicGraph(method, providers, INVALID_COMPILATION_ID, getInitialOptions());
-                    getCode(method, graph);
+            InvocationPlugin plugin = CheckGraalIntrinsics.findPlugin(bindings, intrinsic);
+            if (plugin != null) {
+                if (plugin instanceof MethodSubstitutionPlugin) {
+                    ResolvedJavaMethod method = CheckGraalIntrinsics.resolveIntrinsic(getMetaAccess(), intrinsic);
+                    if (!method.isNative()) {
+                        StructuredGraph graph = compiler.getIntrinsicGraph(method, providers, INVALID_COMPILATION_ID, getInitialOptions());
+                        getCode(method, graph);
+                    }
                 }
             }
         }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/WriteBarrierVerificationTest.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/WriteBarrierVerificationTest.java	Fri May 12 13:56:13 2017 -0700
@@ -25,8 +25,7 @@
 import java.util.List;
 import org.junit.Assert;
 import org.junit.Test;
-
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.debug.Debug;
 import org.graalvm.compiler.debug.Debug.Scope;
 import org.graalvm.compiler.debug.DebugConfig;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationTask.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationTask.java	Fri May 12 13:56:13 2017 -0700
@@ -30,20 +30,8 @@
 import static org.graalvm.compiler.core.GraalCompilerOptions.PrintFilter;
 import static org.graalvm.compiler.core.GraalCompilerOptions.PrintStackTraceOnException;
 import static org.graalvm.compiler.core.phases.HighTier.Options.Inline;
-import static org.graalvm.compiler.debug.Debug.INFO_LEVEL;
-import static org.graalvm.compiler.debug.DelegatingDebugConfig.Feature.DUMP_METHOD;
-import static org.graalvm.compiler.debug.DelegatingDebugConfig.Level.DUMP;
-import static org.graalvm.compiler.debug.GraalDebugConfig.Options.Dump;
-import static org.graalvm.compiler.debug.GraalDebugConfig.Options.DumpPath;
-import static org.graalvm.compiler.debug.GraalDebugConfig.Options.ForceDebugEnable;
-import static org.graalvm.compiler.debug.GraalDebugConfig.Options.PrintCFGFileName;
-import static org.graalvm.compiler.debug.GraalDebugConfig.Options.PrintGraphFile;
-import static org.graalvm.compiler.debug.GraalDebugConfig.Options.PrintGraphFileName;
 import static org.graalvm.compiler.java.BytecodeParserOptions.InlineDuringParsing;
 
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Collection;
 import java.util.List;
 
 import org.graalvm.compiler.code.CompilationResult;
@@ -51,9 +39,7 @@
 import org.graalvm.compiler.debug.Debug.Scope;
 import org.graalvm.compiler.debug.DebugCloseable;
 import org.graalvm.compiler.debug.DebugCounter;
-import org.graalvm.compiler.debug.DebugDumpHandler;
 import org.graalvm.compiler.debug.DebugDumpScope;
-import org.graalvm.compiler.debug.DebugRetryableTask;
 import org.graalvm.compiler.debug.DebugTimer;
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.debug.Management;
@@ -61,7 +47,6 @@
 import org.graalvm.compiler.debug.TimeSource;
 import org.graalvm.compiler.options.OptionKey;
 import org.graalvm.compiler.options.OptionValues;
-import org.graalvm.compiler.printer.GraalDebugConfigCustomizer;
 import org.graalvm.util.EconomicMap;
 
 import jdk.vm.ci.code.BailoutException;
@@ -77,8 +62,6 @@
 import jdk.vm.ci.runtime.JVMCICompiler;
 import jdk.vm.ci.services.JVMCIServiceLocator;
 
-//JaCoCo Exclude
-
 public class CompilationTask {
 
     private static final DebugCounter BAILOUTS = Debug.counter("Bailouts");
@@ -112,14 +95,20 @@
     private final boolean useProfilingInfo;
     private final OptionValues options;
 
-    final class RetryableCompilation extends DebugRetryableTask<HotSpotCompilationRequestResult> {
+    final class RetryableCompilation extends HotSpotRetryableCompilation<HotSpotCompilationRequestResult> {
         private final EventProvider.CompilationEvent compilationEvent;
         CompilationResult result;
 
         RetryableCompilation(EventProvider.CompilationEvent compilationEvent) {
+            super(compiler.getGraalRuntime(), options);
             this.compilationEvent = compilationEvent;
         }
 
+        @Override
+        public String toString() {
+            return getMethod().format("%H.%n");
+        }
+
         @SuppressWarnings("try")
         @Override
         protected HotSpotCompilationRequestResult run(Throwable retryCause) {
@@ -150,6 +139,9 @@
                 compilationEvent.begin();
                 result = compiler.compile(method, entryBCI, useProfilingInfo, compilationId, options);
             } catch (Throwable e) {
+                if (retryCause != null) {
+                    log("Exception during retry", e);
+                }
                 throw Debug.handle(e);
             } finally {
                 // End the compilation event.
@@ -185,61 +177,6 @@
             }
             return null;
         }
-
-        @Override
-        protected boolean onRetry(Throwable t) {
-            if (t instanceof BailoutException) {
-                return false;
-            }
-
-            if (!Debug.isEnabled()) {
-                TTY.printf("Error while processing %s.%nRe-run with -D%s%s=true to capture graph dumps upon a compilation failure.%n", CompilationTask.this,
-                                HotSpotGraalOptionValues.GRAAL_OPTION_PROPERTY_PREFIX, ForceDebugEnable.getName());
-                return false;
-            }
-
-            if (Dump.hasBeenSet(options)) {
-                // If dumping is explicitly enabled, Graal is being debugged
-                // so don't interfere with what the user is expecting to see.
-                return false;
-            }
-
-            String outputDirectory = compiler.getGraalRuntime().getOutputDirectory();
-            if (outputDirectory == null) {
-                return false;
-            }
-            String methodFQN = getMethod().format("%H.%n");
-            File dumpPath = new File(outputDirectory, methodFQN);
-            dumpPath.mkdirs();
-            if (!dumpPath.exists()) {
-                TTY.println("Warning: could not create dump directory " + dumpPath);
-                return false;
-            }
-
-            TTY.println("Retrying " + CompilationTask.this);
-            retryDumpHandlers = new ArrayList<>();
-            retryOptions = new OptionValues(options,
-                            PrintGraphFile, true,
-                            PrintCFGFileName, methodFQN,
-                            PrintGraphFileName, methodFQN,
-                            DumpPath, dumpPath.getPath());
-            override(DUMP, INFO_LEVEL).enable(DUMP_METHOD);
-            new GraalDebugConfigCustomizer().customize(this);
-            return true;
-        }
-
-        private Collection<DebugDumpHandler> retryDumpHandlers;
-        private OptionValues retryOptions;
-
-        @Override
-        public Collection<DebugDumpHandler> dumpHandlers() {
-            return retryDumpHandlers;
-        }
-
-        @Override
-        public OptionValues getOptions() {
-            return retryOptions;
-        }
     }
 
     static class Lazy {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackend.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackend.java	Fri May 12 13:56:13 2017 -0700
@@ -23,6 +23,8 @@
 package org.graalvm.compiler.hotspot;
 
 import java.util.EnumSet;
+
+import org.graalvm.api.word.Pointer;
 import org.graalvm.compiler.code.CompilationResult;
 import org.graalvm.compiler.core.common.CompilationIdentifier;
 import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
@@ -62,7 +64,6 @@
 import org.graalvm.compiler.options.OptionType;
 import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.phases.tiers.SuitesProvider;
-import org.graalvm.compiler.word.Pointer;
 import org.graalvm.compiler.word.Word;
 import org.graalvm.util.Equivalence;
 import org.graalvm.util.EconomicMap;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotForeignCallLinkage.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotForeignCallLinkage.java	Fri May 12 13:56:13 2017 -0700
@@ -24,7 +24,7 @@
 
 import jdk.vm.ci.meta.InvokeTarget;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
 import org.graalvm.compiler.core.target.Backend;
 import org.graalvm.compiler.hotspot.stubs.Stub;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotForeignCallLinkageImpl.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotForeignCallLinkageImpl.java	Fri May 12 13:56:13 2017 -0700
@@ -23,9 +23,11 @@
 package org.graalvm.compiler.hotspot;
 
 import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.RegisterEffect.DESTROYS_REGISTERS;
+
+import org.graalvm.api.word.LocationIdentity;
+
 import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
 import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
 import org.graalvm.compiler.core.target.Backend;
 import org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProvider;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompiler.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompiler.java	Fri May 12 13:56:13 2017 -0700
@@ -31,6 +31,7 @@
 import java.util.Formatter;
 
 import org.graalvm.compiler.api.runtime.GraalJVMCICompiler;
+import org.graalvm.compiler.bytecode.Bytecode;
 import org.graalvm.compiler.code.CompilationResult;
 import org.graalvm.compiler.core.GraalCompiler;
 import org.graalvm.compiler.core.common.CompilationIdentifier;
@@ -100,7 +101,8 @@
         if (graalRuntime.isShutdown()) {
             return HotSpotCompilationRequestResult.failure(String.format("Shutdown entered"), false);
         }
-        OptionValues options = graalRuntime.getOptions();
+        OptionValues options = graalRuntime.getOptions(request.getMethod());
+
         if (graalRuntime.isBootstrapping()) {
             if (GraalDebugConfig.Options.BootstrapInitializeOnly.getValue(options)) {
                 return HotSpotCompilationRequestResult.failure(String.format("Skip compilation because %s is enabled", GraalDebugConfig.Options.BootstrapInitializeOnly.getName()), true);
@@ -186,14 +188,15 @@
     @SuppressWarnings("try")
     public StructuredGraph getIntrinsicGraph(ResolvedJavaMethod method, HotSpotProviders providers, CompilationIdentifier compilationId, OptionValues options) {
         Replacements replacements = providers.getReplacements();
-        ResolvedJavaMethod substMethod = replacements.getSubstitutionMethod(method);
-        if (substMethod != null) {
+        Bytecode subst = replacements.getSubstitutionBytecode(method);
+        if (subst != null) {
+            ResolvedJavaMethod substMethod = subst.getMethod();
             assert !substMethod.equals(method);
             StructuredGraph graph = new StructuredGraph.Builder(options, AllowAssumptions.YES).method(substMethod).compilationId(compilationId).build();
             try (Debug.Scope scope = Debug.scope("GetIntrinsicGraph", graph)) {
                 Plugins plugins = new Plugins(providers.getGraphBuilderPlugins());
                 GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault(plugins);
-                IntrinsicContext initialReplacementContext = new IntrinsicContext(method, substMethod, replacements.getReplacementBytecodeProvider(), ROOT_COMPILATION);
+                IntrinsicContext initialReplacementContext = new IntrinsicContext(method, substMethod, subst.getOrigin(), ROOT_COMPILATION);
                 new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), providers.getConstantReflection(), providers.getConstantFieldProvider(), config,
                                 OptimisticOptimizations.NONE, initialReplacementContext).apply(graph);
                 assert !graph.isFrozen();
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompilerFactory.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompilerFactory.java	Fri May 12 13:56:13 2017 -0700
@@ -40,7 +40,6 @@
 import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
 import jdk.vm.ci.hotspot.HotSpotSignature;
 import jdk.vm.ci.runtime.JVMCIRuntime;
-import jdk.vm.ci.services.Services;
 
 public final class HotSpotGraalCompilerFactory extends HotSpotJVMCICompilerFactory {
 
@@ -155,7 +154,7 @@
     static {
         // Fail-fast detection for package renaming to guard use of package
         // prefixes in adjustCompilationLevelInternal.
-        assert Services.class.getName().equals("jdk.vm.ci.services.Services");
+        assert jdk.vm.ci.services.Services.class.getName().equals("jdk.vm.ci.services.Services");
         assert HotSpotGraalCompilerFactory.class.getName().equals("org.graalvm.compiler.hotspot.HotSpotGraalCompilerFactory");
     }
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalJVMCIServiceLocator.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalJVMCIServiceLocator.java	Fri May 12 13:56:13 2017 -0700
@@ -22,58 +22,27 @@
  */
 package org.graalvm.compiler.hotspot;
 
-import static org.graalvm.compiler.core.common.util.ModuleAPI.addExports;
-import static org.graalvm.compiler.core.common.util.ModuleAPI.addOpens;
-import static org.graalvm.compiler.core.common.util.ModuleAPI.getModule;
-import static org.graalvm.compiler.core.common.util.Util.JAVA_SPECIFICATION_VERSION;
-
 import org.graalvm.compiler.serviceprovider.ServiceProvider;
 
 import jdk.vm.ci.hotspot.HotSpotVMEventListener;
 import jdk.vm.ci.runtime.JVMCICompilerFactory;
 import jdk.vm.ci.services.JVMCIServiceLocator;
-import jdk.vm.ci.services.Services;
 
 @ServiceProvider(JVMCIServiceLocator.class)
 public final class HotSpotGraalJVMCIServiceLocator extends JVMCIServiceLocator {
 
     /**
      * Holds the state shared between all {@link HotSpotGraalJVMCIServiceLocator} instances. This is
-     * necessary as {@link Services} can create a new instance of a service provider each time
-     * {@link Services#load(Class)} or {@link Services#loadSingle(Class, boolean)} is called.
+     * necessary as a service provider instance is created each time the service is loaded.
      */
     private static final class Shared {
         static final Shared SINGLETON = new Shared();
 
-        private boolean exportsAdded;
-
-        /**
-         * Dynamically exports and opens various internal JDK packages to the Graal module. This
-         * requires only a single {@code --add-exports=java.base/jdk.internal.module=<Graal module>}
-         * on the VM command line instead of a {@code --add-exports} instance for each JDK internal
-         * package used by Graal.
-         */
-        private void addExports() {
-            if (JAVA_SPECIFICATION_VERSION >= 9 && !exportsAdded) {
-                Object javaBaseModule = getModule.invoke(String.class);
-                Object graalModule = getModule.invoke(getClass());
-                addExports.invokeStatic(javaBaseModule, "jdk.internal.misc", graalModule);
-                addExports.invokeStatic(javaBaseModule, "jdk.internal.jimage", graalModule);
-                addExports.invokeStatic(javaBaseModule, "com.sun.crypto.provider", graalModule);
-                addOpens.invokeStatic(javaBaseModule, "jdk.internal.misc", graalModule);
-                addOpens.invokeStatic(javaBaseModule, "jdk.internal.jimage", graalModule);
-                addOpens.invokeStatic(javaBaseModule, "com.sun.crypto.provider", graalModule);
-                exportsAdded = true;
-            }
-        }
-
         <T> T getProvider(Class<T> service, HotSpotGraalJVMCIServiceLocator locator) {
             if (service == JVMCICompilerFactory.class) {
-                addExports();
                 return service.cast(new HotSpotGraalCompilerFactory(locator));
             } else if (service == HotSpotVMEventListener.class) {
                 if (graalRuntime != null) {
-                    addExports();
                     return service.cast(new HotSpotGraalVMEventListener(graalRuntime));
                 }
             }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalMBean.java	Fri May 12 13:56:13 2017 -0700
@@ -0,0 +1,177 @@
+/*
+ * 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.hotspot;
+
+import java.lang.management.ManagementFactory;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import javax.management.Attribute;
+import javax.management.AttributeList;
+import javax.management.AttributeNotFoundException;
+import javax.management.DynamicMBean;
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InvalidAttributeValueException;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanException;
+import javax.management.MBeanInfo;
+import javax.management.MBeanRegistrationException;
+import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
+import javax.management.NotCompliantMBeanException;
+import javax.management.ObjectName;
+import javax.management.ReflectionException;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import org.graalvm.compiler.options.OptionDescriptor;
+import org.graalvm.compiler.options.OptionDescriptors;
+import org.graalvm.compiler.options.OptionKey;
+import org.graalvm.compiler.options.OptionValues;
+import org.graalvm.compiler.options.OptionsParser;
+import org.graalvm.util.EconomicMap;
+
+public final class HotSpotGraalMBean implements DynamicMBean {
+    private static Object mBeanServerField;
+    private final OptionValues options;
+    private final EconomicMap<OptionKey<?>, Object> changes;
+    private ObjectName registered;
+
+    private HotSpotGraalMBean(OptionValues options) {
+        this.options = options;
+        this.changes = EconomicMap.create();
+    }
+
+    private static boolean isMXServerOn() {
+        if (mBeanServerField == null) {
+            try {
+                final Field field = ManagementFactory.class.getDeclaredField("platformMBeanServer");
+                field.setAccessible(true);
+                mBeanServerField = field;
+            } catch (Exception ex) {
+                mBeanServerField = ManagementFactory.class;
+            }
+        }
+        if (mBeanServerField instanceof Field) {
+            try {
+                return ((Field) mBeanServerField).get(null) != null;
+            } catch (Exception ex) {
+                return true;
+            }
+        } else {
+            return false;
+        }
+    }
+
+    public static HotSpotGraalMBean create() {
+        OptionValues options = HotSpotGraalOptionValues.HOTSPOT_OPTIONS;
+        HotSpotGraalMBean mbean = new HotSpotGraalMBean(options);
+        return mbean;
+    }
+
+    public ObjectName ensureRegistered(boolean check) {
+        for (int cnt = 0;; cnt++) {
+            if (registered != null) {
+                return registered;
+            }
+            if (check && !isMXServerOn()) {
+                return null;
+            }
+            try {
+                MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+                ObjectName name = new ObjectName("org.graalvm.compiler.hotspot:type=Options" + (cnt == 0 ? "" : cnt));
+                mbs.registerMBean(this, name);
+                registered = name;
+                break;
+            } catch (MalformedObjectNameException | MBeanRegistrationException | NotCompliantMBeanException ex) {
+                throw new IllegalStateException(ex);
+            } catch (InstanceAlreadyExistsException ex) {
+                continue;
+            }
+        }
+        return registered;
+    }
+
+    @SuppressWarnings("unused")
+    OptionValues optionsFor(OptionValues values, ResolvedJavaMethod forMethod) {
+        ensureRegistered(true);
+        if (changes.isEmpty()) {
+            return values;
+        }
+        return new OptionValues(values, changes);
+    }
+
+    @Override
+    public Object getAttribute(String attribute) {
+        for (OptionKey<?> k : options.getMap().getKeys()) {
+            if (k.getName().equals(attribute)) {
+                return options.getMap().get(k);
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public void setAttribute(Attribute attribute) throws AttributeNotFoundException, InvalidAttributeValueException, MBeanException, ReflectionException {
+        throw new InvalidAttributeValueException();
+    }
+
+    @Override
+    public AttributeList getAttributes(String[] names) {
+        AttributeList list = new AttributeList();
+        for (String name : names) {
+            Object value = getAttribute(name);
+            if (value != null) {
+                list.add(new Attribute(name, value));
+            }
+        }
+        return list;
+    }
+
+    @Override
+    public AttributeList setAttributes(AttributeList attributes) {
+        throw new IllegalStateException();
+    }
+
+    @Override
+    public Object invoke(String actionName, Object[] params, String[] signature) throws MBeanException, ReflectionException {
+        return null;
+    }
+
+    @Override
+    public MBeanInfo getMBeanInfo() {
+        List<MBeanAttributeInfo> attrs = new ArrayList<>();
+        if (registered != null) {
+            for (Iterator<OptionDescriptors> it = OptionsParser.getOptionsLoader().iterator(); it.hasNext();) {
+                for (OptionDescriptor descr : it.next()) {
+                    attrs.add(new MBeanAttributeInfo(descr.getName(), descr.getType().getName(), descr.getHelp(), true, false, false));
+                }
+            }
+        }
+        return new MBeanInfo(
+                        HotSpotGraalMBean.class.getName(),
+                        "Graal",
+                        attrs.toArray(new MBeanAttributeInfo[attrs.size()]),
+                        null, null, null);
+    }
+
+}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalOptionValues.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalOptionValues.java	Fri May 12 13:56:13 2017 -0700
@@ -27,7 +27,6 @@
 import java.io.File;
 import java.io.FileReader;
 import java.io.IOException;
-import java.lang.reflect.Field;
 import java.util.Map;
 import java.util.Properties;
 
@@ -73,23 +72,6 @@
         return GRAAL_OPTION_PROPERTY_PREFIX + value.getName() + "=" + value.getValue(options);
     }
 
-    private static Properties getSavedProperties() {
-        try {
-            String value = System.getProperty("java.specification.version");
-            if (value.startsWith("1.")) {
-                value = value.substring(2);
-            }
-            int javaVersion = Integer.parseInt(value);
-            String vmClassName = javaVersion <= 8 ? "sun.misc.VM" : "jdk.internal.misc.VM";
-            Class<?> vmClass = Class.forName(vmClassName);
-            Field savedPropsField = vmClass.getDeclaredField("savedProps");
-            savedPropsField.setAccessible(true);
-            return (Properties) savedPropsField.get(null);
-        } catch (Exception e) {
-            throw new InternalError(e);
-        }
-    }
-
     public static final OptionValues HOTSPOT_OPTIONS = initializeOptions();
 
     /**
@@ -106,8 +88,8 @@
         try (InitTimer t = timer("InitializeOptions")) {
 
             Iterable<OptionDescriptors> loader = OptionsParser.getOptionsLoader();
-            Properties savedProps = getSavedProperties();
-            String optionsFile = savedProps.getProperty(GRAAL_OPTIONS_FILE_PROPERTY_NAME);
+            Map<String, String> savedProps = jdk.vm.ci.services.Services.getSavedProperties();
+            String optionsFile = savedProps.get(GRAAL_OPTIONS_FILE_PROPERTY_NAME);
 
             if (optionsFile != null) {
                 File graalOptions = new File(optionsFile);
@@ -131,15 +113,15 @@
             }
 
             EconomicMap<String, String> optionSettings = EconomicMap.create();
-            for (Map.Entry<Object, Object> e : savedProps.entrySet()) {
-                String name = (String) e.getKey();
+            for (Map.Entry<String, String> e : savedProps.entrySet()) {
+                String name = e.getKey();
                 if (name.startsWith(GRAAL_OPTION_PROPERTY_PREFIX)) {
                     if (name.equals("graal.PrintFlags") || name.equals("graal.ShowFlags")) {
                         System.err.println("The " + name + " option has been removed and will be ignored. Use -XX:+JVMCIPrintProperties instead.");
                     } else if (name.equals(GRAAL_OPTIONS_FILE_PROPERTY_NAME) || name.equals(GRAAL_VERSION_PROPERTY_NAME)) {
                         // Ignore well known properties that do not denote an option
                     } else {
-                        String value = (String) e.getValue();
+                        String value = e.getValue();
                         optionSettings.put(name.substring(GRAAL_OPTION_PROPERTY_PREFIX.length()), value);
                     }
                 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java	Fri May 12 13:56:13 2017 -0700
@@ -40,6 +40,7 @@
 import java.lang.management.ManagementFactory;
 import java.nio.file.FileVisitResult;
 import java.nio.file.Files;
+import java.nio.file.InvalidPathException;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.nio.file.SimpleFileVisitor;
@@ -80,6 +81,7 @@
 import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
 import jdk.vm.ci.hotspot.HotSpotVMConfigStore;
 import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
 import jdk.vm.ci.runtime.JVMCIBackend;
 
 //JaCoCo Exclude
@@ -110,6 +112,7 @@
     private final GraalHotSpotVMConfig config;
 
     private final OptionValues options;
+    private final HotSpotGraalMBean mBean;
 
     /**
      * @param compilerConfigurationFactory factory for the compiler configuration
@@ -127,6 +130,8 @@
             options = initialOptions;
         }
 
+        this.mBean = HotSpotGraalMBean.create();
+
         snippetCounterGroups = GraalOptions.SnippetCounters.getValue(options) ? new ArrayList<>() : null;
         CompilerConfiguration compilerConfiguration = compilerConfigurationFactory.createCompilerConfiguration();
         BackendMap backendMap = compilerConfigurationFactory.createBackendMap();
@@ -224,6 +229,17 @@
 
         runtimeStartTime = System.nanoTime();
         bootstrapJVMCI = config.getFlag("BootstrapJVMCI", Boolean.class);
+
+        assert checkPathIsInvalid(DELETED_OUTPUT_DIRECTORY);
+    }
+
+    private static boolean checkPathIsInvalid(String path) {
+        try {
+            Paths.get(path);
+            return false;
+        } catch (InvalidPathException e) {
+            return true;
+        }
     }
 
     private HotSpotBackend registerBackend(HotSpotBackend backend) {
@@ -245,7 +261,12 @@
 
     @Override
     public OptionValues getOptions() {
-        return options;
+        return mBean == null ? options : mBean.optionsFor(options, null);
+    }
+
+    @Override
+    public OptionValues getOptions(ResolvedJavaMethod forMethod) {
+        return mBean == null ? options : mBean.optionsFor(options, forMethod);
     }
 
     @Override
@@ -363,9 +384,18 @@
 
     private String outputDirectory;
 
+    /**
+     * Use an illegal file name to denote that the output directory has been deleted.
+     */
+    private static final String DELETED_OUTPUT_DIRECTORY = "\u0000";
+
     @Override
     public String getOutputDirectory() {
-        if (outputDirectory == null) {
+        return getOutputDirectory(true);
+    }
+
+    private synchronized String getOutputDirectory(boolean createIfNull) {
+        if (outputDirectory == null && createIfNull) {
             outputDirectory = "graal_output_" + getExecutionID();
             File dir = new File(outputDirectory).getAbsoluteFile();
             if (!dir.exists()) {
@@ -376,22 +406,23 @@
                 }
             }
         }
-        return outputDirectory;
+        return DELETED_OUTPUT_DIRECTORY.equals(outputDirectory) ? null : outputDirectory;
     }
 
     /**
      * Archives and deletes the {@linkplain #getOutputDirectory() output directory} if it exists.
      */
     private void archiveAndDeleteOutputDirectory() {
-        if (outputDirectory != null) {
-            Path dir = Paths.get(outputDirectory);
+        String outDir = getOutputDirectory(false);
+        if (outDir != null) {
+            Path dir = Paths.get(outDir);
             if (dir.toFile().exists()) {
                 try {
                     // Give compiler threads a chance to finishing dumping
                     Thread.sleep(1000);
                 } catch (InterruptedException e1) {
                 }
-                File zip = new File(outputDirectory + ".zip").getAbsoluteFile();
+                File zip = new File(outDir + ".zip").getAbsoluteFile();
                 List<Path> toDelete = new ArrayList<>();
                 try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zip))) {
                     zos.setLevel(Deflater.BEST_COMPRESSION);
@@ -428,6 +459,7 @@
                     }
                 }
             }
+            outputDirectory = DELETED_OUTPUT_DIRECTORY;
         }
     }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntimeProvider.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntimeProvider.java	Fri May 12 13:56:13 2017 -0700
@@ -29,6 +29,7 @@
 import org.graalvm.compiler.runtime.RuntimeProvider;
 
 import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
 
 //JaCoCo Exclude
 
@@ -59,6 +60,16 @@
     OptionValues getOptions();
 
     /**
+     * Gets the option values associated with this runtime that are applicable for given method.
+     *
+     * @param forMethod the method we are seeking for options for
+     * @return the options - by default same as {@link #getOptions()}
+     */
+    default OptionValues getOptions(ResolvedJavaMethod forMethod) {
+        return getOptions();
+    }
+
+    /**
      * Determines if the VM is currently bootstrapping the JVMCI compiler.
      */
     boolean isBootstrapping();
@@ -74,7 +85,7 @@
      * diagnostics are about to be generated.
      *
      * @return the directory into which diagnostics can be written or {@code null} if the directory
-     *         does not exist and could not be created
+     *         does not exist and could not be created or has already been deleted
      */
     String getOutputDirectory();
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotLIRGenerator.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotLIRGenerator.java	Fri May 12 13:56:13 2017 -0700
@@ -22,7 +22,6 @@
  */
 package org.graalvm.compiler.hotspot;
 
-import org.graalvm.compiler.core.common.CompressEncoding;
 import org.graalvm.compiler.core.common.LIRKind;
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction;
@@ -168,8 +167,4 @@
     @Override
     HotSpotProviders getProviders();
 
-    Value emitCompress(Value pointer, CompressEncoding encoding, boolean nonNull);
-
-    Value emitUncompress(Value pointer, CompressEncoding encoding, boolean nonNull);
-
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotNodeLIRBuilder.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotNodeLIRBuilder.java	Fri May 12 13:56:13 2017 -0700
@@ -23,8 +23,8 @@
 package org.graalvm.compiler.hotspot;
 
 import org.graalvm.compiler.core.match.MatchableNode;
-import org.graalvm.compiler.hotspot.nodes.CompressionNode;
 import org.graalvm.compiler.lir.gen.LIRGenerator;
+import org.graalvm.compiler.nodes.CompressionNode;
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotReferenceMapBuilder.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotReferenceMapBuilder.java	Fri May 12 13:56:13 2017 -0700
@@ -104,7 +104,7 @@
             LIRKind kind = (LIRKind) obj.getValueKind();
             int bytes = bytesPerElement(kind);
             if (kind.isUnknownReference()) {
-                throw GraalError.shouldNotReachHere("unknown reference alive across safepoint");
+                throw GraalError.shouldNotReachHere(String.format("unknown reference alive across safepoint: %s", obj));
             } else {
                 Location base = null;
                 if (kind.isDerivedReference()) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotRetryableCompilation.java	Fri May 12 13:56:13 2017 -0700
@@ -0,0 +1,166 @@
+/*
+ * 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.hotspot;
+
+import static org.graalvm.compiler.debug.Debug.VERBOSE_LEVEL;
+import static org.graalvm.compiler.debug.DelegatingDebugConfig.Feature.DUMP_METHOD;
+import static org.graalvm.compiler.debug.DelegatingDebugConfig.Level.DUMP;
+import static org.graalvm.compiler.debug.GraalDebugConfig.Options.Dump;
+import static org.graalvm.compiler.debug.GraalDebugConfig.Options.DumpPath;
+import static org.graalvm.compiler.debug.GraalDebugConfig.Options.ForceDebugEnable;
+import static org.graalvm.compiler.debug.GraalDebugConfig.Options.PrintCFGFileName;
+import static org.graalvm.compiler.debug.GraalDebugConfig.Options.PrintGraphFileName;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.PrintStream;
+import java.nio.file.InvalidPathException;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Collection;
+
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugDumpHandler;
+import org.graalvm.compiler.debug.DebugRetryableTask;
+import org.graalvm.compiler.debug.TTY;
+import org.graalvm.compiler.options.OptionValues;
+import org.graalvm.compiler.printer.GraalDebugConfigCustomizer;
+
+import jdk.vm.ci.code.BailoutException;
+
+/**
+ * Utility for retrying a compilation that throws an exception where the retry enables extra logging
+ * for subsequently diagnosing the failure.
+ */
+public abstract class HotSpotRetryableCompilation<T> extends DebugRetryableTask<T> {
+
+    protected final OptionValues originalOptions;
+    protected final HotSpotGraalRuntimeProvider runtime;
+
+    public HotSpotRetryableCompilation(HotSpotGraalRuntimeProvider runtime, OptionValues options) {
+        this.runtime = runtime;
+        this.originalOptions = options;
+    }
+
+    /**
+     * Gets a value that represents the compilation unit being compiled.
+     */
+    @Override
+    public abstract String toString();
+
+    private static String sanitizedFileName(String name) {
+        StringBuilder buf = new StringBuilder(name.length());
+        for (int i = 0; i < name.length(); i++) {
+            char c = name.charAt(i);
+            try {
+                Paths.get(String.valueOf(c));
+            } catch (InvalidPathException e) {
+                buf.append('_');
+            }
+            buf.append(c);
+        }
+        return buf.toString();
+    }
+
+    @Override
+    protected boolean onRetry(Throwable t) {
+        if (t instanceof BailoutException) {
+            return false;
+        }
+
+        if (!Debug.isEnabled()) {
+            TTY.printf("Error while compiling %s due to %s.%nRe-run with -D%s%s=true to capture graph dumps upon a compilation failure.%n", this,
+                            t, HotSpotGraalOptionValues.GRAAL_OPTION_PROPERTY_PREFIX, ForceDebugEnable.getName());
+            return false;
+        }
+
+        if (Dump.hasBeenSet(originalOptions)) {
+            // If dumping is explicitly enabled, Graal is being debugged
+            // so don't interfere with what the user is expecting to see.
+            return false;
+        }
+
+        String outputDirectory = runtime.getOutputDirectory();
+        if (outputDirectory == null) {
+            return false;
+        }
+        String dumpName = sanitizedFileName(toString());
+        File dumpPath = new File(outputDirectory, dumpName);
+        dumpPath.mkdirs();
+        if (!dumpPath.exists()) {
+            TTY.println("Warning: could not create dump directory " + dumpPath);
+            return false;
+        }
+
+        TTY.println("Retrying compilation of " + this + " due to " + t);
+        retryLogPath = new File(dumpPath, "retry.log").getPath();
+        log("Exception causing retry", t);
+        retryDumpHandlers = new ArrayList<>();
+        retryOptions = new OptionValues(originalOptions,
+                        PrintCFGFileName, dumpName,
+                        PrintGraphFileName, dumpName,
+                        DumpPath, dumpPath.getPath());
+        override(DUMP, VERBOSE_LEVEL).enable(DUMP_METHOD);
+        new GraalDebugConfigCustomizer().customize(this);
+        return true;
+    }
+
+    private Collection<DebugDumpHandler> retryDumpHandlers;
+    private OptionValues retryOptions;
+    private String retryLogPath;
+
+    /**
+     * Prints a message to a retry log file.
+     *
+     * @param message the message to print
+     * @param t if non-{@code null}, the stack trace for this exception is written to the retry log
+     *            after {@code message}
+     */
+    protected void log(String message, Throwable t) {
+        if (retryLogPath != null) {
+            try (PrintStream retryLog = new PrintStream(new FileOutputStream(retryLogPath), true)) {
+                StringBuilder buf = new StringBuilder(Thread.currentThread() + ": " + message);
+                if (t != null) {
+                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
+                    t.printStackTrace(new PrintStream(baos));
+                    buf.append(System.lineSeparator()).append(baos.toString());
+                }
+                retryLog.println(buf);
+            } catch (FileNotFoundException e) {
+                TTY.println("Warning: could not open retry log file " + retryLogPath + " [" + e + "]");
+            }
+        }
+    }
+
+    @Override
+    public Collection<DebugDumpHandler> dumpHandlers() {
+        return retryDumpHandlers;
+    }
+
+    @Override
+    public OptionValues getOptions() {
+        return retryOptions;
+    }
+}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/JVMCIVersionCheck.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/JVMCIVersionCheck.java	Fri May 12 13:56:13 2017 -0700
@@ -38,11 +38,11 @@
 class JVMCIVersionCheck {
 
     private static final int JVMCI8_MIN_MAJOR_VERSION = 0;
-    private static final int JVMCI8_MIN_MINOR_VERSION = 24;
+    private static final int JVMCI8_MIN_MINOR_VERSION = 26;
 
     // MAX_VALUE indicates that no current EA version is compatible with Graal.
     // Note: Keep README.md in sync with the EA version support checked here.
-    private static final int JVMCI9_MIN_EA_BUILD = 161;
+    private static final int JVMCI9_MIN_EA_BUILD = 168;
 
     private static void failVersionCheck(boolean exit, String reason, Object... args) {
         Formatter errorMessage = new Formatter().format(reason, args);
@@ -79,13 +79,27 @@
                 start += "-jvmci-".length();
                 int end = vmVersion.indexOf('.', start);
                 if (end > 0) {
-                    int major = Integer.parseInt(vmVersion.substring(start, end));
+                    int major;
+                    try {
+                        major = Integer.parseInt(vmVersion.substring(start, end));
+                    } catch (NumberFormatException e) {
+                        failVersionCheck(exitOnFailure, "The VM does not support the minimum JVMCI API version required by Graal.%n" +
+                                        "Cannot read JVMCI major version from java.vm.version property: %s.%n", vmVersion);
+                        return;
+                    }
                     start = end + 1;
                     end = start;
                     while (end < vmVersion.length() && Character.isDigit(vmVersion.charAt(end))) {
                         end++;
                     }
-                    int minor = Integer.parseInt(vmVersion.substring(start, end));
+                    int minor;
+                    try {
+                        minor = Integer.parseInt(vmVersion.substring(start, end));
+                    } catch (NumberFormatException e) {
+                        failVersionCheck(exitOnFailure, "The VM does not support the minimum JVMCI API version required by Graal.%n" +
+                                        "Cannot read JVMCI minor version from java.vm.version property: %s.%n", vmVersion);
+                        return;
+                    }
                     if (major >= JVMCI8_MIN_MAJOR_VERSION && minor >= JVMCI8_MIN_MINOR_VERSION) {
                         return;
                     }
@@ -114,7 +128,14 @@
                 while (end < vmVersion.length() && Character.isDigit(vmVersion.charAt(end))) {
                     end++;
                 }
-                int build = Integer.parseInt(vmVersion.substring(start, end));
+                int build;
+                try {
+                    build = Integer.parseInt(vmVersion.substring(start, end));
+                } catch (NumberFormatException e) {
+                    failVersionCheck(exitOnFailure, "The VM does not support the minimum JVMCI API version required by Graal.%n" +
+                                    "Cannot read JDK9 EA build number from java.vm.version property: %s.%n", vmVersion);
+                    return;
+                }
                 if (build >= JVMCI9_MIN_EA_BUILD) {
                     return;
                 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java	Fri May 12 13:56:13 2017 -0700
@@ -23,11 +23,11 @@
 package org.graalvm.compiler.hotspot.meta;
 
 import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayBaseOffset;
+import static org.graalvm.api.word.LocationIdentity.any;
 import static org.graalvm.compiler.core.common.GraalOptions.AlwaysInlineVTableStubs;
 import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
 import static org.graalvm.compiler.core.common.GraalOptions.InlineVTableStubs;
 import static org.graalvm.compiler.core.common.GraalOptions.OmitHotExceptionStacktrace;
-import static org.graalvm.compiler.core.common.LocationIdentity.any;
 import static org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProviderImpl.OSR_MIGRATION_END;
 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.CLASS_KLASS_LOCATION;
 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.CLASS_MIRROR_LOCATION;
@@ -38,11 +38,12 @@
 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.HUB_WRITE_LOCATION;
 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.KLASS_LAYOUT_HELPER_LOCATION;
 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.OBJ_ARRAY_KLASS_ELEMENT_KLASS_LOCATION;
+
 import java.lang.ref.Reference;
 
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.api.directives.GraalDirectives;
 import org.graalvm.compiler.core.common.GraalOptions;
-import org.graalvm.compiler.core.common.LocationIdentity;
 import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
 import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
 import org.graalvm.compiler.core.common.type.ObjectStamp;
@@ -55,8 +56,6 @@
 import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
 import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
 import org.graalvm.compiler.hotspot.nodes.BeginLockScopeNode;
-import org.graalvm.compiler.hotspot.nodes.CompressionNode;
-import org.graalvm.compiler.hotspot.nodes.CompressionNode.CompressionOp;
 import org.graalvm.compiler.hotspot.nodes.ComputeObjectAddressNode;
 import org.graalvm.compiler.hotspot.nodes.G1ArrayRangePostWriteBarrier;
 import org.graalvm.compiler.hotspot.nodes.G1ArrayRangePreWriteBarrier;
@@ -64,6 +63,7 @@
 import org.graalvm.compiler.hotspot.nodes.G1PreWriteBarrier;
 import org.graalvm.compiler.hotspot.nodes.G1ReferentFieldReadBarrier;
 import org.graalvm.compiler.hotspot.nodes.GetObjectAddressNode;
+import org.graalvm.compiler.hotspot.nodes.HotSpotCompressionNode;
 import org.graalvm.compiler.hotspot.nodes.HotSpotDirectCallTargetNode;
 import org.graalvm.compiler.hotspot.nodes.HotSpotIndirectCallTargetNode;
 import org.graalvm.compiler.hotspot.nodes.SerialArrayRangeWriteBarrier;
@@ -72,9 +72,9 @@
 import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantNode;
 import org.graalvm.compiler.hotspot.nodes.aot.ResolveMethodAndLoadCountersNode;
 import org.graalvm.compiler.hotspot.nodes.profiling.ProfileNode;
+import org.graalvm.compiler.hotspot.nodes.type.HotSpotNarrowOopStamp;
 import org.graalvm.compiler.hotspot.nodes.type.KlassPointerStamp;
 import org.graalvm.compiler.hotspot.nodes.type.MethodPointerStamp;
-import org.graalvm.compiler.hotspot.nodes.type.NarrowOopStamp;
 import org.graalvm.compiler.hotspot.replacements.AssertionSnippets;
 import org.graalvm.compiler.hotspot.replacements.ClassGetHubNode;
 import org.graalvm.compiler.hotspot.replacements.HashCodeSnippets;
@@ -98,6 +98,7 @@
 import org.graalvm.compiler.hotspot.word.KlassPointer;
 import org.graalvm.compiler.nodes.AbstractBeginNode;
 import org.graalvm.compiler.nodes.AbstractDeoptimizeNode;
+import org.graalvm.compiler.nodes.CompressionNode.CompressionOp;
 import org.graalvm.compiler.nodes.ConstantNode;
 import org.graalvm.compiler.nodes.FixedNode;
 import org.graalvm.compiler.nodes.Invoke;
@@ -126,8 +127,8 @@
 import org.graalvm.compiler.nodes.extended.OSRLockNode;
 import org.graalvm.compiler.nodes.extended.OSRMonitorEnterNode;
 import org.graalvm.compiler.nodes.extended.OSRStartNode;
+import org.graalvm.compiler.nodes.extended.RawLoadNode;
 import org.graalvm.compiler.nodes.extended.StoreHubNode;
-import org.graalvm.compiler.nodes.extended.RawLoadNode;
 import org.graalvm.compiler.nodes.java.ClassIsAssignableFromNode;
 import org.graalvm.compiler.nodes.java.DynamicNewArrayNode;
 import org.graalvm.compiler.nodes.java.DynamicNewInstanceNode;
@@ -488,7 +489,7 @@
     @Override
     protected Stamp loadStamp(Stamp stamp, JavaKind kind, boolean compressible) {
         if (kind == JavaKind.Object && compressible && runtime.getVMConfig().useCompressedOops) {
-            return NarrowOopStamp.compressed((ObjectStamp) stamp, runtime.getVMConfig().getOopEncoding());
+            return HotSpotNarrowOopStamp.compressed((ObjectStamp) stamp, runtime.getVMConfig().getOopEncoding());
         }
         return super.loadStamp(stamp, kind, compressible);
     }
@@ -496,7 +497,7 @@
     @Override
     protected ValueNode implicitLoadConvert(JavaKind kind, ValueNode value, boolean compressible) {
         if (kind == JavaKind.Object && compressible && runtime.getVMConfig().useCompressedOops) {
-            return new CompressionNode(CompressionOp.Uncompress, value, runtime.getVMConfig().getOopEncoding());
+            return new HotSpotCompressionNode(CompressionOp.Uncompress, value, runtime.getVMConfig().getOopEncoding());
         }
         return super.implicitLoadConvert(kind, value, compressible);
     }
@@ -511,7 +512,7 @@
     @Override
     protected ValueNode implicitStoreConvert(JavaKind kind, ValueNode value, boolean compressible) {
         if (kind == JavaKind.Object && compressible && runtime.getVMConfig().useCompressedOops) {
-            return new CompressionNode(CompressionOp.Compress, value, runtime.getVMConfig().getOopEncoding());
+            return new HotSpotCompressionNode(CompressionOp.Compress, value, runtime.getVMConfig().getOopEncoding());
         }
         return super.implicitStoreConvert(kind, value, compressible);
     }
@@ -737,7 +738,7 @@
         LocationIdentity hubLocation = runtime.getVMConfig().useCompressedClassPointers ? COMPRESSED_HUB_LOCATION : HUB_LOCATION;
         FloatingReadNode memoryRead = graph.unique(new FloatingReadNode(address, hubLocation, null, hubStamp, null, BarrierType.NONE));
         if (runtime.getVMConfig().useCompressedClassPointers) {
-            return CompressionNode.uncompress(memoryRead, runtime.getVMConfig().getKlassEncoding());
+            return HotSpotCompressionNode.uncompress(memoryRead, runtime.getVMConfig().getKlassEncoding());
         } else {
             return memoryRead;
         }
@@ -748,7 +749,7 @@
 
         ValueNode writeValue = value;
         if (runtime.getVMConfig().useCompressedClassPointers) {
-            writeValue = CompressionNode.compress(value, runtime.getVMConfig().getKlassEncoding());
+            writeValue = HotSpotCompressionNode.compress(value, runtime.getVMConfig().getKlassEncoding());
         }
 
         AddressNode address = createOffsetAddress(graph, object, runtime.getVMConfig().hubOffset);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotForeignCallsProviderImpl.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotForeignCallsProviderImpl.java	Fri May 12 13:56:13 2017 -0700
@@ -30,8 +30,8 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.core.common.LIRKind;
-import org.graalvm.compiler.core.common.LocationIdentity;
 import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
 import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage;
 import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.RegisterEffect;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java	Fri May 12 13:56:13 2017 -0700
@@ -25,10 +25,11 @@
 import static jdk.vm.ci.meta.DeoptimizationAction.InvalidateRecompile;
 import static jdk.vm.ci.meta.DeoptimizationReason.Unresolved;
 import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
-import static org.graalvm.compiler.core.common.util.Util.Java8OrEarlier;
 import static org.graalvm.compiler.hotspot.meta.HotSpotAOTProfilingPlugin.Options.TieredAOT;
 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.JAVA_THREAD_THREAD_OBJECT_LOCATION;
 import static org.graalvm.compiler.java.BytecodeParserOptions.InlineDuringParsing;
+import static org.graalvm.compiler.serviceprovider.JDK9Method.Java8OrEarlier;
+
 import java.lang.invoke.ConstantCallSite;
 import java.lang.invoke.MutableCallSite;
 import java.lang.invoke.VolatileCallSite;
@@ -37,9 +38,9 @@
 import java.math.BigInteger;
 import java.util.zip.CRC32;
 
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
 import org.graalvm.compiler.bytecode.BytecodeProvider;
-import org.graalvm.compiler.core.common.LocationIdentity;
 import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.hotspot.FingerprintUtil;
@@ -89,13 +90,15 @@
 import org.graalvm.compiler.nodes.spi.StampProvider;
 import org.graalvm.compiler.nodes.util.GraphUtil;
 import org.graalvm.compiler.options.OptionValues;
+import org.graalvm.compiler.phases.tiers.CompilerConfiguration;
 import org.graalvm.compiler.replacements.InlineDuringParsingPlugin;
 import org.graalvm.compiler.replacements.MethodHandlePlugin;
 import org.graalvm.compiler.replacements.NodeIntrinsificationProvider;
 import org.graalvm.compiler.replacements.ReplacementsImpl;
 import org.graalvm.compiler.replacements.StandardGraphBuilderPlugins;
-import org.graalvm.compiler.replacements.WordOperationPlugin;
 import org.graalvm.compiler.serviceprovider.GraalServices;
+import org.graalvm.compiler.serviceprovider.JDK9Method;
+import org.graalvm.compiler.word.WordOperationPlugin;
 import org.graalvm.compiler.word.WordTypes;
 
 import jdk.vm.ci.code.CodeUtil;
@@ -123,9 +126,10 @@
      * @param foreignCalls
      * @param stampProvider
      */
-    public static Plugins create(GraalHotSpotVMConfig config, HotSpotWordTypes wordTypes, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection,
-                    SnippetReflectionProvider snippetReflection, ForeignCallsProvider foreignCalls, StampProvider stampProvider, ReplacementsImpl replacements) {
-        InvocationPlugins invocationPlugins = new HotSpotInvocationPlugins(config, metaAccess);
+    public static Plugins create(CompilerConfiguration compilerConfiguration, GraalHotSpotVMConfig config, HotSpotWordTypes wordTypes, MetaAccessProvider metaAccess,
+                    ConstantReflectionProvider constantReflection, SnippetReflectionProvider snippetReflection, ForeignCallsProvider foreignCalls, StampProvider stampProvider,
+                    ReplacementsImpl replacements) {
+        InvocationPlugins invocationPlugins = new HotSpotInvocationPlugins(config, compilerConfiguration);
 
         Plugins plugins = new Plugins(invocationPlugins);
         NodeIntrinsificationProvider nodeIntrinsificationProvider = new NodeIntrinsificationProvider(metaAccess, snippetReflection, foreignCalls, wordTypes);
@@ -187,7 +191,7 @@
 
             @Override
             public void run() {
-                BytecodeProvider replacementBytecodeProvider = replacements.getReplacementBytecodeProvider();
+                BytecodeProvider replacementBytecodeProvider = replacements.getDefaultReplacementBytecodeProvider();
                 registerObjectPlugins(invocationPlugins, options, replacementBytecodeProvider);
                 registerClassPlugins(plugins, config, replacementBytecodeProvider);
                 registerSystemPlugins(invocationPlugins, foreignCalls);
@@ -448,7 +452,7 @@
     public static final String constantPoolClass;
 
     static {
-        if (Java8OrEarlier) {
+        if (JDK9Method.Java8OrEarlier) {
             cbcEncryptName = "encrypt";
             cbcDecryptName = "decrypt";
             aesEncryptName = "encryptBlock";
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java	Fri May 12 13:56:13 2017 -0700
@@ -98,7 +98,7 @@
 
 import java.util.EnumMap;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
 import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
 import org.graalvm.compiler.debug.GraalError;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotInvocationPlugins.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotInvocationPlugins.java	Fri May 12 13:56:13 2017 -0700
@@ -22,9 +22,13 @@
  */
 package org.graalvm.compiler.hotspot.meta;
 
+import static org.graalvm.compiler.serviceprovider.JDK9Method.Java8OrEarlier;
+
 import java.lang.reflect.Type;
+import java.util.Set;
 
 import org.graalvm.compiler.core.common.GraalOptions;
+import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.graph.iterators.NodeIterable;
 import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
@@ -35,21 +39,32 @@
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
 import org.graalvm.compiler.nodes.type.StampTool;
+import org.graalvm.compiler.phases.tiers.CompilerConfiguration;
 import org.graalvm.compiler.replacements.nodes.MacroNode;
+import org.graalvm.compiler.serviceprovider.JDK9Method;
+import org.graalvm.util.EconomicSet;
 
+import jdk.vm.ci.hotspot.HotSpotResolvedJavaType;
 import jdk.vm.ci.meta.JavaKind;
-import jdk.vm.ci.meta.MetaAccessProvider;
 import jdk.vm.ci.meta.ResolvedJavaType;
 
 /**
  * Extension of {@link InvocationPlugins} that disables plugins based on runtime configuration.
  */
 final class HotSpotInvocationPlugins extends InvocationPlugins {
-    final GraalHotSpotVMConfig config;
+    private final GraalHotSpotVMConfig config;
+    private final EconomicSet<Object> trustedModules;
+    private final ClassLoader extLoader;
 
-    HotSpotInvocationPlugins(GraalHotSpotVMConfig config, MetaAccessProvider metaAccess) {
-        super(metaAccess);
+    HotSpotInvocationPlugins(GraalHotSpotVMConfig config, CompilerConfiguration compilerConfiguration) {
         this.config = config;
+        if (Java8OrEarlier) {
+            extLoader = getExtLoader();
+            trustedModules = null;
+        } else {
+            extLoader = null;
+            trustedModules = initTrustedModules(compilerConfiguration);
+        }
     }
 
     @Override
@@ -97,4 +112,71 @@
         ResolvedJavaType type = StampTool.typeOrNull(node);
         return type != null && "Ljava/lang/Class;".equals(type.getName());
     }
+
+    /**
+     * {@inheritDoc}
+     *
+     * On JDK 8, only classes loaded by the boot, JVMCI or extension class loaders are trusted.
+     *
+     * On JDK 9 and later, only classes in the {@link CompilerConfiguration} defining module or any
+     * of its module dependencies are trusted.
+     */
+    @Override
+    protected boolean canBeIntrinsified(ResolvedJavaType declaringClass) {
+        if (declaringClass instanceof HotSpotResolvedJavaType) {
+            Class<?> javaClass = ((HotSpotResolvedJavaType) declaringClass).mirror();
+            if (Java8OrEarlier) {
+                ClassLoader cl = javaClass.getClassLoader();
+                return cl == null || cl == getClass().getClassLoader() || cl == extLoader;
+            } else {
+                Object module = JDK9Method.getModule.invoke(javaClass);
+                return trustedModules.contains(module);
+            }
+        }
+        return false;
+    }
+
+    private static ClassLoader getExtLoader() {
+        try {
+            Object launcher = Class.forName("sun.misc.Launcher").getMethod("getLauncher").invoke(null);
+            ClassLoader appLoader = (ClassLoader) launcher.getClass().getMethod("getClassLoader").invoke(launcher);
+            ClassLoader extLoader = appLoader.getParent();
+            assert extLoader.getClass().getName().equals("sun.misc.Launcher$ExtClassLoader") : extLoader;
+            return extLoader;
+        } catch (Exception e) {
+            throw new GraalError(e);
+        }
+    }
+
+    private static EconomicSet<Object> initTrustedModules(CompilerConfiguration compilerConfiguration) throws GraalError {
+        try {
+            EconomicSet<Object> res = EconomicSet.create();
+            Object compilerConfigurationModule = JDK9Method.getModule.invoke(compilerConfiguration.getClass());
+            res.add(compilerConfigurationModule);
+            Class<?> moduleClass = compilerConfigurationModule.getClass();
+            Object layer = new JDK9Method(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);
+            Class<?> moduleDescriptorClass = descriptor.getClass();
+            Set<Object> requires = new JDK9Method(moduleDescriptorClass, "requires").invoke(descriptor);
+            JDK9Method requireNameGetter = null;
+            for (Object require : requires) {
+                if (requireNameGetter == null) {
+                    requireNameGetter = new JDK9Method(require.getClass(), "name");
+                }
+                String name = requireNameGetter.invoke(require);
+                for (Object module : modules) {
+                    String moduleName = getName.invoke(module);
+                    if (moduleName.equals(name)) {
+                        res.add(module);
+                    }
+                }
+            }
+            return res;
+        } catch (Exception e) {
+            throw new GraalError(e);
+        }
+    }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotNodePlugin.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotNodePlugin.java	Fri May 12 13:56:13 2017 -0700
@@ -33,8 +33,8 @@
 import org.graalvm.compiler.nodes.graphbuilderconf.NodePlugin;
 import org.graalvm.compiler.nodes.graphbuilderconf.TypePlugin;
 import org.graalvm.compiler.nodes.util.ConstantFoldUtil;
-import org.graalvm.compiler.replacements.WordOperationPlugin;
 import org.graalvm.compiler.word.Word;
+import org.graalvm.compiler.word.WordOperationPlugin;
 
 import jdk.vm.ci.meta.JavaConstant;
 import jdk.vm.ci.meta.JavaKind;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotWordOperationPlugin.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotWordOperationPlugin.java	Fri May 12 13:56:13 2017 -0700
@@ -22,14 +22,14 @@
  */
 package org.graalvm.compiler.hotspot.meta;
 
-import static org.graalvm.compiler.core.common.LocationIdentity.any;
+import static org.graalvm.api.word.LocationIdentity.any;
 import static org.graalvm.compiler.hotspot.word.HotSpotOperation.HotspotOpcode.POINTER_EQ;
 import static org.graalvm.compiler.hotspot.word.HotSpotOperation.HotspotOpcode.POINTER_NE;
 import static org.graalvm.compiler.nodes.ConstantNode.forBoolean;
 
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
 import org.graalvm.compiler.bytecode.BridgeMethodUtils;
-import org.graalvm.compiler.core.common.LocationIdentity;
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.debug.GraalError;
@@ -51,7 +51,7 @@
 import org.graalvm.compiler.nodes.memory.ReadNode;
 import org.graalvm.compiler.nodes.memory.address.AddressNode;
 import org.graalvm.compiler.nodes.type.StampTool;
-import org.graalvm.compiler.replacements.WordOperationPlugin;
+import org.graalvm.compiler.word.WordOperationPlugin;
 import org.graalvm.compiler.word.WordTypes;
 
 import jdk.vm.ci.meta.JavaKind;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/BeginLockScopeNode.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/BeginLockScopeNode.java	Fri May 12 13:56:13 2017 -0700
@@ -26,7 +26,7 @@
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.hotspot.HotSpotLIRGenerator;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/CompressionNode.java	Fri May 12 13:14:25 2017 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,225 +0,0 @@
-/*
- * Copyright (c) 2014, 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.nodes;
-
-import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
-
-import org.graalvm.compiler.core.common.CompressEncoding;
-import org.graalvm.compiler.core.common.type.AbstractObjectStamp;
-import org.graalvm.compiler.core.common.type.ObjectStamp;
-import org.graalvm.compiler.core.common.type.Stamp;
-import org.graalvm.compiler.debug.GraalError;
-import org.graalvm.compiler.graph.NodeClass;
-import org.graalvm.compiler.graph.spi.CanonicalizerTool;
-import org.graalvm.compiler.hotspot.HotSpotLIRGenerator;
-import org.graalvm.compiler.hotspot.nodes.type.KlassPointerStamp;
-import org.graalvm.compiler.hotspot.nodes.type.NarrowOopStamp;
-import org.graalvm.compiler.nodeinfo.NodeInfo;
-import org.graalvm.compiler.nodes.ConstantNode;
-import org.graalvm.compiler.nodes.ValueNode;
-import org.graalvm.compiler.nodes.calc.ConvertNode;
-import org.graalvm.compiler.nodes.calc.UnaryNode;
-import org.graalvm.compiler.nodes.spi.LIRLowerable;
-import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
-import org.graalvm.compiler.nodes.type.StampTool;
-
-import jdk.vm.ci.hotspot.HotSpotCompressedNullConstant;
-import jdk.vm.ci.hotspot.HotSpotConstant;
-import jdk.vm.ci.meta.Constant;
-import jdk.vm.ci.meta.ConstantReflectionProvider;
-import jdk.vm.ci.meta.JavaConstant;
-import jdk.vm.ci.meta.Value;
-
-/**
- * Compress or uncompress an oop or metaspace pointer.
- */
-@NodeInfo(nameTemplate = "{p#op/s}", cycles = CYCLES_2, size = SIZE_2)
-public final class CompressionNode extends UnaryNode implements ConvertNode, LIRLowerable {
-
-    public static final NodeClass<CompressionNode> TYPE = NodeClass.create(CompressionNode.class);
-
-    public enum CompressionOp {
-        Compress,
-        Uncompress
-    }
-
-    protected final CompressionOp op;
-    protected final CompressEncoding encoding;
-
-    public CompressionNode(CompressionOp op, ValueNode input, CompressEncoding encoding) {
-        super(TYPE, mkStamp(op, input.stamp(), encoding), input);
-        this.op = op;
-        this.encoding = encoding;
-    }
-
-    @Override
-    public Stamp foldStamp(Stamp newStamp) {
-        assert newStamp.isCompatible(getValue().stamp());
-        return mkStamp(op, newStamp, encoding);
-    }
-
-    public static CompressionNode compress(ValueNode input, CompressEncoding encoding) {
-        return input.graph().unique(new CompressionNode(CompressionOp.Compress, input, encoding));
-    }
-
-    public static CompressionNode compressNoUnique(ValueNode input, CompressEncoding encoding) {
-        return new CompressionNode(CompressionOp.Compress, input, encoding);
-    }
-
-    public static CompressionNode uncompress(ValueNode input, CompressEncoding encoding) {
-        return input.graph().unique(new CompressionNode(CompressionOp.Uncompress, input, encoding));
-    }
-
-    private static Constant compress(Constant c) {
-        if (JavaConstant.NULL_POINTER.equals(c)) {
-            return HotSpotCompressedNullConstant.COMPRESSED_NULL;
-        } else if (c instanceof HotSpotConstant) {
-            return ((HotSpotConstant) c).compress();
-        } else {
-            throw GraalError.shouldNotReachHere("invalid constant input for compress op: " + c);
-        }
-    }
-
-    private static Constant uncompress(Constant c) {
-        if (c instanceof HotSpotConstant) {
-            return ((HotSpotConstant) c).uncompress();
-        } else {
-            throw GraalError.shouldNotReachHere("invalid constant input for uncompress op: " + c);
-        }
-    }
-
-    @Override
-    public Constant convert(Constant c, ConstantReflectionProvider constantReflection) {
-        switch (op) {
-            case Compress:
-                return compress(c);
-            case Uncompress:
-                return uncompress(c);
-            default:
-                throw GraalError.shouldNotReachHere();
-        }
-    }
-
-    @Override
-    public Constant reverse(Constant c, ConstantReflectionProvider constantReflection) {
-        switch (op) {
-            case Compress:
-                return uncompress(c);
-            case Uncompress:
-                return compress(c);
-            default:
-                throw GraalError.shouldNotReachHere();
-        }
-    }
-
-    @Override
-    public boolean isLossless() {
-        return true;
-    }
-
-    private static Stamp mkStamp(CompressionOp op, Stamp input, CompressEncoding encoding) {
-        switch (op) {
-            case Compress:
-                if (input instanceof ObjectStamp) {
-                    // compressed oop
-                    return NarrowOopStamp.compressed((ObjectStamp) input, encoding);
-                } else if (input instanceof KlassPointerStamp) {
-                    // compressed klass pointer
-                    return ((KlassPointerStamp) input).compressed(encoding);
-                }
-                break;
-            case Uncompress:
-                if (input instanceof NarrowOopStamp) {
-                    // oop
-                    assert encoding.equals(((NarrowOopStamp) input).getEncoding());
-                    return ((NarrowOopStamp) input).uncompressed();
-                } else if (input instanceof KlassPointerStamp) {
-                    // metaspace pointer
-                    assert encoding.equals(((KlassPointerStamp) input).getEncoding());
-                    return ((KlassPointerStamp) input).uncompressed();
-                }
-                break;
-        }
-        throw GraalError.shouldNotReachHere(String.format("Unexpected input stamp %s", input));
-    }
-
-    public CompressionOp getOp() {
-        return op;
-    }
-
-    public CompressEncoding getEncoding() {
-        return encoding;
-    }
-
-    @Override
-    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
-        if (forValue.isConstant()) {
-            if (GeneratePIC.getValue(tool.getOptions())) {
-                // We always want uncompressed constants
-                return this;
-            }
-            int stableDimension = ((ConstantNode) forValue).getStableDimension();
-            boolean isDefaultStable = ((ConstantNode) forValue).isDefaultStable();
-            return ConstantNode.forConstant(stamp(), convert(forValue.asConstant(), tool.getConstantReflection()), stableDimension, isDefaultStable, tool.getMetaAccess());
-        } else if (forValue instanceof CompressionNode) {
-            CompressionNode other = (CompressionNode) forValue;
-            if (op != other.op && encoding.equals(other.encoding)) {
-                return other.getValue();
-            }
-        }
-        return this;
-    }
-
-    @Override
-    public void generate(NodeLIRBuilderTool gen) {
-        HotSpotLIRGenerator hsGen = (HotSpotLIRGenerator) gen.getLIRGeneratorTool();
-        boolean nonNull;
-        if (getValue().stamp() instanceof AbstractObjectStamp) {
-            nonNull = StampTool.isPointerNonNull(getValue().stamp());
-        } else {
-            // metaspace pointers are never null
-            nonNull = true;
-        }
-
-        Value result;
-        switch (op) {
-            case Compress:
-                result = hsGen.emitCompress(gen.operand(getValue()), encoding, nonNull);
-                break;
-            case Uncompress:
-                result = hsGen.emitUncompress(gen.operand(getValue()), encoding, nonNull);
-                break;
-            default:
-                throw GraalError.shouldNotReachHere();
-        }
-
-        gen.setResult(this, result);
-    }
-
-    @Override
-    public boolean mayNullCheckSkipConversion() {
-        return true;
-    }
-}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/EndLockScopeNode.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/EndLockScopeNode.java	Fri May 12 13:56:13 2017 -0700
@@ -26,7 +26,7 @@
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/HotSpotCompressionNode.java	Fri May 12 13:56:13 2017 -0700
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2017, 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.hotspot.nodes;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
+
+import org.graalvm.compiler.core.common.CompressEncoding;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.hotspot.nodes.type.HotSpotNarrowOopStamp;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.CompressionNode;
+import org.graalvm.compiler.nodes.ValueNode;
+
+import jdk.vm.ci.hotspot.HotSpotCompressedNullConstant;
+import jdk.vm.ci.hotspot.HotSpotConstant;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.JavaConstant;
+
+@NodeInfo(nameTemplate = "{p#op/s}", cycles = CYCLES_2, size = SIZE_2)
+public final class HotSpotCompressionNode extends CompressionNode {
+
+    public static final NodeClass<HotSpotCompressionNode> TYPE = NodeClass.create(HotSpotCompressionNode.class);
+
+    public HotSpotCompressionNode(CompressionOp op, ValueNode input, CompressEncoding encoding) {
+        super(TYPE, op, input, HotSpotNarrowOopStamp.mkStamp(op, input.stamp(), encoding), encoding);
+    }
+
+    public static HotSpotCompressionNode compress(ValueNode input, CompressEncoding encoding) {
+        return input.graph().unique(new HotSpotCompressionNode(CompressionOp.Compress, input, encoding));
+    }
+
+    public static CompressionNode uncompress(ValueNode input, CompressEncoding encoding) {
+        return input.graph().unique(new HotSpotCompressionNode(CompressionOp.Uncompress, input, encoding));
+    }
+
+    @Override
+    protected Constant compress(Constant c) {
+        if (JavaConstant.NULL_POINTER.equals(c)) {
+            return HotSpotCompressedNullConstant.COMPRESSED_NULL;
+        } else if (c instanceof HotSpotConstant) {
+            return ((HotSpotConstant) c).compress();
+        } else {
+            throw GraalError.shouldNotReachHere("invalid constant input for compress op: " + c);
+        }
+    }
+
+    @Override
+    protected Constant uncompress(Constant c) {
+        if (c instanceof HotSpotConstant) {
+            return ((HotSpotConstant) c).uncompress();
+        } else {
+            throw GraalError.shouldNotReachHere("invalid constant input for uncompress op: " + c);
+        }
+    }
+
+    @Override
+    protected Stamp mkStamp(Stamp input) {
+        return HotSpotNarrowOopStamp.mkStamp(op, input, encoding);
+    }
+}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/StubForeignCallNode.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/StubForeignCallNode.java	Fri May 12 13:56:13 2017 -0700
@@ -28,7 +28,7 @@
 
 import java.util.Arrays;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
 import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
 import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/InitializeKlassStubCall.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/InitializeKlassStubCall.java	Fri May 12 13:56:13 2017 -0700
@@ -25,7 +25,7 @@
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_16;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.graph.spi.Canonicalizable;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/type/HotSpotLIRKindTool.java	Fri May 12 13:14:25 2017 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2015, 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
- * 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.nodes.type;
-
-import org.graalvm.compiler.core.common.LIRKind;
-import org.graalvm.compiler.core.common.spi.LIRKindTool;
-
-/**
- * Extension of {@link LIRKindTool} that includes support for compressed pointer kinds.
- */
-public interface HotSpotLIRKindTool extends LIRKindTool {
-
-    /**
-     * Get the platform specific kind used to represent compressed oops.
-     */
-    LIRKind getNarrowOopKind();
-
-    /**
-     * Gets the platform specific kind used to represent compressed metaspace pointers.
-     */
-    LIRKind getNarrowPointerKind();
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/type/HotSpotNarrowOopStamp.java	Fri May 12 13:56:13 2017 -0700
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2014, 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.nodes.type;
+
+import org.graalvm.compiler.core.common.CompressEncoding;
+import org.graalvm.compiler.core.common.type.AbstractObjectStamp;
+import org.graalvm.compiler.core.common.type.ObjectStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.nodes.CompressionNode.CompressionOp;
+import org.graalvm.compiler.nodes.type.NarrowOopStamp;
+
+import jdk.vm.ci.hotspot.HotSpotCompressedNullConstant;
+import jdk.vm.ci.hotspot.HotSpotMemoryAccessProvider;
+import jdk.vm.ci.hotspot.HotSpotObjectConstant;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.MemoryAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+public final class HotSpotNarrowOopStamp extends NarrowOopStamp {
+    private HotSpotNarrowOopStamp(ResolvedJavaType type, boolean exactType, boolean nonNull, boolean alwaysNull, CompressEncoding encoding) {
+        super(type, exactType, nonNull, alwaysNull, encoding);
+    }
+
+    @Override
+    protected AbstractObjectStamp copyWith(ResolvedJavaType type, boolean exactType, boolean nonNull, boolean alwaysNull) {
+        return new HotSpotNarrowOopStamp(type, exactType, nonNull, alwaysNull, getEncoding());
+    }
+
+    public static Stamp compressed(AbstractObjectStamp stamp, CompressEncoding encoding) {
+        return new HotSpotNarrowOopStamp(stamp.type(), stamp.isExactType(), stamp.nonNull(), stamp.alwaysNull(), encoding);
+    }
+
+    @Override
+    public Constant readConstant(MemoryAccessProvider provider, Constant base, long displacement) {
+        try {
+            HotSpotMemoryAccessProvider hsProvider = (HotSpotMemoryAccessProvider) provider;
+            return hsProvider.readNarrowOopConstant(base, displacement);
+        } catch (IllegalArgumentException e) {
+            return null;
+        }
+    }
+
+    @Override
+    public JavaConstant asConstant() {
+        if (alwaysNull()) {
+            return HotSpotCompressedNullConstant.COMPRESSED_NULL;
+        } else {
+            return null;
+        }
+    }
+
+    @Override
+    public boolean isCompatible(Constant other) {
+        if (other instanceof HotSpotObjectConstant) {
+            return ((HotSpotObjectConstant) other).isCompressed();
+        }
+        return true;
+    }
+
+    public static Stamp mkStamp(CompressionOp op, Stamp input, CompressEncoding encoding) {
+        switch (op) {
+            case Compress:
+                if (input instanceof ObjectStamp) {
+                    // compressed oop
+                    return HotSpotNarrowOopStamp.compressed((ObjectStamp) input, encoding);
+                } else if (input instanceof KlassPointerStamp) {
+                    // compressed klass pointer
+                    return ((KlassPointerStamp) input).compressed(encoding);
+                }
+                break;
+            case Uncompress:
+                if (input instanceof NarrowOopStamp) {
+                    // oop
+                    assert encoding.equals(((NarrowOopStamp) input).getEncoding());
+                    return ((NarrowOopStamp) input).uncompressed();
+                } else if (input instanceof KlassPointerStamp) {
+                    // metaspace pointer
+                    assert encoding.equals(((KlassPointerStamp) input).getEncoding());
+                    return ((KlassPointerStamp) input).uncompressed();
+                }
+                break;
+        }
+        throw GraalError.shouldNotReachHere(String.format("Unexpected input stamp %s", input));
+    }
+
+}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/type/KlassPointerStamp.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/type/KlassPointerStamp.java	Fri May 12 13:56:13 2017 -0700
@@ -131,7 +131,7 @@
     @Override
     public LIRKind getLIRKind(LIRKindTool tool) {
         if (isCompressed()) {
-            return ((HotSpotLIRKindTool) tool).getNarrowPointerKind();
+            return tool.getNarrowPointerKind();
         } else {
             return super.getLIRKind(tool);
         }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/type/NarrowOopStamp.java	Fri May 12 13:14:25 2017 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,136 +0,0 @@
-/*
- * Copyright (c) 2014, 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.nodes.type;
-
-import org.graalvm.compiler.core.common.CompressEncoding;
-import org.graalvm.compiler.core.common.LIRKind;
-import org.graalvm.compiler.core.common.spi.LIRKindTool;
-import org.graalvm.compiler.core.common.type.AbstractObjectStamp;
-import org.graalvm.compiler.core.common.type.ObjectStamp;
-import org.graalvm.compiler.core.common.type.Stamp;
-
-import jdk.vm.ci.hotspot.HotSpotCompressedNullConstant;
-import jdk.vm.ci.hotspot.HotSpotMemoryAccessProvider;
-import jdk.vm.ci.hotspot.HotSpotObjectConstant;
-import jdk.vm.ci.meta.Constant;
-import jdk.vm.ci.meta.JavaConstant;
-import jdk.vm.ci.meta.MemoryAccessProvider;
-import jdk.vm.ci.meta.ResolvedJavaType;
-
-public class NarrowOopStamp extends AbstractObjectStamp {
-
-    private final CompressEncoding encoding;
-
-    public NarrowOopStamp(ResolvedJavaType type, boolean exactType, boolean nonNull, boolean alwaysNull, CompressEncoding encoding) {
-        super(type, exactType, nonNull, alwaysNull);
-        this.encoding = encoding;
-    }
-
-    @Override
-    protected AbstractObjectStamp copyWith(ResolvedJavaType type, boolean exactType, boolean nonNull, boolean alwaysNull) {
-        return new NarrowOopStamp(type, exactType, nonNull, alwaysNull, encoding);
-    }
-
-    public static Stamp compressed(AbstractObjectStamp stamp, CompressEncoding encoding) {
-        return new NarrowOopStamp(stamp.type(), stamp.isExactType(), stamp.nonNull(), stamp.alwaysNull(), encoding);
-    }
-
-    public Stamp uncompressed() {
-        return new ObjectStamp(type(), isExactType(), nonNull(), alwaysNull());
-    }
-
-    public CompressEncoding getEncoding() {
-        return encoding;
-    }
-
-    @Override
-    public LIRKind getLIRKind(LIRKindTool tool) {
-        return ((HotSpotLIRKindTool) tool).getNarrowOopKind();
-    }
-
-    @Override
-    public String toString() {
-        StringBuilder str = new StringBuilder();
-        str.append('n');
-        appendString(str);
-        return str.toString();
-    }
-
-    @Override
-    public boolean isCompatible(Stamp other) {
-        if (this == other) {
-            return true;
-        }
-        if (other instanceof NarrowOopStamp) {
-            NarrowOopStamp narrow = (NarrowOopStamp) other;
-            return encoding.equals(narrow.encoding);
-        }
-        return false;
-    }
-
-    @Override
-    public Constant readConstant(MemoryAccessProvider provider, Constant base, long displacement) {
-        HotSpotMemoryAccessProvider hsProvider = (HotSpotMemoryAccessProvider) provider;
-        return hsProvider.readNarrowOopConstant(base, displacement);
-    }
-
-    @Override
-    public int hashCode() {
-        final int prime = 31;
-        int result = super.hashCode();
-        result = prime * result + encoding.hashCode();
-        return result;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        if (obj == null || getClass() != obj.getClass()) {
-            return false;
-        }
-        NarrowOopStamp other = (NarrowOopStamp) obj;
-        if (!encoding.equals(other.encoding)) {
-            return false;
-        }
-        return super.equals(other);
-    }
-
-    @Override
-    public JavaConstant asConstant() {
-        if (alwaysNull()) {
-            return HotSpotCompressedNullConstant.COMPRESSED_NULL;
-        } else {
-            return null;
-        }
-    }
-
-    @Override
-    public boolean isCompatible(Constant other) {
-        if (other instanceof HotSpotObjectConstant) {
-            return ((HotSpotObjectConstant) other).isCompressed();
-        }
-        return true;
-    }
-}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/LoadJavaMirrorWithKlassPhase.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/LoadJavaMirrorWithKlassPhase.java	Fri May 12 13:56:13 2017 -0700
@@ -32,9 +32,9 @@
 import org.graalvm.compiler.core.common.type.TypeReference;
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
-import org.graalvm.compiler.hotspot.nodes.CompressionNode;
+import org.graalvm.compiler.hotspot.nodes.HotSpotCompressionNode;
+import org.graalvm.compiler.hotspot.nodes.type.HotSpotNarrowOopStamp;
 import org.graalvm.compiler.hotspot.nodes.type.KlassPointerStamp;
-import org.graalvm.compiler.hotspot.nodes.type.NarrowOopStamp;
 import org.graalvm.compiler.hotspot.replacements.HubGetClassNode;
 import org.graalvm.compiler.nodes.ConstantNode;
 import org.graalvm.compiler.nodes.StructuredGraph;
@@ -87,7 +87,7 @@
                     ValueNode getClass = graph.unique(new HubGetClassNode(metaAccess, klass));
 
                     if (((HotSpotObjectConstant) constant).isCompressed()) {
-                        return CompressionNode.compress(getClass, oopEncoding);
+                        return HotSpotCompressionNode.compress(getClass, oopEncoding);
                     } else {
                         return getClass;
                     }
@@ -112,7 +112,7 @@
                     }
 
                     if (oopEncoding != null) {
-                        stamp = NarrowOopStamp.compressed((AbstractObjectStamp) stamp, oopEncoding);
+                        stamp = HotSpotNarrowOopStamp.compressed((AbstractObjectStamp) stamp, oopEncoding);
                     }
                     AddressNode address = graph.unique(new OffsetAddressNode(clazz, ConstantNode.forLong(typeField.offset(), graph)));
                     ValueNode read = graph.unique(new FloatingReadNode(address, FINAL_LOCATION, null, stamp));
@@ -120,7 +120,7 @@
                     if (oopEncoding == null || ((HotSpotObjectConstant) constant).isCompressed()) {
                         return read;
                     } else {
-                        return CompressionNode.uncompress(read, oopEncoding);
+                        return HotSpotCompressionNode.uncompress(read, oopEncoding);
                     }
                 }
             }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/EliminateRedundantInitializationPhase.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/EliminateRedundantInitializationPhase.java	Fri May 12 13:56:13 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 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
@@ -22,163 +22,31 @@
  */
 package org.graalvm.compiler.hotspot.phases.aot;
 
-import static org.graalvm.compiler.nodes.ConstantNode.getConstantNodes;
+import static org.graalvm.util.CollectionsUtil.anyMatch;
 
 import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Map.Entry;
+import java.util.Iterator;
+import java.util.List;
 
 import org.graalvm.compiler.graph.Node;
-import org.graalvm.compiler.graph.iterators.NodeIterable;
 import org.graalvm.compiler.hotspot.nodes.aot.InitializeKlassNode;
-import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.AbstractMergeNode;
+import org.graalvm.compiler.nodes.FixedNode;
 import org.graalvm.compiler.nodes.FixedWithNextNode;
 import org.graalvm.compiler.nodes.Invoke;
 import org.graalvm.compiler.nodes.StructuredGraph;
-import org.graalvm.compiler.nodes.cfg.Block;
-import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
 import org.graalvm.compiler.phases.BasePhase;
+import org.graalvm.compiler.phases.graph.MergeableState;
+import org.graalvm.compiler.phases.graph.PostOrderNodeIterator;
 import org.graalvm.compiler.phases.tiers.PhaseContext;
+import org.graalvm.util.EconomicSet;
 
 import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant;
 import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.ResolvedJavaType;
 
 public class EliminateRedundantInitializationPhase extends BasePhase<PhaseContext> {
     /**
-     * Find blocks with class initializing nodes for the class identified the by the constant node.
-     * Return the map of a block to a list of initializing nodes in that block.
-     *
-     * @param cfg an instance of the {@link ControlFlowGraph}.
-     * @param constant common input to the instances of {@link InitializeKlassNode}.
-     * @return map of blocks to lists of initializing nodes.
-     */
-    private static HashMap<Block, ArrayList<Node>> findBlocksWithInitializers(ControlFlowGraph cfg, ConstantNode constant) {
-        // node is ConstantNode representing a metaspace constant (a klass reference).
-        // InitializeKlassNodes for the same class would share the same ConstantNode input.
-        NodeIterable<?> initializers = constant.usages().filter(InitializeKlassNode.class);
-        // Map the found nodes to blocks
-        HashMap<Block, ArrayList<Node>> blockToInits = new HashMap<>();
-        for (Node i : initializers) {
-            Block b = cfg.blockFor(i);
-            ArrayList<Node> initsInBlock = blockToInits.get(b);
-            if (initsInBlock == null) {
-                initsInBlock = new ArrayList<>();
-            }
-            initsInBlock.add(i);
-            blockToInits.put(b, initsInBlock);
-        }
-        return blockToInits;
-    }
-
-    /**
-     * Process the block-to-initializers map and produce a list of blocks that contain more than one
-     * instance of {@link InitializeKlassNode}.
-     *
-     * @param blockToInits a map of blocks to lists of {@link InitializeKlassNode} instances.
-     * @return list of blocks that contain multiple instances of {@link InitializeKlassNode}.
-     */
-    private static ArrayList<Block> findBlocksWithMultipleInitializers(HashMap<Block, ArrayList<Node>> blockToInits) {
-        ArrayList<Block> result = new ArrayList<>();
-        // Select the blocks from the blocksToInits map that have more than one InitializeKlassNode
-        for (Entry<Block, ArrayList<Node>> e : blockToInits.entrySet()) {
-            if (e.getValue().size() > 1) {
-                result.add(e.getKey());
-            }
-        }
-        return result;
-    }
-
-    /**
-     * Iterate through blocks with multiple instances of {@link InitializeKlassNode} and identify
-     * redundant instances. Remove redundant instances from the block-to-list-of-initializer map.
-     *
-     * @param blockToInits a map of blocks to lists of {@link InitializeKlassNode} instances.
-     * @param blocksWithMultipleInits a list of blocks that contain multiple instances of
-     *            {@link InitializeKlassNode}.
-     * @param constant common input to the instances of {@link InitializeKlassNode}.
-     * @return list of {@link InitializeKlassNode} instances that can be removed.
-     */
-    private static ArrayList<Node> findRedundantLocalInitializers(HashMap<Block, ArrayList<Node>> blockToInits, ArrayList<Block> blocksWithMultipleInits, ConstantNode constant) {
-        ArrayList<Node> result = new ArrayList<>();
-        for (Block b : blocksWithMultipleInits) {
-            // First initializer for our constant in the block
-            InitializeKlassNode first = null;
-            for (Node n : b.getNodes()) {
-                if (n instanceof InitializeKlassNode) {
-                    InitializeKlassNode i = (InitializeKlassNode) n;
-                    if (i.value() == constant) {
-                        if (first == null) {
-                            // First instance of {@link InitializeKlassNode} stays.
-                            first = i;
-                        } else {
-                            // All the following instances of {@link InitializeKlassNode} can be
-                            // removed.
-                            result.add(i);
-                        }
-                    }
-                }
-            }
-            assert first != null;
-
-            // Replace the entry in the initsInBlock map to contain just a single initializer
-            ArrayList<Node> initsInBlock = new ArrayList<>();
-            initsInBlock.add(first);
-            blockToInits.put(b, initsInBlock);
-        }
-        return result;
-    }
-
-    /**
-     * Find cases when one {@link InitializeKlassNode} instance dominates another. The dominated
-     * instance can be removed.
-     *
-     * @param blockToInits a map of blocks to lists of {@link InitializeKlassNode} instances.
-     * @return list of {@link InitializeKlassNode} instances that can be removed.
-     */
-    private static ArrayList<Node> findRedundantGlobalInitializers(HashMap<Block, ArrayList<Node>> blockToInits) {
-        ArrayList<Node> result = new ArrayList<>();
-        for (Entry<Block, ArrayList<Node>> e : blockToInits.entrySet()) {
-            Block currentBlock = e.getKey();
-            ArrayList<Node> nodesInCurrent = e.getValue();
-            if (nodesInCurrent != null) { // if the list is null, the initializer has already been
-                                          // eliminated.
-                Block d = currentBlock.getFirstDominated();
-                while (d != null) {
-                    ArrayList<Node> nodesInDominated = blockToInits.get(d);
-                    if (nodesInDominated != null) { // if the list is null, the initializer has
-                                                    // already been eliminated.
-                        assert nodesInDominated.size() == 1;
-                        Node n = nodesInDominated.iterator().next();
-                        result.add(n);
-                        blockToInits.put(d, null);
-                    }
-                    d = d.getDominatedSibling();
-                }
-            }
-        }
-        return result;
-    }
-
-    /**
-     * Compute the list of redundant {@link InitializeKlassNode} instances that have the common
-     * {@link ConstantNode}.
-     *
-     * @param cfg an instance of the {@link ControlFlowGraph}.
-     * @param constant common input to the instances of {@link InitializeKlassNode}.
-     * @return list of {@link InitializeKlassNode} instances that can be removed.
-     */
-    private static ArrayList<Node> processConstantNode(ControlFlowGraph cfg, ConstantNode constant) {
-        HashMap<Block, ArrayList<Node>> blockToInits = findBlocksWithInitializers(cfg, constant);
-        ArrayList<Block> blocksWithMultipleInits = findBlocksWithMultipleInitializers(blockToInits);
-        ArrayList<Node> redundantInits = findRedundantLocalInitializers(blockToInits, blocksWithMultipleInits, constant);
-        // At this point each block has at most one initializer for this constant
-        if (blockToInits.size() > 1) {
-            redundantInits.addAll(findRedundantGlobalInitializers(blockToInits));
-        }
-        return redundantInits;
-    }
-
-    /**
      * Find each {@link Invoke} that has a corresponding {@link InitializeKlassNode}. These
      * {@link InitializeKlassNode} are redundant and are removed.
      *
@@ -194,25 +62,175 @@
     }
 
     /**
+     * Remove redundant {@link InitializeKlassNode} instances from the graph.
+     *
+     * @param graph the program graph
+     */
+    private static void removeRedundantInits(StructuredGraph graph) {
+        // Find and remove redundant instances of {@link InitializeKlassNode} from the graph.
+        List<InitializeKlassNode> redundantInits = findRedundantInits(graph);
+        for (InitializeKlassNode n : redundantInits) {
+            graph.removeFixed(n);
+        }
+    }
+
+    /**
      * Find {@link InitializeKlassNode} instances that can be removed because there is an existing
      * dominating initialization.
      *
-     * @param graph the program graph.
+     * @param graph the program graph
+     */
+    private static List<InitializeKlassNode> findRedundantInits(StructuredGraph graph) {
+        EliminateRedundantInitializationIterator i = new EliminateRedundantInitializationIterator(graph.start(), new InitializedTypes());
+        i.apply();
+        return i.getRedundantInits();
+    }
+
+    /**
+     * State for {@link EliminateRedundantInitializationIterator}.
      */
-    private static void removeRedundantInits(StructuredGraph graph) {
-        // Create cfg, we need blocks and dominators.
-        ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, false, true, false);
-        ArrayList<Node> redundantInits = new ArrayList<>();
-        for (ConstantNode node : getConstantNodes(graph)) {
-            Constant constant = node.asConstant();
-            if (constant instanceof HotSpotMetaspaceConstant) {
-                redundantInits.addAll(processConstantNode(cfg, node));
+    private static class InitializedTypes extends MergeableState<InitializedTypes> implements Cloneable {
+        private EconomicSet<ResolvedJavaType> types;
+
+        InitializedTypes() {
+            types = EconomicSet.create();
+        }
+
+        private InitializedTypes(EconomicSet<ResolvedJavaType> types) {
+            this.types = types;
+        }
+
+        @Override
+        public InitializedTypes clone() {
+            return new InitializedTypes(EconomicSet.create(types));
+        }
+
+        public boolean contains(ResolvedJavaType type) {
+            if (type.isInterface()) {
+                // Check for exact match for interfaces
+                return types.contains(type);
+            }
+            // For other types see if there is the same type or a subtype
+            return anyMatch(types, t -> type.isAssignableFrom(t));
+        }
+
+        public void add(ResolvedJavaType type) {
+            types.add(type);
+        }
+
+        /**
+         * Merge two given types. Interfaces have to be the same to merge successfully. For other
+         * types the answer is the LCA.
+         *
+         * @param a initialized type
+         * @param b initialized type
+         * @return lowest common type that is initialized if either a or b are initialized, null if
+         *         no such type exists.
+         */
+        private static ResolvedJavaType merge(ResolvedJavaType a, ResolvedJavaType b) {
+            // We want exact match for interfaces
+            if (a.isInterface() || b.isInterface()) {
+                if (a.equals(b)) {
+                    return a;
+                } else {
+                    return null;
+                }
+            } else {
+                // And LCA for other types
+                ResolvedJavaType c = a.findLeastCommonAncestor(b);
+                if (c.isJavaLangObject()) {
+                    // Not a very useful type, always initialized, don't pollute the sets.
+                    return null;
+                }
+                return c;
             }
         }
-        // Remove redundant instances of {@link InitializeKlassNode} from the graph.
-        for (Node n : redundantInits) {
-            graph.removeFixed((FixedWithNextNode) n);
+
+        /**
+         * Merge two sets of types. Essentially a computation of the LCA for each element of the
+         * cartesian product of the input sets. Interfaces have to match exactly.
+         *
+         * @param a set of initialized types
+         * @param b set of initialized types
+         * @return set of common types that would be initialized if types in either a or b are
+         *         initialized
+         */
+        private static EconomicSet<ResolvedJavaType> merge(EconomicSet<ResolvedJavaType> a, EconomicSet<ResolvedJavaType> b) {
+            EconomicSet<ResolvedJavaType> c = EconomicSet.create();
+            for (ResolvedJavaType ta : a) {
+                for (ResolvedJavaType tb : b) {
+                    ResolvedJavaType tc = merge(ta, tb);
+                    if (tc != null) {
+                        c.add(tc);
+                        if (tc.isInterface()) {
+                            // Interface is not going merge with anything else, so bail out early.
+                            break;
+                        }
+                    }
+                }
+            }
+            return c;
+        }
+
+        @Override
+        public boolean merge(AbstractMergeNode merge, List<InitializedTypes> withStates) {
+            for (InitializedTypes ts : withStates) {
+                types = merge(types, ts.types);
+            }
+            return true;
         }
+
+        protected static String toString(EconomicSet<ResolvedJavaType> types) {
+            StringBuilder b = new StringBuilder();
+            b.append("[");
+            Iterator<ResolvedJavaType> i = types.iterator();
+            while (i.hasNext()) {
+                ResolvedJavaType t = i.next();
+                b.append(t.toString());
+                if (i.hasNext()) {
+                    b.append(",");
+                }
+            }
+            b.append("]");
+            return b.toString();
+        }
+
+        @Override
+        public String toString() {
+            return toString(types);
+        }
+    }
+
+    /**
+     * Do data flow analysis of class initializations. Collect redundant initialization nodes.
+     */
+    private static class EliminateRedundantInitializationIterator extends PostOrderNodeIterator<InitializedTypes> {
+        private List<InitializeKlassNode> redundantInits = new ArrayList<>();
+
+        public List<InitializeKlassNode> getRedundantInits() {
+            return redundantInits;
+        }
+
+        EliminateRedundantInitializationIterator(FixedNode start, InitializedTypes initialState) {
+            super(start, initialState);
+        }
+
+        @Override
+        protected void node(FixedNode node) {
+            if (node instanceof InitializeKlassNode) {
+                InitializeKlassNode i = (InitializeKlassNode) node;
+                Constant c = i.value().asConstant();
+                assert c != null : "Klass should be a constant at this point";
+                HotSpotMetaspaceConstant klass = (HotSpotMetaspaceConstant) c;
+                ResolvedJavaType t = klass.asResolvedJavaType();
+                if (state.contains(t)) {
+                    redundantInits.add(i);
+                } else {
+                    state.add(t);
+                }
+            }
+        }
+
     }
 
     @Override
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/AESCryptSubstitutions.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/AESCryptSubstitutions.java	Fri May 12 13:56:13 2017 -0700
@@ -22,18 +22,18 @@
  */
 package org.graalvm.compiler.hotspot.replacements;
 
+import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayBaseOffset;
 import static org.graalvm.compiler.hotspot.HotSpotBackend.DECRYPT_BLOCK;
 import static org.graalvm.compiler.hotspot.HotSpotBackend.DECRYPT_BLOCK_WITH_ORIGINAL_KEY;
 import static org.graalvm.compiler.hotspot.HotSpotBackend.ENCRYPT_BLOCK;
 import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.VERY_SLOW_PATH_PROBABILITY;
 import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.probability;
-import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayBaseOffset;
 
-import java.lang.reflect.Field;
-
+import org.graalvm.api.word.LocationIdentity;
+import org.graalvm.api.word.Pointer;
+import org.graalvm.api.word.WordFactory;
 import org.graalvm.compiler.api.replacements.ClassSubstitution;
 import org.graalvm.compiler.api.replacements.MethodSubstitution;
-import org.graalvm.compiler.core.common.LocationIdentity;
 import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.graph.Node.ConstantNodeParameter;
@@ -43,7 +43,6 @@
 import org.graalvm.compiler.nodes.PiNode;
 import org.graalvm.compiler.nodes.extended.ForeignCallNode;
 import org.graalvm.compiler.nodes.extended.RawLoadNode;
-import org.graalvm.compiler.word.Pointer;
 import org.graalvm.compiler.word.Word;
 
 import jdk.vm.ci.meta.DeoptimizationAction;
@@ -61,7 +60,12 @@
     static final long kOffset;
     static final long lastKeyOffset;
     static final Class<?> AESCryptClass;
-    static final int AES_BLOCK_SIZE;
+
+    /**
+     * The AES block size is a constant 128 bits as defined by the
+     * <a href="http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.197.pdf">standard<a/>.
+     */
+    static final int AES_BLOCK_SIZE_IN_BYTES = 16;
 
     static {
         try {
@@ -72,9 +76,6 @@
             AESCryptClass = Class.forName("com.sun.crypto.provider.AESCrypt", true, cl);
             kOffset = UnsafeAccess.UNSAFE.objectFieldOffset(AESCryptClass.getDeclaredField("K"));
             lastKeyOffset = UnsafeAccess.UNSAFE.objectFieldOffset(AESCryptClass.getDeclaredField("lastKey"));
-            Field aesBlockSizeField = Class.forName("com.sun.crypto.provider.AESConstants", true, cl).getDeclaredField("AES_BLOCK_SIZE");
-            aesBlockSizeField.setAccessible(true);
-            AES_BLOCK_SIZE = aesBlockSizeField.getInt(null);
         } catch (Exception ex) {
             throw new GraalError(ex);
         }
@@ -122,8 +123,8 @@
         Object realReceiver = PiNode.piCastNonNull(rcvr, AESCryptClass);
         Object kObject = RawLoadNode.load(realReceiver, kOffset, JavaKind.Object, LocationIdentity.any());
         Pointer kAddr = Word.objectToTrackedPointer(kObject).add(getArrayBaseOffset(JavaKind.Int));
-        Word inAddr = Word.unsigned(ComputeObjectAddressNode.get(in, getArrayBaseOffset(JavaKind.Byte) + inOffset));
-        Word outAddr = Word.unsigned(ComputeObjectAddressNode.get(out, getArrayBaseOffset(JavaKind.Byte) + outOffset));
+        Word inAddr = WordFactory.unsigned(ComputeObjectAddressNode.get(in, getArrayBaseOffset(JavaKind.Byte) + inOffset));
+        Word outAddr = WordFactory.unsigned(ComputeObjectAddressNode.get(out, getArrayBaseOffset(JavaKind.Byte) + outOffset));
         if (encrypt) {
             encryptBlockStub(ENCRYPT_BLOCK, inAddr, outAddr, kAddr);
         } else {
@@ -141,7 +142,7 @@
      * Perform null and array bounds checks for arguments to a cipher operation.
      */
     static void checkArgs(byte[] in, int inOffset, byte[] out, int outOffset) {
-        if (probability(VERY_SLOW_PATH_PROBABILITY, inOffset < 0 || in.length - AES_BLOCK_SIZE < inOffset || outOffset < 0 || out.length - AES_BLOCK_SIZE < outOffset)) {
+        if (probability(VERY_SLOW_PATH_PROBABILITY, inOffset < 0 || in.length - AES_BLOCK_SIZE_IN_BYTES < inOffset || outOffset < 0 || out.length - AES_BLOCK_SIZE_IN_BYTES < outOffset)) {
             DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
         }
     }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/CRC32Substitutions.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/CRC32Substitutions.java	Fri May 12 13:56:13 2017 -0700
@@ -26,6 +26,9 @@
 
 import java.util.zip.CRC32;
 
+import org.graalvm.api.word.Pointer;
+import org.graalvm.api.word.WordBase;
+import org.graalvm.api.word.WordFactory;
 import org.graalvm.compiler.api.replacements.ClassSubstitution;
 import org.graalvm.compiler.api.replacements.Fold;
 import org.graalvm.compiler.api.replacements.Fold.InjectedParameter;
@@ -62,12 +65,12 @@
      */
     @MethodSubstitution(optional = true)
     static int update(int crc, int b) {
-        final long crcTableRawAddress = GraalHotSpotVMConfigNode.crcTableAddress();
+        final Pointer crcTableRawAddress = WordFactory.pointer(GraalHotSpotVMConfigNode.crcTableAddress());
 
         int c = ~crc;
         int index = (b ^ c) & 0xFF;
         int offset = index << 2;
-        int result = Word.unsigned(crcTableRawAddress).readInt(offset);
+        int result = crcTableRawAddress.readInt(offset);
         result = result ^ (c >>> 8);
         return ~result;
     }
@@ -77,7 +80,7 @@
      */
     @MethodSubstitution(optional = true)
     static int updateBytes(int crc, byte[] buf, int off, int len) {
-        Word bufAddr = Word.unsigned(ComputeObjectAddressNode.get(buf, arrayBaseOffset(JavaKind.Byte) + off));
+        Word bufAddr = WordFactory.unsigned(ComputeObjectAddressNode.get(buf, arrayBaseOffset(JavaKind.Byte) + off));
         return updateBytesCRC32(UPDATE_BYTES_CRC32, crc, bufAddr, len);
     }
 
@@ -86,7 +89,7 @@
      */
     @MethodSubstitution(optional = true)
     static int updateBytes0(int crc, byte[] buf, int off, int len) {
-        Word bufAddr = Word.unsigned(ComputeObjectAddressNode.get(buf, arrayBaseOffset(JavaKind.Byte) + off));
+        Word bufAddr = WordFactory.unsigned(ComputeObjectAddressNode.get(buf, arrayBaseOffset(JavaKind.Byte) + off));
         return updateBytesCRC32(UPDATE_BYTES_CRC32, crc, bufAddr, len);
     }
 
@@ -95,7 +98,7 @@
      */
     @MethodSubstitution(optional = true)
     static int updateByteBuffer(int crc, long addr, int off, int len) {
-        Word bufAddr = Word.unsigned(addr).add(off);
+        WordBase bufAddr = WordFactory.unsigned(addr).add(off);
         return updateBytesCRC32(UPDATE_BYTES_CRC32, crc, bufAddr, len);
     }
 
@@ -104,12 +107,12 @@
      */
     @MethodSubstitution(optional = true)
     static int updateByteBuffer0(int crc, long addr, int off, int len) {
-        Word bufAddr = Word.unsigned(addr).add(off);
+        WordBase bufAddr = WordFactory.unsigned(addr).add(off);
         return updateBytesCRC32(UPDATE_BYTES_CRC32, crc, bufAddr, len);
     }
 
-    public static final ForeignCallDescriptor UPDATE_BYTES_CRC32 = new ForeignCallDescriptor("updateBytesCRC32", int.class, int.class, Word.class, int.class);
+    public static final ForeignCallDescriptor UPDATE_BYTES_CRC32 = new ForeignCallDescriptor("updateBytesCRC32", int.class, int.class, WordBase.class, int.class);
 
     @NodeIntrinsic(ForeignCallNode.class)
-    public static native int updateBytesCRC32(@ConstantNodeParameter ForeignCallDescriptor descriptor, int crc, Word buf, int length);
+    public static native int updateBytesCRC32(@ConstantNodeParameter ForeignCallDescriptor descriptor, int crc, WordBase buf, int length);
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/CipherBlockChainingSubstitutions.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/CipherBlockChainingSubstitutions.java	Fri May 12 13:56:13 2017 -0700
@@ -26,12 +26,16 @@
 import static org.graalvm.compiler.hotspot.HotSpotBackend.DECRYPT_WITH_ORIGINAL_KEY;
 import static org.graalvm.compiler.hotspot.HotSpotBackend.ENCRYPT;
 import static org.graalvm.compiler.hotspot.replacements.UnsafeAccess.UNSAFE;
+
+import org.graalvm.api.word.LocationIdentity;
+import org.graalvm.api.word.Pointer;
+import org.graalvm.api.word.WordFactory;
+
 import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayBaseOffset;
 
 import org.graalvm.compiler.api.replacements.ClassSubstitution;
 import org.graalvm.compiler.api.replacements.Fold;
 import org.graalvm.compiler.api.replacements.MethodSubstitution;
-import org.graalvm.compiler.core.common.LocationIdentity;
 import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.graph.Node.ConstantNodeParameter;
@@ -40,7 +44,6 @@
 import org.graalvm.compiler.nodes.PiNode;
 import org.graalvm.compiler.nodes.extended.ForeignCallNode;
 import org.graalvm.compiler.nodes.extended.RawLoadNode;
-import org.graalvm.compiler.word.Pointer;
 import org.graalvm.compiler.word.Word;
 
 import jdk.vm.ci.meta.JavaKind;
@@ -172,8 +175,8 @@
         Object rObject = RawLoadNode.load(realReceiver, rOffset, JavaKind.Object, LocationIdentity.any());
         Pointer kAddr = Word.objectToTrackedPointer(kObject).add(getArrayBaseOffset(JavaKind.Int));
         Pointer rAddr = Word.objectToTrackedPointer(rObject).add(getArrayBaseOffset(JavaKind.Byte));
-        Word inAddr = Word.unsigned(ComputeObjectAddressNode.get(in, getArrayBaseOffset(JavaKind.Byte) + inOffset));
-        Word outAddr = Word.unsigned(ComputeObjectAddressNode.get(out, getArrayBaseOffset(JavaKind.Byte) + outOffset));
+        Word inAddr = WordFactory.unsigned(ComputeObjectAddressNode.get(in, getArrayBaseOffset(JavaKind.Byte) + inOffset));
+        Word outAddr = WordFactory.unsigned(ComputeObjectAddressNode.get(out, getArrayBaseOffset(JavaKind.Byte) + outOffset));
         if (encrypt) {
             encryptAESCryptStub(ENCRYPT, inAddr, outAddr, kAddr, rAddr, inLength);
         } else {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ClassGetHubNode.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ClassGetHubNode.java	Fri May 12 13:56:13 2017 -0700
@@ -25,9 +25,11 @@
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_1;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
 
+import org.graalvm.api.word.LocationIdentity;
+
 import jdk.vm.ci.meta.JavaKind;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
-import org.graalvm.compiler.core.common.LocationIdentity;
+
 import org.graalvm.compiler.core.common.calc.Condition;
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.graph.Node;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HashCodeSnippets.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HashCodeSnippets.java	Fri May 12 13:56:13 2017 -0700
@@ -35,6 +35,7 @@
 import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.NOT_FREQUENT_PROBABILITY;
 import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.probability;
 
+import org.graalvm.api.word.WordFactory;
 import org.graalvm.compiler.api.replacements.Snippet;
 import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
 import org.graalvm.compiler.nodes.StructuredGraph;
@@ -64,7 +65,7 @@
 
         // this code is independent from biased locking (although it does not look that way)
         final Word biasedLock = mark.and(biasedLockMaskInPlace(INJECTED_VMCONFIG));
-        if (probability(FAST_PATH_PROBABILITY, biasedLock.equal(Word.unsigned(unlockedMask(INJECTED_VMCONFIG))))) {
+        if (probability(FAST_PATH_PROBABILITY, biasedLock.equal(WordFactory.unsigned(unlockedMask(INJECTED_VMCONFIG))))) {
             int hash = (int) mark.unsignedShiftRight(identityHashCodeShift(INJECTED_VMCONFIG)).rawValue();
             if (probability(FAST_PATH_PROBABILITY, hash != uninitializedIdentityHashCodeValue(INJECTED_VMCONFIG))) {
                 return hash;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotReplacementsUtil.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotReplacementsUtil.java	Fri May 12 13:56:13 2017 -0700
@@ -22,15 +22,16 @@
  */
 package org.graalvm.compiler.hotspot.replacements;
 
+import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayBaseOffset;
+import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayIndexScale;
 import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG;
 import static org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProviderImpl.VERIFY_OOP;
 import static org.graalvm.compiler.hotspot.replacements.UnsafeAccess.UNSAFE;
-import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayBaseOffset;
-import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayIndexScale;
 
+import org.graalvm.api.word.LocationIdentity;
+import org.graalvm.api.word.WordFactory;
 import org.graalvm.compiler.api.replacements.Fold;
 import org.graalvm.compiler.api.replacements.Fold.InjectedParameter;
-import org.graalvm.compiler.core.common.LocationIdentity;
 import org.graalvm.compiler.core.common.SuppressFBWarnings;
 import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
 import org.graalvm.compiler.core.common.type.ObjectStamp;
@@ -40,17 +41,17 @@
 import org.graalvm.compiler.graph.Node.NodeIntrinsic;
 import org.graalvm.compiler.graph.spi.CanonicalizerTool;
 import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
-import org.graalvm.compiler.hotspot.nodes.CompressionNode;
 import org.graalvm.compiler.hotspot.nodes.ComputeObjectAddressNode;
 import org.graalvm.compiler.hotspot.word.KlassPointer;
 import org.graalvm.compiler.nodes.CanonicalizableLocation;
+import org.graalvm.compiler.nodes.CompressionNode;
 import org.graalvm.compiler.nodes.ConstantNode;
 import org.graalvm.compiler.nodes.NamedLocationIdentity;
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.extended.ForeignCallNode;
 import org.graalvm.compiler.nodes.extended.LoadHubNode;
+import org.graalvm.compiler.nodes.extended.RawLoadNode;
 import org.graalvm.compiler.nodes.extended.StoreHubNode;
-import org.graalvm.compiler.nodes.extended.RawLoadNode;
 import org.graalvm.compiler.nodes.memory.Access;
 import org.graalvm.compiler.nodes.memory.address.AddressNode;
 import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
@@ -559,7 +560,7 @@
     }
 
     public static Word arrayStart(int[] a) {
-        return Word.unsigned(ComputeObjectAddressNode.get(a, getArrayBaseOffset(JavaKind.Int)));
+        return WordFactory.unsigned(ComputeObjectAddressNode.get(a, getArrayBaseOffset(JavaKind.Int)));
     }
 
     @Fold
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/IdentityHashCodeNode.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/IdentityHashCodeNode.java	Fri May 12 13:56:13 2017 -0700
@@ -26,7 +26,7 @@
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.core.common.type.AbstractObjectStamp;
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.graph.Node;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/LoadExceptionObjectSnippets.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/LoadExceptionObjectSnippets.java	Fri May 12 13:56:13 2017 -0700
@@ -33,6 +33,7 @@
 import static org.graalvm.compiler.nodes.PiNode.piCastToSnippetReplaceeStamp;
 import static org.graalvm.compiler.replacements.SnippetTemplate.DEFAULT_REPLACER;
 
+import org.graalvm.api.word.WordFactory;
 import org.graalvm.compiler.api.replacements.Snippet;
 import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter;
 import org.graalvm.compiler.core.common.type.Stamp;
@@ -72,7 +73,7 @@
         Word thread = registerAsWord(threadRegister);
         Object exception = readExceptionOop(thread);
         writeExceptionOop(thread, null);
-        writeExceptionPc(thread, Word.zero());
+        writeExceptionPc(thread, WordFactory.zero());
         return piCastToSnippetReplaceeStamp(exception);
     }
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/MonitorSnippets.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/MonitorSnippets.java	Fri May 12 13:56:13 2017 -0700
@@ -71,12 +71,15 @@
 
 import java.util.List;
 
+import org.graalvm.api.word.LocationIdentity;
+import org.graalvm.api.word.Pointer;
+import org.graalvm.api.word.WordBase;
+import org.graalvm.api.word.WordFactory;
 import org.graalvm.compiler.api.replacements.Fold;
 import org.graalvm.compiler.api.replacements.Snippet;
 import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter;
 import org.graalvm.compiler.bytecode.Bytecode;
 import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecode;
-import org.graalvm.compiler.core.common.LocationIdentity;
 import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
 import org.graalvm.compiler.core.common.type.ObjectStamp;
 import org.graalvm.compiler.core.common.type.StampFactory;
@@ -118,9 +121,7 @@
 import org.graalvm.compiler.replacements.SnippetTemplate.Arguments;
 import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo;
 import org.graalvm.compiler.replacements.Snippets;
-import org.graalvm.compiler.word.Pointer;
 import org.graalvm.compiler.word.Word;
-import org.graalvm.compiler.word.WordBase;
 
 import jdk.vm.ci.code.BytecodeFrame;
 import jdk.vm.ci.code.Register;
@@ -282,11 +283,11 @@
                 //
                 // assuming both the stack pointer and page_size have their least
                 // significant 2 bits cleared and page_size is a power of 2
-                final Word alignedMask = Word.unsigned(wordSize() - 1);
+                final Word alignedMask = WordFactory.unsigned(wordSize() - 1);
                 final Word stackPointer = registerAsWord(stackPointerRegister).add(config(INJECTED_VMCONFIG).stackBias);
                 if (probability(FAST_PATH_PROBABILITY, currentMark.subtract(stackPointer).and(alignedMask.subtract(pageSize())).equal(0))) {
                     // Recursively locked => write 0 to the lock slot
-                    lock.writeWord(lockDisplacedMarkOffset(INJECTED_VMCONFIG), Word.zero(), DISPLACED_MARK_WORD_LOCATION);
+                    lock.writeWord(lockDisplacedMarkOffset(INJECTED_VMCONFIG), WordFactory.zero(), DISPLACED_MARK_WORD_LOCATION);
                     traceObject(trace, "+lock{cas:recursive}", object, true, options);
                     counters.lockCasRecursive.inc();
                     return;
@@ -323,7 +324,7 @@
         }
 
         // Now check to see whether biasing is enabled for this object
-        if (probability(NOT_FREQUENT_PROBABILITY, biasableLockBits.equal(Word.unsigned(biasedLockPattern(INJECTED_VMCONFIG))))) {
+        if (probability(NOT_FREQUENT_PROBABILITY, biasableLockBits.equal(WordFactory.unsigned(biasedLockPattern(INJECTED_VMCONFIG))))) {
             Pointer objectPointer = Word.objectToTrackedPointer(object);
             // At this point we know that the mark word has the bias pattern and
             // that we are not the bias owner in the current epoch. We need to
@@ -486,7 +487,7 @@
             // lock, the object could not be rebiased toward another thread, so
             // the bias bit would be clear.
             trace(trace, "             mark: 0x%016lx\n", mark);
-            if (probability(FREQUENT_PROBABILITY, mark.and(biasedLockMaskInPlace(INJECTED_VMCONFIG)).equal(Word.unsigned(biasedLockPattern(INJECTED_VMCONFIG))))) {
+            if (probability(FREQUENT_PROBABILITY, mark.and(biasedLockMaskInPlace(INJECTED_VMCONFIG)).equal(WordFactory.unsigned(biasedLockPattern(INJECTED_VMCONFIG))))) {
                 endLockScope();
                 decCounter(options);
                 traceObject(trace, "-lock{bias}", object, false, options);
@@ -561,7 +562,7 @@
                     // Nobody is waiting, success
                     // release_store
                     MembarNode.memoryBarrier(LOAD_STORE | STORE_STORE);
-                    monitor.writeWord(ownerOffset, Word.zero());
+                    monitor.writeWord(ownerOffset, WordFactory.zero());
                     traceObject(trace, "-lock{inflated:simple}", object, false, options);
                     counters.unlockInflatedSimple.inc();
                     return true;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/NewObjectSnippets.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/NewObjectSnippets.java	Fri May 12 13:56:13 2017 -0700
@@ -68,11 +68,12 @@
 import static org.graalvm.compiler.replacements.nodes.CStringConstant.cstring;
 import static org.graalvm.compiler.replacements.nodes.ExplodeLoopNode.explodeLoop;
 
+import org.graalvm.api.word.LocationIdentity;
+import org.graalvm.api.word.WordFactory;
 import org.graalvm.compiler.api.replacements.Fold;
 import org.graalvm.compiler.api.replacements.Snippet;
 import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter;
 import org.graalvm.compiler.api.replacements.Snippet.VarargsParameter;
-import org.graalvm.compiler.core.common.LocationIdentity;
 import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.debug.Debug;
@@ -467,7 +468,7 @@
             }
         } else {
             // Use Word instead of int to avoid extension to long in generated code
-            Word off = Word.signed(offset);
+            Word off = WordFactory.signed(offset);
             if (constantSize && ((size - offset) / 8) <= MAX_UNROLLED_OBJECT_ZEROING_STORES) {
                 if (counters != null && counters.instanceSeqInit != null) {
                     counters.instanceSeqInit.inc();
@@ -525,9 +526,9 @@
     protected static void verifyHeap(@ConstantParameter Register threadRegister) {
         Word thread = registerAsWord(threadRegister);
         Word topValue = readTlabTop(thread);
-        if (!topValue.equal(Word.zero())) {
+        if (!topValue.equal(WordFactory.zero())) {
             Word topValueContents = topValue.readWord(0, MARK_WORD_LOCATION);
-            if (topValueContents.equal(Word.zero())) {
+            if (topValueContents.equal(WordFactory.zero())) {
                 AssertionSnippets.vmMessageC(AssertionSnippets.ASSERTION_VM_MESSAGE_C, true, cstring("overzeroing of TLAB detected"), 0L, 0L, 0L);
             }
         }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/SHA2Substitutions.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/SHA2Substitutions.java	Fri May 12 13:56:13 2017 -0700
@@ -22,12 +22,13 @@
  */
 package org.graalvm.compiler.hotspot.replacements;
 
-import static org.graalvm.compiler.core.common.util.Util.Java8OrEarlier;
 import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayBaseOffset;
+import static org.graalvm.compiler.serviceprovider.JDK9Method.Java8OrEarlier;
 
+import org.graalvm.api.word.LocationIdentity;
+import org.graalvm.api.word.WordFactory;
 import org.graalvm.compiler.api.replacements.ClassSubstitution;
 import org.graalvm.compiler.api.replacements.MethodSubstitution;
-import org.graalvm.compiler.core.common.LocationIdentity;
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.hotspot.HotSpotBackend;
 import org.graalvm.compiler.hotspot.nodes.ComputeObjectAddressNode;
@@ -63,8 +64,8 @@
     static void implCompress0(Object receiver, byte[] buf, int ofs) {
         Object realReceiver = PiNode.piCastNonNull(receiver, shaClass);
         Object state = RawLoadNode.load(realReceiver, stateOffset, JavaKind.Object, LocationIdentity.any());
-        Word bufAddr = Word.unsigned(ComputeObjectAddressNode.get(buf, getArrayBaseOffset(JavaKind.Byte) + ofs));
-        Word stateAddr = Word.unsigned(ComputeObjectAddressNode.get(state, getArrayBaseOffset(JavaKind.Int)));
+        Word bufAddr = WordFactory.unsigned(ComputeObjectAddressNode.get(buf, getArrayBaseOffset(JavaKind.Byte) + ofs));
+        Word stateAddr = WordFactory.unsigned(ComputeObjectAddressNode.get(state, getArrayBaseOffset(JavaKind.Int)));
         HotSpotBackend.sha2ImplCompressStub(bufAddr, stateAddr);
     }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/SHA5Substitutions.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/SHA5Substitutions.java	Fri May 12 13:56:13 2017 -0700
@@ -22,12 +22,13 @@
  */
 package org.graalvm.compiler.hotspot.replacements;
 
-import static org.graalvm.compiler.core.common.util.Util.Java8OrEarlier;
 import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayBaseOffset;
+import static org.graalvm.compiler.serviceprovider.JDK9Method.Java8OrEarlier;
 
+import org.graalvm.api.word.LocationIdentity;
+import org.graalvm.api.word.WordFactory;
 import org.graalvm.compiler.api.replacements.ClassSubstitution;
 import org.graalvm.compiler.api.replacements.MethodSubstitution;
-import org.graalvm.compiler.core.common.LocationIdentity;
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.hotspot.HotSpotBackend;
 import org.graalvm.compiler.hotspot.nodes.ComputeObjectAddressNode;
@@ -63,8 +64,8 @@
     static void implCompress0(Object receiver, byte[] buf, int ofs) {
         Object realReceiver = PiNode.piCastNonNull(receiver, shaClass);
         Object state = RawLoadNode.load(realReceiver, stateOffset, JavaKind.Object, LocationIdentity.any());
-        Word bufAddr = Word.unsigned(ComputeObjectAddressNode.get(buf, getArrayBaseOffset(JavaKind.Byte) + ofs));
-        Word stateAddr = Word.unsigned(ComputeObjectAddressNode.get(state, getArrayBaseOffset(JavaKind.Int)));
+        Word bufAddr = WordFactory.unsigned(ComputeObjectAddressNode.get(buf, getArrayBaseOffset(JavaKind.Byte) + ofs));
+        Word stateAddr = WordFactory.unsigned(ComputeObjectAddressNode.get(state, getArrayBaseOffset(JavaKind.Int)));
         HotSpotBackend.sha5ImplCompressStub(bufAddr, stateAddr);
     }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/SHASubstitutions.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/SHASubstitutions.java	Fri May 12 13:56:13 2017 -0700
@@ -22,12 +22,13 @@
  */
 package org.graalvm.compiler.hotspot.replacements;
 
-import static org.graalvm.compiler.core.common.util.Util.Java8OrEarlier;
 import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayBaseOffset;
+import static org.graalvm.compiler.serviceprovider.JDK9Method.Java8OrEarlier;
 
+import org.graalvm.api.word.LocationIdentity;
+import org.graalvm.api.word.WordFactory;
 import org.graalvm.compiler.api.replacements.ClassSubstitution;
 import org.graalvm.compiler.api.replacements.MethodSubstitution;
-import org.graalvm.compiler.core.common.LocationIdentity;
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.hotspot.HotSpotBackend;
 import org.graalvm.compiler.hotspot.nodes.ComputeObjectAddressNode;
@@ -63,8 +64,8 @@
     static void implCompress0(Object receiver, byte[] buf, int ofs) {
         Object realReceiver = PiNode.piCastNonNull(receiver, shaClass);
         Object state = RawLoadNode.load(realReceiver, stateOffset, JavaKind.Object, LocationIdentity.any());
-        Word bufAddr = Word.unsigned(ComputeObjectAddressNode.get(buf, getArrayBaseOffset(JavaKind.Byte) + ofs));
-        Word stateAddr = Word.unsigned(ComputeObjectAddressNode.get(state, getArrayBaseOffset(JavaKind.Int)));
+        Word bufAddr = WordFactory.unsigned(ComputeObjectAddressNode.get(buf, getArrayBaseOffset(JavaKind.Byte) + ofs));
+        Word stateAddr = WordFactory.unsigned(ComputeObjectAddressNode.get(state, getArrayBaseOffset(JavaKind.Int)));
         HotSpotBackend.shaImplCompressStub(bufAddr, stateAddr);
     }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/StringToBytesSnippets.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/StringToBytesSnippets.java	Fri May 12 13:56:13 2017 -0700
@@ -25,10 +25,10 @@
 import static org.graalvm.compiler.hotspot.replacements.UnsafeAccess.UNSAFE;
 import static org.graalvm.compiler.replacements.SnippetTemplate.DEFAULT_REPLACER;
 
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.api.replacements.Fold;
 import org.graalvm.compiler.api.replacements.Snippet;
 import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter;
-import org.graalvm.compiler.core.common.LocationIdentity;
 import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
 import org.graalvm.compiler.nodes.NamedLocationIdentity;
 import org.graalvm.compiler.nodes.debug.StringToBytesNode;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ThreadSubstitutions.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ThreadSubstitutions.java	Fri May 12 13:56:13 2017 -0700
@@ -22,7 +22,7 @@
  */
 package org.graalvm.compiler.hotspot.replacements;
 
-import static org.graalvm.compiler.core.common.LocationIdentity.any;
+import static org.graalvm.api.word.LocationIdentity.any;
 import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG;
 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.JAVA_THREAD_OSTHREAD_LOCATION;
 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.JAVA_THREAD_THREAD_OBJECT_LOCATION;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/WriteBarrierSnippets.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/WriteBarrierSnippets.java	Fri May 12 13:56:13 2017 -0700
@@ -44,17 +44,19 @@
 import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.probability;
 import static org.graalvm.compiler.replacements.SnippetTemplate.DEFAULT_REPLACER;
 
+import org.graalvm.api.word.LocationIdentity;
+import org.graalvm.api.word.Pointer;
+import org.graalvm.api.word.Unsigned;
+import org.graalvm.api.word.WordFactory;
 import org.graalvm.compiler.api.replacements.Snippet;
 import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter;
 import org.graalvm.compiler.core.common.CompressEncoding;
 import org.graalvm.compiler.core.common.GraalOptions;
-import org.graalvm.compiler.core.common.LocationIdentity;
 import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
 import org.graalvm.compiler.graph.Node.ConstantNodeParameter;
 import org.graalvm.compiler.graph.Node.NodeIntrinsic;
 import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
 import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider;
-import org.graalvm.compiler.hotspot.nodes.CompressionNode;
 import org.graalvm.compiler.hotspot.nodes.G1ArrayRangePostWriteBarrier;
 import org.graalvm.compiler.hotspot.nodes.G1ArrayRangePreWriteBarrier;
 import org.graalvm.compiler.hotspot.nodes.G1PostWriteBarrier;
@@ -62,10 +64,10 @@
 import org.graalvm.compiler.hotspot.nodes.G1ReferentFieldReadBarrier;
 import org.graalvm.compiler.hotspot.nodes.GetObjectAddressNode;
 import org.graalvm.compiler.hotspot.nodes.GraalHotSpotVMConfigNode;
+import org.graalvm.compiler.hotspot.nodes.HotSpotCompressionNode;
 import org.graalvm.compiler.hotspot.nodes.SerialArrayRangeWriteBarrier;
 import org.graalvm.compiler.hotspot.nodes.SerialWriteBarrier;
 import org.graalvm.compiler.hotspot.nodes.VMErrorNode;
-import org.graalvm.compiler.hotspot.nodes.type.NarrowOopStamp;
 import org.graalvm.compiler.nodes.NamedLocationIdentity;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.ValueNode;
@@ -78,6 +80,7 @@
 import org.graalvm.compiler.nodes.memory.address.AddressNode.Address;
 import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
 import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.nodes.type.NarrowOopStamp;
 import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.replacements.Log;
 import org.graalvm.compiler.replacements.SnippetCounter;
@@ -87,8 +90,6 @@
 import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo;
 import org.graalvm.compiler.replacements.Snippets;
 import org.graalvm.compiler.replacements.nodes.DirectStoreNode;
-import org.graalvm.compiler.word.Pointer;
-import org.graalvm.compiler.word.Unsigned;
 import org.graalvm.compiler.word.Word;
 
 import jdk.vm.ci.code.Register;
@@ -134,7 +135,7 @@
         if (((int) startAddress) == startAddress && GraalHotSpotVMConfigNode.isCardTableAddressConstant()) {
             base.writeByte((int) startAddress, (byte) 0, GC_CARD_LOCATION);
         } else {
-            base.writeByte(Word.unsigned(startAddress), (byte) 0, GC_CARD_LOCATION);
+            base.writeByte(WordFactory.unsigned(startAddress), (byte) 0, GC_CARD_LOCATION);
         }
     }
 
@@ -176,12 +177,13 @@
         Word thread = registerAsWord(threadRegister);
         verifyOop(object);
         Object fixedExpectedObject = FixedValueAnchorNode.getObject(expectedObject);
-        Pointer field = Word.fromAddress(address);
+        Word field = Word.fromAddress(address);
         Pointer previousOop = Word.objectToTrackedPointer(fixedExpectedObject);
         byte markingValue = thread.readByte(g1SATBQueueMarkingOffset(INJECTED_VMCONFIG));
         int gcCycle = 0;
         if (trace) {
-            gcCycle = (int) Word.unsigned(HotSpotReplacementsUtil.gcTotalCollectionsAddress(INJECTED_VMCONFIG)).readLong(0);
+            Pointer gcTotalCollectionsAddress = WordFactory.pointer(HotSpotReplacementsUtil.gcTotalCollectionsAddress(INJECTED_VMCONFIG));
+            gcCycle = (int) gcTotalCollectionsAddress.readLong(0);
             log(trace, "[%d] G1-Pre Thread %p Object %p\n", gcCycle, thread.rawValue(), Word.objectToTrackedPointer(object).rawValue());
             log(trace, "[%d] G1-Pre Thread %p Expected Object %p\n", gcCycle, thread.rawValue(), Word.objectToTrackedPointer(fixedExpectedObject).rawValue());
             log(trace, "[%d] G1-Pre Thread %p Field %p\n", gcCycle, thread.rawValue(), field.rawValue());
@@ -238,7 +240,8 @@
         }
         int gcCycle = 0;
         if (trace) {
-            gcCycle = (int) Word.unsigned(HotSpotReplacementsUtil.gcTotalCollectionsAddress(INJECTED_VMCONFIG)).readLong(0);
+            Pointer gcTotalCollectionsAddress = WordFactory.pointer(HotSpotReplacementsUtil.gcTotalCollectionsAddress(INJECTED_VMCONFIG));
+            gcCycle = (int) gcTotalCollectionsAddress.readLong(0);
             log(trace, "[%d] G1-Post Thread: %p Object: %p\n", gcCycle, thread.rawValue(), Word.objectToTrackedPointer(object).rawValue());
             log(trace, "[%d] G1-Post Thread: %p Field: %p\n", gcCycle, thread.rawValue(), oop.rawValue());
         }
@@ -256,7 +259,7 @@
         if (((int) startAddress) == startAddress && GraalHotSpotVMConfigNode.isCardTableAddressConstant()) {
             displacement = (int) startAddress;
         } else {
-            cardBase = cardBase.add(Word.unsigned(startAddress));
+            cardBase = cardBase.add(WordFactory.unsigned(startAddress));
         }
         Word cardAddress = (Word) cardBase.add(displacement);
 
@@ -274,7 +277,7 @@
                     MembarNode.memoryBarrier(STORE_LOAD, GC_CARD_LOCATION);
                     byte cardByteReload = cardAddress.readByte(0, GC_CARD_LOCATION);
                     if (probability(NOT_FREQUENT_PROBABILITY, cardByteReload != dirtyCardValue(INJECTED_VMCONFIG))) {
-                        log(trace, "[%d] G1-Post Thread: %p Card: %p \n", gcCycle, thread.rawValue(), Word.unsigned(cardByte).rawValue());
+                        log(trace, "[%d] G1-Post Thread: %p Card: %p \n", gcCycle, thread.rawValue(), WordFactory.unsigned((int) cardByte).rawValue());
                         cardAddress.writeByte(0, (byte) 0, GC_CARD_LOCATION);
                         counters.g1ExecutedPostWriteBarrierCounter.inc();
 
@@ -316,16 +319,16 @@
         int header = arrayBaseOffset(JavaKind.Object);
 
         for (int i = startIndex; i < length; i++) {
-            long address = dstAddr + header + (i * scale);
-            Pointer oop = Word.objectToTrackedPointer(Word.unsigned(address).readObject(0, BarrierType.NONE));
+            Word address = WordFactory.pointer(dstAddr + header + (i * scale));
+            Pointer oop = Word.objectToTrackedPointer(address.readObject(0, BarrierType.NONE));
             verifyOop(oop.toObject());
             if (oop.notEqual(0)) {
                 if (indexValue != 0) {
                     indexValue = indexValue - wordSize();
-                    Word logAddress = bufferAddress.add(Word.unsigned(indexValue));
+                    Word logAddress = bufferAddress.add(WordFactory.unsigned(indexValue));
                     // Log the object to be marked as well as update the SATB's buffer next index.
                     logAddress.writeWord(0, oop, GC_LOG_LOCATION);
-                    indexAddress.writeWord(0, Word.unsigned(indexValue), GC_INDEX_LOCATION);
+                    indexAddress.writeWord(0, WordFactory.unsigned(indexValue), GC_INDEX_LOCATION);
                 } else {
                     g1PreBarrierStub(G1WBPRECALL, oop.toObject());
                 }
@@ -354,7 +357,7 @@
         long count = end - start + 1;
 
         while (count-- > 0) {
-            Word cardAddress = Word.unsigned((start + cardStart) + count);
+            Word cardAddress = WordFactory.unsigned((start + cardStart) + count);
             byte cardByte = cardAddress.readByte(0, GC_CARD_LOCATION);
             // If the card is already dirty, (hence already enqueued) skip the insertion.
             if (probability(NOT_FREQUENT_PROBABILITY, cardByte != g1YoungCardValue(INJECTED_VMCONFIG))) {
@@ -366,11 +369,11 @@
                     // initialize a new one and add the card entry.
                     if (indexValue != 0) {
                         indexValue = indexValue - wordSize();
-                        Word logAddress = bufferAddress.add(Word.unsigned(indexValue));
+                        Word logAddress = bufferAddress.add(WordFactory.unsigned(indexValue));
                         // Log the object to be scanned as well as update
                         // the card queue's next index.
                         logAddress.writeWord(0, cardAddress, GC_LOG_LOCATION);
-                        indexAddress.writeWord(0, Word.unsigned(indexValue), GC_INDEX_LOCATION);
+                        indexAddress.writeWord(0, WordFactory.unsigned(indexValue), GC_INDEX_LOCATION);
                     } else {
                         g1PostBarrierStub(G1WBPOSTCALL, cardAddress);
                     }
@@ -444,7 +447,7 @@
             ValueNode expected = writeBarrierPre.getExpectedObject();
             if (expected != null && expected.stamp() instanceof NarrowOopStamp) {
                 assert oopEncoding != null;
-                expected = CompressionNode.uncompress(expected, oopEncoding);
+                expected = HotSpotCompressionNode.uncompress(expected, oopEncoding);
             }
             args.add("expectedObject", expected);
 
@@ -469,7 +472,7 @@
             ValueNode expected = readBarrier.getExpectedObject();
             if (expected != null && expected.stamp() instanceof NarrowOopStamp) {
                 assert oopEncoding != null;
-                expected = CompressionNode.uncompress(expected, oopEncoding);
+                expected = HotSpotCompressionNode.uncompress(expected, oopEncoding);
             }
 
             args.add("expectedObject", expected);
@@ -500,7 +503,7 @@
             ValueNode value = writeBarrierPost.getValue();
             if (value.stamp() instanceof NarrowOopStamp) {
                 assert oopEncoding != null;
-                value = CompressionNode.uncompress(value, oopEncoding);
+                value = HotSpotCompressionNode.uncompress(value, oopEncoding);
             }
             args.add("value", value);
 
@@ -553,7 +556,8 @@
 
     public static boolean traceBarrier(StructuredGraph graph) {
         return GraalOptions.GCDebugStartCycle.getValue(graph.getOptions()) > 0 &&
-                        ((int) Word.unsigned(HotSpotReplacementsUtil.gcTotalCollectionsAddress(INJECTED_VMCONFIG)).readLong(0) > GraalOptions.GCDebugStartCycle.getValue(graph.getOptions()));
+                        ((int) ((Pointer) WordFactory.pointer(HotSpotReplacementsUtil.gcTotalCollectionsAddress(INJECTED_VMCONFIG))).readLong(0) > GraalOptions.GCDebugStartCycle.getValue(
+                                        graph.getOptions()));
     }
 
     /**
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopyCallNode.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopyCallNode.java	Fri May 12 13:56:13 2017 -0700
@@ -26,10 +26,12 @@
 import static org.graalvm.compiler.nodeinfo.InputType.Memory;
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN;
+
+import org.graalvm.api.word.LocationIdentity;
+
 import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayBaseOffset;
 import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayIndexScale;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
 import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.core.common.type.StampFactory;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopyNode.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopyNode.java	Fri May 12 13:56:13 2017 -0700
@@ -22,9 +22,9 @@
  */
 package org.graalvm.compiler.hotspot.replacements.arraycopy;
 
-import static org.graalvm.compiler.core.common.LocationIdentity.any;
+import static org.graalvm.api.word.LocationIdentity.any;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
 import org.graalvm.compiler.nodes.NamedLocationIdentity;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopySlowPathNode.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopySlowPathNode.java	Fri May 12 13:56:13 2017 -0700
@@ -25,9 +25,9 @@
 import jdk.vm.ci.code.BytecodeFrame;
 import jdk.vm.ci.meta.JavaKind;
 
-import static org.graalvm.compiler.core.common.LocationIdentity.any;
+import static org.graalvm.api.word.LocationIdentity.any;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.hotspot.word.KlassPointer;
 import org.graalvm.compiler.nodeinfo.InputType;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopySnippets.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopySnippets.java	Fri May 12 13:56:13 2017 -0700
@@ -39,11 +39,12 @@
 import java.lang.reflect.Method;
 import java.util.EnumMap;
 
+import org.graalvm.api.word.LocationIdentity;
+import org.graalvm.api.word.WordFactory;
 import org.graalvm.compiler.api.directives.GraalDirectives;
 import org.graalvm.compiler.api.replacements.Fold;
 import org.graalvm.compiler.api.replacements.Snippet;
 import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter;
-import org.graalvm.compiler.core.common.LocationIdentity;
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
@@ -247,7 +248,7 @@
                 ArrayCopyCallNode.arraycopyObjectKillsAny(nonNullSrc, srcPos, nonNullDest, destPos, length);
             } else {
                 KlassPointer destElemKlass = destKlass.readKlassPointer(arrayClassElementOffset(INJECTED_VMCONFIG), OBJ_ARRAY_KLASS_ELEMENT_KLASS_LOCATION);
-                Word superCheckOffset = Word.signed(destElemKlass.readInt(superCheckOffsetOffset(INJECTED_VMCONFIG), KLASS_SUPER_CHECK_OFFSET_LOCATION));
+                Word superCheckOffset = WordFactory.signed(destElemKlass.readInt(superCheckOffsetOffset(INJECTED_VMCONFIG), KLASS_SUPER_CHECK_OFFSET_LOCATION));
                 counters.objectCheckcastCounter.inc();
                 counters.objectCheckcastCopiedCounter.add(length);
                 int copiedElements = CheckcastArrayCopyCallNode.checkcastArraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, superCheckOffset, destElemKlass, false);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopyUnrollNode.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopyUnrollNode.java	Fri May 12 13:56:13 2017 -0700
@@ -24,9 +24,9 @@
 
 import jdk.vm.ci.meta.JavaKind;
 
-import static org.graalvm.compiler.core.common.LocationIdentity.any;
+import static org.graalvm.api.word.LocationIdentity.any;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.nodeinfo.InputType;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/CheckcastArrayCopyCallNode.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/CheckcastArrayCopyCallNode.java	Fri May 12 13:56:13 2017 -0700
@@ -25,10 +25,12 @@
 
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN;
+
+import org.graalvm.api.word.LocationIdentity;
+
 import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayBaseOffset;
 import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayIndexScale;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
 import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.graph.NodeClass;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/UnsafeArrayCopyNode.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/UnsafeArrayCopyNode.java	Fri May 12 13:56:13 2017 -0700
@@ -22,11 +22,11 @@
  */
 package org.graalvm.compiler.hotspot.replacements.arraycopy;
 
-import static org.graalvm.compiler.core.common.LocationIdentity.any;
+import static org.graalvm.api.word.LocationIdentity.any;
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_256;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_64;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.nodeinfo.InputType;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/UnsafeArrayCopySnippets.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/UnsafeArrayCopySnippets.java	Fri May 12 13:56:13 2017 -0700
@@ -35,12 +35,16 @@
 import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.NOT_FREQUENT_PROBABILITY;
 import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.probability;
 import static org.graalvm.compiler.replacements.SnippetTemplate.DEFAULT_REPLACER;
+
+import org.graalvm.api.word.LocationIdentity;
+import org.graalvm.api.word.Unsigned;
+import org.graalvm.api.word.WordFactory;
+
 import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayIndexScale;
 
 import org.graalvm.compiler.api.replacements.Fold;
 import org.graalvm.compiler.api.replacements.Snippet;
 import org.graalvm.compiler.core.common.NumUtil;
-import org.graalvm.compiler.core.common.LocationIdentity;
 import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
 import org.graalvm.compiler.hotspot.phases.WriteBarrierAdditionPhase;
 import org.graalvm.compiler.nodes.NamedLocationIdentity;
@@ -53,11 +57,8 @@
 import org.graalvm.compiler.replacements.SnippetTemplate.AbstractTemplates;
 import org.graalvm.compiler.replacements.SnippetTemplate.Arguments;
 import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo;
+import org.graalvm.compiler.word.ObjectAccess;
 import org.graalvm.compiler.replacements.Snippets;
-import org.graalvm.compiler.word.ObjectAccess;
-import org.graalvm.compiler.word.Unsigned;
-import org.graalvm.compiler.word.Word;
-
 import jdk.vm.ci.code.TargetDescription;
 import jdk.vm.ci.meta.JavaKind;
 
@@ -236,15 +237,15 @@
         int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift(INJECTED_VMCONFIG)) & layoutHelperLog2ElementSizeMask(INJECTED_VMCONFIG);
         int headerSize = (layoutHelper >> layoutHelperHeaderSizeShift(INJECTED_VMCONFIG)) & layoutHelperHeaderSizeMask(INJECTED_VMCONFIG);
 
-        Unsigned vectorSize = Word.unsigned(VECTOR_SIZE);
-        Unsigned srcOffset = Word.unsigned(srcPos).shiftLeft(log2ElementSize).add(headerSize);
-        Unsigned destOffset = Word.unsigned(destPos).shiftLeft(log2ElementSize).add(headerSize);
+        Unsigned vectorSize = WordFactory.unsigned(VECTOR_SIZE);
+        Unsigned srcOffset = WordFactory.unsigned(srcPos).shiftLeft(log2ElementSize).add(headerSize);
+        Unsigned destOffset = WordFactory.unsigned(destPos).shiftLeft(log2ElementSize).add(headerSize);
         Unsigned destStart = destOffset;
-        Unsigned destEnd = destOffset.add(Word.unsigned(length).shiftLeft(log2ElementSize));
+        Unsigned destEnd = destOffset.add(WordFactory.unsigned(length).shiftLeft(log2ElementSize));
 
         Unsigned destVectorEnd = null;
         Unsigned nonVectorBytes = null;
-        Unsigned sizeInBytes = Word.unsigned(length).shiftLeft(log2ElementSize);
+        Unsigned sizeInBytes = WordFactory.unsigned(length).shiftLeft(log2ElementSize);
         if (supportsUnalignedMemoryAccess) {
             nonVectorBytes = sizeInBytes.unsignedRemainder(vectorSize);
             destVectorEnd = destEnd;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/CreateExceptionStub.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/CreateExceptionStub.java	Fri May 12 13:56:13 2017 -0700
@@ -22,7 +22,7 @@
  */
 package org.graalvm.compiler.hotspot.stubs;
 
-import static org.graalvm.compiler.core.common.LocationIdentity.any;
+import static org.graalvm.api.word.LocationIdentity.any;
 import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.RegisterEffect.DESTROYS_REGISTERS;
 import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.Transition.SAFEPOINT;
 import static org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProviderImpl.REEXECUTABLE;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/ExceptionHandlerStub.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/ExceptionHandlerStub.java	Fri May 12 13:56:13 2017 -0700
@@ -36,6 +36,7 @@
 import static org.graalvm.compiler.hotspot.stubs.StubUtil.newDescriptor;
 import static org.graalvm.compiler.hotspot.stubs.StubUtil.printf;
 
+import org.graalvm.api.word.WordFactory;
 import org.graalvm.compiler.api.replacements.Fold;
 import org.graalvm.compiler.api.replacements.Fold.InjectedParameter;
 import org.graalvm.compiler.api.replacements.Snippet;
@@ -127,7 +128,7 @@
                 // This thread-local is only cleared in DEBUG builds of the VM
                 // (see OptoRuntime::generate_exception_blob)
                 Word currentExceptionPc = readExceptionPc(thread);
-                if (currentExceptionPc.notEqual(Word.zero())) {
+                if (currentExceptionPc.notEqual(WordFactory.zero())) {
                     fatal("exception PC in thread must be zero, not %p", currentExceptionPc.rawValue());
                 }
             }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/ForeignCallStub.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/ForeignCallStub.java	Fri May 12 13:56:13 2017 -0700
@@ -24,13 +24,15 @@
 
 import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.RegisterEffect.DESTROYS_REGISTERS;
 import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.RegisterEffect.PRESERVES_REGISTERS;
+
+import org.graalvm.api.word.LocationIdentity;
+
 import static jdk.vm.ci.hotspot.HotSpotCallingConventionType.JavaCall;
 import static jdk.vm.ci.hotspot.HotSpotCallingConventionType.JavaCallee;
 import static jdk.vm.ci.hotspot.HotSpotCallingConventionType.NativeCall;
 
 import org.graalvm.compiler.core.common.CompilationIdentifier;
 import org.graalvm.compiler.core.common.LIRKind;
-import org.graalvm.compiler.core.common.LocationIdentity;
 import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.core.common.type.StampFactory;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/NewArrayStub.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/NewArrayStub.java	Fri May 12 13:56:13 2017 -0700
@@ -41,6 +41,9 @@
 import static org.graalvm.compiler.hotspot.stubs.StubUtil.newDescriptor;
 import static org.graalvm.compiler.hotspot.stubs.StubUtil.printf;
 import static org.graalvm.compiler.hotspot.stubs.StubUtil.verifyObject;
+
+import org.graalvm.api.word.WordFactory;
+
 import static jdk.vm.ci.hotspot.HotSpotMetaAccessProvider.computeArrayAllocationSize;
 
 import org.graalvm.compiler.api.replacements.Fold;
@@ -128,7 +131,7 @@
                     printf("newArray: allocated new array at %p\n", memory.rawValue());
                 }
                 return verifyObject(
-                                formatArray(hub, sizeInBytes, length, headerSize, memory, Word.unsigned(arrayPrototypeMarkWord(INJECTED_VMCONFIG)), fillContents, false, null));
+                                formatArray(hub, sizeInBytes, length, headerSize, memory, WordFactory.unsigned(arrayPrototypeMarkWord(INJECTED_VMCONFIG)), fillContents, false, null));
             }
         }
         if (logging(options)) {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/NewInstanceStub.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/NewInstanceStub.java	Fri May 12 13:56:13 2017 -0700
@@ -63,6 +63,8 @@
 import static org.graalvm.compiler.hotspot.stubs.StubUtil.verifyObject;
 import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.FAST_PATH_PROBABILITY;
 import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.probability;
+
+import org.graalvm.api.word.WordFactory;
 import org.graalvm.compiler.api.replacements.Fold;
 import org.graalvm.compiler.api.replacements.Snippet;
 import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter;
@@ -122,7 +124,7 @@
             writeTlabTop(thread, newTop);
             return top;
         }
-        return Word.zero();
+        return WordFactory.zero();
     }
 
     @Fold
@@ -173,19 +175,19 @@
      * @param sizeInBytes the size of the allocation
      * @param log specifies if logging is enabled
      *
-     * @return the newly allocated, uninitialized chunk of memory, or {@link Word#zero()} if the
-     *         operation was unsuccessful
+     * @return the newly allocated, uninitialized chunk of memory, or {@link WordFactory#zero()} if
+     *         the operation was unsuccessful
      */
     static Word refillAllocate(Word thread, KlassPointer intArrayHub, int sizeInBytes, boolean log) {
         // If G1 is enabled, the "eden" allocation space is not the same always
         // and therefore we have to go to slowpath to allocate a new TLAB.
         if (useG1GC(INJECTED_VMCONFIG)) {
-            return Word.zero();
+            return WordFactory.zero();
         }
         if (!useTLAB(INJECTED_VMCONFIG)) {
-            return edenAllocate(Word.unsigned(sizeInBytes), log);
+            return edenAllocate(WordFactory.unsigned(sizeInBytes), log);
         }
-        Word intArrayMarkWord = Word.unsigned(tlabIntArrayMarkWord(INJECTED_VMCONFIG));
+        Word intArrayMarkWord = WordFactory.unsigned(tlabIntArrayMarkWord(INJECTED_VMCONFIG));
         int alignmentReserveInBytes = tlabAlignmentReserveInHeapWords(INJECTED_VMCONFIG) * wordSize();
 
         Word top = readTlabTop(thread);
@@ -247,7 +249,7 @@
 
                 return NewInstanceStub.allocate(thread, sizeInBytes);
             } else {
-                return Word.zero();
+                return WordFactory.zero();
             }
         } else {
             // Retain TLAB
@@ -262,7 +264,7 @@
                                 TLAB_SLOW_ALLOCATIONS_LOCATION);
             }
 
-            return edenAllocate(Word.unsigned(sizeInBytes), log);
+            return edenAllocate(WordFactory.unsigned(sizeInBytes), log);
         }
     }
 
@@ -271,25 +273,25 @@
      *
      * @param sizeInBytes the size of the chunk to allocate
      * @param log specifies if logging is enabled
-     * @return the allocated chunk or {@link Word#zero()} if allocation fails
+     * @return the allocated chunk or {@link WordFactory#zero()} if allocation fails
      */
     public static Word edenAllocate(Word sizeInBytes, boolean log) {
         final long heapTopRawAddress = GraalHotSpotVMConfigNode.heapTopAddress();
         final long heapEndRawAddress = GraalHotSpotVMConfigNode.heapEndAddress();
 
-        Word heapTopAddress = Word.unsigned(heapTopRawAddress);
-        Word heapEndAddress = Word.unsigned(heapEndRawAddress);
+        Word heapTopAddress = WordFactory.unsigned(heapTopRawAddress);
+        Word heapEndAddress = WordFactory.unsigned(heapEndRawAddress);
 
         while (true) {
             Word heapTop = heapTopAddress.readWord(0, HEAP_TOP_LOCATION);
             Word newHeapTop = heapTop.add(sizeInBytes);
             if (newHeapTop.belowOrEqual(heapTop)) {
-                return Word.zero();
+                return WordFactory.zero();
             }
 
             Word heapEnd = heapEndAddress.readWord(0, HEAP_END_LOCATION);
             if (newHeapTop.aboveThan(heapEnd)) {
-                return Word.zero();
+                return WordFactory.zero();
             }
             if (heapTopAddress.logicCompareAndSwapWord(0, heapTop, newHeapTop, HEAP_TOP_LOCATION)) {
                 return heapTop;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/SnippetStub.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/SnippetStub.java	Fri May 12 13:56:13 2017 -0700
@@ -139,7 +139,7 @@
     }
 
     protected BytecodeProvider getReplacementsBytecodeProvider() {
-        return providers.getReplacements().getReplacementBytecodeProvider();
+        return providers.getReplacements().getDefaultReplacementBytecodeProvider();
     }
 
     protected boolean checkConstArg(int index, String expectedName) {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/StubUtil.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/StubUtil.java	Fri May 12 13:56:13 2017 -0700
@@ -22,20 +22,21 @@
  */
 package org.graalvm.compiler.hotspot.stubs;
 
+import static jdk.vm.ci.meta.DeoptimizationReason.RuntimeConstraint;
 import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG;
 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.clearPendingException;
 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.getAndClearObjectResult;
 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.loadHubIntrinsic;
 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.verifyOops;
 import static org.graalvm.compiler.replacements.nodes.CStringConstant.cstring;
-import static org.graalvm.compiler.word.Word.unsigned;
-import static jdk.vm.ci.meta.DeoptimizationReason.RuntimeConstraint;
 
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.util.Arrays;
 import java.util.List;
 
+import org.graalvm.api.word.Pointer;
+import org.graalvm.api.word.WordFactory;
 import org.graalvm.compiler.api.replacements.Fold;
 import org.graalvm.compiler.api.replacements.Fold.InjectedParameter;
 import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
@@ -50,7 +51,6 @@
 import org.graalvm.compiler.nodes.SnippetAnchorNode;
 import org.graalvm.compiler.nodes.extended.GuardingNode;
 import org.graalvm.compiler.replacements.Log;
-import org.graalvm.compiler.word.Pointer;
 import org.graalvm.compiler.word.Word;
 
 import jdk.vm.ci.meta.DeoptimizationAction;
@@ -171,7 +171,7 @@
      * Analyzes a given value and prints information about it to the log stream.
      */
     public static void decipher(long value) {
-        vmMessageC(VM_MESSAGE_C, false, Word.zero(), value, 0L, 0L);
+        vmMessageC(VM_MESSAGE_C, false, WordFactory.zero(), value, 0L, 0L);
     }
 
     /**
@@ -233,14 +233,14 @@
      */
     public static Object verifyObject(Object object) {
         if (verifyOops(INJECTED_VMCONFIG)) {
-            Word verifyOopCounter = Word.unsigned(verifyOopCounterAddress(INJECTED_VMCONFIG));
+            Word verifyOopCounter = WordFactory.unsigned(verifyOopCounterAddress(INJECTED_VMCONFIG));
             verifyOopCounter.writeInt(0, verifyOopCounter.readInt(0) + 1);
 
             Pointer oop = Word.objectToTrackedPointer(object);
             if (object != null) {
                 GuardingNode anchorNode = SnippetAnchorNode.anchor();
                 // make sure object is 'reasonable'
-                if (!oop.and(unsigned(verifyOopMask(INJECTED_VMCONFIG))).equal(unsigned(verifyOopBits(INJECTED_VMCONFIG)))) {
+                if (!oop.and(WordFactory.unsigned(verifyOopMask(INJECTED_VMCONFIG))).equal(WordFactory.unsigned(verifyOopBits(INJECTED_VMCONFIG)))) {
                     fatal("oop not in heap: %p", oop.rawValue());
                 }
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/UnwindExceptionToCallerStub.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/UnwindExceptionToCallerStub.java	Fri May 12 13:56:13 2017 -0700
@@ -32,6 +32,7 @@
 import static org.graalvm.compiler.hotspot.stubs.StubUtil.newDescriptor;
 import static org.graalvm.compiler.hotspot.stubs.StubUtil.printf;
 
+import org.graalvm.api.word.Pointer;
 import org.graalvm.compiler.api.replacements.Fold;
 import org.graalvm.compiler.api.replacements.Fold.InjectedParameter;
 import org.graalvm.compiler.api.replacements.Snippet;
@@ -46,7 +47,6 @@
 import org.graalvm.compiler.hotspot.nodes.StubForeignCallNode;
 import org.graalvm.compiler.nodes.UnwindNode;
 import org.graalvm.compiler.options.OptionValues;
-import org.graalvm.compiler.word.Pointer;
 import org.graalvm.compiler.word.Word;
 
 import jdk.vm.ci.code.Register;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/word/KlassPointer.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/word/KlassPointer.java	Fri May 12 13:56:13 2017 -0700
@@ -27,8 +27,8 @@
 import static org.graalvm.compiler.hotspot.word.HotSpotOperation.HotspotOpcode.READ_KLASS_POINTER;
 import static org.graalvm.compiler.hotspot.word.HotSpotOperation.HotspotOpcode.TO_KLASS_POINTER;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
-import org.graalvm.compiler.word.Pointer;
+import org.graalvm.api.word.LocationIdentity;
+import org.graalvm.api.word.Pointer;
 import org.graalvm.compiler.word.Word.Opcode;
 import org.graalvm.compiler.word.Word.Operation;
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/word/MetaspacePointer.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/word/MetaspacePointer.java	Fri May 12 13:56:13 2017 -0700
@@ -25,15 +25,15 @@
 import static org.graalvm.compiler.hotspot.word.HotSpotOperation.HotspotOpcode.FROM_POINTER;
 import static org.graalvm.compiler.hotspot.word.HotSpotOperation.HotspotOpcode.IS_NULL;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
+import org.graalvm.api.word.Pointer;
+import org.graalvm.api.word.Signed;
+import org.graalvm.api.word.Unsigned;
+import org.graalvm.api.word.WordBase;
 import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType;
-import org.graalvm.compiler.word.Pointer;
-import org.graalvm.compiler.word.Signed;
-import org.graalvm.compiler.word.Unsigned;
 import org.graalvm.compiler.word.Word;
 import org.graalvm.compiler.word.Word.Opcode;
 import org.graalvm.compiler.word.Word.Operation;
-import org.graalvm.compiler.word.WordBase;
 
 /**
  * Marker type for a metaspace pointer.
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/word/MethodPointer.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/word/MethodPointer.java	Fri May 12 13:56:13 2017 -0700
@@ -26,7 +26,7 @@
 import static org.graalvm.compiler.hotspot.word.HotSpotOperation.HotspotOpcode.POINTER_NE;
 import static org.graalvm.compiler.hotspot.word.HotSpotOperation.HotspotOpcode.TO_METHOD_POINTER;
 
-import org.graalvm.compiler.word.Pointer;
+import org.graalvm.api.word.Pointer;
 
 /**
  * Marker type for a metaspace pointer to a method.
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java	Fri May 12 13:56:13 2017 -0700
@@ -247,6 +247,7 @@
 import static org.graalvm.compiler.core.common.type.StampFactory.objectNonNull;
 import static org.graalvm.compiler.debug.GraalError.guarantee;
 import static org.graalvm.compiler.debug.GraalError.shouldNotReachHere;
+import static org.graalvm.compiler.java.BytecodeParserOptions.DumpWithInfopoints;
 import static org.graalvm.compiler.java.BytecodeParserOptions.TraceBytecodeParserLevel;
 import static org.graalvm.compiler.java.BytecodeParserOptions.TraceInlineDuringParsing;
 import static org.graalvm.compiler.java.BytecodeParserOptions.TraceParserPlugins;
@@ -262,6 +263,7 @@
 import java.util.Formatter;
 import java.util.List;
 
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.bytecode.Bytecode;
 import org.graalvm.compiler.bytecode.BytecodeDisassembler;
 import org.graalvm.compiler.bytecode.BytecodeLookupSwitch;
@@ -273,7 +275,6 @@
 import org.graalvm.compiler.bytecode.Bytes;
 import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecode;
 import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecodeProvider;
-import org.graalvm.compiler.core.common.LocationIdentity;
 import org.graalvm.compiler.core.common.PermanentBailoutException;
 import org.graalvm.compiler.core.common.calc.Condition;
 import org.graalvm.compiler.core.common.calc.FloatConvert;
@@ -427,6 +428,7 @@
 import jdk.vm.ci.meta.ResolvedJavaField;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 import jdk.vm.ci.meta.ResolvedJavaType;
+import jdk.vm.ci.meta.Signature;
 import jdk.vm.ci.meta.TriState;
 
 /**
@@ -1087,7 +1089,7 @@
     }
 
     protected ValueNode genNormalizeCompare(ValueNode x, ValueNode y, boolean isUnorderedLess) {
-        return NormalizeCompareNode.create(x, y, isUnorderedLess, constantReflection);
+        return NormalizeCompareNode.create(x, y, isUnorderedLess, JavaKind.Int, constantReflection);
     }
 
     protected ValueNode genFloatConvert(FloatConvert op, ValueNode input) {
@@ -1374,7 +1376,7 @@
 
     @Override
     public void handleReplacedInvoke(CallTargetNode callTarget, JavaKind resultType) {
-        createNonInlinedInvoke(callTarget, resultType, null);
+        createNonInlinedInvoke(bci(), callTarget, resultType, null);
     }
 
     private Invoke appendInvoke(InvokeKind initialInvokeKind, ResolvedJavaMethod initialTargetMethod, ValueNode[] args) {
@@ -1440,23 +1442,74 @@
             currentInvokeKind = null;
         }
 
+        int bci = bci();
+        boolean partialIntrinsicExit = false;
+        if (intrinsicContext != null && intrinsicContext.isCallToOriginal(targetMethod)) {
+            partialIntrinsicExit = true;
+            ResolvedJavaMethod originalMethod = intrinsicContext.getOriginalMethod();
+            if (originalMethod.isStatic()) {
+                invokeKind = InvokeKind.Static;
+            } else {
+                // The original call to the intrinsic must have been devirtualized
+                // otherwise we wouldn't be here.
+                invokeKind = InvokeKind.Special;
+            }
+            Signature sig = originalMethod.getSignature();
+            returnType = sig.getReturnType(method.getDeclaringClass());
+            resultType = sig.getReturnKind();
+            bci = intrinsicContext.bci();
+            assert checkPartialIntrinsicExit(args);
+            targetMethod = originalMethod;
+        }
         JavaTypeProfile profile = null;
         if (invokeKind.isIndirect() && profilingInfo != null && this.optimisticOpts.useTypeCheckHints(getOptions())) {
             profile = profilingInfo.getTypeProfile(bci());
         }
-        return createNonInlinedInvoke(args, targetMethod, invokeKind, resultType, returnType, inlineInfo, profile);
+        Invoke invoke = createNonInlinedInvoke(args, bci, targetMethod, invokeKind, resultType, returnType, inlineInfo, profile);
+        if (partialIntrinsicExit) {
+            // This invoke must never be later inlined as it might select the intrinsic graph.
+            // Until there is a mechanism to guarantee that any late inlining will not select
+            // the intrinsic graph, prevent this invoke from being inlined.
+            invoke.setUseForInlining(false);
+        }
+        return invoke;
     }
 
-    protected Invoke createNonInlinedInvoke(ValueNode[] args, ResolvedJavaMethod targetMethod, InvokeKind invokeKind,
-                    JavaKind resultType, JavaType returnType, InlineInfo inlineInfo, JavaTypeProfile profile) {
+    /**
+     * A partial intrinsic exits by (effectively) calling the intrinsified method. This call must
+     * use exactly the arguments to the call being intrinsified.
+     *
+     * @param args arguments of recursive call to intrinsified method
+     */
+    private boolean checkPartialIntrinsicExit(ValueNode[] args) {
+        if (intrinsicContext.getArgs() != null) {
+            assert intrinsicContext.bci() >= 0;
+            ValueNode[] icArgs = intrinsicContext.getArgs();
+            for (int i = 0; i < icArgs.length; i++) {
+                ValueNode arg = GraphUtil.unproxify(args[i]);
+                ValueNode icArg = GraphUtil.unproxify(icArgs[i]);
+                assert arg == icArg : String.format("argument %d of call denoting partial intrinsic exit should be %s, not %s", i, icArg, arg);
+            }
+        } else {
+            for (int i = 0; i < args.length; i++) {
+                ValueNode arg = GraphUtil.unproxify(args[i]);
+                assert arg instanceof ParameterNode && ((ParameterNode) arg).index() == i : String.format("argument %d of call denoting partial intrinsic exit should be a %s with index %d, not %s", i,
+                                ParameterNode.class.getSimpleName(), i, arg);
+            }
+        }
+        return true;
+    }
+
+    protected Invoke createNonInlinedInvoke(ValueNode[] invokeArgs, int invokeBci, ResolvedJavaMethod targetMethod,
+                    InvokeKind invokeKind, JavaKind resultType, JavaType returnType, InlineInfo inlineInfo, JavaTypeProfile profile) {
 
         StampPair returnStamp = graphBuilderConfig.getPlugins().getOverridingStamp(this, returnType, false);
         if (returnStamp == null) {
             returnStamp = StampFactory.forDeclaredType(graph.getAssumptions(), returnType, false);
         }
 
-        MethodCallTargetNode callTarget = graph.add(createMethodCallTarget(invokeKind, targetMethod, args, returnStamp, profile));
-        Invoke invoke = createNonInlinedInvoke(callTarget, resultType, inlineInfo);
+        MethodCallTargetNode callTarget = graph.add(createMethodCallTarget(invokeKind, targetMethod, invokeArgs, returnStamp, profile));
+        Invoke invoke = createNonInlinedInvoke(invokeBci, callTarget, resultType, inlineInfo);
 
         for (InlineInvokePlugin plugin : graphBuilderConfig.getPlugins().getInlineInvokePlugins()) {
             plugin.notifyNotInlined(this, targetMethod, invoke);
@@ -1465,11 +1518,11 @@
         return invoke;
     }
 
-    protected Invoke createNonInlinedInvoke(CallTargetNode callTarget, JavaKind resultType, InlineInfo inlineInfo) {
+    protected Invoke createNonInlinedInvoke(int invokeBci, CallTargetNode callTarget, JavaKind resultType, InlineInfo inlineInfo) {
         if (omitInvokeExceptionEdge(callTarget, inlineInfo)) {
-            return createInvoke(callTarget, resultType);
+            return createInvoke(invokeBci, callTarget, resultType);
         } else {
-            Invoke invoke = createInvokeWithException(callTarget, resultType);
+            Invoke invoke = createInvokeWithException(invokeBci, callTarget, resultType);
             AbstractBeginNode beginNode = graph.add(KillingBeginNode.create(LocationIdentity.any()));
             invoke.setNext(beginNode);
             lastInstr = beginNode;
@@ -1678,15 +1731,15 @@
 
     /**
      * Performs any action required after execution of an invocation plugin. This includes
-     * {@linkplain InvocationPluginAssertions#check(boolean) checking} invocation plugin invariants
-     * as well as weaving the {@code else} branch of the code woven by {@link #guardIntrinsic} if
+     * {@linkplain InvocationPluginAssertions#check checking} invocation plugin invariants as well
+     * as weaving the {@code else} branch of the code woven by {@link #guardIntrinsic} if
      * {@code guard != null}.
      */
-    protected void afterInvocationPluginExecution(boolean pluginResult, InvocationPluginAssertions assertions, IntrinsicGuard intrinsicGuard,
+    protected void afterInvocationPluginExecution(boolean pluginHandledInvoke, InvocationPluginAssertions assertions, IntrinsicGuard intrinsicGuard,
                     InvokeKind invokeKind, ValueNode[] args, ResolvedJavaMethod targetMethod, JavaKind resultType, JavaType returnType) {
-        assert assertions.check(pluginResult);
+        assert assertions.check(pluginHandledInvoke);
         if (intrinsicGuard != null) {
-            if (pluginResult) {
+            if (pluginHandledInvoke) {
                 if (intrinsicGuard.nonIntrinsicBranch != null) {
                     // Intrinsic emitted: emit a virtual call to the target method and
                     // merge it with the intrinsic branch
@@ -1701,7 +1754,7 @@
                     }
 
                     lastInstr = intrinsicGuard.nonIntrinsicBranch;
-                    createNonInlinedInvoke(args, targetMethod, invokeKind, resultType, returnType, null, intrinsicGuard.profile);
+                    createNonInlinedInvoke(args, bci(), targetMethod, invokeKind, resultType, returnType, null, intrinsicGuard.profile);
 
                     EndNode nonIntrinsicEnd = append(new EndNode());
                     AbstractMergeNode mergeNode = graph.add(new MergeNode());
@@ -1825,7 +1878,9 @@
                     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);
                     return true;
                 }
             }
@@ -1844,7 +1899,6 @@
     }
 
     private boolean inline(ResolvedJavaMethod targetMethod, ResolvedJavaMethod inlinedMethod, BytecodeProvider intrinsicBytecodeProvider, ValueNode[] args) {
-        traceInlining(targetMethod, inlinedMethod);
         IntrinsicContext intrinsic = this.intrinsicContext;
 
         if (intrinsic == null && !graphBuilderConfig.insertFullInfopoints() &&
@@ -1864,32 +1918,35 @@
                 printInlining(targetMethod, inlinedMethod, true, "compilation root (bytecode parsing)");
                 return true;
             } else {
-                // Otherwise inline the original method. Any frame state created
-                // during the inlining will exclude frame(s) in the
-                // intrinsic method (see HIRFrameStateBuilder.create(int bci)).
                 if (intrinsic.getOriginalMethod().isNative()) {
                     printInlining(targetMethod, inlinedMethod, false, "native method (bytecode parsing)");
                     return false;
                 }
-                printInlining(targetMethod, inlinedMethod, true, "inline intrinsic (bytecode parsing)");
-                parseAndInlineCallee(intrinsic.getOriginalMethod(), args, null);
-                return true;
+                if (inlinePartialIntrinsicExit()) {
+                    // Otherwise inline the original method. Any frame state created
+                    // during the inlining will exclude frame(s) in the
+                    // intrinsic method (see HIRFrameStateBuilder.create(int bci)).
+                    notifyBeforeInline(inlinedMethod);
+                    printInlining(targetMethod, inlinedMethod, true, "partial intrinsic exit (bytecode parsing)");
+                    parseAndInlineCallee(intrinsic.getOriginalMethod(), args, null);
+                    notifyAfterInline(inlinedMethod);
+                    return true;
+                } else {
+                    printInlining(targetMethod, inlinedMethod, false, "partial intrinsic exit (bytecode parsing)");
+                    return false;
+                }
             }
         } else {
             boolean isIntrinsic = intrinsicBytecodeProvider != null;
             if (intrinsic == null && isIntrinsic) {
                 assert !inlinedMethod.equals(targetMethod);
-                intrinsic = new IntrinsicContext(targetMethod, inlinedMethod, intrinsicBytecodeProvider, INLINE_DURING_PARSING);
+                intrinsic = new IntrinsicContext(targetMethod, inlinedMethod, intrinsicBytecodeProvider, INLINE_DURING_PARSING, args, bci());
             }
             if (inlinedMethod.hasBytecodes()) {
-                for (InlineInvokePlugin plugin : graphBuilderConfig.getPlugins().getInlineInvokePlugins()) {
-                    plugin.notifyBeforeInline(inlinedMethod);
-                }
+                notifyBeforeInline(inlinedMethod);
                 printInlining(targetMethod, inlinedMethod, true, "inline method (bytecode parsing)");
                 parseAndInlineCallee(inlinedMethod, args, intrinsic);
-                for (InlineInvokePlugin plugin : graphBuilderConfig.getPlugins().getInlineInvokePlugins()) {
-                    plugin.notifyAfterInline(inlinedMethod);
-                }
+                notifyAfterInline(inlinedMethod);
             } else {
                 printInlining(targetMethod, inlinedMethod, false, "no bytecodes (abstract or native) (bytecode parsing)");
                 return false;
@@ -1898,17 +1955,36 @@
         return true;
     }
 
-    private void traceInlining(ResolvedJavaMethod targetMethod, ResolvedJavaMethod inlinedMethod) {
-        if (TraceInlineDuringParsing.getValue(options) || TraceParserPlugins.getValue(options)) {
-            if (targetMethod.equals(inlinedMethod)) {
-                traceWithContext("inlining call to %s", inlinedMethod.format("%h.%n(%p)"));
-            } else {
-                traceWithContext("inlining call to %s as intrinsic for %s", inlinedMethod.format("%h.%n(%p)"), targetMethod.format("%h.%n(%p)"));
-            }
+    protected void notifyBeforeInline(ResolvedJavaMethod inlinedMethod) {
+        for (InlineInvokePlugin plugin : graphBuilderConfig.getPlugins().getInlineInvokePlugins()) {
+            plugin.notifyBeforeInline(inlinedMethod);
         }
     }
 
+    protected void notifyAfterInline(ResolvedJavaMethod inlinedMethod) {
+        for (InlineInvokePlugin plugin : graphBuilderConfig.getPlugins().getInlineInvokePlugins()) {
+            plugin.notifyAfterInline(inlinedMethod);
+        }
+    }
+
+    /**
+     * Determines if a partial intrinsic exit (i.e., a call to the original method within an
+     * intrinsic) should be inlined.
+     */
+    protected boolean inlinePartialIntrinsicExit() {
+        return true;
+    }
+
     private void printInlining(ResolvedJavaMethod targetMethod, ResolvedJavaMethod inlinedMethod, boolean success, String msg) {
+        if (success) {
+            if (TraceInlineDuringParsing.getValue(options) || TraceParserPlugins.getValue(options)) {
+                if (targetMethod.equals(inlinedMethod)) {
+                    traceWithContext("inlining call to %s", inlinedMethod.format("%h.%n(%p)"));
+                } else {
+                    traceWithContext("inlining call to %s as intrinsic for %s", inlinedMethod.format("%h.%n(%p)"), targetMethod.format("%h.%n(%p)"));
+                }
+            }
+        }
         if (HotSpotPrintInlining.getValue(options)) {
             if (targetMethod.equals(inlinedMethod)) {
                 Util.printInlining(inlinedMethod, bci(), getDepth(), success, "%s", msg);
@@ -1934,8 +2010,12 @@
 
     protected void traceWithContext(String format, Object... args) {
         StackTraceElement where = code.asStackTraceElement(bci());
-        TTY.println(format("%s%s (%s:%d) %s", nSpaces(getDepth()), method.isConstructor() ? method.format("%h.%n") : method.getName(), where.getFileName(), where.getLineNumber(),
-                        format(format, args)));
+        String s = format("%s%s (%s:%d) %s", nSpaces(getDepth()), method.isConstructor() ? method.format("%h.%n") : method.getName(), where.getFileName(), where.getLineNumber(),
+                        format(format, args));
+        if (s.equals("decrypt (CipherBlockChainingSubstitutions.java:117) inlining call to CipherBlockChainingSubstitutions.decrypt(Object, byte[], int, int, byte[], int)")) {
+            System.console();
+        }
+        TTY.println(s);
     }
 
     protected BytecodeParserError asParserError(Throwable e) {
@@ -2003,14 +2083,15 @@
         return new MethodCallTargetNode(invokeKind, targetMethod, args, returnStamp, profile);
     }
 
-    protected InvokeNode createInvoke(CallTargetNode callTarget, JavaKind resultType) {
-        InvokeNode invoke = append(new InvokeNode(callTarget, bci()));
+    protected InvokeNode createInvoke(int invokeBci, CallTargetNode callTarget, JavaKind resultType) {
+        InvokeNode invoke = append(new InvokeNode(callTarget, invokeBci));
         frameState.pushReturn(resultType, invoke);
         invoke.setStateAfter(createFrameState(stream.nextBCI(), invoke));
         return invoke;
     }
 
-    protected InvokeWithExceptionNode createInvokeWithException(CallTargetNode callTarget, JavaKind resultType) {
+    protected InvokeWithExceptionNode createInvokeWithException(int invokeBci, CallTargetNode callTarget, JavaKind resultType) {
+        assert bci() == invokeBci;
         if (currentBlock != null && stream.nextBCI() > currentBlock.endBci) {
             /*
              * Clear non-live locals early so that the exception handler entry gets the cleared
@@ -2642,7 +2723,7 @@
     }
 
     private DebugCloseable openNodeContext() {
-        if ((graphBuilderConfig.trackNodeSourcePosition() || Debug.isDumpEnabledForMethod()) && !parsingIntrinsic()) {
+        if ((graphBuilderConfig.trackNodeSourcePosition() || (Debug.isDumpEnabledForMethod() && DumpWithInfopoints.getValue(options))) && !parsingIntrinsic()) {
             return graph.withNodeSourcePosition(createBytecodePosition());
         }
         return null;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParserOptions.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParserOptions.java	Fri May 12 13:56:13 2017 -0700
@@ -57,5 +57,9 @@
 
     @Option(help = "Use intrinsics guarded by a virtual dispatch test at indirect call sites.", type = OptionType.Debug)
     public static final OptionKey<Boolean> UseGuardedIntrinsics = new OptionKey<>(true);
+
+    // Remove once GR-3604 reduces the memory overhead of including node source info dumps
+    @Option(help = "Enable node source positions if dumping is enabled.", type = OptionType.Debug)
+    public static final OptionKey<Boolean> DumpWithInfopoints = new OptionKey<>(false);
     // @formatter:on
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/bytecode/BC_newarray_02.java	Fri May 12 13:56:13 2017 -0700
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2016, 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.jtt.bytecode;
+
+import org.graalvm.compiler.jtt.JTTTest;
+import org.junit.Test;
+
+public class BC_newarray_02 extends JTTTest {
+    public static byte[] test(int l) {
+        return new byte[l];
+    }
+
+    @Test
+    public void testZero() {
+        runTest("test", 0);
+    }
+
+    @Test
+    public void testOne() {
+        runTest("test", 1);
+    }
+
+    @Test
+    public void testNegative() {
+        runTest("test", -1);
+    }
+
+    @Test
+    public void testLarge() {
+        runTest("test", 17 * 1024 * 1024);
+    }
+}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotspot/Test6959129.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotspot/Test6959129.java	Fri May 12 13:56:13 2017 -0700
@@ -23,10 +23,16 @@
 package org.graalvm.compiler.jtt.hotspot;
 
 import org.graalvm.compiler.jtt.JTTTest;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.DisableOnDebug;
+import org.junit.rules.TestRule;
+import org.junit.rules.Timeout;
 
 public class Test6959129 extends JTTTest {
 
+    @Rule public TestRule timeout = new DisableOnDebug(Timeout.seconds(20));
+
     public static long test() {
         int min = Integer.MAX_VALUE - 30000;
         int max = Integer.MAX_VALUE;
@@ -73,7 +79,7 @@
         return maxmoves;
     }
 
-    @Test(timeout = 20000)
+    @Test
     public void run0() throws Throwable {
         initializeForTimeout();
         runTest("test");
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Monitor_contended01.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Monitor_contended01.java	Fri May 12 13:56:13 2017 -0700
@@ -25,10 +25,16 @@
 package org.graalvm.compiler.jtt.threads;
 
 import org.graalvm.compiler.jtt.JTTTest;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.DisableOnDebug;
+import org.junit.rules.TestRule;
+import org.junit.rules.Timeout;
 
 public final class Monitor_contended01 extends JTTTest {
 
+    @Rule public TestRule timeout = new DisableOnDebug(Timeout.seconds(20));
+
     private static class TestClass implements Runnable {
         boolean started = false;
         boolean acquired = false;
@@ -74,7 +80,7 @@
         return object.acquired;
     }
 
-    @Test(timeout = 20000)
+    @Test
     public void run0() throws Throwable {
         initializeForTimeout();
         runTest("test");
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Monitor_notowner01.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Monitor_notowner01.java	Fri May 12 13:56:13 2017 -0700
@@ -25,10 +25,16 @@
 package org.graalvm.compiler.jtt.threads;
 
 import org.graalvm.compiler.jtt.JTTTest;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.DisableOnDebug;
+import org.junit.rules.TestRule;
+import org.junit.rules.Timeout;
 
 public class Monitor_notowner01 extends JTTTest {
 
+    @Rule public TestRule timeout = new DisableOnDebug(Timeout.seconds(20));
+
     static Object monitor = new Object();
     static Object finished = new Object();
 
@@ -63,7 +69,7 @@
         }
     }
 
-    @Test(timeout = 20000)
+    @Test
     public void run0() throws Throwable {
         initializeForTimeout();
         runTest("test");
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Monitorenter01.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Monitorenter01.java	Fri May 12 13:56:13 2017 -0700
@@ -25,10 +25,16 @@
 package org.graalvm.compiler.jtt.threads;
 
 import org.graalvm.compiler.jtt.JTTTest;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.DisableOnDebug;
+import org.junit.rules.TestRule;
+import org.junit.rules.Timeout;
 
 public final class Monitorenter01 extends JTTTest {
 
+    @Rule public TestRule timeout = new DisableOnDebug(Timeout.seconds(20));
+
     static final Object object = new Object();
 
     public static boolean test() {
@@ -40,7 +46,7 @@
         }
     }
 
-    @Test(timeout = 20000)
+    @Test
     public void run0() throws Throwable {
         initializeForTimeout();
         runTest("test");
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Monitorenter02.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Monitorenter02.java	Fri May 12 13:56:13 2017 -0700
@@ -25,10 +25,16 @@
 package org.graalvm.compiler.jtt.threads;
 
 import org.graalvm.compiler.jtt.JTTTest;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.DisableOnDebug;
+import org.junit.rules.TestRule;
+import org.junit.rules.Timeout;
 
 public final class Monitorenter02 extends JTTTest {
 
+    @Rule public TestRule timeout = new DisableOnDebug(Timeout.seconds(20));
+
     static final Object object = new Object();
 
     public static boolean test() {
@@ -44,7 +50,7 @@
         }
     }
 
-    @Test(timeout = 20000)
+    @Test
     public void run0() throws Throwable {
         initializeForTimeout();
         runTest("test");
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Object_wait01.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Object_wait01.java	Fri May 12 13:56:13 2017 -0700
@@ -25,10 +25,16 @@
 package org.graalvm.compiler.jtt.threads;
 
 import org.graalvm.compiler.jtt.JTTTest;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.DisableOnDebug;
+import org.junit.rules.TestRule;
+import org.junit.rules.Timeout;
 
 public class Object_wait01 extends JTTTest {
 
+    @Rule public TestRule timeout = new DisableOnDebug(Timeout.seconds(20));
+
     private static class TestClass implements Runnable {
         @Override
         public void run() {
@@ -59,25 +65,25 @@
         }
     }
 
-    @Test(timeout = 20000)
+    @Test
     public void run0() throws Throwable {
         initializeForTimeout();
         runTest("test", 0);
     }
 
-    @Test(timeout = 20000)
+    @Test
     public void run1() throws Throwable {
         initializeForTimeout();
         runTest("test", 1);
     }
 
-    @Test(timeout = 20000)
+    @Test
     public void run2() throws Throwable {
         initializeForTimeout();
         runTest("test", 3);
     }
 
-    @Test(timeout = 20000)
+    @Test
     public void run3() throws Throwable {
         initializeForTimeout();
         runTest("test", 15);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Object_wait02.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Object_wait02.java	Fri May 12 13:56:13 2017 -0700
@@ -25,10 +25,16 @@
 package org.graalvm.compiler.jtt.threads;
 
 import org.graalvm.compiler.jtt.JTTTest;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.DisableOnDebug;
+import org.junit.rules.TestRule;
+import org.junit.rules.Timeout;
 
 public class Object_wait02 extends JTTTest {
 
+    @Rule public TestRule timeout = new DisableOnDebug(Timeout.seconds(20));
+
     private static class TestClass implements Runnable {
         @Override
         public void run() {
@@ -60,19 +66,19 @@
         return done;
     }
 
-    @Test(timeout = 20000)
+    @Test
     public void run0() throws Throwable {
         initializeForTimeout();
         runTest("test", 0);
     }
 
-    @Test(timeout = 20000)
+    @Test
     public void run1() throws Throwable {
         initializeForTimeout();
         runTest("test", 1);
     }
 
-    @Test(timeout = 20000)
+    @Test
     public void run2() throws Throwable {
         initializeForTimeout();
         runTest("test", 2);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Object_wait03.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Object_wait03.java	Fri May 12 13:56:13 2017 -0700
@@ -24,11 +24,32 @@
  */
 package org.graalvm.compiler.jtt.threads;
 
+import org.graalvm.compiler.core.common.CancellationBailoutException;
+import org.graalvm.compiler.debug.Debug;
 import org.graalvm.compiler.jtt.JTTTest;
+import org.graalvm.compiler.nodes.Cancellable;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.DisableOnDebug;
+import org.junit.rules.TestRule;
+import org.junit.rules.Timeout;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
 
 public class Object_wait03 extends JTTTest {
 
+    /**
+     * Timeout for compilation.
+     */
+    static final long COMPILATION_TIMEOUT_MS = 15_000;
+
+    /**
+     * Total timeout for compilation and execution of compiled code.
+     */
+    static final long TIMEOUT_MS = COMPILATION_TIMEOUT_MS * 2;
+
+    @Rule public TestRule timeout = new DisableOnDebug(Timeout.millis(TIMEOUT_MS));
+
     private static class TestClass implements Runnable {
         @Override
         public void run() {
@@ -66,22 +87,61 @@
         }
     }
 
-    @Test(timeout = 20000)
-    public void run0() throws Throwable {
-        initializeForTimeout();
-        runTest("test", 0);
+    static class CompilationTimeout extends Thread implements Cancellable {
+        boolean timedOut;
+        final long durationMS;
+
+        CompilationTimeout(long durationMS) {
+            super("CompilationTimeout-" + durationMS + "ms");
+            this.durationMS = durationMS;
+            setDaemon(true);
+            start();
+        }
+
+        @Override
+        public void run() {
+            try {
+                Thread.sleep(durationMS);
+            } catch (InterruptedException e) {
+            }
+            timedOut = true;
+        }
+
+        @Override
+        public boolean isCancelled() {
+            return timedOut;
+        }
     }
 
-    @Test(timeout = 20000)
-    public void run1() throws Throwable {
-        initializeForTimeout();
-        runTest("test", 1);
+    @Override
+    protected Cancellable getCancellable(ResolvedJavaMethod method) {
+        return new CompilationTimeout(COMPILATION_TIMEOUT_MS);
     }
 
-    @Test(timeout = 20000)
-    public void run2() throws Throwable {
+    private void run(int i) throws Throwable {
         initializeForTimeout();
-        runTest("test", 2);
+        try {
+            runTest("test", i);
+        } catch (CancellationBailoutException e) {
+            String message = String.format("Compilation cancelled after " + COMPILATION_TIMEOUT_MS + " ms");
+            // For diagnosing expectedly long compilations (GR-3853)
+            Debug.forceDump(lastCompiledGraph, message);
+            throw new AssertionError(message, e);
+        }
     }
 
+    @Test
+    public void run0() throws Throwable {
+        run(0);
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        run(1);
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        run(2);
+    }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Object_wait04.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Object_wait04.java	Fri May 12 13:56:13 2017 -0700
@@ -25,10 +25,16 @@
 package org.graalvm.compiler.jtt.threads;
 
 import org.graalvm.compiler.jtt.JTTTest;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.DisableOnDebug;
+import org.junit.rules.TestRule;
+import org.junit.rules.Timeout;
 
 public class Object_wait04 extends JTTTest {
 
+    @Rule public TestRule timeout = new DisableOnDebug(Timeout.seconds(20));
+
     private static class TestClass implements Runnable {
         @Override
         public void run() {
@@ -70,37 +76,37 @@
         }
     }
 
-    @Test(timeout = 20000)
+    @Test
     public void run0() throws Throwable {
         initializeForTimeout();
         runTest("test", 0);
     }
 
-    @Test(timeout = 20000)
+    @Test
     public void run1() throws Throwable {
         initializeForTimeout();
         runTest("test", 1);
     }
 
-    @Test(timeout = 20000)
+    @Test
     public void run2() throws Throwable {
         initializeForTimeout();
         runTest("test", 2);
     }
 
-    @Test(timeout = 20000)
+    @Test
     public void run3() throws Throwable {
         initializeForTimeout();
         runTest("test", 3);
     }
 
-    @Test(timeout = 20000)
+    @Test
     public void run4() throws Throwable {
         initializeForTimeout();
         runTest("test", 4);
     }
 
-    @Test(timeout = 20000)
+    @Test
     public void run5() throws Throwable {
         initializeForTimeout();
         runTest("test", 5);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/SynchronizedLoopExit01.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/SynchronizedLoopExit01.java	Fri May 12 13:56:13 2017 -0700
@@ -25,7 +25,11 @@
 package org.graalvm.compiler.jtt.threads;
 
 import org.graalvm.compiler.jtt.JTTTest;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.DisableOnDebug;
+import org.junit.rules.TestRule;
+import org.junit.rules.Timeout;
 
 /**
  * Inspired by {@code com.sun.media.sound.DirectAudioDevice$DirectDL.drain()}.
@@ -35,6 +39,8 @@
  */
 public final class SynchronizedLoopExit01 extends JTTTest {
 
+    @Rule public TestRule timeout = new DisableOnDebug(Timeout.seconds(20));
+
     protected Object object = new Object();
     protected volatile boolean drained = false;
     protected volatile boolean someBoolean = true;
@@ -52,7 +58,7 @@
         return b;
     }
 
-    @Test(timeout = 20000)
+    @Test
     public void run0() throws Throwable {
         initializeForTimeout();
         runTest("test");
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_isInterrupted02.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_isInterrupted02.java	Fri May 12 13:56:13 2017 -0700
@@ -28,11 +28,17 @@
 
 import org.graalvm.compiler.jtt.JTTTest;
 import org.junit.Assert;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.DisableOnDebug;
+import org.junit.rules.TestRule;
+import org.junit.rules.Timeout;
 
 //Test all, mainly monitors
 public class Thread_isInterrupted02 extends JTTTest {
 
+    @Rule public TestRule timeout = new DisableOnDebug(Timeout.seconds(20));
+
     private static final Object start = new Object();
     private static final Object end = new Object();
     private static int waitTime;
@@ -102,13 +108,13 @@
         }
     }
 
-    @Test(timeout = 20000)
+    @Test
     public void run0() throws Throwable {
         initializeForTimeout();
         runTest("test", 0, 0);
     }
 
-    @Test(timeout = 20000)
+    @Test
     public void run1() throws Throwable {
         initializeForTimeout();
         runTest("test", 1, 500);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_isInterrupted03.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_isInterrupted03.java	Fri May 12 13:56:13 2017 -0700
@@ -23,7 +23,11 @@
 package org.graalvm.compiler.jtt.threads;
 
 import org.graalvm.compiler.jtt.JTTTest;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.DisableOnDebug;
+import org.junit.rules.TestRule;
+import org.junit.rules.Timeout;
 
 /*
  */
@@ -31,6 +35,8 @@
 // Interrupted while sleeping, throws an interrupted exception
 public class Thread_isInterrupted03 extends JTTTest {
 
+    @Rule public TestRule timeout = new DisableOnDebug(Timeout.seconds(20));
+
     public static boolean test() throws InterruptedException {
         final Thread1 thread = new Thread1();
         thread.start();
@@ -68,7 +74,7 @@
         }
     }
 
-    @Test(timeout = 20000)
+    @Test
     public void run0() throws Throwable {
         initializeForTimeout();
         runTest("test");
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_isInterrupted05.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_isInterrupted05.java	Fri May 12 13:56:13 2017 -0700
@@ -23,7 +23,11 @@
 package org.graalvm.compiler.jtt.threads;
 
 import org.graalvm.compiler.jtt.JTTTest;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.DisableOnDebug;
+import org.junit.rules.TestRule;
+import org.junit.rules.Timeout;
 
 /*
  */
@@ -31,6 +35,8 @@
 // Interrupted during wait, with interrupter joining
 public class Thread_isInterrupted05 extends JTTTest {
 
+    @Rule public TestRule timeout = new DisableOnDebug(Timeout.seconds(20));
+
     public static boolean test() throws InterruptedException {
         final WaitInterruptee waitInterruptee = new WaitInterruptee();
         waitInterruptee.start();
@@ -66,7 +72,7 @@
         }
     }
 
-    @Test(timeout = 20000)
+    @Test
     public void run0() throws Throwable {
         initializeForTimeout();
         runTest("test");
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_join01.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_join01.java	Fri May 12 13:56:13 2017 -0700
@@ -25,10 +25,16 @@
 package org.graalvm.compiler.jtt.threads;
 
 import org.graalvm.compiler.jtt.JTTTest;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.DisableOnDebug;
+import org.junit.rules.TestRule;
+import org.junit.rules.Timeout;
 
 public class Thread_join01 extends JTTTest {
 
+    @Rule public TestRule timeout = new DisableOnDebug(Timeout.seconds(20));
+
     private static class TestClass implements Runnable {
         @Override
         public void run() {
@@ -46,7 +52,7 @@
         return cont;
     }
 
-    @Test(timeout = 20000)
+    @Test
     public void run0() throws Throwable {
         initializeForTimeout();
         runTest("test");
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_join02.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_join02.java	Fri May 12 13:56:13 2017 -0700
@@ -28,10 +28,16 @@
 package org.graalvm.compiler.jtt.threads;
 
 import org.graalvm.compiler.jtt.JTTTest;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.DisableOnDebug;
+import org.junit.rules.TestRule;
+import org.junit.rules.Timeout;
 
 public class Thread_join02 extends JTTTest {
 
+    @Rule public TestRule timeout = new DisableOnDebug(Timeout.seconds(20));
+
     private static class TestClass implements Runnable {
         @Override
         public void run() {
@@ -53,7 +59,7 @@
         return cont;
     }
 
-    @Test(timeout = 20000)
+    @Test
     public void run0() throws Throwable {
         initializeForTimeout();
         runTest("test");
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_join03.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_join03.java	Fri May 12 13:56:13 2017 -0700
@@ -28,10 +28,16 @@
 package org.graalvm.compiler.jtt.threads;
 
 import org.graalvm.compiler.jtt.JTTTest;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.DisableOnDebug;
+import org.junit.rules.TestRule;
+import org.junit.rules.Timeout;
 
 public class Thread_join03 extends JTTTest {
 
+    @Rule public TestRule timeout = new DisableOnDebug(Timeout.seconds(20));
+
     private static class TestClass implements Runnable {
         @Override
         public void run() {
@@ -50,7 +56,7 @@
         return cont;
     }
 
-    @Test(timeout = 20000)
+    @Test
     public void run0() throws Throwable {
         initializeForTimeout();
         runTest("test");
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_sleep01.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_sleep01.java	Fri May 12 13:56:13 2017 -0700
@@ -25,29 +25,35 @@
 package org.graalvm.compiler.jtt.threads;
 
 import org.graalvm.compiler.jtt.JTTTest;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.DisableOnDebug;
+import org.junit.rules.TestRule;
+import org.junit.rules.Timeout;
 
 public final class Thread_sleep01 extends JTTTest {
 
+    @Rule public TestRule timeout = new DisableOnDebug(Timeout.seconds(20));
+
     public static boolean test(int i) throws InterruptedException {
         final long before = System.currentTimeMillis();
         Thread.sleep(i);
         return System.currentTimeMillis() - before >= i;
     }
 
-    @Test(timeout = 20000)
+    @Test
     public void run0() throws Throwable {
         initializeForTimeout();
         runTest("test", 10);
     }
 
-    @Test(timeout = 20000)
+    @Test
     public void run1() throws Throwable {
         initializeForTimeout();
         runTest("test", 20);
     }
 
-    @Test(timeout = 20000)
+    @Test
     public void run2() throws Throwable {
         initializeForTimeout();
         runTest("test", 100);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_yield01.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/threads/Thread_yield01.java	Fri May 12 13:56:13 2017 -0700
@@ -25,16 +25,22 @@
 package org.graalvm.compiler.jtt.threads;
 
 import org.graalvm.compiler.jtt.JTTTest;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.DisableOnDebug;
+import org.junit.rules.TestRule;
+import org.junit.rules.Timeout;
 
 public final class Thread_yield01 extends JTTTest {
 
+    @Rule public TestRule timeout = new DisableOnDebug(Timeout.seconds(20));
+
     public static boolean test() {
         Thread.yield();
         return true;
     }
 
-    @Test(timeout = 20000)
+    @Test
     public void run0() throws Throwable {
         initializeForTimeout();
         runTest("test");
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.jtt/src/org/graalvm/compiler/lir/jtt/LIRTest.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.jtt/src/org/graalvm/compiler/lir/jtt/LIRTest.java	Fri May 12 13:56:13 2017 -0700
@@ -40,7 +40,6 @@
 import org.graalvm.compiler.nodeinfo.NodeInfo;
 import org.graalvm.compiler.nodes.FixedWithNextNode;
 import org.graalvm.compiler.nodes.ValueNode;
-import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
@@ -191,9 +190,7 @@
     };
 
     @Override
-    protected GraphBuilderConfiguration editGraphBuilderConfiguration(GraphBuilderConfiguration conf) {
-        InvocationPlugins invocationPlugins = conf.getPlugins().getInvocationPlugins();
-
+    protected void registerInvocationPlugins(InvocationPlugins invocationPlugins) {
         Class<? extends LIRTest> c = getClass();
         for (Method m : c.getMethods()) {
             if (m.getAnnotation(LIRIntrinsic.class) != null) {
@@ -215,7 +212,7 @@
         };
         invocationPlugins.register(outputPlugin, LIRTest.class, "getOutput", new Class<?>[]{LIRTestSpecification.class, String.class, Object.class});
         invocationPlugins.register(outputPlugin, LIRTest.class, "getOutput", new Class<?>[]{LIRTestSpecification.class, String.class, int.class});
-        return super.editGraphBuilderConfiguration(conf);
+        super.registerInvocationPlugins(invocationPlugins);
     }
 
     @SuppressWarnings("unused")
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.jtt/src/org/graalvm/compiler/lir/jtt/SPARCBranchBailoutTest.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.jtt/src/org/graalvm/compiler/lir/jtt/SPARCBranchBailoutTest.java	Fri May 12 13:56:13 2017 -0700
@@ -22,17 +22,18 @@
  */
 package org.graalvm.compiler.lir.jtt;
 
-import org.junit.Assert;
-import org.junit.Assume;
-import org.junit.Test;
-
 import org.graalvm.compiler.api.directives.GraalDirectives;
 import org.graalvm.compiler.core.common.PermanentBailoutException;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugConfigScope;
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.lir.LIRInstruction;
 import org.graalvm.compiler.lir.LIRInstructionClass;
 import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
 import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
+import org.junit.Assert;
+import org.junit.Assume;
+import org.junit.Test;
 
 import jdk.vm.ci.code.BailoutException;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
@@ -76,12 +77,15 @@
         return GraalDirectives.opaque(res);
     }
 
+    @SuppressWarnings("try")
     @Test
     public void testBailoutOnBranchOverflow() throws Throwable {
         Assume.assumeTrue(getBackend().getTarget().arch instanceof SPARC);
         ResolvedJavaMethod m = getResolvedJavaMethod("testBranch");
         try {
-            compile(m, null);
+            try (DebugConfigScope s = Debug.setConfig(Debug.silentConfig())) {
+                compile(m, null);
+            }
         } catch (GraalError e) {
             Assert.assertEquals(PermanentBailoutException.class, e.getCause().getClass());
         }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/EdgeMoveOptimizer.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/EdgeMoveOptimizer.java	Fri May 12 13:56:13 2017 -0700
@@ -94,16 +94,16 @@
             assert op1 != null;
             assert op2 != null;
 
-            if (op1 instanceof ValueMoveOp && op2 instanceof ValueMoveOp) {
-                ValueMoveOp move1 = (ValueMoveOp) op1;
-                ValueMoveOp move2 = (ValueMoveOp) op2;
+            if (ValueMoveOp.isValueMoveOp(op1) && ValueMoveOp.isValueMoveOp(op2)) {
+                ValueMoveOp move1 = ValueMoveOp.asValueMoveOp(op1);
+                ValueMoveOp move2 = ValueMoveOp.asValueMoveOp(op2);
                 if (move1.getInput().equals(move2.getInput()) && move1.getResult().equals(move2.getResult())) {
                     // these moves are exactly equal and can be optimized
                     return true;
                 }
-            } else if (op1 instanceof LoadConstantOp && op2 instanceof LoadConstantOp) {
-                LoadConstantOp move1 = (LoadConstantOp) op1;
-                LoadConstantOp move2 = (LoadConstantOp) op2;
+            } else if (LoadConstantOp.isLoadConstantOp(op1) && LoadConstantOp.isLoadConstantOp(op2)) {
+                LoadConstantOp move1 = LoadConstantOp.asLoadConstantOp(op1);
+                LoadConstantOp move2 = LoadConstantOp.asLoadConstantOp(op2);
                 if (move1.getConstant().equals(move2.getConstant()) && move1.getResult().equals(move2.getResult())) {
                     // these moves are exactly equal and can be optimized
                     return true;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/FullInfopointOp.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/FullInfopointOp.java	Fri May 12 13:56:13 2017 -0700
@@ -45,7 +45,7 @@
 
     @Override
     public void emitCode(CompilationResultBuilder crb) {
+        crb.recordInfopoint(crb.asm.position(), state, reason);
         crb.asm.ensureUniquePC();
-        crb.recordInfopoint(crb.asm.position(), state, reason);
     }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/LIRInstruction.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/LIRInstruction.java	Fri May 12 13:56:13 2017 -0700
@@ -47,6 +47,9 @@
 import org.graalvm.compiler.debug.Debug;
 import org.graalvm.compiler.debug.DebugCounter;
 import org.graalvm.compiler.graph.NodeSourcePosition;
+import org.graalvm.compiler.lir.StandardOp.LoadConstantOp;
+import org.graalvm.compiler.lir.StandardOp.MoveOp;
+import org.graalvm.compiler.lir.StandardOp.ValueMoveOp;
 import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
 
 import jdk.vm.ci.code.RegisterValue;
@@ -349,6 +352,38 @@
         return instructionClass.forEachRegisterHint(this, mode, proc);
     }
 
+    // Checkstyle: stop
+    /**
+     * Returns {@code true} if the instruction is a {@link MoveOp}.
+     *
+     * This function is preferred to {@code instanceof MoveOp} since the type check is more
+     * expensive than reading a field from {@link LIRInstructionClass}.
+     */
+    public final boolean isMoveOp() {
+        return instructionClass.isMoveOp();
+    }
+
+    /**
+     * Returns {@code true} if the instruction is a {@link ValueMoveOp}.
+     *
+     * This function is preferred to {@code instanceof ValueMoveOp} since the type check is more
+     * expensive than reading a field from {@link LIRInstructionClass}.
+     */
+    public final boolean isValueMoveOp() {
+        return instructionClass.isValueMoveOp();
+    }
+
+    /**
+     * Returns {@code true} if the instruction is a {@link LoadConstantOp}.
+     *
+     * This function is preferred to {@code instanceof LoadConstantOp} since the type check is more
+     * expensive than reading a field from {@link LIRInstructionClass}.
+     */
+    public final boolean isLoadConstantOp() {
+        return instructionClass.isLoadConstantOp();
+    }
+    // Checkstyle: resume
+
     /**
      * Utility method to add stack arguments to a list of temporaries. Useful for modeling calling
      * conventions that kill outgoing argument space.
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/LIRInstructionClass.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/LIRInstructionClass.java	Fri May 12 13:56:13 2017 -0700
@@ -31,6 +31,9 @@
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
 import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
+import org.graalvm.compiler.lir.StandardOp.LoadConstantOp;
+import org.graalvm.compiler.lir.StandardOp.MoveOp;
+import org.graalvm.compiler.lir.StandardOp.ValueMoveOp;
 
 import jdk.vm.ci.code.BytecodeFrame;
 import jdk.vm.ci.meta.Value;
@@ -50,6 +53,10 @@
     private final Values defs;
     private final Fields states;
 
+    private final boolean isMoveOp;
+    private final boolean isValueMoveOp;
+    private final boolean isLoadConstantOp;
+
     private String opcodeConstant;
     private int opcodeIndex;
 
@@ -78,6 +85,10 @@
         } else {
             opcodeIndex = ifs.data.indexOf(ifs.opcodeField);
         }
+
+        isMoveOp = MoveOp.class.isAssignableFrom(clazz);
+        isValueMoveOp = ValueMoveOp.class.isAssignableFrom(clazz);
+        isLoadConstantOp = LoadConstantOp.class.isAssignableFrom(clazz);
     }
 
     @SuppressWarnings("unchecked")
@@ -346,4 +357,16 @@
 
         return result.toString();
     }
+
+    final boolean isMoveOp() {
+        return isMoveOp;
+    }
+
+    final boolean isValueMoveOp() {
+        return isValueMoveOp;
+    }
+
+    final boolean isLoadConstantOp() {
+        return isLoadConstantOp;
+    }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/RedundantMoveElimination.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/RedundantMoveElimination.java	Fri May 12 13:56:13 2017 -0700
@@ -182,7 +182,7 @@
                 ArrayList<LIRInstruction> instructions = lir.getLIRforBlock(block);
                 for (LIRInstruction op : instructions) {
                     if (isEligibleMove(op)) {
-                        Value dest = ((MoveOp) op).getResult();
+                        Value dest = MoveOp.asMoveOp(op).getResult();
                         if (isRegister(dest)) {
                             int regNum = ((RegisterValue) dest).getRegister().number;
                             if (regNum >= numRegs) {
@@ -346,7 +346,7 @@
                         for (int idx = 0; idx < numInsts; idx++) {
                             LIRInstruction op = instructions.get(idx);
                             if (isEligibleMove(op)) {
-                                ValueMoveOp moveOp = (ValueMoveOp) op;
+                                ValueMoveOp moveOp = ValueMoveOp.asValueMoveOp(op);
                                 int sourceIdx = getStateIdx(moveOp.getInput());
                                 int destIdx = getStateIdx(moveOp.getResult());
                                 if (sourceIdx >= 0 && destIdx >= 0 && iterState[sourceIdx] == iterState[destIdx]) {
@@ -381,7 +381,7 @@
                     /*
                      * Handle the special case of a move instruction
                      */
-                    ValueMoveOp moveOp = (ValueMoveOp) op;
+                    ValueMoveOp moveOp = ValueMoveOp.asValueMoveOp(op);
                     int sourceIdx = getStateIdx(moveOp.getInput());
                     int destIdx = getStateIdx(moveOp.getResult());
                     if (sourceIdx >= 0 && destIdx >= 0) {
@@ -547,8 +547,8 @@
          * Returns true for a move instruction which is a candidate for elimination.
          */
         private static boolean isEligibleMove(LIRInstruction op) {
-            if (op instanceof ValueMoveOp) {
-                ValueMoveOp moveOp = (ValueMoveOp) op;
+            if (ValueMoveOp.isValueMoveOp(op)) {
+                ValueMoveOp moveOp = ValueMoveOp.asValueMoveOp(op);
                 Value source = moveOp.getInput();
                 Value dest = moveOp.getResult();
                 /*
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/StandardOp.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/StandardOp.java	Fri May 12 13:56:13 2017 -0700
@@ -239,6 +239,16 @@
     public interface MoveOp {
 
         AllocatableValue getResult();
+
+        // Checkstyle: stop
+        static MoveOp asMoveOp(LIRInstruction op) {
+            return (MoveOp) op;
+        }
+        // Checkstyle: resume
+
+        static boolean isMoveOp(LIRInstruction op) {
+            return op.isMoveOp();
+        }
     }
 
     /**
@@ -247,6 +257,16 @@
     public interface ValueMoveOp extends MoveOp {
 
         AllocatableValue getInput();
+
+        // Checkstyle: stop
+        static ValueMoveOp asValueMoveOp(LIRInstruction op) {
+            return (ValueMoveOp) op;
+        }
+        // Checkstyle: resume
+
+        static boolean isValueMoveOp(LIRInstruction op) {
+            return op.isValueMoveOp();
+        }
     }
 
     /**
@@ -255,6 +275,16 @@
     public interface LoadConstantOp extends MoveOp {
 
         Constant getConstant();
+
+        // Checkstyle: stop
+        static LoadConstantOp asLoadConstantOp(LIRInstruction op) {
+            return (LoadConstantOp) op;
+        }
+        // Checkstyle: resume
+
+        static boolean isLoadConstantOp(LIRInstruction op) {
+            return op.isLoadConstantOp();
+        }
     }
 
     /**
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanAssignLocationsPhase.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanAssignLocationsPhase.java	Fri May 12 13:56:13 2017 -0700
@@ -37,7 +37,6 @@
 import org.graalvm.compiler.debug.Indent;
 import org.graalvm.compiler.lir.ConstantValue;
 import org.graalvm.compiler.lir.InstructionValueProcedure;
-import org.graalvm.compiler.lir.LIRFrameState;
 import org.graalvm.compiler.lir.LIRInstruction;
 import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
 import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
@@ -115,14 +114,7 @@
         return interval.location();
     }
 
-    /**
-     * @param op
-     * @param operand
-     * @param valueMode
-     * @param flags
-     * @see InstructionValueProcedure#doValue(LIRInstruction, Value, OperandMode, EnumSet)
-     */
-    private Value debugInfoProcedure(LIRInstruction op, Value operand, OperandMode valueMode, EnumSet<OperandFlag> flags) {
+    private Value debugInfoProcedure(LIRInstruction op, Value operand) {
         if (isVirtualStackSlot(operand)) {
             return operand;
         }
@@ -157,10 +149,6 @@
         return result;
     }
 
-    private void computeDebugInfo(final LIRInstruction op, LIRFrameState info) {
-        info.forEachState(op, this::debugInfoProcedure);
-    }
-
     private void assignLocations(ArrayList<LIRInstruction> instructions) {
         int numInst = instructions.size();
         boolean hasDead = false;
@@ -184,6 +172,22 @@
         }
     }
 
+    private final InstructionValueProcedure assignProc = new InstructionValueProcedure() {
+        @Override
+        public Value doValue(LIRInstruction instruction, Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
+            if (isVariable(value)) {
+                return colorLirOperand(instruction, (Variable) value, mode);
+            }
+            return value;
+        }
+    };
+    private final InstructionValueProcedure debugInfoProc = new InstructionValueProcedure() {
+        @Override
+        public Value doValue(LIRInstruction instruction, Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
+            return debugInfoProcedure(instruction, value);
+        }
+    };
+
     /**
      * Assigns the operand of an {@link LIRInstruction}.
      *
@@ -193,10 +197,9 @@
     protected boolean assignLocations(LIRInstruction op) {
         assert op != null;
 
-        InstructionValueProcedure assignProc = (inst, operand, mode, flags) -> isVariable(operand) ? colorLirOperand(inst, (Variable) operand, mode) : operand;
         // remove useless moves
-        if (op instanceof MoveOp) {
-            AllocatableValue result = ((MoveOp) op).getResult();
+        if (MoveOp.isMoveOp(op)) {
+            AllocatableValue result = MoveOp.asMoveOp(op).getResult();
             if (isVariable(result) && allocator.isMaterialized(result, op.id(), OperandMode.DEF)) {
                 /*
                  * This happens if a materializable interval is originally not spilled but then
@@ -213,11 +216,11 @@
         op.forEachOutput(assignProc);
 
         // compute reference map and debug information
-        op.forEachState((inst, state) -> computeDebugInfo(inst, state));
+        op.forEachState(debugInfoProc);
 
         // remove useless moves
-        if (op instanceof ValueMoveOp) {
-            ValueMoveOp move = (ValueMoveOp) op;
+        if (ValueMoveOp.isValueMoveOp(op)) {
+            ValueMoveOp move = ValueMoveOp.asValueMoveOp(op);
             if (move.getInput().equals(move.getResult())) {
                 return true;
             }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanEliminateSpillMovePhase.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanEliminateSpillMovePhase.java	Fri May 12 13:56:13 2017 -0700
@@ -114,7 +114,7 @@
                         int opId = op.id();
 
                         if (opId == -1) {
-                            MoveOp move = (MoveOp) op;
+                            MoveOp move = MoveOp.asMoveOp(op);
                             /*
                              * Remove move from register to stack if the stack slot is guaranteed to
                              * be correct. Only moves that have been inserted by LinearScan can be
@@ -126,12 +126,12 @@
                                  * instruction.
                                  */
                                 if (Debug.isLogEnabled()) {
-                                    if (move instanceof ValueMoveOp) {
-                                        ValueMoveOp vmove = (ValueMoveOp) move;
+                                    if (ValueMoveOp.isValueMoveOp(op)) {
+                                        ValueMoveOp vmove = ValueMoveOp.asValueMoveOp(op);
                                         Debug.log("eliminating move from interval %d (%s) to %d (%s) in block %s", allocator.operandNumber(vmove.getInput()), vmove.getInput(),
                                                         allocator.operandNumber(vmove.getResult()), vmove.getResult(), block);
                                     } else {
-                                        LoadConstantOp load = (LoadConstantOp) move;
+                                        LoadConstantOp load = LoadConstantOp.asLoadConstantOp(op);
                                         Debug.log("eliminating constant load from %s to %d (%s) in block %s", load.getConstant(), allocator.operandNumber(load.getResult()), load.getResult(), block);
                                     }
                                 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanLifetimeAnalysisPhase.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanLifetimeAnalysisPhase.java	Fri May 12 13:56:13 2017 -0700
@@ -565,8 +565,8 @@
      * of such moves is assigned the stack slot (which is in the caller's frame) as its spill slot.
      */
     protected void handleMethodArguments(LIRInstruction op) {
-        if (op instanceof ValueMoveOp) {
-            ValueMoveOp move = (ValueMoveOp) op;
+        if (ValueMoveOp.isValueMoveOp(op)) {
+            ValueMoveOp move = ValueMoveOp.asValueMoveOp(op);
             if (optimizeMethodArgument(move.getInput())) {
                 StackSlot slot = asStackSlot(move.getInput());
                 if (DetailedAsserts.getValue(allocator.getOptions())) {
@@ -659,8 +659,8 @@
      * Determines the register priority for an instruction's output/result operand.
      */
     protected RegisterPriority registerPriorityOfOutputOperand(LIRInstruction op) {
-        if (op instanceof ValueMoveOp) {
-            ValueMoveOp move = (ValueMoveOp) op;
+        if (ValueMoveOp.isValueMoveOp(op)) {
+            ValueMoveOp move = ValueMoveOp.asValueMoveOp(op);
             if (optimizeMethodArgument(move.getInput())) {
                 return RegisterPriority.None;
             }
@@ -833,8 +833,8 @@
      *         can only be a {@link JavaConstant}.
      */
     protected Constant getMaterializedValue(LIRInstruction op, Value operand, Interval interval) {
-        if (op instanceof LoadConstantOp) {
-            LoadConstantOp move = (LoadConstantOp) op;
+        if (LoadConstantOp.isLoadConstantOp(op)) {
+            LoadConstantOp move = LoadConstantOp.asLoadConstantOp(op);
 
             if (!allocator.neverSpillConstants()) {
                 /*
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanWalker.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanWalker.java	Fri May 12 13:56:13 2017 -0700
@@ -946,8 +946,8 @@
     }
 
     static boolean isMove(LIRInstruction op, Interval from, Interval to) {
-        if (op instanceof ValueMoveOp) {
-            ValueMoveOp move = (ValueMoveOp) op;
+        if (ValueMoveOp.isValueMoveOp(op)) {
+            ValueMoveOp move = ValueMoveOp.asValueMoveOp(op);
             if (isVariable(move.getInput()) && isVariable(move.getResult())) {
                 return move.getInput() != null && move.getInput().equals(from.operand) && move.getResult() != null && move.getResult().equals(to.operand);
             }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/MoveResolver.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/MoveResolver.java	Fri May 12 13:56:13 2017 -0700
@@ -241,7 +241,7 @@
             return true;
         }
         if (from != null && isRegister(from) && isRegister(to) && asRegister(from).equals(asRegister(to))) {
-            assert LIRKind.verifyMoveKinds(to.getValueKind(), from.getValueKind()) : String.format("Same register but Kind mismatch %s <- %s", to, from);
+            assert LIRKind.verifyMoveKinds(to.getValueKind(), from.getValueKind(), allocator.getRegisterAllocationConfig()) : String.format("Same register but Kind mismatch %s <- %s", to, from);
             return true;
         }
         return false;
@@ -267,7 +267,7 @@
 
     private void insertMove(Interval fromInterval, Interval toInterval) {
         assert !fromInterval.operand.equals(toInterval.operand) : "from and to interval equal: " + fromInterval;
-        assert LIRKind.verifyMoveKinds(toInterval.kind(), fromInterval.kind()) : "move between different types";
+        assert LIRKind.verifyMoveKinds(toInterval.kind(), fromInterval.kind(), allocator.getRegisterAllocationConfig()) : "move between different types";
         assert insertIdx != -1 : "must setup insert position first";
 
         insertionBuffer.append(insertIdx, createMove(fromInterval.operand, toInterval.operand, fromInterval.location(), toInterval.location()));
@@ -469,8 +469,8 @@
         }
 
         assert !fromInterval.operand.equals(toInterval.operand) : "from and to interval equal: " + fromInterval;
-        assert LIRKind.verifyMoveKinds(toInterval.kind(), fromInterval.kind()) : String.format("Kind mismatch: %s vs. %s, from=%s, to=%s", fromInterval.kind(), toInterval.kind(), fromInterval,
-                        toInterval);
+        assert LIRKind.verifyMoveKinds(toInterval.kind(), fromInterval.kind(), allocator.getRegisterAllocationConfig()) : String.format("Kind mismatch: %s vs. %s, from=%s, to=%s", fromInterval.kind(),
+                        toInterval.kind(), fromInterval, toInterval);
         mappingFrom.add(fromInterval);
         mappingFromOpr.add(null);
         mappingTo.add(toInterval);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceGlobalMoveResolutionPhase.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceGlobalMoveResolutionPhase.java	Fri May 12 13:56:13 2017 -0700
@@ -33,6 +33,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 
+import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig;
 import org.graalvm.compiler.core.common.alloc.Trace;
 import org.graalvm.compiler.core.common.alloc.TraceBuilderResult;
 import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
@@ -68,14 +69,15 @@
     public static void resolve(TargetDescription target, LIRGenerationResult lirGenRes, TraceAllocationContext context) {
         Debug.dump(Debug.VERBOSE_LEVEL, lirGenRes.getLIR(), "Before TraceGlobalMoveResultion");
         MoveFactory spillMoveFactory = context.spillMoveFactory;
-        resolveGlobalDataFlow(context.resultTraces, lirGenRes, spillMoveFactory, target.arch, context.livenessInfo);
+        resolveGlobalDataFlow(context.resultTraces, lirGenRes, spillMoveFactory, target.arch, context.livenessInfo, context.registerAllocationConfig);
     }
 
     @SuppressWarnings("try")
-    private static void resolveGlobalDataFlow(TraceBuilderResult resultTraces, LIRGenerationResult lirGenRes, MoveFactory spillMoveFactory, Architecture arch, GlobalLivenessInfo livenessInfo) {
+    private static void resolveGlobalDataFlow(TraceBuilderResult resultTraces, LIRGenerationResult lirGenRes, MoveFactory spillMoveFactory, Architecture arch, GlobalLivenessInfo livenessInfo,
+                    RegisterAllocationConfig registerAllocationConfig) {
         LIR lir = lirGenRes.getLIR();
         /* Resolve trace global data-flow mismatch. */
-        TraceGlobalMoveResolver moveResolver = new TraceGlobalMoveResolver(lirGenRes, spillMoveFactory, arch);
+        TraceGlobalMoveResolver moveResolver = new TraceGlobalMoveResolver(lirGenRes, spillMoveFactory, registerAllocationConfig, arch);
 
         try (Indent indent = Debug.logAndIndent("Trace global move resolution")) {
             for (Trace trace : resultTraces.getTraces()) {
@@ -139,8 +141,7 @@
         assert Arrays.asList(toBlock.getPredecessors()).contains(fromBlock) : String.format("%s not in predecessor list: %s", fromBlock,
                         Arrays.toString(toBlock.getPredecessors()));
         assert fromBlock.getSuccessorCount() == 1 || toBlock.getPredecessorCount() == 1 : String.format("Critical Edge? %s has %d successors and %s has %d predecessors",
-                        fromBlock,
-                        fromBlock.getSuccessorCount(), toBlock, toBlock.getPredecessorCount());
+                        fromBlock, fromBlock.getSuccessorCount(), toBlock, toBlock.getPredecessorCount());
         assert Arrays.asList(fromBlock.getSuccessors()).contains(toBlock) : String.format("Predecessor block %s has wrong successor: %s, should contain: %s", fromBlock,
                         Arrays.toString(fromBlock.getSuccessors()), toBlock);
         return true;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceGlobalMoveResolver.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceGlobalMoveResolver.java	Fri May 12 13:56:13 2017 -0700
@@ -39,6 +39,7 @@
 import java.util.HashSet;
 
 import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig;
 import org.graalvm.compiler.debug.Debug;
 import org.graalvm.compiler.debug.DebugCounter;
 import org.graalvm.compiler.debug.GraalError;
@@ -79,6 +80,7 @@
     private final MoveFactory spillMoveFactory;
     private final FrameMapBuilder frameMapBuilder;
     private final OptionValues options;
+    private final RegisterAllocationConfig registerAllocationConfig;
 
     private void setValueBlocked(Value location, int direction) {
         assert direction == 1 || direction == -1 : "out of bounds";
@@ -136,7 +138,7 @@
         return frameMapBuilder.getRegisterConfig().getAllocatableRegisters();
     }
 
-    public TraceGlobalMoveResolver(LIRGenerationResult res, MoveFactory spillMoveFactory, Architecture arch) {
+    public TraceGlobalMoveResolver(LIRGenerationResult res, MoveFactory spillMoveFactory, RegisterAllocationConfig registerAllocationConfig, Architecture arch) {
 
         this.mappingFrom = new ArrayList<>(8);
         this.mappingFromStack = new ArrayList<>(8);
@@ -147,6 +149,7 @@
         this.frameMapBuilder = res.getFrameMapBuilder();
         this.spillMoveFactory = spillMoveFactory;
         this.registerBlocked = new int[arch.getRegisters().size()];
+        this.registerAllocationConfig = registerAllocationConfig;
 
         FrameMapBuilderTool frameMapBuilderTool = (FrameMapBuilderTool) frameMapBuilder;
         this.stackBlocked = new int[frameMapBuilderTool.getNumberOfStackSlots()];
@@ -288,7 +291,6 @@
         }
         if (isRegister(from) && isRegister(to) && asRegister(from).equals(asRegister(to))) {
             // Values differ but Registers are the same
-            assert LIRKind.verifyMoveKinds(to.getValueKind(), from.getValueKind()) : String.format("Same register but Kind mismatch %s <- %s", to, from);
             return true;
         }
         return false;
@@ -314,7 +316,7 @@
 
     private void insertMove(Value fromOperand, AllocatableValue toOperand) {
         assert !fromOperand.equals(toOperand) : "from and to are equal: " + fromOperand + " vs. " + toOperand;
-        assert LIRKind.verifyMoveKinds(fromOperand.getValueKind(), fromOperand.getValueKind()) : "move between different types";
+        assert LIRKind.verifyMoveKinds(fromOperand.getValueKind(), fromOperand.getValueKind(), registerAllocationConfig) : "move between different types";
         assert insertIdx != -1 : "must setup insert position first";
 
         insertionBuffer.append(insertIdx, createMove(fromOperand, toOperand));
@@ -451,8 +453,10 @@
         }
 
         assert !from.equals(to) : "from and to interval equal: " + from;
-        assert LIRKind.verifyMoveKinds(to.getValueKind(), from.getValueKind()) : String.format("Kind mismatch: %s vs. %s, from=%s, to=%s", from.getValueKind(), to.getValueKind(), from, to);
-        assert fromStack == null || LIRKind.verifyMoveKinds(to.getValueKind(), fromStack.getValueKind()) : String.format("Kind mismatch: %s vs. %s, fromStack=%s, to=%s", fromStack.getValueKind(),
+        assert LIRKind.verifyMoveKinds(to.getValueKind(), from.getValueKind(), registerAllocationConfig) : String.format("Kind mismatch: %s vs. %s, from=%s, to=%s", from.getValueKind(),
+                        to.getValueKind(), from, to);
+        assert fromStack == null || LIRKind.verifyMoveKinds(to.getValueKind(), fromStack.getValueKind(), registerAllocationConfig) : String.format("Kind mismatch: %s vs. %s, fromStack=%s, to=%s",
+                        fromStack.getValueKind(),
                         to.getValueKind(), fromStack, to);
         mappingFrom.add(from);
         mappingFromStack.add(fromStack);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/bu/BottomUpAllocator.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/bu/BottomUpAllocator.java	Fri May 12 13:56:13 2017 -0700
@@ -126,7 +126,7 @@
         this.registerAttributes = registerAllocationConfig.getRegisterConfig().getAttributesMap();
         this.allocatedBlocks = new BitSet(lirGenRes.getLIR().getControlFlowGraph().getBlocks().length);
         this.resultTraces = resultTraces;
-        this.moveResolver = new TraceGlobalMoveResolver(lirGenRes, spillMoveFactory, target.arch);
+        this.moveResolver = new TraceGlobalMoveResolver(lirGenRes, spillMoveFactory, registerAllocationConfig, target.arch);
         this.neverSpillConstants = neverSpillConstant;
         this.livenessInfo = livenessInfo;
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanAssignLocationsPhase.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanAssignLocationsPhase.java	Fri May 12 13:56:13 2017 -0700
@@ -42,7 +42,6 @@
 import org.graalvm.compiler.debug.Indent;
 import org.graalvm.compiler.lir.ConstantValue;
 import org.graalvm.compiler.lir.InstructionValueProcedure;
-import org.graalvm.compiler.lir.LIRFrameState;
 import org.graalvm.compiler.lir.LIRInstruction;
 import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
 import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
@@ -163,10 +162,6 @@
             return result;
         }
 
-        private void computeDebugInfo(final LIRInstruction op, LIRFrameState info) {
-            info.forEachState(op, this::debugInfoProcedure);
-        }
-
         @SuppressWarnings("try")
         private void assignBlock(AbstractBlockBase<?> block) {
             try (Indent indent2 = Debug.logAndIndent("assign locations in block B%d", block.getId())) {
@@ -259,6 +254,12 @@
                 return value;
             }
         };
+        private final InstructionValueProcedure debugInfoValueProc = new InstructionValueProcedure() {
+            @Override
+            public Value doValue(LIRInstruction instruction, Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
+                return debugInfoProcedure(instruction, value, mode, flags);
+            }
+        };
 
         /**
          * Assigns the operand of an {@link LIRInstruction}.
@@ -272,8 +273,8 @@
             assert op != null && instructions.get(j) == op;
 
             // remove useless moves
-            if (op instanceof MoveOp) {
-                AllocatableValue result = ((MoveOp) op).getResult();
+            if (MoveOp.isMoveOp(op)) {
+                AllocatableValue result = MoveOp.asMoveOp(op).getResult();
                 if (isVariable(result) && allocator.isMaterialized(result, op.id(), OperandMode.DEF)) {
                     /*
                      * This happens if a materializable interval is originally not spilled but then
@@ -291,11 +292,11 @@
             op.forEachOutput(assignProc);
 
             // compute reference map and debug information
-            op.forEachState((inst, state) -> computeDebugInfo(inst, state));
+            op.forEachState(debugInfoValueProc);
 
             // remove useless moves
-            if (op instanceof ValueMoveOp) {
-                ValueMoveOp move = (ValueMoveOp) op;
+            if (ValueMoveOp.isValueMoveOp(op)) {
+                ValueMoveOp move = ValueMoveOp.asValueMoveOp(op);
                 if (move.getInput().equals(move.getResult())) {
                     instructions.set(j, null);
                     return true;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanEliminateSpillMovePhase.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanEliminateSpillMovePhase.java	Fri May 12 13:56:13 2017 -0700
@@ -107,7 +107,7 @@
                         try (Indent indent2 = Debug.logAndIndent("%5d %s", opId, op)) {
 
                             if (opId == -1) {
-                                MoveOp move = (MoveOp) op;
+                                MoveOp move = MoveOp.asMoveOp(op);
                                 /*
                                  * Remove move from register to stack if the stack slot is
                                  * guaranteed to be correct. Only moves that have been inserted by
@@ -119,12 +119,12 @@
                                      * eliminate instruction.
                                      */
                                     if (Debug.isLogEnabled()) {
-                                        if (move instanceof ValueMoveOp) {
-                                            ValueMoveOp vmove = (ValueMoveOp) move;
+                                        if (ValueMoveOp.isValueMoveOp(op)) {
+                                            ValueMoveOp vmove = ValueMoveOp.asValueMoveOp(op);
                                             Debug.log("eliminating move from interval %d (%s) to %d (%s) in block %s", allocator.operandNumber(vmove.getInput()), vmove.getInput(),
                                                             allocator.operandNumber(vmove.getResult()), vmove.getResult(), block);
                                         } else {
-                                            LoadConstantOp load = (LoadConstantOp) move;
+                                            LoadConstantOp load = LoadConstantOp.asLoadConstantOp(op);
                                             Debug.log("eliminating constant load from %s to %d (%s) in block %s", load.getConstant(), allocator.operandNumber(load.getResult()), load.getResult(),
                                                             block);
                                         }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanLifetimeAnalysisPhase.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanLifetimeAnalysisPhase.java	Fri May 12 13:56:13 2017 -0700
@@ -440,8 +440,8 @@
                 // skip method header
                 return RegisterPriority.None;
             }
-            if (op instanceof ValueMoveOp) {
-                ValueMoveOp move = (ValueMoveOp) op;
+            if (ValueMoveOp.isValueMoveOp(op)) {
+                ValueMoveOp move = ValueMoveOp.asValueMoveOp(op);
                 if (optimizeMethodArgument(move.getInput())) {
                     return RegisterPriority.None;
                 }
@@ -715,8 +715,8 @@
      *         can only be a {@link JavaConstant}.
      */
     private static JavaConstant getMaterializedValue(LIRInstruction op, Value operand, TraceInterval interval, boolean neverSpillConstants, MoveFactory spillMoveFactory) {
-        if (op instanceof LoadConstantOp) {
-            LoadConstantOp move = (LoadConstantOp) op;
+        if (LoadConstantOp.isLoadConstantOp(op)) {
+            LoadConstantOp move = LoadConstantOp.asLoadConstantOp(op);
             if (move.getConstant() instanceof JavaConstant) {
                 if (!neverSpillConstants) {
                     if (!spillMoveFactory.allowConstantToStackMove(move.getConstant())) {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanWalker.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanWalker.java	Fri May 12 13:56:13 2017 -0700
@@ -1042,8 +1042,8 @@
     }
 
     private static boolean isMove(LIRInstruction op, TraceInterval from, TraceInterval to) {
-        if (op instanceof ValueMoveOp) {
-            ValueMoveOp move = (ValueMoveOp) op;
+        if (ValueMoveOp.isValueMoveOp(op)) {
+            ValueMoveOp move = ValueMoveOp.asValueMoveOp(op);
             if (isVariable(move.getInput()) && isVariable(move.getResult())) {
                 return move.getInput() != null && move.getInput().equals(from.operand) && move.getResult() != null && move.getResult().equals(to.operand);
             }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLocalMoveResolver.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLocalMoveResolver.java	Fri May 12 13:56:13 2017 -0700
@@ -293,7 +293,6 @@
             return true;
         }
         if (from != null && isRegister(from) && isRegister(to) && asRegister(from).equals(asRegister(to))) {
-            assert LIRKind.verifyMoveKinds(to.getValueKind(), from.getValueKind()) : String.format("Same register but Kind mismatch %s <- %s", to, from);
             return true;
         }
         return false;
@@ -325,7 +324,7 @@
 
     private void insertMove(TraceInterval fromInterval, TraceInterval toInterval) {
         assert !fromInterval.operand.equals(toInterval.operand) : "from and to interval equal: " + fromInterval;
-        assert LIRKind.verifyMoveKinds(toInterval.kind(), fromInterval.kind()) : "move between different types";
+        assert LIRKind.verifyMoveKinds(toInterval.kind(), fromInterval.kind(), allocator.getRegisterAllocationConfig()) : "move between different types";
         assert insertIdx != -1 : "must setup insert position first";
 
         insertionBuffer.append(insertIdx, createMove(fromInterval.operand, toInterval.operand, fromInterval.location(), toInterval.location()));
@@ -537,8 +536,8 @@
         }
 
         assert !fromInterval.operand.equals(toInterval.operand) : "from and to interval equal: " + fromInterval;
-        assert LIRKind.verifyMoveKinds(toInterval.kind(), fromInterval.kind()) : String.format("Kind mismatch: %s vs. %s, from=%s, to=%s", fromInterval.kind(), toInterval.kind(), fromInterval,
-                        toInterval);
+        assert LIRKind.verifyMoveKinds(toInterval.kind(), fromInterval.kind(), allocator.getRegisterAllocationConfig()) : String.format("Kind mismatch: %s vs. %s, from=%s, to=%s", fromInterval.kind(),
+                        toInterval.kind(), fromInterval, toInterval);
         mappingFrom.add(fromInterval);
         mappingFromOpr.add(null);
         mappingTo.add(toInterval);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/constopt/ConstantLoadOptimization.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/constopt/ConstantLoadOptimization.java	Fri May 12 13:56:13 2017 -0700
@@ -170,11 +170,10 @@
         }
 
         private static boolean isConstantLoad(LIRInstruction inst) {
-            if (!(inst instanceof LoadConstantOp)) {
+            if (!LoadConstantOp.isLoadConstantOp(inst)) {
                 return false;
             }
-            LoadConstantOp load = (LoadConstantOp) inst;
-            return isVariable(load.getResult());
+            return isVariable(LoadConstantOp.asLoadConstantOp(inst).getResult());
         }
 
         private void addUsageToBlockMap(UseEntry entry) {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/constopt/DefUseTree.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/constopt/DefUseTree.java	Fri May 12 13:56:13 2017 -0700
@@ -43,8 +43,8 @@
     private final List<UseEntry> uses;
 
     DefUseTree(LIRInstruction instruction, AbstractBlockBase<?> block) {
-        assert instruction instanceof LoadConstantOp : "Not a LoadConstantOp: " + instruction;
-        this.instruction = (LoadConstantOp) instruction;
+        assert LoadConstantOp.isLoadConstantOp(instruction) : "Not a LoadConstantOp: " + instruction;
+        this.instruction = LoadConstantOp.asLoadConstantOp(instruction);
         this.block = block;
         this.uses = new ArrayList<>();
     }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/LIRGeneratorTool.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/LIRGeneratorTool.java	Fri May 12 13:56:13 2017 -0700
@@ -22,6 +22,7 @@
  */
 package org.graalvm.compiler.lir.gen;
 
+import org.graalvm.compiler.core.common.CompressEncoding;
 import org.graalvm.compiler.core.common.LIRKind;
 import org.graalvm.compiler.core.common.calc.Condition;
 import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
@@ -260,4 +261,9 @@
     void emitPause();
 
     void emitPrefetchAllocate(Value address);
+
+    Value emitCompress(Value pointer, CompressEncoding encoding, boolean nonNull);
+
+    Value emitUncompress(Value pointer, CompressEncoding encoding, boolean nonNull);
+
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/VerifyingMoveFactory.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/VerifyingMoveFactory.java	Fri May 12 13:56:13 2017 -0700
@@ -76,7 +76,7 @@
     @Override
     public LIRInstruction createLoad(AllocatableValue result, Constant input) {
         LIRInstruction inst = inner.createLoad(result, input);
-        assert inst instanceof LoadConstantOp && checkResult(inst, result, null);
+        assert LoadConstantOp.isLoadConstantOp(inst) && checkResult(inst, result, null);
         return inst;
     }
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/profiling/MoveProfiler.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/profiling/MoveProfiler.java	Fri May 12 13:56:13 2017 -0700
@@ -87,12 +87,12 @@
         MoveStatistics stats = null;
         // analysis phase
         for (LIRInstruction inst : instructions) {
-            if (inst instanceof MoveOp) {
+            if (MoveOp.isMoveOp(inst)) {
                 if (stats == null) {
                     stats = new MoveStatistics();
                     blockMap.put(block, stats);
                 }
-                stats.add(MoveType.get((MoveOp) inst));
+                stats.add(MoveType.get(inst));
             }
         }
     }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/profiling/MoveType.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/profiling/MoveType.java	Fri May 12 13:56:13 2017 -0700
@@ -26,6 +26,7 @@
 import static jdk.vm.ci.code.ValueUtil.isStackSlot;
 
 import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.lir.LIRInstruction;
 import org.graalvm.compiler.lir.StandardOp.LoadConstantOp;
 import org.graalvm.compiler.lir.StandardOp.MoveOp;
 import org.graalvm.compiler.lir.StandardOp.ValueMoveOp;
@@ -52,17 +53,18 @@
         return name;
     }
 
-    public static MoveType get(MoveOp move) {
-        AllocatableValue dst = move.getResult();
+    public static MoveType get(LIRInstruction inst) {
+        assert MoveOp.isMoveOp(inst);
+        AllocatableValue dst = MoveOp.asMoveOp(inst).getResult();
         Value src = null;
-        if (move instanceof LoadConstantOp) {
+        if (LoadConstantOp.isLoadConstantOp(inst)) {
             if (isRegister(dst)) {
                 return CONST2REG;
             } else if (isStackSlot(dst)) {
                 return CONST2STACK;
             }
-        } else if (move instanceof ValueMoveOp) {
-            src = ((ValueMoveOp) move).getInput();
+        } else if (ValueMoveOp.isValueMoveOp(inst)) {
+            src = ValueMoveOp.asValueMoveOp(inst).getInput();
             if (isRegister(dst)) {
                 if (isRegister(src)) {
                     return REG2REG;
@@ -77,6 +79,6 @@
                 }
             }
         }
-        throw GraalError.shouldNotReachHere(String.format("Unrecognized Move: %s dst=%s, src=%s", move, dst, src));
+        throw GraalError.shouldNotReachHere(String.format("Unrecognized Move: %s dst=%s, src=%s", inst, dst, src));
     }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/stackslotalloc/FixPointIntervalBuilder.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/stackslotalloc/FixPointIntervalBuilder.java	Fri May 12 13:56:13 2017 -0700
@@ -271,7 +271,7 @@
                                 from.setLocationHint(to);
                             }
                             if (Debug.isLogEnabled()) {
-                                Debug.log("operation %s at opId %d: added hint from interval %d to %d", op, op.id(), from, to);
+                                Debug.log("operation %s at opId %d: added hint from interval %s to %s", op, op.id(), from, to);
                             }
 
                             return registerHint;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/CountedLoopInfo.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/CountedLoopInfo.java	Fri May 12 13:56:13 2017 -0700
@@ -90,15 +90,50 @@
         return graph.unique(new ConditionalNode(graph.unique(new IntegerLessThanNode(zero, div)), div, zero));
     }
 
+    /**
+     * @return true if the loop has constant bounds and the trip count is representable as a
+     *         positive integer.
+     */
     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() {
+        assert isConstantMaxTripCount();
+        return 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.
+     */
+    protected long rawConstantMaxTripCount() {
         assert iv.direction() != null;
         long off = oneOff ? iv.direction() == Direction.Up ? 1 : -1 : 0;
-        long max = (((ConstantNode) end).asJavaConstant().asLong() + off - iv.constantInit()) / iv.constantStride();
-        return Math.max(0, max);
+        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;
+        }
     }
 
     public boolean isExactTripCount() {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/ConditionalEliminationBenchmark.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/ConditionalEliminationBenchmark.java	Fri May 12 13:56:13 2017 -0700
@@ -22,14 +22,12 @@
  */
 package org.graalvm.compiler.microbenchmarks.graal;
 
-import org.openjdk.jmh.annotations.Benchmark;
-
 import org.graalvm.compiler.microbenchmarks.graal.util.GraalState;
 import org.graalvm.compiler.microbenchmarks.graal.util.GraphState;
 import org.graalvm.compiler.microbenchmarks.graal.util.MethodSpec;
-import org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase;
-import org.graalvm.compiler.phases.common.NewConditionalEliminationPhase;
+import org.graalvm.compiler.phases.common.ConditionalEliminationPhase;
 import org.graalvm.compiler.phases.tiers.PhaseContext;
+import org.openjdk.jmh.annotations.Benchmark;
 
 public class ConditionalEliminationBenchmark extends GraalBenchmark {
 
@@ -109,12 +107,12 @@
 
     @Benchmark
     public void nullness(Nullness s, GraalState g) {
-        new DominatorConditionalEliminationPhase(false).apply(s.graph, new PhaseContext(g.providers));
+        new ConditionalEliminationPhase(false).apply(s.graph, new PhaseContext(g.providers));
     }
 
     @Benchmark
     public void newDominatorConditionalElimination(Nullness s, GraalState g) {
-        new NewConditionalEliminationPhase(false).apply(s.graph, new PhaseContext(g.providers));
+        new ConditionalEliminationPhase(false).apply(s.graph, new PhaseContext(g.providers));
     }
 
     @MethodSpec(declaringClass = ConditionalEliminationBenchmark.class, name = "searchSnippet")
@@ -165,6 +163,6 @@
 
     @Benchmark
     public void search(Search s, GraalState g) {
-        new DominatorConditionalEliminationPhase(false).apply(s.graph, new PhaseContext(g.providers));
+        new ConditionalEliminationPhase(false).apply(s.graph, new PhaseContext(g.providers));
     }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/util/GraalUtil.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/util/GraalUtil.java	Fri May 12 13:56:13 2017 -0700
@@ -38,7 +38,6 @@
 import org.graalvm.compiler.phases.PhaseSuite;
 import org.graalvm.compiler.phases.tiers.HighTierContext;
 
-import jdk.vm.ci.meta.MetaAccessProvider;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 
 public class GraalUtil {
@@ -136,8 +135,7 @@
     public static StructuredGraph getGraph(GraalState graal, ResolvedJavaMethod javaMethod, boolean useProfilingInfo) {
         StructuredGraph graph = new StructuredGraph.Builder(Graal.getRequiredCapability(OptionValues.class), AllowAssumptions.YES).useProfilingInfo(useProfilingInfo).method(javaMethod).build();
         PhaseSuite<HighTierContext> graphBuilderSuite = new PhaseSuite<>();
-        MetaAccessProvider metaAccess = graal.providers.getMetaAccess();
-        graphBuilderSuite.appendPhase(new GraphBuilderPhase(GraphBuilderConfiguration.getDefault(new Plugins(new InvocationPlugins(metaAccess)))));
+        graphBuilderSuite.appendPhase(new GraphBuilderPhase(GraphBuilderConfiguration.getDefault(new Plugins(new InvocationPlugins()))));
         graphBuilderSuite.apply(graph, new HighTierContext(graal.providers, graphBuilderSuite, OptimisticOptimizations.ALL));
         return graph;
     }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/lir/GraalCompilerState.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/lir/GraalCompilerState.java	Fri May 12 13:56:13 2017 -0700
@@ -246,14 +246,16 @@
         return structuredGraph;
     }
 
-    protected Suites createSuites() {
-        Suites ret = backend.getSuites().getDefaultSuites(options).copy();
-        return ret;
+    protected OptionValues getOptions() {
+        return options;
     }
 
-    protected LIRSuites createLIRSuites() {
-        LIRSuites ret = backend.getSuites().getDefaultLIRSuites(options).copy();
-        return ret;
+    protected Suites createSuites(OptionValues opts) {
+        return backend.getSuites().getDefaultSuites(opts).copy();
+    }
+
+    protected LIRSuites createLIRSuites(OptionValues opts) {
+        return backend.getSuites().getDefaultLIRSuites(opts).copy();
     }
 
     protected Backend getBackend() {
@@ -323,7 +325,7 @@
         assert !graph.isFrozen();
         ResolvedJavaMethod installedCodeOwner = graph.method();
         request = new Request<>(graph, installedCodeOwner, getProviders(), getBackend(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL,
-                        graph.getProfilingInfo(), createSuites(), createLIRSuites(), new CompilationResult(), CompilationResultBuilderFactory.Default);
+                        graph.getProfilingInfo(), createSuites(getOptions()), createLIRSuites(getOptions()), new CompilationResult(), CompilationResultBuilderFactory.Default);
     }
 
     /**
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/lir/RegisterAllocationTimeBenchmark.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/lir/RegisterAllocationTimeBenchmark.java	Fri May 12 13:56:13 2017 -0700
@@ -22,68 +22,26 @@
  */
 package org.graalvm.compiler.microbenchmarks.lir;
 
-import java.util.HashMap;
-
+import org.graalvm.compiler.lir.gen.LIRGenerationResult;
+import org.graalvm.compiler.microbenchmarks.graal.GraalBenchmark;
 import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.Measurement;
+import org.openjdk.jmh.annotations.Param;
+import org.openjdk.jmh.annotations.Warmup;
 
-import org.graalvm.compiler.lir.gen.LIRGenerationResult;
-import org.graalvm.compiler.lir.phases.LIRSuites;
-import org.graalvm.compiler.microbenchmarks.graal.GraalBenchmark;
-import org.graalvm.compiler.microbenchmarks.graal.util.MethodSpec;
-
+@Warmup(iterations = 10)
+@Measurement(iterations = 10)
 public class RegisterAllocationTimeBenchmark extends GraalBenchmark {
 
-    // Checkstyle: stop method name check
-    public static class LSRA_Allocation extends GraalCompilerState.AllocationStage {
-        @SuppressWarnings("try")
-        @Override
-        protected LIRSuites createLIRSuites() {
-            return super.createLIRSuites();
-        }
-    }
-
-    @MethodSpec(declaringClass = String.class, name = "equals")
-    public static class LSRA_StringEquals extends LSRA_Allocation {
-    }
-
-    @MethodSpec(declaringClass = HashMap.class, name = "computeIfAbsent")
-    public static class LSRA_HashMapComputeIfAbsent extends LSRA_Allocation {
+    public static class State extends GraalCompilerState.AllocationStage {
+        @MethodDescString @Param({
+                        "java.lang.String#equals",
+                        "java.util.HashMap#computeIfAbsent"
+        }) public String method;
     }
 
     @Benchmark
-    public LIRGenerationResult lsra_STRING_equals(LSRA_StringEquals s) {
-        return s.compile();
-    }
-
-    @Benchmark
-    public LIRGenerationResult lsra_HASHMAP_computeIfAbsent(LSRA_HashMapComputeIfAbsent s) {
+    public LIRGenerationResult allocateRegisters(State s) {
         return s.compile();
     }
-
-    public static class TraceRA_Allocation extends GraalCompilerState.AllocationStage {
-        @SuppressWarnings("try")
-        @Override
-        protected LIRSuites createLIRSuites() {
-            return super.createLIRSuites();
-        }
-    }
-
-    @MethodSpec(declaringClass = String.class, name = "equals")
-    public static class TraceRA_StringEquals extends TraceRA_Allocation {
-    }
-
-    @MethodSpec(declaringClass = HashMap.class, name = "computeIfAbsent")
-    public static class TraceRA_HashMapComputeIfAbsent extends TraceRA_Allocation {
-    }
-
-    @Benchmark
-    public LIRGenerationResult tracera_STRING_equals(TraceRA_StringEquals s) {
-        return s.compile();
-    }
-
-    @Benchmark
-    public LIRGenerationResult tracera_HASHMAP_computeIfAbsent(TraceRA_HashMapComputeIfAbsent s) {
-        return s.compile();
-    }
-    // Checkstyle: resume method name check
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/NegateNodeCanonicalizationTest.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/NegateNodeCanonicalizationTest.java	Fri May 12 13:56:13 2017 -0700
@@ -29,7 +29,6 @@
 import org.graalvm.compiler.nodes.ConstantNode;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
-import org.graalvm.compiler.test.AddExports;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -38,7 +37,6 @@
 /**
  * This class tests that the canonicalization for constant negate nodes cover all cases.
  */
-@AddExports("jdk.internal.vm.ci/jdk.vm.ci.meta")
 public class NegateNodeCanonicalizationTest {
 
     private StructuredGraph graph;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/ShortCircuitOrNodeTest.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/ShortCircuitOrNodeTest.java	Fri May 12 13:56:13 2017 -0700
@@ -36,9 +36,9 @@
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
 import org.graalvm.compiler.nodes.calc.ConditionalNode;
 import org.graalvm.compiler.nodes.calc.IntegerEqualsNode;
-import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.tiers.PhaseContext;
@@ -53,9 +53,8 @@
     }
 
     @Override
-    protected Plugins getDefaultGraphBuilderPlugins() {
-        Plugins plugins = super.getDefaultGraphBuilderPlugins();
-        Registration r = new Registration(plugins.getInvocationPlugins(), ShortCircuitOrNodeTest.class);
+    protected void registerInvocationPlugins(InvocationPlugins invocationPlugins) {
+        Registration r = new Registration(invocationPlugins, ShortCircuitOrNodeTest.class);
         r.register2("shortCircuitOr", boolean.class, boolean.class, new InvocationPlugin() {
             @Override
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode b1, ValueNode b2) {
@@ -66,8 +65,7 @@
                 return true;
             }
         });
-
-        return plugins;
+        super.registerInvocationPlugins(invocationPlugins);
     }
 
     public static int testSharedConditionSnippet(Object o) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/CompressionNode.java	Fri May 12 13:56:13 2017 -0700
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2014, 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.nodes;
+
+import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
+
+import org.graalvm.compiler.core.common.CompressEncoding;
+import org.graalvm.compiler.core.common.type.AbstractObjectStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.calc.ConvertNode;
+import org.graalvm.compiler.nodes.calc.UnaryNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.nodes.type.StampTool;
+
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.Value;
+
+/**
+ * Compress or uncompress an oop or metaspace pointer.
+ */
+@NodeInfo(nameTemplate = "{p#op/s}", cycles = CYCLES_2, size = SIZE_2)
+public abstract class CompressionNode extends UnaryNode implements ConvertNode, LIRLowerable {
+
+    public static final NodeClass<CompressionNode> TYPE = NodeClass.create(CompressionNode.class);
+
+    public enum CompressionOp {
+        Compress,
+        Uncompress
+    }
+
+    protected final CompressionOp op;
+    protected final CompressEncoding encoding;
+
+    public CompressionNode(NodeClass<? extends UnaryNode> c, CompressionOp op, ValueNode input, Stamp stamp, CompressEncoding encoding) {
+        super(c, stamp, input);
+        this.op = op;
+        this.encoding = encoding;
+    }
+
+    @Override
+    public Stamp foldStamp(Stamp newStamp) {
+        assert newStamp.isCompatible(getValue().stamp());
+        return mkStamp(newStamp);
+    }
+
+    protected abstract Constant compress(Constant c);
+
+    protected abstract Constant uncompress(Constant c);
+
+    @Override
+    public Constant convert(Constant c, ConstantReflectionProvider constantReflection) {
+        switch (op) {
+            case Compress:
+                return compress(c);
+            case Uncompress:
+                return uncompress(c);
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+    }
+
+    @Override
+    public Constant reverse(Constant c, ConstantReflectionProvider constantReflection) {
+        switch (op) {
+            case Compress:
+                return uncompress(c);
+            case Uncompress:
+                return compress(c);
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+    }
+
+    @Override
+    public boolean isLossless() {
+        return true;
+    }
+
+    protected abstract Stamp mkStamp(Stamp input);
+
+    public CompressionOp getOp() {
+        return op;
+    }
+
+    public CompressEncoding getEncoding() {
+        return encoding;
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        if (forValue.isConstant()) {
+            if (GeneratePIC.getValue(tool.getOptions())) {
+                // We always want uncompressed constants
+                return this;
+            }
+            int stableDimension = ((ConstantNode) forValue).getStableDimension();
+            boolean isDefaultStable = ((ConstantNode) forValue).isDefaultStable();
+            return ConstantNode.forConstant(stamp(), convert(forValue.asConstant(), tool.getConstantReflection()), stableDimension, isDefaultStable, tool.getMetaAccess());
+        } else if (forValue instanceof CompressionNode) {
+            CompressionNode other = (CompressionNode) forValue;
+            if (op != other.op && encoding.equals(other.encoding)) {
+                return other.getValue();
+            }
+        }
+        return this;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool gen) {
+        LIRGeneratorTool hsGen = gen.getLIRGeneratorTool();
+        boolean nonNull;
+        if (getValue().stamp() instanceof AbstractObjectStamp) {
+            nonNull = StampTool.isPointerNonNull(getValue().stamp());
+        } else {
+            // metaspace pointers are never null
+            nonNull = true;
+        }
+
+        Value result;
+        switch (op) {
+            case Compress:
+                result = hsGen.emitCompress(gen.operand(getValue()), encoding, nonNull);
+                break;
+            case Uncompress:
+                result = hsGen.emitUncompress(gen.operand(getValue()), encoding, nonNull);
+                break;
+            default:
+                throw GraalError.shouldNotReachHere();
+        }
+
+        gen.setResult(this, result);
+    }
+
+    @Override
+    public boolean mayNullCheckSkipConversion() {
+        return true;
+    }
+}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FieldLocationIdentity.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FieldLocationIdentity.java	Fri May 12 13:56:13 2017 -0700
@@ -22,9 +22,10 @@
  */
 package org.graalvm.compiler.nodes;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import jdk.vm.ci.meta.JavaKind.FormatWithToString;
 
-import jdk.vm.ci.meta.JavaKind.FormatWithToString;
+import org.graalvm.api.word.LocationIdentity;
+
 import jdk.vm.ci.meta.ResolvedJavaField;
 
 public class FieldLocationIdentity extends LocationIdentity implements FormatWithToString {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FrameState.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FrameState.java	Fri May 12 13:56:13 2017 -0700
@@ -137,6 +137,7 @@
         }
         assert stackSize >= 0;
         this.outerFrameState = outerFrameState;
+        assert outerFrameState == null || outerFrameState.bci >= 0;
         this.code = code;
         this.bci = bci;
         this.localsSize = localsSize;
@@ -236,7 +237,7 @@
     }
 
     public void setOuterFrameState(FrameState x) {
-        assert x == null || !x.isDeleted();
+        assert x == null || (!x.isDeleted() && x.bci >= 0);
         updateUsages(this.outerFrameState, x);
         this.outerFrameState = x;
     }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/IfNode.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/IfNode.java	Fri May 12 13:56:13 2017 -0700
@@ -297,7 +297,7 @@
                  * since the two inputs get simplified into one.
                  */
                 phi.setValueAt(trueEnd, result);
-                removeThroughFalseBranch(tool);
+                removeThroughFalseBranch(tool, merge);
                 return true;
             }
         }
@@ -563,7 +563,7 @@
                      * Multiple phis but merging same values for true and false, so simply delete
                      * the path
                      */
-                    removeThroughFalseBranch(tool);
+                    removeThroughFalseBranch(tool, merge);
                     return true;
                 } else if (distinct == 1) {
                     ValueNode trueValue = singlePhi.valueAt(trueEnd);
@@ -571,7 +571,7 @@
                     ValueNode conditional = canonicalizeConditionalCascade(trueValue, falseValue);
                     if (conditional != null) {
                         singlePhi.setValueAt(trueEnd, conditional);
-                        removeThroughFalseBranch(tool);
+                        removeThroughFalseBranch(tool, merge);
                         return true;
                     }
                 }
@@ -601,13 +601,24 @@
         return false;
     }
 
-    protected void removeThroughFalseBranch(SimplifierTool tool) {
+    protected void removeThroughFalseBranch(SimplifierTool tool, AbstractMergeNode merge) {
         AbstractBeginNode trueBegin = trueSuccessor();
         graph().removeSplitPropagate(this, trueBegin);
         tool.addToWorkList(trueBegin);
         if (condition() != null) {
             GraphUtil.tryKillUnused(condition());
         }
+        if (merge.isAlive() && merge.forwardEndCount() > 1) {
+            for (FixedNode end : merge.forwardEnds()) {
+                Node cur = end;
+                while (cur != null && cur.predecessor() instanceof BeginNode) {
+                    cur = cur.predecessor();
+                }
+                if (cur != null && cur.predecessor() instanceof IfNode) {
+                    tool.addToWorkList(cur.predecessor());
+                }
+            }
+        }
     }
 
     private ValueNode canonicalizeConditionalCascade(ValueNode trueValue, ValueNode falseValue) {
@@ -619,7 +630,7 @@
         }
         if (trueValue.isConstant() && falseValue.isConstant()) {
             return graph().unique(new ConditionalNode(condition(), trueValue, falseValue));
-        } else {
+        } else if (!graph().isAfterExpandLogic()) {
             ConditionalNode conditional = null;
             ValueNode constant = null;
             boolean negateCondition;
@@ -643,12 +654,10 @@
                 otherValue = conditional.trueValue();
                 negateConditionalCondition = true;
             }
-            if (otherValue != null) {
-                if (otherValue.isConstant() && graph().allowShortCircuitOr()) {
-                    double shortCutProbability = probability(trueSuccessor());
-                    LogicNode newCondition = LogicNode.or(condition(), negateCondition, conditional.condition(), negateConditionalCondition, shortCutProbability);
-                    return graph().unique(new ConditionalNode(newCondition, constant, otherValue));
-                }
+            if (otherValue != null && otherValue.isConstant()) {
+                double shortCutProbability = probability(trueSuccessor());
+                LogicNode newCondition = LogicNode.or(condition(), negateCondition, conditional.condition(), negateConditionalCondition, shortCutProbability);
+                return graph().unique(new ConditionalNode(newCondition, constant, otherValue));
             } else if (!negateCondition && constant.isJavaConstant() && conditional.trueValue().isJavaConstant() && conditional.falseValue().isJavaConstant()) {
                 IntegerLessThanNode lessThan = null;
                 IntegerEqualsNode equals = null;
@@ -664,7 +673,7 @@
                 if (lessThan != null) {
                     assert equals != null;
                     if ((lessThan.getX() == equals.getX() && lessThan.getY() == equals.getY()) || (lessThan.getX() == equals.getY() && lessThan.getY() == equals.getX())) {
-                        return graph().unique(new NormalizeCompareNode(lessThan.getX(), lessThan.getY(), false));
+                        return graph().unique(new NormalizeCompareNode(lessThan.getX(), lessThan.getY(), conditional.trueValue().stamp().getStackKind(), false));
                     }
                 }
             }
@@ -826,7 +835,7 @@
     @SuppressWarnings("unchecked")
     private static LogicNode computeCondition(SimplifierTool tool, LogicNode condition, PhiNode phi, Node value) {
         if (condition instanceof ShortCircuitOrNode) {
-            if (condition.graph().getGuardsStage().areDeoptsFixed() && condition.graph().allowShortCircuitOr()) {
+            if (condition.graph().getGuardsStage().areDeoptsFixed() && !condition.graph().isAfterExpandLogic()) {
                 ShortCircuitOrNode orNode = (ShortCircuitOrNode) condition;
                 LogicNode resultX = computeCondition(tool, orNode.x, phi, value);
                 LogicNode resultY = computeCondition(tool, orNode.y, phi, value);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InvokeNode.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InvokeNode.java	Fri May 12 13:56:13 2017 -0700
@@ -36,7 +36,7 @@
 
 import java.util.Map;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.graph.NodeClass;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InvokeWithExceptionNode.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InvokeWithExceptionNode.java	Fri May 12 13:56:13 2017 -0700
@@ -30,7 +30,7 @@
 
 import java.util.Map;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.graph.NodeClass;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/KillingBeginNode.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/KillingBeginNode.java	Fri May 12 13:56:13 2017 -0700
@@ -26,7 +26,7 @@
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
 import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/NamedLocationIdentity.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/NamedLocationIdentity.java	Fri May 12 13:56:13 2017 -0700
@@ -24,8 +24,8 @@
 
 import java.util.EnumMap;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
 import org.graalvm.util.Equivalence;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.util.EconomicSet;
 
 import jdk.vm.ci.meta.JavaKind;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StartNode.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StartNode.java	Fri May 12 13:56:13 2017 -0700
@@ -26,7 +26,7 @@
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
 import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StructuredGraph.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StructuredGraph.java	Fri May 12 13:56:13 2017 -0700
@@ -235,7 +235,7 @@
     private GuardsStage guardsStage = GuardsStage.FLOATING_GUARDS;
     private boolean isAfterFloatingReadPhase = false;
     private boolean hasValueProxies = true;
-    private boolean allowShortCircuitOr = true;
+    private boolean isAfterExpandLogic = false;
     private final boolean useProfilingInfo;
     private final Cancellable cancellable;
     /**
@@ -426,7 +426,7 @@
         copy.setGuardsStage(getGuardsStage());
         copy.isAfterFloatingReadPhase = isAfterFloatingReadPhase;
         copy.hasValueProxies = hasValueProxies;
-        copy.allowShortCircuitOr = allowShortCircuitOr;
+        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);
@@ -699,13 +699,12 @@
         hasValueProxies = state;
     }
 
-    public boolean allowShortCircuitOr() {
-        return allowShortCircuitOr;
+    public boolean isAfterExpandLogic() {
+        return isAfterExpandLogic;
     }
 
-    public void setAllowShortCircuitOr(boolean state) {
-        assert !state : "cannot 'unapply' logic expansion";
-        allowShortCircuitOr = state;
+    public void setAfterExpandLogic() {
+        isAfterExpandLogic = true;
     }
 
     /**
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/NormalizeCompareNode.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/NormalizeCompareNode.java	Fri May 12 13:56:13 2017 -0700
@@ -25,9 +25,9 @@
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
 
 import org.graalvm.compiler.core.common.calc.Condition;
-import org.graalvm.compiler.core.common.type.FloatStamp;
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.IterableNodeType;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.graph.spi.CanonicalizerTool;
 import org.graalvm.compiler.nodeinfo.NodeCycles;
@@ -36,8 +36,6 @@
 import org.graalvm.compiler.nodes.LogicConstantNode;
 import org.graalvm.compiler.nodes.LogicNode;
 import org.graalvm.compiler.nodes.ValueNode;
-import org.graalvm.compiler.nodes.spi.Lowerable;
-import org.graalvm.compiler.nodes.spi.LoweringTool;
 
 import jdk.vm.ci.meta.ConstantReflectionProvider;
 import jdk.vm.ci.meta.JavaKind;
@@ -48,39 +46,50 @@
  * true.
  */
 @NodeInfo(cycles = NodeCycles.CYCLES_2, size = SIZE_2)
-public final class NormalizeCompareNode extends BinaryNode implements Lowerable {
+public final class NormalizeCompareNode extends BinaryNode implements IterableNodeType {
 
     public static final NodeClass<NormalizeCompareNode> TYPE = NodeClass.create(NormalizeCompareNode.class);
     protected final boolean isUnorderedLess;
 
-    public NormalizeCompareNode(ValueNode x, ValueNode y, boolean isUnorderedLess) {
-        super(TYPE, StampFactory.forKind(JavaKind.Int), x, y);
+    public NormalizeCompareNode(ValueNode x, ValueNode y, JavaKind kind, boolean isUnorderedLess) {
+        super(TYPE, StampFactory.forInteger(kind, -1, 1), x, y);
         this.isUnorderedLess = isUnorderedLess;
     }
 
-    public static ValueNode create(ValueNode x, ValueNode y, boolean isUnorderedLess, ConstantReflectionProvider constantReflection) {
-        LogicNode result = CompareNode.tryConstantFold(Condition.EQ, x, y, constantReflection, false);
+    public static ValueNode create(ValueNode x, ValueNode y, boolean isUnorderedLess, JavaKind kind, ConstantReflectionProvider constantReflection) {
+        ValueNode result = tryConstantFold(x, y, isUnorderedLess, kind, constantReflection);
+        if (result != null) {
+            return result;
+        }
+
+        return new NormalizeCompareNode(x, y, kind, isUnorderedLess);
+    }
+
+    protected static ValueNode tryConstantFold(ValueNode x, ValueNode y, boolean isUnorderedLess, JavaKind kind, ConstantReflectionProvider constantReflection) {
+        LogicNode result = CompareNode.tryConstantFold(Condition.EQ, x, y, null, false);
         if (result instanceof LogicConstantNode) {
             LogicConstantNode logicConstantNode = (LogicConstantNode) result;
             LogicNode resultLT = CompareNode.tryConstantFold(Condition.LT, x, y, constantReflection, isUnorderedLess);
             if (resultLT instanceof LogicConstantNode) {
                 LogicConstantNode logicConstantNodeLT = (LogicConstantNode) resultLT;
                 if (logicConstantNodeLT.getValue()) {
-                    return ConstantNode.forInt(-1);
+                    return ConstantNode.forIntegerKind(kind, -1);
                 } else if (logicConstantNode.getValue()) {
-                    return ConstantNode.forInt(0);
+                    return ConstantNode.forIntegerKind(kind, 0);
                 } else {
-                    return ConstantNode.forInt(1);
+                    return ConstantNode.forIntegerKind(kind, 1);
                 }
             }
         }
-
-        return new NormalizeCompareNode(x, y, isUnorderedLess);
+        return null;
     }
 
     @Override
     public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
-        // nothing to do
+        ValueNode result = tryConstantFold(x, y, isUnorderedLess, stamp().getStackKind(), tool.getConstantReflection());
+        if (result != null) {
+            return result;
+        }
         return this;
     }
 
@@ -90,24 +99,11 @@
     }
 
     @Override
-    public void lower(LoweringTool tool) {
-        LogicNode equalComp;
-        LogicNode lessComp;
-        if (getX().stamp() instanceof FloatStamp) {
-            equalComp = graph().addOrUniqueWithInputs(FloatEqualsNode.create(getX(), getY()));
-            lessComp = graph().addOrUniqueWithInputs(FloatLessThanNode.create(getX(), getY(), isUnorderedLess));
-        } else {
-            equalComp = graph().addOrUniqueWithInputs(IntegerEqualsNode.create(getX(), getY()));
-            lessComp = graph().addOrUniqueWithInputs(IntegerLessThanNode.create(getX(), getY()));
-        }
-
-        ConditionalNode equalValue = graph().unique(new ConditionalNode(equalComp, ConstantNode.forInt(0, graph()), ConstantNode.forInt(1, graph())));
-        ConditionalNode value = graph().unique(new ConditionalNode(lessComp, ConstantNode.forInt(-1, graph()), equalValue));
-        replaceAtUsagesAndDelete(value);
-    }
-
-    @Override
     public Stamp foldStamp(Stamp stampX, Stamp stampY) {
         return stamp();
     }
+
+    public boolean isUnorderedLess() {
+        return isUnorderedLess;
+    }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/RemNode.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/RemNode.java	Fri May 12 13:56:13 2017 -0700
@@ -22,7 +22,7 @@
  */
 package org.graalvm.compiler.nodes.calc;
 
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_32;
 
 import org.graalvm.compiler.core.common.type.ArithmeticOpTable;
 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Rem;
@@ -34,7 +34,7 @@
 import org.graalvm.compiler.nodes.spi.LoweringTool;
 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
 
-@NodeInfo(shortName = "%", cycles = CYCLES_8/* div */)
+@NodeInfo(shortName = "%", cycles = CYCLES_32/* div */)
 public class RemNode extends BinaryArithmeticNode<Rem> implements Lowerable {
 
     public static final NodeClass<RemNode> TYPE = NodeClass.create(RemNode.class);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/Block.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/Block.java	Fri May 12 13:56:13 2017 -0700
@@ -25,7 +25,7 @@
 import java.util.ArrayList;
 import java.util.Iterator;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
 import org.graalvm.compiler.core.common.cfg.AbstractControlFlowGraph;
 import org.graalvm.compiler.core.common.cfg.Loop;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/ControlFlowGraph.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/ControlFlowGraph.java	Fri May 12 13:56:13 2017 -0700
@@ -184,18 +184,27 @@
         return block;
     }
 
-    private static final class DeferredExit {
+    public static final class DeferredExit {
 
-        private DeferredExit(Block block, DeferredExit next) {
+        public DeferredExit(Block block, DeferredExit next) {
             this.block = block;
             this.next = next;
         }
 
         private final Block block;
         private final DeferredExit next;
+
+        public Block getBlock() {
+            return block;
+        }
+
+        public DeferredExit getNext() {
+            return next;
+        }
+
     }
 
-    private static void addDeferredExit(DeferredExit[] deferredExits, Block b) {
+    public static void addDeferredExit(DeferredExit[] deferredExits, Block b) {
         Loop<Block> outermostExited = b.getDominator().getLoop();
         Loop<Block> exitBlockLoop = b.getLoop();
         assert outermostExited != null;
@@ -282,7 +291,7 @@
         }
     }
 
-    private static boolean isDominatorTreeLoopExit(Block b) {
+    public static boolean isDominatorTreeLoopExit(Block b) {
         Block dominator = b.getDominator();
         return dominator != null && b.getLoop() != dominator.getLoop() && (!b.isLoopHeader() || dominator.getLoopDepth() >= b.getLoopDepth());
     }
@@ -406,6 +415,10 @@
         return loops;
     }
 
+    public int getMaxDominatorDepth() {
+        return maxDominatorDepth;
+    }
+
     private void identifyBlock(Block block) {
         FixedWithNextNode cur = block.getBeginNode();
         while (true) {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/HIRLoop.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/HIRLoop.java	Fri May 12 13:56:13 2017 -0700
@@ -22,7 +22,7 @@
  */
 package org.graalvm.compiler.nodes.cfg;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.core.common.cfg.Loop;
 import org.graalvm.compiler.nodes.LoopBeginNode;
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/LocationSet.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/LocationSet.java	Fri May 12 13:56:13 2017 -0700
@@ -26,7 +26,7 @@
 import java.util.Arrays;
 import java.util.List;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 
 public class LocationSet {
     private LocationIdentity firstLocation;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/StringToBytesNode.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/StringToBytesNode.java	Fri May 12 13:56:13 2017 -0700
@@ -25,7 +25,7 @@
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.nodeinfo.InputType;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/BytecodeExceptionNode.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/BytecodeExceptionNode.java	Fri May 12 13:56:13 2017 -0700
@@ -25,7 +25,7 @@
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_8;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.core.common.type.TypeReference;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/ForeignCallNode.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/ForeignCallNode.java	Fri May 12 13:56:13 2017 -0700
@@ -29,7 +29,7 @@
 
 import java.util.List;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
 import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
 import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/GuardedUnsafeLoadNode.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/GuardedUnsafeLoadNode.java	Fri May 12 13:56:13 2017 -0700
@@ -24,7 +24,7 @@
 
 import static org.graalvm.compiler.nodeinfo.InputType.Guard;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
 import org.graalvm.compiler.nodes.ValueNode;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/JavaReadNode.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/JavaReadNode.java	Fri May 12 13:56:13 2017 -0700
@@ -25,7 +25,7 @@
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.graph.NodeClass;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/JavaWriteNode.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/JavaWriteNode.java	Fri May 12 13:56:13 2017 -0700
@@ -22,7 +22,7 @@
  */
 package org.graalvm.compiler.nodes.extended;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
 import org.graalvm.compiler.nodes.StateSplit;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/MembarNode.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/MembarNode.java	Fri May 12 13:56:13 2017 -0700
@@ -26,7 +26,7 @@
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawLoadNode.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawLoadNode.java	Fri May 12 13:56:13 2017 -0700
@@ -25,7 +25,7 @@
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.core.common.type.PrimitiveStamp;
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.core.common.type.StampFactory;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawStoreNode.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawStoreNode.java	Fri May 12 13:56:13 2017 -0700
@@ -26,7 +26,7 @@
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
@@ -124,10 +124,27 @@
                 int entryIndex = virtual.entryIndexForOffset(off, accessKind());
                 if (entryIndex != -1) {
                     JavaKind entryKind = virtual.entryKind(entryIndex);
-                    if (entryKind == accessKind() || entryKind == accessKind().getStackKind()) {
+                    boolean canVirtualize = entryKind == accessKind() || entryKind == accessKind().getStackKind();
+                    if (!canVirtualize) {
+                        /*
+                         * Special case: If the entryKind is long, allow arbitrary kinds as long as
+                         * a value of the same kind is already there. This can only happen if some
+                         * other node initialized the entry with a value of a different kind. One
+                         * example where this happens is the Truffle NewFrameNode.
+                         */
+                        ValueNode entry = tool.getEntry(virtual, entryIndex);
+                        if (entryKind == JavaKind.Long && entry.getStackKind() == value.getStackKind()) {
+                            canVirtualize = true;
+                        }
+                    }
+                    if (canVirtualize) {
                         tool.setVirtualEntry(virtual, entryIndex, value(), true);
                         tool.delete();
                     } else {
+                        /*
+                         * Special case: Allow storing a single long or double value into two
+                         * consecutive int slots.
+                         */
                         if ((accessKind() == JavaKind.Long || accessKind() == JavaKind.Double) && entryKind == JavaKind.Int) {
                             int nextIndex = virtual.entryIndexForOffset(off + 4, entryKind);
                             if (nextIndex != -1) {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnsafeAccessNode.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnsafeAccessNode.java	Fri May 12 13:56:13 2017 -0700
@@ -25,7 +25,7 @@
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.graph.NodeClass;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnsafeCopyNode.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnsafeCopyNode.java	Fri May 12 13:56:13 2017 -0700
@@ -22,7 +22,7 @@
  */
 package org.graalvm.compiler.nodes.extended;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.graph.Node.ConstantNodeParameter;
 import org.graalvm.compiler.graph.Node.NodeIntrinsic;
 import org.graalvm.compiler.nodes.ValueNode;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnsafeMemoryLoadNode.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnsafeMemoryLoadNode.java	Fri May 12 13:56:13 2017 -0700
@@ -25,7 +25,7 @@
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnsafeMemoryStoreNode.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnsafeMemoryStoreNode.java	Fri May 12 13:56:13 2017 -0700
@@ -25,7 +25,7 @@
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/IntrinsicContext.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/IntrinsicContext.java	Fri May 12 13:56:13 2017 -0700
@@ -22,11 +22,12 @@
  */
 package org.graalvm.compiler.nodes.graphbuilderconf;
 
-import static org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.INLINE_AFTER_PARSING;
-import static org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.ROOT_COMPILATION;
 import static jdk.vm.ci.code.BytecodeFrame.AFTER_BCI;
 import static jdk.vm.ci.code.BytecodeFrame.BEFORE_BCI;
 import static jdk.vm.ci.code.BytecodeFrame.INVALID_FRAMESTATE_BCI;
+import static jdk.vm.ci.code.BytecodeFrame.UNKNOWN_BCI;
+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.bytecode.BytecodeProvider;
 import org.graalvm.compiler.nodes.AbstractMergeNode;
@@ -34,7 +35,9 @@
 import org.graalvm.compiler.nodes.Invoke;
 import org.graalvm.compiler.nodes.StateSplit;
 import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
 
+import jdk.vm.ci.code.BytecodeFrame;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 
 /**
@@ -95,12 +98,41 @@
 
     final CompilationContext compilationContext;
 
+    private final ValueNode[] args;
+
+    /**
+     * Gets the arguments to the intrinsic invocation (if available).
+     *
+     * @return {@code null} if the arguments to the intrinsic invocation are not available
+     */
+    public ValueNode[] getArgs() {
+        return args;
+    }
+
+    /**
+     * Gets the bytecode index of the intrinsic invocation (if available).
+     *
+     * @return {@value BytecodeFrame#UNKNOWN_BCI} if the bytecode index of the intrinsic invocation
+     *         is not available
+     */
+    public int bci() {
+        return bci;
+    }
+
+    private final int bci;
+
     public IntrinsicContext(ResolvedJavaMethod method, ResolvedJavaMethod intrinsic, BytecodeProvider bytecodeProvider, CompilationContext compilationContext) {
+        this(method, intrinsic, bytecodeProvider, compilationContext, null, UNKNOWN_BCI);
+    }
+
+    public IntrinsicContext(ResolvedJavaMethod method, ResolvedJavaMethod intrinsic, BytecodeProvider bytecodeProvider, CompilationContext compilationContext, ValueNode[] args, int bci) {
         this.method = method;
         this.intrinsic = intrinsic;
         this.bytecodeProvider = bytecodeProvider;
         assert bytecodeProvider != null;
         this.compilationContext = compilationContext;
+        this.args = args;
+        this.bci = bci;
         assert !isCompilationRoot() || method.hasBytecodes() : "Cannot root compile intrinsic for native or abstract method " + method.format("%H.%n(%p)");
     }
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InvocationPlugin.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InvocationPlugin.java	Fri May 12 13:56:13 2017 -0700
@@ -40,8 +40,8 @@
 
     /**
      * The receiver in a non-static method. The class literal for this interface must be used with
-     * {@link InvocationPlugins#put(InvocationPlugin, boolean, boolean, boolean, Class, String, Class...)}
-     * to denote the receiver argument for such a non-static method.
+     * {@link InvocationPlugins#put(InvocationPlugin, boolean, boolean, Class, String, Class...)} to
+     * denote the receiver argument for such a non-static method.
      */
     public interface Receiver {
         /**
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InvocationPlugins.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InvocationPlugins.java	Fri May 12 13:56:13 2017 -0700
@@ -23,34 +23,52 @@
 package org.graalvm.compiler.nodes.graphbuilderconf;
 
 import static java.lang.String.format;
+import static org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.LateClassPlugins.CLOSED_LATE_CLASS_PLUGIN;
 
-import java.lang.reflect.Executable;
+import java.lang.reflect.Constructor;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.lang.reflect.Type;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 import java.util.Map;
+
 import org.graalvm.compiler.api.replacements.MethodSubstitution;
 import org.graalvm.compiler.api.replacements.MethodSubstitutionRegistry;
 import org.graalvm.compiler.bytecode.BytecodeProvider;
+import org.graalvm.compiler.debug.Assertions;
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.graph.iterators.NodeIterable;
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin.Receiver;
+import org.graalvm.util.EconomicMap;
 import org.graalvm.util.Equivalence;
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.EconomicSet;
+import org.graalvm.util.MapCursor;
+import org.graalvm.util.Pair;
+import org.graalvm.util.UnmodifiableEconomicMap;
 import org.graalvm.util.UnmodifiableMapCursor;
 
-import jdk.vm.ci.meta.MetaAccessProvider;
 import jdk.vm.ci.meta.MetaUtil;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+import jdk.vm.ci.meta.Signature;
 
 /**
  * Manages a set of {@link InvocationPlugin}s.
+ *
+ * Most plugins are registered during initialization (i.e., before
+ * {@link #lookupInvocation(ResolvedJavaMethod)} or {@link #getBindings} is called). These
+ * registrations can be made with {@link Registration},
+ * {@link #register(InvocationPlugin, String, String, Type...)},
+ * {@link #register(InvocationPlugin, Type, String, Type...)} or
+ * {@link #registerOptional(InvocationPlugin, Type, String, Type...)}. Initialization is not
+ * thread-safe and so must only be performed by a single thread.
+ *
+ * Plugins that are not guaranteed to be made during initialization must use
+ * {@link LateRegistration}.
  */
 public class InvocationPlugins {
 
@@ -369,161 +387,138 @@
     }
 
     /**
-     * Key for a {@linkplain ClassPlugins#entries resolved} plugin registration. Due to the
-     * possibility of class redefinition, we cannot directly use {@link ResolvedJavaMethod}s as
-     * keys. A {@link ResolvedJavaMethod} implementation might implement {@code equals()} and
-     * {@code hashCode()} based on internal representation subject to change by class redefinition.
+     * Utility for registering plugins after Graal may have been initialized. Registrations made via
+     * this class are not finalized until {@link #close} is called.
      */
-    static final class ResolvedJavaMethodKey {
-        private final ResolvedJavaMethod method;
+    public static class LateRegistration implements AutoCloseable {
+
+        private InvocationPlugins plugins;
+        private final List<Binding> bindings = new ArrayList<>();
+        private final Type declaringType;
+
+        /**
+         * Creates an object for registering {@link InvocationPlugin}s for methods declared by a
+         * given class.
+         *
+         * @param plugins where to register the plugins
+         * @param declaringType the class declaring the methods for which plugins will be registered
+         *            via this object
+         */
+        public LateRegistration(InvocationPlugins plugins, Type declaringType) {
+            this.plugins = plugins;
+            this.declaringType = declaringType;
+        }
 
-        ResolvedJavaMethodKey(ResolvedJavaMethod method) {
-            this.method = method;
+        /**
+         * Registers an invocation plugin for a given method. There must be no plugin currently
+         * registered for {@code method}.
+         *
+         * @param argumentTypes the argument types of the method. Element 0 of this array must be
+         *            the {@link Class} value for {@link InvocationPlugin.Receiver} iff the method
+         *            is non-static. Upon returning, element 0 will have been rewritten to
+         *            {@code declaringClass}
+         */
+        public void register(InvocationPlugin plugin, String name, Type... argumentTypes) {
+            boolean isStatic = argumentTypes.length == 0 || argumentTypes[0] != InvocationPlugin.Receiver.class;
+            if (!isStatic) {
+                argumentTypes[0] = declaringType;
+            }
+
+            assert isStatic || argumentTypes[0] == declaringType;
+            Binding binding = new Binding(plugin, isStatic, name, argumentTypes);
+            bindings.add(binding);
+
+            assert Checks.check(this.plugins, declaringType, binding);
+            assert Checks.checkResolvable(false, declaringType, binding);
         }
 
         @Override
-        public boolean equals(Object obj) {
-            if (obj instanceof ResolvedJavaMethodKey) {
-                ResolvedJavaMethodKey that = (ResolvedJavaMethodKey) obj;
-                if (this.method.isStatic() == that.method.isStatic()) {
-                    if (this.method.getDeclaringClass().equals(that.method.getDeclaringClass())) {
-                        if (this.method.getName().equals(that.method.getName())) {
-                            if (this.method.getSignature().equals(that.method.getSignature())) {
-                                return true;
-                            }
-                        }
-                    }
-                }
-            }
-            return false;
-        }
-
-        @Override
-        public int hashCode() {
-            return this.method.getName().hashCode();
-        }
-
-        @Override
-        public String toString() {
-            return "ResolvedJavaMethodKey<" + method + ">";
+        public void close() {
+            assert plugins != null : String.format("Late registrations of invocation plugins for %s is already closed", declaringType);
+            plugins.registerLate(declaringType, bindings);
+            plugins = null;
         }
     }
 
     /**
-     * Key for {@linkplain ClassPlugins#registrations registering} an {@link InvocationPlugin} for a
-     * specific method.
+     * Associates an {@link InvocationPlugin} with the details of a method it substitutes.
      */
-    static class MethodKey {
-        final boolean isStatic;
+    public static class Binding {
+        /**
+         * The plugin this binding is for.
+         */
+        public final InvocationPlugin plugin;
 
         /**
-         * This method is optional. This is used for new API methods not present in previous JDK
-         * versions.
+         * Specifies if the associated method is static.
          */
-        final boolean isOptional;
+        public final boolean isStatic;
 
-        final String name;
-        final Type[] argumentTypes;
-        final InvocationPlugin value;
+        /**
+         * The name of the associated method.
+         */
+        public final String name;
 
         /**
-         * Used to lazily initialize {@link #resolved}.
+         * A partial
+         * <a href="http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.3.3">method
+         * descriptor</a> for the associated method. The descriptor includes enclosing {@code '('}
+         * and {@code ')'} characters but omits the return type suffix.
          */
-        private final MetaAccessProvider metaAccess;
-
-        private volatile ResolvedJavaMethod resolved;
+        public final String argumentsDescriptor;
 
-        MethodKey(MetaAccessProvider metaAccess, InvocationPlugin data, boolean isStatic, boolean isOptional, String name, Type... argumentTypes) {
-            this.metaAccess = metaAccess;
-            this.value = data;
+        /**
+         * Link in a list of bindings.
+         */
+        private Binding next;
+
+        Binding(InvocationPlugin data, boolean isStatic, String name, Type... argumentTypes) {
+            this.plugin = data;
             this.isStatic = isStatic;
-            this.isOptional = isOptional;
             this.name = name;
-            this.argumentTypes = argumentTypes;
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (obj instanceof MethodKey) {
-                MethodKey that = (MethodKey) obj;
-                boolean res = this.name.equals(that.name) && areEqual(this.argumentTypes, that.argumentTypes);
-                assert !res || this.isStatic == that.isStatic;
-                return res;
+            StringBuilder buf = new StringBuilder();
+            buf.append('(');
+            for (int i = isStatic ? 0 : 1; i < argumentTypes.length; i++) {
+                buf.append(MetaUtil.toInternalName(argumentTypes[i].getTypeName()));
             }
-            return false;
+            buf.append(')');
+            this.argumentsDescriptor = buf.toString();
+            assert !name.equals("<init>") || !isStatic : this;
         }
 
-        private static boolean areEqual(Type[] args1, Type[] args2) {
-            if (args1.length == args2.length) {
-                for (int i = 0; i < args1.length; i++) {
-                    if (!args1[i].getTypeName().equals(args2[i].getTypeName())) {
-                        return false;
-                    }
-                }
-                return true;
-            }
-            return false;
-        }
-
-        public int getDeclaredParameterCount() {
-            return isStatic ? argumentTypes.length : argumentTypes.length - 1;
-        }
-
-        @Override
-        public int hashCode() {
-            return name.hashCode();
-        }
-
-        private ResolvedJavaMethod resolve(Class<?> declaringClass) {
-            if (resolved == null) {
-                Executable method = resolveJava(declaringClass);
-                if (method == null) {
-                    return null;
-                }
-                resolved = metaAccess.lookupJavaMethod(method);
-            }
-            return resolved;
-        }
-
-        private Executable resolveJava(Class<?> declaringClass) {
-            try {
-                Executable res;
-                Class<?>[] parameterTypes = resolveTypes(argumentTypes, isStatic ? 0 : 1, argumentTypes.length);
-                if (name.equals("<init>")) {
-                    res = declaringClass.getDeclaredConstructor(parameterTypes);
-                } else {
-                    res = declaringClass.getDeclaredMethod(name, parameterTypes);
-                }
-                assert Modifier.isStatic(res.getModifiers()) == isStatic : res;
-                return res;
-            } catch (NoSuchMethodException | SecurityException e) {
-                if (isOptional) {
-                    return null;
-                }
-                throw new InternalError(e);
-            }
+        Binding(ResolvedJavaMethod resolved, InvocationPlugin data) {
+            this.plugin = data;
+            this.isStatic = resolved.isStatic();
+            this.name = resolved.getName();
+            Signature sig = resolved.getSignature();
+            String desc = sig.toMethodDescriptor();
+            assert desc.indexOf(')') != -1 : desc;
+            this.argumentsDescriptor = desc.substring(0, desc.indexOf(')') + 1);
+            assert !name.equals("<init>") || !isStatic : this;
         }
 
         @Override
         public String toString() {
-            StringBuilder sb = new StringBuilder(name).append('(');
-            for (Type p : argumentTypes) {
-                if (sb.charAt(sb.length() - 1) != '(') {
-                    sb.append(", ");
-                }
-                sb.append(p.getTypeName());
-            }
-            return sb.append(')').toString();
+            return name + argumentsDescriptor;
         }
     }
 
-    private final MetaAccessProvider metaAccess;
-
-    private final EconomicMap<String, ClassPlugins> registrations = EconomicMap.create(Equivalence.DEFAULT);
+    /**
+     * Plugin registrations for already resolved methods. If non-null, then {@link #registrations}
+     * is null and no further registrations can be made.
+     */
+    private final UnmodifiableEconomicMap<ResolvedJavaMethod, InvocationPlugin> resolvedRegistrations;
 
     /**
-     * Deferred registrations as well as guard for initialization. The guard uses double-checked
-     * locking which is why this field is {@code volatile}.
+     * Map from class names in {@linkplain MetaUtil#toInternalName(String) internal} form to the
+     * invocation plugin bindings for the class. Tf non-null, then {@link #resolvedRegistrations}
+     * will be null.
+     */
+    private final EconomicMap<String, ClassPlugins> registrations;
+
+    /**
+     * Deferred registrations as well as the guard for delimiting the initial registration phase.
+     * The guard uses double-checked locking which is why this field is {@code volatile}.
      */
     private volatile List<Runnable> deferredRegistrations = new ArrayList<>();
 
@@ -537,119 +532,179 @@
     }
 
     /**
-     * Per-class invocation plugins.
+     * Support for registering plugins once this object may be accessed by multiple threads.
+     */
+    private volatile LateClassPlugins lateRegistrations;
+
+    /**
+     * Per-class bindings.
      */
-    protected static class ClassPlugins {
-        private final Type declaringType;
+    static class ClassPlugins {
+
+        /**
+         * Maps method names to binding lists.
+         */
+        private final EconomicMap<String, Binding> bindings = EconomicMap.create(Equivalence.DEFAULT);
 
-        private final List<MethodKey> registrations = new ArrayList<>();
+        /**
+         * Gets the invocation plugin for a given method.
+         *
+         * @return the invocation plugin for {@code method} or {@code null}
+         */
+        InvocationPlugin get(ResolvedJavaMethod method) {
+            assert !method.isBridge();
+            Binding binding = bindings.get(method.getName());
+            while (binding != null) {
+                if (method.isStatic() == binding.isStatic) {
+                    if (method.getSignature().toMethodDescriptor().startsWith(binding.argumentsDescriptor)) {
+                        return binding.plugin;
+                    }
+                }
+                binding = binding.next;
+            }
+            return null;
+        }
 
-        public ClassPlugins(Type declaringClass) {
-            this.declaringType = declaringClass;
+        public void register(Binding binding, boolean allowOverwrite) {
+            if (allowOverwrite) {
+                if (lookup(binding) != null) {
+                    register(binding);
+                    return;
+                }
+            } else {
+                assert lookup(binding) == null : "a value is already registered for " + binding;
+            }
+            register(binding);
+        }
+
+        InvocationPlugin lookup(Binding binding) {
+            Binding b = bindings.get(binding.name);
+            while (b != null) {
+                if (b.isStatic == binding.isStatic && b.argumentsDescriptor.equals(binding.argumentsDescriptor)) {
+                    return b.plugin;
+                }
+                b = b.next;
+            }
+            return null;
         }
 
         /**
-         * Entry map that is initialized upon first call to {@link #get(ResolvedJavaMethod)}.
-         *
-         * Note: this must be volatile as threads may race to initialize it.
+         * Registers {@code binding}.
          */
-        private volatile EconomicMap<ResolvedJavaMethodKey, InvocationPlugin> entries;
+        void register(Binding binding) {
+            Binding head = bindings.get(binding.name);
+            assert binding.next == null;
+            binding.next = head;
+            bindings.put(binding.name, binding);
+        }
+    }
 
-        void initializeMap() {
-            if (!isClosed()) {
-                if (registrations.isEmpty()) {
-                    entries = EconomicMap.create(Equivalence.DEFAULT);
-                } else {
-                    Class<?> declaringClass = resolveType(declaringType, true);
-                    if (declaringClass == null) {
-                        // An optional type that could not be resolved
-                        entries = EconomicMap.create(Equivalence.DEFAULT);
-                    } else {
-                        EconomicMap<ResolvedJavaMethodKey, InvocationPlugin> newEntries = EconomicMap.create(Equivalence.DEFAULT);
-                        for (MethodKey methodKey : registrations) {
-                            ResolvedJavaMethod m = methodKey.resolve(declaringClass);
-                            if (m != null) {
-                                newEntries.put(new ResolvedJavaMethodKey(m), methodKey.value);
-                                if (entries != null) {
-                                    // Another thread finished initializing entries first
-                                    return;
-                                }
-                            }
-                        }
-                        entries = newEntries;
-                    }
-                }
-            }
-        }
+    static class LateClassPlugins extends ClassPlugins {
+        static final String CLOSED_LATE_CLASS_PLUGIN = "-----";
+        private final String className;
+        private final LateClassPlugins next;
 
-        public InvocationPlugin get(ResolvedJavaMethod method) {
-            if (!isClosed()) {
-                initializeMap();
-            }
-            return entries.get(new ResolvedJavaMethodKey(method));
-        }
-
-        public void register(MethodKey methodKey, boolean allowOverwrite) {
-            assert !isClosed() : "registration is closed: " + methodKey;
-            if (allowOverwrite) {
-                int index = registrations.indexOf(methodKey);
-                if (index >= 0) {
-                    registrations.set(index, methodKey);
-                    return;
-                }
-            } else {
-                assert !registrations.contains(methodKey) : "a value is already registered for " + declaringType + "." + methodKey;
-            }
-            registrations.add(methodKey);
-        }
-
-        public boolean isClosed() {
-            return entries != null;
+        LateClassPlugins(LateClassPlugins next, String className) {
+            assert next == null || next.className != CLOSED_LATE_CLASS_PLUGIN : "Late registration of invocation plugins is closed";
+            this.next = next;
+            this.className = className;
         }
     }
 
     /**
-     * Adds an entry to this map for a specified method.
+     * Registers a binding of a method to an invocation plugin.
      *
-     * @param value value to be associated with the specified method
+     * @param plugin invocation plugin to be associated with the specified method
      * @param isStatic specifies if the method is static
-     * @param isOptional specifies if the method is optional
      * @param declaringClass the class declaring the method
      * @param name the name of the method
      * @param argumentTypes the argument types of the method. Element 0 of this array must be
      *            {@code declaringClass} iff the method is non-static.
      * @return an object representing the method
      */
-    MethodKey put(InvocationPlugin value, boolean isStatic, boolean isOptional, boolean allowOverwrite, Type declaringClass, String name, Type... argumentTypes) {
+    Binding put(InvocationPlugin plugin, boolean isStatic, boolean allowOverwrite, Type declaringClass, String name, Type... argumentTypes) {
+        assert resolvedRegistrations == null : "registration is closed";
+        String internalName = MetaUtil.toInternalName(declaringClass.getTypeName());
         assert isStatic || argumentTypes[0] == declaringClass;
+        assert deferredRegistrations != null : "initial registration is closed - use " + LateRegistration.class.getName() + " for late registrations";
 
-        String internalName = MetaUtil.toInternalName(declaringClass.getTypeName());
         ClassPlugins classPlugins = registrations.get(internalName);
         if (classPlugins == null) {
-            classPlugins = new ClassPlugins(declaringClass);
+            classPlugins = new ClassPlugins();
             registrations.put(internalName, classPlugins);
         }
-        assert isStatic || argumentTypes[0] == declaringClass;
-        MethodKey methodKey = new MethodKey(metaAccess, value, isStatic, isOptional, name, argumentTypes);
-        classPlugins.register(methodKey, allowOverwrite);
-        return methodKey;
+        Binding binding = new Binding(plugin, isStatic, name, argumentTypes);
+        classPlugins.register(binding, allowOverwrite);
+        return binding;
+    }
+
+    InvocationPlugin get(ResolvedJavaMethod method) {
+        if (resolvedRegistrations != null) {
+            return resolvedRegistrations.get(method);
+        } else {
+            if (!method.isBridge()) {
+                ResolvedJavaType declaringClass = method.getDeclaringClass();
+                flushDeferrables();
+                String internalName = declaringClass.getName();
+                ClassPlugins classPlugins = registrations.get(internalName);
+                InvocationPlugin res = null;
+                if (classPlugins != null) {
+                    res = classPlugins.get(method);
+                }
+                if (res == null) {
+                    LateClassPlugins lcp = findLateClassPlugins(internalName);
+                    if (lcp != null) {
+                        res = lcp.get(method);
+                    }
+                }
+                if (res != null) {
+                    if (canBeIntrinsified(declaringClass)) {
+                        return res;
+                    }
+                }
+                if (testExtensions != null) {
+                    // Avoid the synchronization in the common case that there
+                    // are no test extensions.
+                    synchronized (this) {
+                        if (testExtensions != null) {
+                            List<Binding> bindings = testExtensions.get(internalName);
+                            if (bindings != null) {
+                                String name = method.getName();
+                                String descriptor = method.getSignature().toMethodDescriptor();
+                                for (Binding b : bindings) {
+                                    if (b.isStatic == method.isStatic() &&
+                                                    b.name.equals(name) &&
+                                                    descriptor.startsWith(b.argumentsDescriptor)) {
+                                        return b.plugin;
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            } else {
+                // Supporting plugins for bridge methods would require including
+                // the return type in the registered signature. Until needed,
+                // this extra complexity is best avoided.
+            }
+        }
+        return null;
     }
 
     /**
-     * Determines if a method denoted by a given {@link MethodKey} is in this map.
+     * Determines if methods in a given class can have invocation plugins.
+     *
+     * @param declaringClass the class to test
      */
-    boolean containsKey(Type declaringType, MethodKey key) {
-        String internalName = MetaUtil.toInternalName(declaringType.getTypeName());
-        ClassPlugins classPlugins = registrations.get(internalName);
-        return classPlugins != null && classPlugins.registrations.contains(key);
+    protected boolean canBeIntrinsified(ResolvedJavaType declaringClass) {
+        return true;
     }
 
-    InvocationPlugin get(ResolvedJavaMethod method) {
-        flushDeferrables();
-        String internalName = method.getDeclaringClass().getName();
-        ClassPlugins classPlugins = registrations.get(internalName);
-        if (classPlugins != null) {
-            return classPlugins.get(method);
+    LateClassPlugins findLateClassPlugins(String internalClassName) {
+        for (LateClassPlugins lcp = lateRegistrations; lcp != null; lcp = lcp.next) {
+            if (lcp.className.equals(internalClassName)) {
+                return lcp;
+            }
         }
         return null;
     }
@@ -664,25 +719,121 @@
                     deferredRegistrations = null;
                 }
             }
-            for (ClassPlugins e : registrations.getValues()) {
-                e.initializeMap();
+        }
+    }
+
+    private volatile EconomicMap<String, List<Binding>> testExtensions;
+
+    private static int findBinding(List<Binding> list, Binding key) {
+        for (int i = 0; i < list.size(); i++) {
+            Binding b = list.get(i);
+            if (b.isStatic == key.isStatic && b.name.equals(key.name) && b.argumentsDescriptor.equals(key.argumentsDescriptor)) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * Extends the plugins in this object with those from {@code other}. The added plugins should be
+     * {@linkplain #removeTestPlugins(InvocationPlugins) removed} after the test.
+     *
+     * This extension mechanism exists only for tests that want to add extra invocation plugins
+     * after the compiler has been initialized.
+     *
+     * @param ignored if non-null, the bindings from {@code other} already in this object prior to
+     *            calling this method are added to this list. These bindings are not added to this
+     *            object.
+     */
+    public synchronized void addTestPlugins(InvocationPlugins other, List<Pair<String, Binding>> ignored) {
+        assert resolvedRegistrations == null : "registration is closed";
+        EconomicMap<String, List<Binding>> otherBindings = other.getBindings(true, false);
+        if (otherBindings.isEmpty()) {
+            return;
+        }
+        if (testExtensions == null) {
+            testExtensions = EconomicMap.create();
+        }
+        MapCursor<String, List<Binding>> c = otherBindings.getEntries();
+        while (c.advance()) {
+            String declaringClass = c.getKey();
+            List<Binding> bindings = testExtensions.get(declaringClass);
+            if (bindings == null) {
+                bindings = new ArrayList<>();
+                testExtensions.put(declaringClass, bindings);
+            }
+            for (Binding b : c.getValue()) {
+                int index = findBinding(bindings, b);
+                if (index != -1) {
+                    if (ignored != null) {
+                        ignored.add(Pair.create(declaringClass, b));
+                    }
+                } else {
+                    bindings.add(b);
+                }
             }
         }
     }
 
     /**
-     * Disallows new registrations of new plugins, and creates the internal tables for method
-     * lookup.
+     * Removes the plugins from {@code other} in this object that were added by
+     * {@link #addTestPlugins}.
      */
-    public void closeRegistration() {
-        flushDeferrables();
-        for (ClassPlugins e : registrations.getValues()) {
-            e.initializeMap();
+    public synchronized void removeTestPlugins(InvocationPlugins other) {
+        assert resolvedRegistrations == null : "registration is closed";
+        if (testExtensions != null) {
+            MapCursor<String, List<Binding>> c = other.getBindings(false).getEntries();
+            while (c.advance()) {
+                String declaringClass = c.getKey();
+                List<Binding> bindings = testExtensions.get(declaringClass);
+                if (bindings != null) {
+                    for (Binding b : c.getValue()) {
+                        int index = findBinding(bindings, b);
+                        if (index != -1) {
+                            bindings.remove(index);
+                        }
+                    }
+                    if (bindings.isEmpty()) {
+                        testExtensions.removeKey(declaringClass);
+                    }
+                }
+            }
+            if (testExtensions.isEmpty()) {
+                testExtensions = null;
+            }
         }
     }
 
-    public int size() {
-        return registrations.size();
+    synchronized void registerLate(Type declaringType, List<Binding> bindings) {
+        String internalName = MetaUtil.toInternalName(declaringType.getTypeName());
+        assert findLateClassPlugins(internalName) == null : "Cannot have more than one late registration of invocation plugins for " + internalName;
+        LateClassPlugins lateClassPlugins = new LateClassPlugins(lateRegistrations, internalName);
+        for (Binding b : bindings) {
+            lateClassPlugins.register(b);
+        }
+        lateRegistrations = lateClassPlugins;
+    }
+
+    private synchronized boolean closeLateRegistrations() {
+        if (lateRegistrations == null || lateRegistrations.className != CLOSED_LATE_CLASS_PLUGIN) {
+            lateRegistrations = new LateClassPlugins(lateRegistrations, CLOSED_LATE_CLASS_PLUGIN);
+        }
+        return true;
+    }
+
+    /**
+     * Processes deferred registrations and then closes this object for future registration.
+     */
+    public void closeRegistration() {
+        assert closeLateRegistrations();
+        flushDeferrables();
+    }
+
+    public boolean isEmpty() {
+        if (resolvedRegistrations != null) {
+            return resolvedRegistrations.isEmpty();
+        }
+        return registrations.size() == 0 && lateRegistrations == null;
     }
 
     /**
@@ -691,47 +842,39 @@
      */
     protected final InvocationPlugins parent;
 
-    private InvocationPlugins(InvocationPlugins parent, MetaAccessProvider metaAccess) {
-        this.metaAccess = metaAccess;
-        InvocationPlugins p = parent;
-        this.parent = p;
+    /**
+     * Creates a set of invocation plugins with no parent.
+     */
+    public InvocationPlugins() {
+        this(null);
     }
 
     /**
-     * Creates a set of invocation plugins with a non-null {@linkplain #getParent() parent}.
+     * Creates a set of invocation plugins.
+     *
+     * @param parent if non-null, this object will be searched first when looking up plugins
      */
     public InvocationPlugins(InvocationPlugins parent) {
-        this(parent, parent.getMetaAccess());
+        InvocationPlugins p = parent;
+        this.parent = p;
+        this.registrations = EconomicMap.create();
+        this.resolvedRegistrations = null;
     }
 
-    public InvocationPlugins(Map<ResolvedJavaMethod, InvocationPlugin> plugins, InvocationPlugins parent, MetaAccessProvider metaAccess) {
-        this.metaAccess = metaAccess;
+    /**
+     * Creates a closed set of invocation plugins for a set of resolved methods. Such an object
+     * cannot have further plugins registered.
+     */
+    public InvocationPlugins(Map<ResolvedJavaMethod, InvocationPlugin> plugins, InvocationPlugins parent) {
         this.parent = parent;
-
+        this.registrations = null;
         this.deferredRegistrations = null;
+        EconomicMap<ResolvedJavaMethod, InvocationPlugin> map = EconomicMap.create(plugins.size());
 
         for (Map.Entry<ResolvedJavaMethod, InvocationPlugin> entry : plugins.entrySet()) {
-            ResolvedJavaMethod method = entry.getKey();
-            InvocationPlugin plugin = entry.getValue();
-
-            String internalName = method.getDeclaringClass().getName();
-            ClassPlugins classPlugins = registrations.get(internalName);
-            if (classPlugins == null) {
-                classPlugins = new ClassPlugins(null);
-                registrations.put(internalName, classPlugins);
-                classPlugins.entries = EconomicMap.create(Equivalence.DEFAULT);
-            }
-
-            classPlugins.entries.put(new ResolvedJavaMethodKey(method), plugin);
+            map.put(entry.getKey(), entry.getValue());
         }
-    }
-
-    public MetaAccessProvider getMetaAccess() {
-        return metaAccess;
-    }
-
-    public InvocationPlugins(MetaAccessProvider metaAccess) {
-        this(null, metaAccess);
+        this.resolvedRegistrations = map;
     }
 
     protected void register(InvocationPlugin plugin, boolean isOptional, boolean allowOverwrite, Type declaringClass, String name, Type... argumentTypes) {
@@ -739,8 +882,9 @@
         if (!isStatic) {
             argumentTypes[0] = declaringClass;
         }
-        MethodKey methodKey = put(plugin, isStatic, isOptional, allowOverwrite, declaringClass, name, argumentTypes);
-        assert Checker.check(this, declaringClass, methodKey, plugin);
+        Binding binding = put(plugin, isStatic, allowOverwrite, declaringClass, name, argumentTypes);
+        assert Checks.check(this, declaringClass, binding);
+        assert Checks.checkResolvable(isOptional, declaringClass, binding);
     }
 
     /**
@@ -790,23 +934,89 @@
     }
 
     /**
-     * Gets the set of methods for which invocation plugins have been registered. Once this method
-     * is called, no further registrations can be made.
+     * Gets the set of registered invocation plugins.
+     *
+     * @return a map from class names in {@linkplain MetaUtil#toInternalName(String) internal} form
+     *         to the invocation plugin bindings for methods in the class
+     */
+    public EconomicMap<String, List<Binding>> getBindings(boolean includeParents) {
+        return getBindings(includeParents, true);
+    }
+
+    /**
+     * Gets the set of registered invocation plugins.
+     *
+     * @return a map from class names in {@linkplain MetaUtil#toInternalName(String) internal} form
+     *         to the invocation plugin bindings for methods in the class
      */
-    public EconomicSet<ResolvedJavaMethod> getMethods() {
-        EconomicSet<ResolvedJavaMethod> res = EconomicSet.create(Equivalence.DEFAULT);
-        if (parent != null) {
-            res.addAll(parent.getMethods());
+    private EconomicMap<String, List<Binding>> getBindings(boolean includeParents, boolean flushDeferrables) {
+        EconomicMap<String, List<Binding>> res = EconomicMap.create(Equivalence.DEFAULT);
+        if (parent != null && includeParents) {
+            res.putAll(parent.getBindings(true, flushDeferrables));
         }
-        flushDeferrables();
-        for (ClassPlugins cp : registrations.getValues()) {
-            for (ResolvedJavaMethodKey key : cp.entries.getKeys()) {
-                res.add(key.method);
+        if (resolvedRegistrations != null) {
+            UnmodifiableMapCursor<ResolvedJavaMethod, InvocationPlugin> cursor = resolvedRegistrations.getEntries();
+            while (cursor.advance()) {
+                ResolvedJavaMethod method = cursor.getKey();
+                InvocationPlugin plugin = cursor.getValue();
+                String type = method.getDeclaringClass().getName();
+                List<Binding> bindings = res.get(type);
+                if (bindings == null) {
+                    bindings = new ArrayList<>();
+                    res.put(type, bindings);
+                }
+                bindings.add(new Binding(method, plugin));
+            }
+        } else {
+            if (flushDeferrables) {
+                flushDeferrables();
+            }
+            MapCursor<String, ClassPlugins> classes = registrations.getEntries();
+            while (classes.advance()) {
+                String type = classes.getKey();
+                ClassPlugins cp = classes.getValue();
+                collectBindingsTo(res, type, cp);
+            }
+            for (LateClassPlugins lcp = lateRegistrations; lcp != null; lcp = lcp.next) {
+                String type = lcp.className;
+                collectBindingsTo(res, type, lcp);
+            }
+            if (testExtensions != null) {
+                // Avoid the synchronization in the common case that there
+                // are no test extensions.
+                synchronized (this) {
+                    if (testExtensions != null) {
+                        MapCursor<String, List<Binding>> c = testExtensions.getEntries();
+                        while (c.advance()) {
+                            String name = c.getKey();
+                            List<Binding> bindings = res.get(name);
+                            if (bindings == null) {
+                                bindings = new ArrayList<>();
+                                res.put(name, bindings);
+                            }
+                            bindings.addAll(c.getValue());
+                        }
+                    }
+                }
             }
         }
         return res;
     }
 
+    private static void collectBindingsTo(EconomicMap<String, List<Binding>> res, String type, ClassPlugins cp) {
+        MapCursor<String, Binding> methods = cp.bindings.getEntries();
+        while (methods.advance()) {
+            List<Binding> bindings = res.get(type);
+            if (bindings == null) {
+                bindings = new ArrayList<>();
+                res.put(type, bindings);
+            }
+            for (Binding b = methods.getValue(); b != null; b = b.next) {
+                bindings.add(b);
+            }
+        }
+    }
+
     /**
      * Gets the invocation plugins {@linkplain #lookupInvocation(ResolvedJavaMethod) searched}
      * before searching in this object.
@@ -817,20 +1027,36 @@
 
     @Override
     public String toString() {
-        StringBuilder buf = new StringBuilder();
-        UnmodifiableMapCursor<String, ClassPlugins> entries = registrations.getEntries();
+        UnmodifiableMapCursor<String, List<Binding>> entries = getBindings(false, false).getEntries();
+        List<String> all = new ArrayList<>();
         while (entries.advance()) {
-            buf.append(entries.getKey()).append('.').append(entries.getValue()).append(", ");
+            String c = MetaUtil.internalNameToJava(entries.getKey(), true, false);
+            for (Binding b : entries.getValue()) {
+                all.add(c + '.' + b);
+            }
         }
-
-        String s = buf.toString();
-        if (buf.length() != 0) {
-            s = s.substring(buf.length() - ", ".length());
+        Collections.sort(all);
+        StringBuilder buf = new StringBuilder();
+        String nl = String.format("%n");
+        for (String s : all) {
+            if (buf.length() != 0) {
+                buf.append(nl);
+            }
+            buf.append(s);
         }
-        return s + " / parent: " + this.parent;
+        if (parent != null) {
+            if (buf.length() != 0) {
+                buf.append(nl);
+            }
+            buf.append("// parent").append(nl).append(parent);
+        }
+        return buf.toString();
     }
 
-    private static class Checker {
+    /**
+     * Code only used in assertions. Putting this in a separate class reduces class load time.
+     */
+    private static class Checks {
         private static final int MAX_ARITY = 7;
         /**
          * The set of all {@link InvocationPlugin#apply} method signatures.
@@ -838,6 +1064,9 @@
         static final Class<?>[][] SIGS;
 
         static {
+            if (!Assertions.ENABLED) {
+                throw new GraalError("%s must only be used in assertions", Checks.class.getName());
+            }
             ArrayList<Class<?>[]> sigs = new ArrayList<>(MAX_ARITY);
             for (Method method : InvocationPlugin.class.getDeclaredMethods()) {
                 if (!Modifier.isStatic(method.getModifiers()) && method.getName().equals("apply")) {
@@ -857,10 +1086,17 @@
             SIGS = sigs.toArray(new Class<?>[sigs.size()][]);
         }
 
-        public static boolean check(InvocationPlugins plugins, Type declaringType, MethodKey method, InvocationPlugin plugin) {
+        static boolean containsBinding(InvocationPlugins p, Type declaringType, Binding key) {
+            String internalName = MetaUtil.toInternalName(declaringType.getTypeName());
+            ClassPlugins classPlugins = p.registrations.get(internalName);
+            return classPlugins != null && classPlugins.lookup(key) != null;
+        }
+
+        public static boolean check(InvocationPlugins plugins, Type declaringType, Binding binding) {
+            InvocationPlugin plugin = binding.plugin;
             InvocationPlugins p = plugins.parent;
             while (p != null) {
-                assert !p.containsKey(declaringType, method) : "a plugin is already registered for " + method;
+                assert !containsBinding(p, declaringType, binding) : "a plugin is already registered for " + binding;
                 p = p.parent;
             }
             if (plugin instanceof ForeignCallPlugin || plugin instanceof GeneratedInvocationPlugin) {
@@ -872,8 +1108,8 @@
                 assert substitute.getAnnotation(MethodSubstitution.class) != null : format("Substitute method must be annotated with @%s: %s", MethodSubstitution.class.getSimpleName(), substitute);
                 return true;
             }
-            int arguments = method.getDeclaredParameterCount();
-            assert arguments < SIGS.length : format("need to extend %s to support method with %d arguments: %s", InvocationPlugin.class.getSimpleName(), arguments, method);
+            int arguments = parseParameters(binding.argumentsDescriptor).size();
+            assert arguments < SIGS.length : format("need to extend %s to support method with %d arguments: %s", InvocationPlugin.class.getSimpleName(), arguments, binding);
             for (Method m : plugin.getClass().getDeclaredMethods()) {
                 if (m.getName().equals("apply")) {
                     Class<?>[] parameterTypes = m.getParameterTypes();
@@ -882,7 +1118,24 @@
                     }
                 }
             }
-            throw new AssertionError(format("graph builder plugin for %s not found", method));
+            throw new AssertionError(format("graph builder plugin for %s not found", binding));
+        }
+
+        static boolean checkResolvable(boolean isOptional, Type declaringType, Binding binding) {
+            Class<?> declaringClass = InvocationPlugins.resolveType(declaringType, isOptional);
+            if (declaringClass == null) {
+                return true;
+            }
+            if (binding.name.equals("<init>")) {
+                if (resolveConstructor(declaringClass, binding) == null && !isOptional) {
+                    throw new AssertionError(String.format("Constructor not found: %s%s", declaringClass.getName(), binding.argumentsDescriptor));
+                }
+            } else {
+                if (resolveMethod(declaringClass, binding) == null && !isOptional) {
+                    throw new AssertionError(String.format("Method not found: %s.%s%s", declaringClass.getName(), binding.name, binding.argumentsDescriptor));
+                }
+            }
+            return true;
         }
     }
 
@@ -933,31 +1186,119 @@
         if (type instanceof Class) {
             return (Class<?>) type;
         }
-        if (optional && type instanceof OptionalLazySymbol) {
+        if (type instanceof OptionalLazySymbol) {
             return ((OptionalLazySymbol) type).resolve();
         }
         return resolveClass(type.getTypeName(), optional);
     }
 
-    private static final Class<?>[] NO_CLASSES = {};
+    private static List<String> toInternalTypeNames(Class<?>[] types) {
+        String[] res = new String[types.length];
+        for (int i = 0; i < types.length; i++) {
+            res[i] = MetaUtil.toInternalName(types[i].getTypeName());
+        }
+        return Arrays.asList(res);
+    }
+
+    /**
+     * Resolves a given binding to a method in a given class. If more than one method with the
+     * parameter types matching {@code binding} is found and the return types of all the matching
+     * methods form an inheritance chain, the one with the most specific type is returned; otherwise
+     * {@link NoSuchMethodError} is thrown.
+     *
+     * @param declaringClass the class to search for a method matching {@code binding}
+     * @return the method (if any) in {@code declaringClass} matching binding
+     */
+    public static Method resolveMethod(Class<?> declaringClass, Binding binding) {
+        if (binding.name.equals("<init>")) {
+            return null;
+        }
+        Method[] methods = declaringClass.getDeclaredMethods();
+        List<String> parameterTypeNames = parseParameters(binding.argumentsDescriptor);
+        for (int i = 0; i < methods.length; ++i) {
+            Method m = methods[i];
+            if (binding.isStatic == Modifier.isStatic(m.getModifiers()) && m.getName().equals(binding.name)) {
+                if (parameterTypeNames.equals(toInternalTypeNames(m.getParameterTypes()))) {
+                    for (int j = i + 1; j < methods.length; ++j) {
+                        Method other = methods[j];
+                        if (binding.isStatic == Modifier.isStatic(other.getModifiers()) && other.getName().equals(binding.name)) {
+                            if (parameterTypeNames.equals(toInternalTypeNames(other.getParameterTypes()))) {
+                                if (m.getReturnType().isAssignableFrom(other.getReturnType())) {
+                                    // `other` has a more specific return type - choose it
+                                    // (m is most likely a bridge method)
+                                    m = other;
+                                } else {
+                                    if (!other.getReturnType().isAssignableFrom(m.getReturnType())) {
+                                        throw new NoSuchMethodError(String.format(
+                                                        "Found 2 methods with same name and parameter types but unrelated return types:%n %s%n %s", m, other));
+                                    }
+                                }
+                            }
+                        }
+                    }
+                    return m;
+                }
+            }
+        }
+        return null;
+    }
 
     /**
-     * Resolves an array of {@link Type}s to an array of {@link Class}es.
+     * Resolves a given binding to a constructor in a given class.
      *
-     * @param types the types to resolve
-     * @param from the initial index of the range to be resolved, inclusive
-     * @param to the final index of the range to be resolved, exclusive
-     * @return the resolved class or null if resolution fails and {@code optional} is true
+     * @param declaringClass the class to search for a constructor matching {@code binding}
+     * @return the constructor (if any) in {@code declaringClass} matching binding
      */
-    public static Class<?>[] resolveTypes(Type[] types, int from, int to) {
-        int length = to - from;
-        if (length <= 0) {
-            return NO_CLASSES;
+    public static Constructor<?> resolveConstructor(Class<?> declaringClass, Binding binding) {
+        if (!binding.name.equals("<init>")) {
+            return null;
+        }
+        Constructor<?>[] constructors = declaringClass.getDeclaredConstructors();
+        List<String> parameterTypeNames = parseParameters(binding.argumentsDescriptor);
+        for (int i = 0; i < constructors.length; ++i) {
+            Constructor<?> c = constructors[i];
+            if (parameterTypeNames.equals(toInternalTypeNames(c.getParameterTypes()))) {
+                return c;
+            }
         }
-        Class<?>[] classes = new Class<?>[length];
-        for (int i = 0; i < length; i++) {
-            classes[i] = resolveType(types[i + from], false);
+        return null;
+    }
+
+    private static List<String> parseParameters(String argumentsDescriptor) {
+        assert argumentsDescriptor.startsWith("(") && argumentsDescriptor.endsWith(")") : argumentsDescriptor;
+        List<String> res = new ArrayList<>();
+        int cur = 1;
+        int end = argumentsDescriptor.length() - 1;
+        while (cur != end) {
+            char first;
+            int start = cur;
+            do {
+                first = argumentsDescriptor.charAt(cur++);
+            } while (first == '[');
+
+            switch (first) {
+                case 'L':
+                    int endObject = argumentsDescriptor.indexOf(';', cur);
+                    if (endObject == -1) {
+                        throw new GraalError("Invalid object type at index %d in signature: %s", cur, argumentsDescriptor);
+                    }
+                    cur = endObject + 1;
+                    break;
+                case 'V':
+                case 'I':
+                case 'B':
+                case 'C':
+                case 'D':
+                case 'F':
+                case 'J':
+                case 'S':
+                case 'Z':
+                    break;
+                default:
+                    throw new GraalError("Invalid character at index %d in signature: %s", cur, argumentsDescriptor);
+            }
+            res.add(argumentsDescriptor.substring(start, cur));
         }
-        return classes;
+        return res;
     }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/MethodSubstitutionPlugin.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/MethodSubstitutionPlugin.java	Fri May 12 13:56:13 2017 -0700
@@ -106,6 +106,13 @@
     }
 
     /**
+     * Gets the object used to access the bytecodes of the substitute method.
+     */
+    public BytecodeProvider getBytecodeProvider() {
+        return bytecodeProvider;
+    }
+
+    /**
      * Gets the reflection API version of the substitution method.
      */
     Method getJavaSubstitute() throws GraalError {
@@ -139,20 +146,29 @@
                         return false;
                     }
                 }
+                return true;
             }
-            return true;
         }
         return false;
     }
 
+    private Method lookupSubstitute(Method excluding) {
+        for (Method m : declaringClass.getDeclaredMethods()) {
+            if (!m.equals(excluding) && isSubstitute(m)) {
+                return m;
+            }
+        }
+        return null;
+    }
+
     /**
      * Gets the substitute method of this plugin.
      */
     private Method lookupSubstitute() {
-        for (Method m : declaringClass.getDeclaredMethods()) {
-            if (isSubstitute(m)) {
-                return m;
-            }
+        Method m = lookupSubstitute(null);
+        if (m != null) {
+            assert lookupSubstitute(m) == null : String.format("multiple matches found for %s:%n%s%n%s", this, m, lookupSubstitute(m));
+            return m;
         }
         throw new GraalError("No method found specified by %s", this);
     }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AbstractCompareAndSwapNode.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AbstractCompareAndSwapNode.java	Fri May 12 13:56:13 2017 -0700
@@ -25,7 +25,7 @@
 import static org.graalvm.compiler.nodeinfo.InputType.Memory;
 import static org.graalvm.compiler.nodeinfo.InputType.State;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.nodeinfo.InputType;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AtomicReadAndAddNode.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AtomicReadAndAddNode.java	Fri May 12 13:56:13 2017 -0700
@@ -27,7 +27,7 @@
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AtomicReadAndWriteNode.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AtomicReadAndWriteNode.java	Fri May 12 13:56:13 2017 -0700
@@ -25,7 +25,7 @@
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/ExceptionObjectNode.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/ExceptionObjectNode.java	Fri May 12 13:56:13 2017 -0700
@@ -26,7 +26,7 @@
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_8;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.core.common.type.TypeReference;
 import org.graalvm.compiler.graph.NodeClass;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LogicCompareAndSwapNode.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LogicCompareAndSwapNode.java	Fri May 12 13:56:13 2017 -0700
@@ -25,8 +25,8 @@
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_8;
 
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.core.common.LIRKind;
-import org.graalvm.compiler.core.common.LocationIdentity;
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LoweredAtomicReadAndWriteNode.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LoweredAtomicReadAndWriteNode.java	Fri May 12 13:56:13 2017 -0700
@@ -27,7 +27,7 @@
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/MonitorEnterNode.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/MonitorEnterNode.java	Fri May 12 13:56:13 2017 -0700
@@ -25,7 +25,7 @@
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_64;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_64;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.graph.IterableNodeType;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/MonitorExitNode.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/MonitorExitNode.java	Fri May 12 13:56:13 2017 -0700
@@ -25,7 +25,7 @@
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_64;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_64;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.graph.IterableNodeType;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/RawMonitorEnterNode.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/RawMonitorEnterNode.java	Fri May 12 13:56:13 2017 -0700
@@ -25,7 +25,7 @@
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_64;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_64;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.core.common.type.ObjectStamp;
 import org.graalvm.compiler.graph.IterableNodeType;
 import org.graalvm.compiler.graph.NodeClass;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/UnsafeCompareAndSwapNode.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/UnsafeCompareAndSwapNode.java	Fri May 12 13:56:13 2017 -0700
@@ -27,7 +27,7 @@
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_8;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/ValueCompareAndSwapNode.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/ValueCompareAndSwapNode.java	Fri May 12 13:56:13 2017 -0700
@@ -25,7 +25,7 @@
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_8;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/AbstractWriteNode.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/AbstractWriteNode.java	Fri May 12 13:56:13 2017 -0700
@@ -25,7 +25,7 @@
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.graph.NodeClass;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/Access.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/Access.java	Fri May 12 13:56:13 2017 -0700
@@ -22,7 +22,7 @@
  */
 package org.graalvm.compiler.nodes.memory;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.nodes.extended.GuardedNode;
 import org.graalvm.compiler.nodes.memory.address.AddressNode;
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/FixedAccessNode.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/FixedAccessNode.java	Fri May 12 13:56:13 2017 -0700
@@ -22,7 +22,7 @@
  */
 package org.graalvm.compiler.nodes.memory;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.graph.IterableNodeType;
 import org.graalvm.compiler.graph.NodeClass;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/FloatableAccessNode.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/FloatableAccessNode.java	Fri May 12 13:56:13 2017 -0700
@@ -22,7 +22,7 @@
  */
 package org.graalvm.compiler.nodes.memory;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/FloatingAccessNode.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/FloatingAccessNode.java	Fri May 12 13:56:13 2017 -0700
@@ -22,7 +22,7 @@
  */
 package org.graalvm.compiler.nodes.memory;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.nodeinfo.InputType;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/FloatingReadNode.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/FloatingReadNode.java	Fri May 12 13:56:13 2017 -0700
@@ -26,8 +26,8 @@
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
 
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.core.common.LIRKind;
-import org.graalvm.compiler.core.common.LocationIdentity;
 import org.graalvm.compiler.core.common.type.ObjectStamp;
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.debug.DebugCloseable;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryAccess.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryAccess.java	Fri May 12 13:56:13 2017 -0700
@@ -22,7 +22,7 @@
  */
 package org.graalvm.compiler.nodes.memory;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 
 /**
  * This interface marks nodes that access some memory location, and that have an edge to the last
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryCheckpoint.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryCheckpoint.java	Fri May 12 13:56:13 2017 -0700
@@ -22,7 +22,7 @@
  */
 package org.graalvm.compiler.nodes.memory;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.nodes.FixedNode;
 import org.graalvm.compiler.nodes.FixedNodeInterface;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryMap.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryMap.java	Fri May 12 13:56:13 2017 -0700
@@ -22,7 +22,7 @@
  */
 package org.graalvm.compiler.nodes.memory;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 
 /**
  * Maps a {@linkplain LocationIdentity location} to the last node that (potentially) wrote to the
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryMapNode.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryMapNode.java	Fri May 12 13:56:13 2017 -0700
@@ -22,7 +22,7 @@
  */
 package org.graalvm.compiler.nodes.memory;
 
-import static org.graalvm.compiler.core.common.LocationIdentity.any;
+import static org.graalvm.api.word.LocationIdentity.any;
 import static org.graalvm.compiler.nodeinfo.InputType.Extension;
 import static org.graalvm.compiler.nodeinfo.InputType.Memory;
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
@@ -32,7 +32,7 @@
 import java.util.Collection;
 import java.util.List;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.graph.NodeInputList;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryPhiNode.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryPhiNode.java	Fri May 12 13:56:13 2017 -0700
@@ -22,7 +22,7 @@
  */
 package org.graalvm.compiler.nodes.memory;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.graph.NodeInputList;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/ReadNode.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/ReadNode.java	Fri May 12 13:56:13 2017 -0700
@@ -26,8 +26,8 @@
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
 import static org.graalvm.compiler.nodes.NamedLocationIdentity.ARRAY_LENGTH_LOCATION;
 
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.core.common.LIRKind;
-import org.graalvm.compiler.core.common.LocationIdentity;
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.debug.DebugCloseable;
 import org.graalvm.compiler.debug.GraalError;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/WriteNode.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/WriteNode.java	Fri May 12 13:56:13 2017 -0700
@@ -22,8 +22,8 @@
  */
 package org.graalvm.compiler.nodes.memory;
 
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.core.common.LIRKind;
-import org.graalvm.compiler.core.common.LocationIdentity;
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/MemoryProxy.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/MemoryProxy.java	Fri May 12 13:56:13 2017 -0700
@@ -22,7 +22,7 @@
  */
 package org.graalvm.compiler.nodes.spi;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.nodes.memory.MemoryNode;
 
 public interface MemoryProxy extends Proxy, MemoryNode {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/Replacements.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/Replacements.java	Fri May 12 13:56:13 2017 -0700
@@ -24,8 +24,10 @@
 
 import org.graalvm.compiler.api.replacements.MethodSubstitution;
 import org.graalvm.compiler.api.replacements.SnippetTemplateCache;
+import org.graalvm.compiler.bytecode.Bytecode;
 import org.graalvm.compiler.bytecode.BytecodeProvider;
 import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
 import org.graalvm.compiler.options.OptionValues;
 
@@ -39,6 +41,12 @@
     OptionValues getOptions();
 
     /**
+     * Gets the object managing the various graph builder plugins used by this object when parsing
+     * bytecode into a graph.
+     */
+    GraphBuilderConfiguration.Plugins getGraphBuilderPlugins();
+
+    /**
      * Gets the snippet graph derived from a given method.
      *
      * @param args arguments to the snippet if available, otherwise {@code null}
@@ -72,11 +80,12 @@
     StructuredGraph getSubstitution(ResolvedJavaMethod method, int invokeBci);
 
     /**
-     * Gets a method that is a substitution for a given method.
+     * Gets the substitute bytecode for a given method.
      *
-     * @return the method, if any, whose bytecode are a substitution for {@code method}
+     * @return the bytecode to substitute for {@code method} or {@code null} if there is no
+     *         substitute bytecode for {@code method}
      */
-    ResolvedJavaMethod getSubstitutionMethod(ResolvedJavaMethod method);
+    Bytecode getSubstitutionBytecode(ResolvedJavaMethod method);
 
     /**
      * Determines if there may be a {@linkplain #getSubstitution(ResolvedJavaMethod, int)
@@ -94,9 +103,10 @@
     boolean hasSubstitution(ResolvedJavaMethod method, int invokeBci);
 
     /**
-     * Gets the provider for accessing the bytecode of a substitution method.
+     * Gets the provider for accessing the bytecode of a substitution method if no other provider is
+     * associated with the substitution method.
      */
-    BytecodeProvider getReplacementBytecodeProvider();
+    BytecodeProvider getDefaultReplacementBytecodeProvider();
 
     /**
      * Register snippet templates.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/type/NarrowOopStamp.java	Fri May 12 13:56:13 2017 -0700
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2014, 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.nodes.type;
+
+import org.graalvm.compiler.core.common.CompressEncoding;
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.spi.LIRKindTool;
+import org.graalvm.compiler.core.common.type.AbstractObjectStamp;
+import org.graalvm.compiler.core.common.type.ObjectStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.MemoryAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+public abstract class NarrowOopStamp extends AbstractObjectStamp {
+
+    private final CompressEncoding encoding;
+
+    protected NarrowOopStamp(ResolvedJavaType type, boolean exactType, boolean nonNull, boolean alwaysNull, CompressEncoding encoding) {
+        super(type, exactType, nonNull, alwaysNull);
+        this.encoding = encoding;
+    }
+
+    @Override
+    protected abstract AbstractObjectStamp copyWith(ResolvedJavaType type, boolean exactType, boolean nonNull, boolean alwaysNull);
+
+    public Stamp uncompressed() {
+        return new ObjectStamp(type(), isExactType(), nonNull(), alwaysNull());
+    }
+
+    public CompressEncoding getEncoding() {
+        return encoding;
+    }
+
+    @Override
+    public LIRKind getLIRKind(LIRKindTool tool) {
+        return tool.getNarrowOopKind();
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder str = new StringBuilder();
+        str.append('n');
+        appendString(str);
+        return str.toString();
+    }
+
+    @Override
+    public boolean isCompatible(Stamp other) {
+        if (this == other) {
+            return true;
+        }
+        if (other instanceof NarrowOopStamp) {
+            NarrowOopStamp narrow = (NarrowOopStamp) other;
+            return encoding.equals(narrow.encoding);
+        }
+        return false;
+    }
+
+    @Override
+    public abstract Constant readConstant(MemoryAccessProvider provider, Constant base, long displacement);
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = super.hashCode();
+        result = prime * result + encoding.hashCode();
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null || getClass() != obj.getClass()) {
+            return false;
+        }
+        NarrowOopStamp other = (NarrowOopStamp) obj;
+        if (!encoding.equals(other.encoding)) {
+            return false;
+        }
+        return super.equals(other);
+    }
+
+    @Override
+    public abstract JavaConstant asConstant();
+
+    @Override
+    public abstract boolean isCompatible(Constant other);
+}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/util/GraphUtil.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/util/GraphUtil.java	Fri May 12 13:56:13 2017 -0700
@@ -35,9 +35,9 @@
 import org.graalvm.compiler.debug.Debug;
 import org.graalvm.compiler.graph.Graph;
 import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeBitMap;
 import org.graalvm.compiler.graph.NodeSourcePosition;
 import org.graalvm.compiler.graph.NodeStack;
-import org.graalvm.compiler.graph.NodeWorkList;
 import org.graalvm.compiler.graph.Position;
 import org.graalvm.compiler.graph.iterators.NodeIterable;
 import org.graalvm.compiler.graph.spi.SimplifierTool;
@@ -680,28 +680,115 @@
      * unambiguous phis. Note that this method will perform an exhaustive search through phis. It is
      * intended to be used during graph building, when phi nodes aren't yet canonicalized.
      *
-     * @param proxy The node whose original value should be determined.
+     * @param value The node whose original value should be determined.
+     * @return The original value (which might be the input value itself).
      */
-    public static ValueNode originalValue(ValueNode proxy) {
-        ValueNode v = proxy;
-        do {
-            if (v instanceof LimitedValueProxy) {
-                v = ((LimitedValueProxy) v).getOriginalNode();
-            } else if (v instanceof PhiNode) {
-                PhiNode phiNode = (PhiNode) v;
-                v = phiNode.singleValueOrThis();
-                if (v == phiNode) {
-                    v = null;
+    public static ValueNode originalValue(ValueNode value) {
+        ValueNode result = originalValueSimple(value);
+        assert result != null;
+        return result;
+    }
+
+    private static ValueNode originalValueSimple(ValueNode value) {
+        /* The very simple case: look through proxies. */
+        ValueNode cur = originalValueForProxy(value);
+
+        while (cur instanceof PhiNode) {
+            /*
+             * We found a phi function. Check if we can analyze it without allocating temporary data
+             * structures.
+             */
+            PhiNode phi = (PhiNode) cur;
+
+            ValueNode phiSingleValue = null;
+            int count = phi.valueCount();
+            for (int i = 0; i < count; ++i) {
+                ValueNode phiCurValue = originalValueForProxy(phi.valueAt(i));
+                if (phiCurValue == phi) {
+                    /* Simple cycle, we can ignore the input value. */
+                } else if (phiSingleValue == null) {
+                    /* The first input. */
+                    phiSingleValue = phiCurValue;
+                } else if (phiSingleValue != phiCurValue) {
+                    /* Another input that is different from the first input. */
+
+                    if (phiSingleValue instanceof PhiNode || phiCurValue instanceof PhiNode) {
+                        /*
+                         * We have two different input values for the phi function, and at least one
+                         * of the inputs is another phi function. We need to do a complicated
+                         * exhaustive check.
+                         */
+                        return originalValueForComplicatedPhi(phi, new NodeBitMap(value.graph()));
+                    } else {
+                        /*
+                         * We have two different input values for the phi function, but none of them
+                         * is another phi function. This phi function cannot be reduce any further,
+                         * so the phi function is the original value.
+                         */
+                        return phi;
+                    }
                 }
-            } else {
-                break;
             }
-        } while (v != null);
+
+            /*
+             * Successfully reduced the phi function to a single input value. The single input value
+             * can itself be a phi function again, so we might take another loop iteration.
+             */
+            assert phiSingleValue != null;
+            cur = phiSingleValue;
+        }
+
+        /* We reached a "normal" node, which is the original value. */
+        assert !(cur instanceof LimitedValueProxy) && !(cur instanceof PhiNode);
+        return cur;
+    }
+
+    private static ValueNode originalValueForProxy(ValueNode value) {
+        ValueNode cur = value;
+        while (cur instanceof LimitedValueProxy) {
+            cur = ((LimitedValueProxy) cur).getOriginalNode();
+        }
+        return cur;
+    }
 
-        if (v == null) {
-            v = new OriginalValueSearch(proxy).result;
+    /**
+     * Handling for complicated nestings of phi functions. We need to reduce phi functions
+     * recursively, and need a temporary map of visited nodes to avoid endless recursion of cycles.
+     */
+    private static ValueNode originalValueForComplicatedPhi(PhiNode phi, NodeBitMap visited) {
+        if (visited.isMarked(phi)) {
+            /*
+             * Found a phi function that was already seen. Either a cycle, or just a second phi
+             * input to a path we have already processed.
+             */
+            return null;
         }
-        return v;
+        visited.mark(phi);
+
+        ValueNode phiSingleValue = null;
+        int count = phi.valueCount();
+        for (int i = 0; i < count; ++i) {
+            ValueNode phiCurValue = originalValueForProxy(phi.valueAt(i));
+            if (phiCurValue instanceof PhiNode) {
+                /* Recursively process a phi function input. */
+                phiCurValue = originalValueForComplicatedPhi((PhiNode) phiCurValue, visited);
+            }
+
+            if (phiCurValue == null) {
+                /* Cycle to a phi function that was already seen. We can ignore this input. */
+            } else if (phiSingleValue == null) {
+                /* The first input. */
+                phiSingleValue = phiCurValue;
+            } else if (phiCurValue != phiSingleValue) {
+                /*
+                 * Another input that is different from the first input. Since we already
+                 * recursively looked through other phi functions, we now know that this phi
+                 * function cannot be reduce any further, so the phi function is the original value.
+                 */
+                return phi;
+            }
+        }
+        return phiSingleValue;
     }
 
     public static boolean tryKillUnused(Node node) {
@@ -713,64 +800,6 @@
     }
 
     /**
-     * Exhaustive search for {@link GraphUtil#originalValue(ValueNode)} when a simple search fails.
-     * This can happen in the presence of complicated phi/proxy/phi constructs.
-     */
-    static class OriginalValueSearch {
-        ValueNode result;
-
-        OriginalValueSearch(ValueNode proxy) {
-            NodeWorkList worklist = proxy.graph().createNodeWorkList();
-            worklist.add(proxy);
-            for (Node node : worklist) {
-                if (node instanceof LimitedValueProxy) {
-                    ValueNode originalValue = ((LimitedValueProxy) node).getOriginalNode();
-                    if (!process(originalValue, worklist)) {
-                        return;
-                    }
-                } else if (node instanceof PhiNode) {
-                    for (Node value : ((PhiNode) node).values()) {
-                        if (!process((ValueNode) value, worklist)) {
-                            return;
-                        }
-                    }
-                } else {
-                    if (!process((ValueNode) node, null)) {
-                        return;
-                    }
-                }
-            }
-        }
-
-        /**
-         * Process a node as part of this search.
-         *
-         * @param node the next node encountered in the search
-         * @param worklist if non-null, {@code node} will be added to this list. Otherwise,
-         *            {@code node} is treated as a candidate result.
-         * @return true if the search should continue, false if a definitive {@link #result} has
-         *         been found
-         */
-        private boolean process(ValueNode node, NodeWorkList worklist) {
-            if (node.isAlive()) {
-                if (worklist == null) {
-                    if (result == null) {
-                        // Initial candidate result: continue search
-                        result = node;
-                    } else if (result != node) {
-                        // Conflicts with existing candidate: stop search with null result
-                        result = null;
-                        return false;
-                    }
-                } else {
-                    worklist.add(node);
-                }
-            }
-            return true;
-        }
-    }
-
-    /**
      * Returns an iterator that will return the given node followed by all its predecessors, up
      * until the point where {@link Node#predecessor()} returns null.
      *
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/CommitAllocationNode.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/CommitAllocationNode.java	Fri May 12 13:56:13 2017 -0700
@@ -24,6 +24,7 @@
 
 import static org.graalvm.compiler.nodeinfo.InputType.Association;
 import static org.graalvm.compiler.nodeinfo.InputType.Extension;
+import static org.graalvm.compiler.nodeinfo.InputType.Memory;
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN;
 
@@ -32,6 +33,7 @@
 import java.util.List;
 import java.util.Map;
 
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.graph.NodeClass;
@@ -46,6 +48,7 @@
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.java.AbstractNewObjectNode;
 import org.graalvm.compiler.nodes.java.MonitorIdNode;
+import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
 import org.graalvm.compiler.nodes.memory.WriteNode;
 import org.graalvm.compiler.nodes.spi.Lowerable;
 import org.graalvm.compiler.nodes.spi.LoweringTool;
@@ -54,14 +57,14 @@
 
 // @formatter:off
 @NodeInfo(nameTemplate = "Alloc {i#virtualObjects}",
-          allowedUsageTypes = Extension,
+          allowedUsageTypes = {Extension, Memory},
           cycles = CYCLES_UNKNOWN,
           cyclesRationale = "We don't know statically how many, and which, allocations are done.",
           size = SIZE_UNKNOWN,
           sizeRationale = "We don't know statically how much code for which allocations has to be generated."
 )
 // @formatter:on
-public final class CommitAllocationNode extends FixedWithNextNode implements VirtualizableAllocation, Lowerable, Simplifiable {
+public final class CommitAllocationNode extends FixedWithNextNode implements VirtualizableAllocation, Lowerable, Simplifiable, MemoryCheckpoint.Single {
 
     public static final NodeClass<CommitAllocationNode> TYPE = NodeClass.create(CommitAllocationNode.class);
 
@@ -115,6 +118,11 @@
     }
 
     @Override
+    public LocationIdentity getLocationIdentity() {
+        return locks.isEmpty() ? LocationIdentity.init() : LocationIdentity.any();
+    }
+
+    @Override
     public void afterClone(Node other) {
         lockIndexes = new ArrayList<>(lockIndexes);
     }
@@ -166,8 +174,7 @@
     public void simplify(SimplifierTool tool) {
         boolean[] used = new boolean[virtualObjects.size()];
         int usedCount = 0;
-        for (Node usage : usages()) {
-            AllocatedObjectNode addObject = (AllocatedObjectNode) usage;
+        for (AllocatedObjectNode addObject : usages().filter(AllocatedObjectNode.class)) {
             int index = virtualObjects.indexOf(addObject.getVirtualObject());
             assert !used[index];
             used[index] = true;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionKey.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionKey.java	Fri May 12 13:56:13 2017 -0700
@@ -152,6 +152,21 @@
     }
 
     /**
+     * Sets the value of this option in a given map if it doesn't already have a value. The
+     * {@link #onValueUpdate(EconomicMap, Object, Object)} method is called once the value is set.
+     *
+     * @param values map of option values
+     * @param v the value to set for this key in {@code map}
+     */
+    @SuppressWarnings("unchecked")
+    public void putIfAbsent(EconomicMap<OptionKey<?>, Object> values, Object v) {
+        if (!values.containsKey(this)) {
+            T oldValue = (T) values.put(this, v);
+            onValueUpdate(values, oldValue, (T) v);
+        }
+    }
+
+    /**
      * Notifies this object when a value associated with this key is set or updated in
      * {@code values}.
      *
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/CanonicalizerPhase.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/CanonicalizerPhase.java	Fri May 12 13:56:13 2017 -0700
@@ -26,6 +26,7 @@
 import org.graalvm.compiler.debug.Debug;
 import org.graalvm.compiler.debug.DebugCloseable;
 import org.graalvm.compiler.debug.DebugCounter;
+import org.graalvm.compiler.graph.GraalGraphError;
 import org.graalvm.compiler.graph.Graph;
 import org.graalvm.compiler.graph.Graph.Mark;
 import org.graalvm.compiler.graph.Graph.NodeEventListener;
@@ -326,7 +327,7 @@
                             canonical = ((BinaryCommutative<?>) node).maybeCommuteInputs();
                         }
                     } catch (Throwable e) {
-                        throw new RuntimeException(e);
+                        throw new GraalGraphError(e).addContext(node);
                     }
                     if (performReplacement(node, canonical)) {
                         return true;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ConditionalEliminationPhase.java	Fri May 12 13:56:13 2017 -0700
@@ -0,0 +1,1068 @@
+/*
+ * Copyright (c) 2015, 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.phases.common;
+
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.List;
+
+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;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.And;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Or;
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+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.Debug;
+import org.graalvm.compiler.debug.DebugCloseable;
+import org.graalvm.compiler.debug.DebugCounter;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeMap;
+import org.graalvm.compiler.graph.NodeStack;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodes.AbstractBeginNode;
+import org.graalvm.compiler.nodes.AbstractMergeNode;
+import org.graalvm.compiler.nodes.BinaryOpLogicNode;
+import org.graalvm.compiler.nodes.ConditionAnchorNode;
+import org.graalvm.compiler.nodes.DeoptimizeNode;
+import org.graalvm.compiler.nodes.DeoptimizingGuard;
+import org.graalvm.compiler.nodes.EndNode;
+import org.graalvm.compiler.nodes.FixedGuardNode;
+import org.graalvm.compiler.nodes.FixedNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.GuardNode;
+import org.graalvm.compiler.nodes.IfNode;
+import org.graalvm.compiler.nodes.LogicNode;
+import org.graalvm.compiler.nodes.LoopExitNode;
+import org.graalvm.compiler.nodes.MergeNode;
+import org.graalvm.compiler.nodes.ParameterNode;
+import org.graalvm.compiler.nodes.PiNode;
+import org.graalvm.compiler.nodes.ProxyNode;
+import org.graalvm.compiler.nodes.ShortCircuitOrNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.UnaryOpLogicNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.ValuePhiNode;
+import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult;
+import org.graalvm.compiler.nodes.calc.AndNode;
+import org.graalvm.compiler.nodes.calc.BinaryArithmeticNode;
+import org.graalvm.compiler.nodes.calc.BinaryNode;
+import org.graalvm.compiler.nodes.calc.IntegerEqualsNode;
+import org.graalvm.compiler.nodes.calc.UnaryNode;
+import org.graalvm.compiler.nodes.cfg.Block;
+import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
+import org.graalvm.compiler.nodes.extended.GuardingNode;
+import org.graalvm.compiler.nodes.extended.IntegerSwitchNode;
+import org.graalvm.compiler.nodes.extended.LoadHubNode;
+import org.graalvm.compiler.nodes.extended.ValueAnchorNode;
+import org.graalvm.compiler.nodes.java.TypeSwitchNode;
+import org.graalvm.compiler.nodes.spi.NodeWithState;
+import org.graalvm.compiler.nodes.spi.StampInverter;
+import org.graalvm.compiler.nodes.util.GraphUtil;
+import org.graalvm.compiler.phases.BasePhase;
+import org.graalvm.compiler.phases.schedule.SchedulePhase;
+import org.graalvm.compiler.phases.schedule.SchedulePhase.SchedulingStrategy;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+import org.graalvm.util.EconomicMap;
+import org.graalvm.util.Equivalence;
+import org.graalvm.util.MapCursor;
+import org.graalvm.util.Pair;
+
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.TriState;
+
+public class ConditionalEliminationPhase extends BasePhase<PhaseContext> {
+
+    private static final DebugCounter counterStampsRegistered = Debug.counter("StampsRegistered");
+    private static final DebugCounter counterStampsFound = Debug.counter("StampsFound");
+    private static final DebugCounter counterIfsKilled = Debug.counter("CE_KilledIfs");
+    private static final DebugCounter counterPhiStampsImproved = Debug.counter("CE_ImprovedPhis");
+    private final boolean fullSchedule;
+    private final boolean moveGuards;
+
+    public ConditionalEliminationPhase(boolean fullSchedule) {
+        this(fullSchedule, true);
+    }
+
+    public ConditionalEliminationPhase(boolean fullSchedule, boolean moveGuards) {
+        this.fullSchedule = fullSchedule;
+        this.moveGuards = moveGuards;
+    }
+
+    @Override
+    @SuppressWarnings("try")
+    protected void run(StructuredGraph graph, PhaseContext context) {
+        try (Debug.Scope s = Debug.scope("DominatorConditionalElimination")) {
+            BlockMap<List<Node>> blockToNodes = null;
+            NodeMap<Block> nodeToBlock = null;
+            ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, true, true);
+            if (fullSchedule) {
+                if (moveGuards) {
+                    cfg.visitDominatorTree(new MoveGuardsUpwards(), graph.hasValueProxies());
+                }
+                SchedulePhase.run(graph, SchedulingStrategy.EARLIEST, cfg);
+                ScheduleResult r = graph.getLastSchedule();
+                blockToNodes = r.getBlockToNodesMap();
+                nodeToBlock = r.getNodeToBlockMap();
+            } else {
+                nodeToBlock = cfg.getNodeToBlock();
+                blockToNodes = getBlockToNodes(cfg);
+            }
+            ControlFlowGraph.RecursiveVisitor<?> visitor = createVisitor(graph, cfg, blockToNodes, nodeToBlock, context);
+            cfg.visitDominatorTree(visitor, graph.hasValueProxies());
+        }
+    }
+
+    protected BlockMap<List<Node>> getBlockToNodes(@SuppressWarnings("unused") ControlFlowGraph cfg) {
+        return null;
+    }
+
+    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);
+    }
+
+    public static class MoveGuardsUpwards implements ControlFlowGraph.RecursiveVisitor<Block> {
+
+        Block anchorBlock;
+
+        @Override
+        @SuppressWarnings("try")
+        public Block enter(Block b) {
+            Block oldAnchorBlock = anchorBlock;
+            if (b.getDominator() == null || b.getDominator().getPostdominator() != b) {
+                // New anchor.
+                anchorBlock = b;
+            }
+
+            AbstractBeginNode beginNode = b.getBeginNode();
+            if (beginNode instanceof AbstractMergeNode && anchorBlock != b) {
+                AbstractMergeNode mergeNode = (AbstractMergeNode) beginNode;
+                for (GuardNode guard : mergeNode.guards().snapshot()) {
+                    try (DebugCloseable closeable = guard.withNodeSourcePosition()) {
+                        GuardNode newlyCreatedGuard = new GuardNode(guard.getCondition(), anchorBlock.getBeginNode(), guard.getReason(), guard.getAction(), guard.isNegated(), guard.getSpeculation());
+                        GuardNode newGuard = mergeNode.graph().unique(newlyCreatedGuard);
+                        guard.replaceAndDelete(newGuard);
+                    }
+                }
+            }
+
+            FixedNode endNode = b.getEndNode();
+            if (endNode instanceof IfNode) {
+                IfNode node = (IfNode) endNode;
+
+                // Check if we can move guards upwards.
+                AbstractBeginNode trueSuccessor = node.trueSuccessor();
+                EconomicMap<LogicNode, GuardNode> trueGuards = EconomicMap.create(Equivalence.IDENTITY);
+                for (GuardNode guard : trueSuccessor.guards()) {
+                    LogicNode condition = guard.getCondition();
+                    if (condition.hasMoreThanOneUsage()) {
+                        trueGuards.put(condition, guard);
+                    }
+                }
+
+                if (!trueGuards.isEmpty()) {
+                    for (GuardNode guard : node.falseSuccessor().guards().snapshot()) {
+                        GuardNode otherGuard = trueGuards.get(guard.getCondition());
+                        if (otherGuard != null && guard.isNegated() == otherGuard.isNegated()) {
+                            JavaConstant speculation = otherGuard.getSpeculation();
+                            if (speculation == null) {
+                                speculation = guard.getSpeculation();
+                            } else if (guard.getSpeculation() != null && guard.getSpeculation() != speculation) {
+                                // Cannot optimize due to different speculations.
+                                continue;
+                            }
+                            try (DebugCloseable closeable = guard.withNodeSourcePosition()) {
+                                GuardNode newlyCreatedGuard = new GuardNode(guard.getCondition(), anchorBlock.getBeginNode(), guard.getReason(), guard.getAction(), guard.isNegated(), speculation);
+                                GuardNode newGuard = node.graph().unique(newlyCreatedGuard);
+                                if (otherGuard.isAlive()) {
+                                    otherGuard.replaceAndDelete(newGuard);
+                                }
+                                guard.replaceAndDelete(newGuard);
+                            }
+                        }
+                    }
+                }
+            }
+            return oldAnchorBlock;
+        }
+
+        @Override
+        public void exit(Block b, Block value) {
+            anchorBlock = value;
+        }
+
+    }
+
+    private static final class PhiInfoElement {
+
+        private EconomicMap<EndNode, InfoElement> infoElements;
+
+        public void set(EndNode end, InfoElement infoElement) {
+            if (infoElements == null) {
+                infoElements = EconomicMap.create(Equivalence.IDENTITY);
+            }
+            infoElements.put(end, infoElement);
+        }
+
+        public InfoElement get(EndNode end) {
+            if (infoElements == null) {
+                return null;
+            }
+            return infoElements.get(end);
+        }
+    }
+
+    public static class Instance implements ControlFlowGraph.RecursiveVisitor<Integer> {
+        protected final NodeMap<InfoElement> map;
+        protected final BlockMap<List<Node>> blockToNodes;
+        protected final CanonicalizerTool tool;
+        protected final NodeStack undoOperations;
+        protected final StructuredGraph graph;
+        protected final EconomicMap<MergeNode, EconomicMap<ValuePhiNode, PhiInfoElement>> mergeMaps;
+
+        /**
+         * Tests which may be eliminated because post dominating tests to prove a broader condition.
+         */
+        private Deque<PendingTest> pendingTests;
+
+        public Instance(StructuredGraph graph, BlockMap<List<Node>> blockToNodes, PhaseContext context) {
+            this.graph = graph;
+            this.blockToNodes = blockToNodes;
+            this.undoOperations = new NodeStack();
+            this.map = graph.createNodeMap();
+            pendingTests = new ArrayDeque<>();
+            tool = GraphUtil.getDefaultSimplifier(context.getMetaAccess(), context.getConstantReflection(), context.getConstantFieldProvider(), false, graph.getAssumptions(), graph.getOptions(),
+                            context.getLowerer());
+            mergeMaps = EconomicMap.create();
+        }
+
+        protected void processConditionAnchor(ConditionAnchorNode node) {
+            tryProveCondition(node.condition(), (guard, result, guardedValueStamp, newInput) -> {
+                if (result != node.isNegated()) {
+                    node.replaceAtUsages(guard.asNode());
+                    GraphUtil.unlinkFixedNode(node);
+                    GraphUtil.killWithUnusedFloatingInputs(node);
+                } else {
+                    ValueAnchorNode valueAnchor = node.graph().add(new ValueAnchorNode(null));
+                    node.replaceAtUsages(valueAnchor);
+                    node.graph().replaceFixedWithFixed(node, valueAnchor);
+                }
+                return true;
+            });
+        }
+
+        protected void processGuard(GuardNode node) {
+            if (!tryProveGuardCondition(node, node.getCondition(), (guard, result, guardedValueStamp, newInput) -> {
+                if (result != node.isNegated()) {
+                    node.replaceAndDelete(guard.asNode());
+                } else {
+                    DeoptimizeNode deopt = node.graph().add(new DeoptimizeNode(node.getAction(), node.getReason(), node.getSpeculation()));
+                    AbstractBeginNode beginNode = (AbstractBeginNode) node.getAnchor();
+                    FixedNode next = beginNode.next();
+                    beginNode.setNext(deopt);
+                    GraphUtil.killCFG(next);
+                }
+                return true;
+            })) {
+                registerNewCondition(node.getCondition(), node.isNegated(), node);
+            }
+        }
+
+        protected void processFixedGuard(FixedGuardNode node) {
+            if (!tryProveGuardCondition(node, node.condition(), (guard, result, guardedValueStamp, newInput) -> {
+                if (result != node.isNegated()) {
+                    node.replaceAtUsages(guard.asNode());
+                    GraphUtil.unlinkFixedNode(node);
+                    GraphUtil.killWithUnusedFloatingInputs(node);
+                } else {
+                    DeoptimizeNode deopt = node.graph().add(new DeoptimizeNode(node.getAction(), node.getReason(), node.getSpeculation()));
+                    deopt.setStateBefore(node.stateBefore());
+                    node.replaceAtPredecessor(deopt);
+                    GraphUtil.killCFG(node);
+                }
+                Debug.log("Kill fixed guard guard");
+                return true;
+            })) {
+                registerNewCondition(node.condition(), node.isNegated(), node);
+            }
+        }
+
+        protected void processIf(IfNode node) {
+            tryProveCondition(node.condition(), (guard, result, guardedValueStamp, newInput) -> {
+                AbstractBeginNode survivingSuccessor = node.getSuccessor(result);
+                survivingSuccessor.replaceAtUsages(InputType.Guard, guard.asNode());
+                survivingSuccessor.replaceAtPredecessor(null);
+                node.replaceAtPredecessor(survivingSuccessor);
+                GraphUtil.killCFG(node);
+                counterIfsKilled.increment();
+                return true;
+            });
+        }
+
+        @Override
+        public Integer enter(Block block) {
+            int mark = undoOperations.size();
+            Debug.log("[Pre Processing block %s]", block);
+            // For now conservatively collect guards only within the same block.
+            pendingTests.clear();
+            processNodes(block);
+            return mark;
+        }
+
+        protected void processNodes(Block block) {
+            if (blockToNodes != null) {
+                for (Node n : blockToNodes.get(block)) {
+                    if (n.isAlive()) {
+                        processNode(n);
+                    }
+                }
+            } else {
+                processBlock(block);
+            }
+        }
+
+        private void processBlock(Block block) {
+            FixedNode n = block.getBeginNode();
+            FixedNode endNode = block.getEndNode();
+            Debug.log("[Processing block %s]", block);
+            while (n != endNode) {
+                if (n.isDeleted() || endNode.isDeleted()) {
+                    // This branch was deleted!
+                    return;
+                }
+                FixedNode next = ((FixedWithNextNode) n).next();
+                processNode(n);
+                n = next;
+            }
+            if (endNode.isAlive()) {
+                processNode(endNode);
+            }
+        }
+
+        @SuppressWarnings("try")
+        protected void processNode(Node node) {
+            try (DebugCloseable closeable = node.withNodeSourcePosition()) {
+                if (node instanceof NodeWithState && !(node instanceof GuardingNode)) {
+                    pendingTests.clear();
+                }
+
+                if (node instanceof MergeNode) {
+                    introducePisForPhis((MergeNode) node);
+                }
+
+                if (node instanceof AbstractBeginNode) {
+                    if (node instanceof LoopExitNode && graph.hasValueProxies()) {
+                        // Condition must not be used down this path.
+                        return;
+                    }
+                    processAbstractBegin((AbstractBeginNode) node);
+                } else if (node instanceof FixedGuardNode) {
+                    processFixedGuard((FixedGuardNode) node);
+                } else if (node instanceof GuardNode) {
+                    processGuard((GuardNode) node);
+                } else if (node instanceof ConditionAnchorNode) {
+                    processConditionAnchor((ConditionAnchorNode) node);
+                } else if (node instanceof IfNode) {
+                    processIf((IfNode) node);
+                } else if (node instanceof EndNode) {
+                    processEnd((EndNode) node);
+                }
+            }
+        }
+
+        protected void introducePisForPhis(MergeNode merge) {
+            EconomicMap<ValuePhiNode, PhiInfoElement> mergeMap = this.mergeMaps.get(merge);
+            if (mergeMap != null) {
+                MapCursor<ValuePhiNode, PhiInfoElement> entries = mergeMap.getEntries();
+                while (entries.advance()) {
+                    ValuePhiNode phi = entries.getKey();
+                    PhiInfoElement phiInfoElements = entries.getValue();
+                    Stamp bestPossibleStamp = null;
+                    for (int i = 0; i < phi.valueCount(); ++i) {
+                        ValueNode valueAt = phi.valueAt(i);
+                        Stamp curBestStamp = valueAt.stamp();
+                        InfoElement infoElement = phiInfoElements.get(merge.forwardEndAt(i));
+                        if (infoElement != null) {
+                            curBestStamp = curBestStamp.join(infoElement.getStamp());
+                        }
+
+                        if (bestPossibleStamp == null) {
+                            bestPossibleStamp = curBestStamp;
+                        } else {
+                            bestPossibleStamp = bestPossibleStamp.meet(curBestStamp);
+                        }
+                    }
+
+                    Stamp oldStamp = phi.stamp();
+                    if (oldStamp.tryImproveWith(bestPossibleStamp) != null) {
+
+                        // Need to be careful to not run into stamp update cycles with the iterative
+                        // canonicalization.
+                        boolean allow = false;
+                        if (bestPossibleStamp instanceof ObjectStamp) {
+                            // Always allow object stamps.
+                            allow = true;
+                        } else if (bestPossibleStamp instanceof IntegerStamp) {
+                            IntegerStamp integerStamp = (IntegerStamp) bestPossibleStamp;
+                            IntegerStamp oldIntegerStamp = (IntegerStamp) oldStamp;
+                            if (integerStamp.isPositive() != oldIntegerStamp.isPositive()) {
+                                allow = true;
+                            } else if (integerStamp.isNegative() != oldIntegerStamp.isNegative()) {
+                                allow = true;
+                            } else if (integerStamp.isStrictlyPositive() != oldIntegerStamp.isStrictlyPositive()) {
+                                allow = true;
+                            } else if (integerStamp.isStrictlyNegative() != oldIntegerStamp.isStrictlyNegative()) {
+                                allow = true;
+                            } else if (integerStamp.asConstant() != null) {
+                                allow = true;
+                            } else if (oldStamp.isUnrestricted()) {
+                                allow = true;
+                            }
+                        } else {
+                            allow = (bestPossibleStamp.asConstant() != null);
+                        }
+
+                        if (allow) {
+                            ValuePhiNode newPhi = graph.addWithoutUnique(new ValuePhiNode(bestPossibleStamp, merge));
+                            for (int i = 0; i < phi.valueCount(); ++i) {
+                                ValueNode valueAt = phi.valueAt(i);
+                                if (bestPossibleStamp.meet(valueAt.stamp()).equals(bestPossibleStamp)) {
+                                    // Pi not required here.
+                                } else {
+                                    InfoElement infoElement = phiInfoElements.get(merge.forwardEndAt(i));
+                                    assert infoElement != null;
+                                    Stamp curBestStamp = infoElement.getStamp();
+                                    ValueNode input = infoElement.getProxifiedInput();
+                                    if (input == null) {
+                                        input = valueAt;
+                                    }
+                                    ValueNode valueNode = graph.maybeAddOrUnique(PiNode.create(input, curBestStamp, (ValueNode) infoElement.guard));
+                                    valueAt = valueNode;
+                                }
+                                newPhi.addInput(valueAt);
+                            }
+                            counterPhiStampsImproved.increment();
+                            phi.replaceAtUsagesAndDelete(newPhi);
+                        }
+                    }
+                }
+            }
+        }
+
+        protected void processEnd(EndNode end) {
+            AbstractMergeNode abstractMerge = end.merge();
+            if (abstractMerge instanceof MergeNode) {
+                MergeNode merge = (MergeNode) abstractMerge;
+
+                EconomicMap<ValuePhiNode, PhiInfoElement> mergeMap = this.mergeMaps.get(merge);
+                for (ValuePhiNode phi : merge.valuePhis()) {
+                    ValueNode valueAt = phi.valueAt(end);
+                    InfoElement infoElement = this.getInfoElements(valueAt);
+                    while (infoElement != null) {
+                        Stamp newStamp = infoElement.getStamp();
+                        if (phi.stamp().tryImproveWith(newStamp) != null) {
+                            if (mergeMap == null) {
+                                mergeMap = EconomicMap.create();
+                                mergeMaps.put(merge, mergeMap);
+                            }
+
+                            PhiInfoElement phiInfoElement = mergeMap.get(phi);
+                            if (phiInfoElement == null) {
+                                phiInfoElement = new PhiInfoElement();
+                                mergeMap.put(phi, phiInfoElement);
+                            }
+
+                            phiInfoElement.set(end, infoElement);
+                            break;
+                        }
+                        infoElement = nextElement(infoElement);
+                    }
+                }
+            }
+        }
+
+        protected void registerNewCondition(LogicNode condition, boolean negated, GuardingNode guard) {
+            if (condition instanceof UnaryOpLogicNode) {
+                UnaryOpLogicNode unaryLogicNode = (UnaryOpLogicNode) condition;
+                ValueNode value = unaryLogicNode.getValue();
+                if (maybeMultipleUsages(value)) {
+                    Stamp newStamp = unaryLogicNode.getSucceedingStampForValue(negated);
+                    registerNewStamp(value, newStamp, guard);
+                }
+            } else if (condition instanceof BinaryOpLogicNode) {
+                BinaryOpLogicNode binaryOpLogicNode = (BinaryOpLogicNode) condition;
+                ValueNode x = binaryOpLogicNode.getX();
+                ValueNode y = binaryOpLogicNode.getY();
+                if (!x.isConstant() && maybeMultipleUsages(x)) {
+                    Stamp newStampX = binaryOpLogicNode.getSucceedingStampForX(negated, getSafeStamp(x), getOtherSafeStamp(y));
+                    registerNewStamp(x, newStampX, guard);
+                }
+
+                if (!y.isConstant() && maybeMultipleUsages(y)) {
+                    Stamp newStampY = binaryOpLogicNode.getSucceedingStampForY(negated, getOtherSafeStamp(x), getSafeStamp(y));
+                    registerNewStamp(y, newStampY, guard);
+                }
+
+                if (condition instanceof IntegerEqualsNode && guard instanceof DeoptimizingGuard && !negated) {
+                    if (y.isConstant() && x instanceof AndNode) {
+                        AndNode and = (AndNode) x;
+                        ValueNode andX = and.getX();
+                        if (and.getY() == y && maybeMultipleUsages(andX)) {
+                            /*
+                             * This 'and' proves something about some of the bits in and.getX().
+                             * It's equivalent to or'ing in the mask value since those values are
+                             * known to be set.
+                             */
+                            BinaryOp<Or> op = ArithmeticOpTable.forStamp(x.stamp()).getOr();
+                            IntegerStamp newStampX = (IntegerStamp) op.foldStamp(getSafeStamp(andX), getOtherSafeStamp(y));
+                            registerNewStamp(andX, newStampX, guard);
+                        }
+                    }
+                }
+            }
+            if (guard instanceof DeoptimizingGuard) {
+                pendingTests.push(new PendingTest(condition, (DeoptimizingGuard) guard));
+            }
+            registerCondition(condition, negated, guard);
+        }
+
+        Pair<InfoElement, Stamp> recursiveFoldStamp(Node node) {
+            if (node instanceof UnaryNode) {
+                UnaryNode unary = (UnaryNode) node;
+                ValueNode value = unary.getValue();
+                InfoElement infoElement = getInfoElements(value);
+                while (infoElement != null) {
+                    Stamp result = unary.foldStamp(infoElement.getStamp());
+                    if (result != null) {
+                        return Pair.create(infoElement, result);
+                    }
+                    infoElement = nextElement(infoElement);
+                }
+            } else if (node instanceof BinaryNode) {
+                BinaryNode binary = (BinaryNode) node;
+                ValueNode y = binary.getY();
+                ValueNode x = binary.getX();
+                if (y.isConstant()) {
+                    InfoElement infoElement = getInfoElements(x);
+                    while (infoElement != null) {
+                        Stamp result = binary.foldStamp(infoElement.stamp, y.stamp());
+                        if (result != null) {
+                            return Pair.create(infoElement, result);
+                        }
+                        infoElement = nextElement(infoElement);
+                    }
+                }
+            }
+            return null;
+        }
+
+        /**
+         * Get the stamp that may be used for the value for which we are registering the condition.
+         * We may directly use the stamp here without restriction, because any later lookup of the
+         * registered info elements is in the same chain of pi nodes.
+         */
+        private static Stamp getSafeStamp(ValueNode x) {
+            return x.stamp();
+        }
+
+        /**
+         * We can only use the stamp of a second value involved in the condition if we are sure that
+         * we are not implicitly creating a dependency on a pi node that is responsible for that
+         * stamp. For now, we are conservatively only using the stamps of constants. Under certain
+         * circumstances, we may also be able to use the stamp of the value after skipping pi nodes
+         * (e.g., the stamp of a parameter after inlining, or the stamp of a fixed node that can
+         * never be replaced with a pi node via canonicalization).
+         */
+        private static Stamp getOtherSafeStamp(ValueNode x) {
+            if (x.isConstant()) {
+                return x.stamp();
+            }
+            return x.stamp().unrestricted();
+        }
+
+        /**
+         * Recursively try to fold stamps within this expression using information from
+         * {@link #getInfoElements(ValueNode)}. It's only safe to use constants and one
+         * {@link InfoElement} otherwise more than one guard would be required.
+         *
+         * @param node
+         * @return the pair of the @{link InfoElement} used and the stamp produced for the whole
+         *         expression
+         */
+        Pair<InfoElement, Stamp> recursiveFoldStampFromInfo(Node node) {
+            return recursiveFoldStamp(node);
+        }
+
+        protected boolean foldPendingTest(DeoptimizingGuard thisGuard, ValueNode original, Stamp newStamp, GuardRewirer rewireGuardFunction) {
+            for (PendingTest pending : pendingTests) {
+                TriState result = TriState.UNKNOWN;
+                if (pending.condition instanceof UnaryOpLogicNode) {
+                    UnaryOpLogicNode unaryLogicNode = (UnaryOpLogicNode) pending.condition;
+                    if (unaryLogicNode.getValue() == original) {
+                        result = unaryLogicNode.tryFold(newStamp);
+                    }
+                } else if (pending.condition instanceof BinaryOpLogicNode) {
+                    BinaryOpLogicNode binaryOpLogicNode = (BinaryOpLogicNode) pending.condition;
+                    ValueNode x = binaryOpLogicNode.getX();
+                    ValueNode y = binaryOpLogicNode.getY();
+                    if (x == original) {
+                        result = binaryOpLogicNode.tryFold(newStamp, getOtherSafeStamp(y));
+                    } else if (y == original) {
+                        result = binaryOpLogicNode.tryFold(getOtherSafeStamp(x), newStamp);
+                    } else if (binaryOpLogicNode instanceof IntegerEqualsNode && y.isConstant() && x instanceof AndNode) {
+                        AndNode and = (AndNode) x;
+                        if (and.getY() == y && and.getX() == original) {
+                            BinaryOp<And> andOp = ArithmeticOpTable.forStamp(newStamp).getAnd();
+                            result = binaryOpLogicNode.tryFold(andOp.foldStamp(newStamp, getOtherSafeStamp(y)), getOtherSafeStamp(y));
+                        }
+                    }
+                }
+                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.
+                     */
+                    InputFilter v = new InputFilter(original);
+                    thisGuard.getCondition().applyInputs(v);
+                    if (v.ok && foldGuard(thisGuard, pending.guard, newStamp, rewireGuardFunction)) {
+                        return true;
+                    }
+                }
+            }
+            return false;
+        }
+
+        protected boolean foldGuard(DeoptimizingGuard thisGuard, DeoptimizingGuard otherGuard, Stamp guardedValueStamp, GuardRewirer rewireGuardFunction) {
+            if (otherGuard.getAction() == thisGuard.getAction() && otherGuard.getSpeculation() == thisGuard.getSpeculation()) {
+                LogicNode condition = (LogicNode) thisGuard.getCondition().copyWithInputs();
+                GuardRewirer rewirer = (guard, result, innerGuardedValueStamp, newInput) -> {
+                    if (rewireGuardFunction.rewire(guard, result, innerGuardedValueStamp, newInput)) {
+                        otherGuard.setCondition(condition, thisGuard.isNegated());
+                        return true;
+                    }
+                    condition.safeDelete();
+                    return false;
+                };
+                // Move the later test up
+                return rewireGuards(otherGuard, !thisGuard.isNegated(), null, guardedValueStamp, rewirer);
+            }
+            return false;
+        }
+
+        protected void registerCondition(LogicNode condition, boolean negated, GuardingNode guard) {
+            if (condition.getUsageCount() > 1) {
+                registerNewStamp(condition, negated ? StampFactory.contradiction() : StampFactory.tautology(), guard);
+            }
+        }
+
+        protected InfoElement getInfoElements(ValueNode proxiedValue) {
+            ValueNode value = GraphUtil.skipPi(proxiedValue);
+            if (value == null) {
+                return null;
+            }
+            return map.getAndGrow(value);
+        }
+
+        protected boolean rewireGuards(GuardingNode guard, boolean result, ValueNode proxifiedInput, Stamp guardedValueStamp, GuardRewirer rewireGuardFunction) {
+            counterStampsFound.increment();
+            return rewireGuardFunction.rewire(guard, result, guardedValueStamp, proxifiedInput);
+        }
+
+        protected boolean tryProveCondition(LogicNode node, GuardRewirer rewireGuardFunction) {
+            return tryProveGuardCondition(null, node, rewireGuardFunction);
+        }
+
+        private InfoElement nextElement(InfoElement current) {
+            InfoElement parent = current.getParent();
+            if (parent != null) {
+                return parent;
+            } else {
+                ValueNode proxifiedInput = current.getProxifiedInput();
+                if (proxifiedInput instanceof PiNode) {
+                    PiNode piNode = (PiNode) proxifiedInput;
+                    return getInfoElements(piNode.getOriginalNode());
+                }
+            }
+            return null;
+        }
+
+        protected boolean tryProveGuardCondition(DeoptimizingGuard thisGuard, LogicNode node, GuardRewirer rewireGuardFunction) {
+            InfoElement infoElement = getInfoElements(node);
+            while (infoElement != null) {
+                Stamp stamp = infoElement.getStamp();
+                JavaConstant constant = (JavaConstant) stamp.asConstant();
+                if (constant != null) {
+                    // No proxified input and stamp required.
+                    return rewireGuards(infoElement.getGuard(), constant.asBoolean(), null, null, rewireGuardFunction);
+                }
+                infoElement = nextElement(infoElement);
+            }
+
+            if (node instanceof UnaryOpLogicNode) {
+                UnaryOpLogicNode unaryLogicNode = (UnaryOpLogicNode) node;
+                ValueNode value = unaryLogicNode.getValue();
+                infoElement = getInfoElements(value);
+                while (infoElement != null) {
+                    Stamp stamp = infoElement.getStamp();
+                    TriState result = unaryLogicNode.tryFold(stamp);
+                    if (result.isKnown()) {
+                        return rewireGuards(infoElement.getGuard(), result.toBoolean(), infoElement.getProxifiedInput(), infoElement.getStamp(), rewireGuardFunction);
+                    }
+                    infoElement = nextElement(infoElement);
+                }
+                Pair<InfoElement, Stamp> foldResult = recursiveFoldStampFromInfo(value);
+                if (foldResult != null) {
+                    TriState result = unaryLogicNode.tryFold(foldResult.getRight());
+                    if (result.isKnown()) {
+                        return rewireGuards(foldResult.getLeft().getGuard(), result.toBoolean(), foldResult.getLeft().getProxifiedInput(), foldResult.getRight(), rewireGuardFunction);
+                    }
+                }
+                if (thisGuard != null) {
+                    Stamp newStamp = unaryLogicNode.getSucceedingStampForValue(thisGuard.isNegated());
+                    if (newStamp != null && foldPendingTest(thisGuard, value, newStamp, rewireGuardFunction)) {
+                        return true;
+                    }
+
+                }
+            } 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);
+                while (infoElement != null) {
+                    TriState result = binaryOpLogicNode.tryFold(infoElement.getStamp(), y.stamp());
+                    if (result.isKnown()) {
+                        return rewireGuards(infoElement.getGuard(), result.toBoolean(), infoElement.getProxifiedInput(), infoElement.getStamp(), rewireGuardFunction);
+                    }
+                    infoElement = nextElement(infoElement);
+                }
+
+                if (y.isConstant()) {
+                    Pair<InfoElement, Stamp> foldResult = recursiveFoldStampFromInfo(x);
+                    if (foldResult != null) {
+                        TriState result = binaryOpLogicNode.tryFold(foldResult.getRight(), y.stamp());
+                        if (result.isKnown()) {
+                            return rewireGuards(foldResult.getLeft().getGuard(), result.toBoolean(), foldResult.getLeft().getProxifiedInput(), foldResult.getRight(), rewireGuardFunction);
+                        }
+                    }
+                } else {
+                    infoElement = getInfoElements(y);
+                    while (infoElement != null) {
+                        TriState result = binaryOpLogicNode.tryFold(x.stamp(), infoElement.getStamp());
+                        if (result.isKnown()) {
+                            return rewireGuards(infoElement.getGuard(), result.toBoolean(), infoElement.getProxifiedInput(), infoElement.getStamp(), rewireGuardFunction);
+                        }
+                        infoElement = nextElement(infoElement);
+                    }
+                }
+
+                /*
+                 * For complex expressions involving constants, see if it's possible to fold the
+                 * tests by using stamps one level up in the expression. For instance, (x + n < y)
+                 * might fold if something is known about x and all other values are constants. The
+                 * reason for the constant restriction is that if more than 1 real value is involved
+                 * the code might need to adopt multiple guards to have proper dependences.
+                 */
+                if (x instanceof BinaryArithmeticNode<?> && y.isConstant()) {
+                    BinaryArithmeticNode<?> binary = (BinaryArithmeticNode<?>) x;
+                    if (binary.getY().isConstant()) {
+                        infoElement = getInfoElements(binary.getX());
+                        while (infoElement != null) {
+                            Stamp newStampX = binary.foldStamp(infoElement.getStamp(), binary.getY().stamp());
+                            TriState result = binaryOpLogicNode.tryFold(newStampX, y.stamp());
+                            if (result.isKnown()) {
+                                return rewireGuards(infoElement.getGuard(), result.toBoolean(), infoElement.getProxifiedInput(), newStampX, rewireGuardFunction);
+                            }
+                            infoElement = nextElement(infoElement);
+                        }
+                    }
+                }
+
+                if (thisGuard != null && binaryOpLogicNode instanceof IntegerEqualsNode && !thisGuard.isNegated()) {
+                    if (y.isConstant() && x instanceof AndNode) {
+                        AndNode and = (AndNode) x;
+                        if (and.getY() == y) {
+                            /*
+                             * This 'and' proves something about some of the bits in and.getX().
+                             * It's equivalent to or'ing in the mask value since those values are
+                             * known to be set.
+                             */
+                            BinaryOp<Or> op = ArithmeticOpTable.forStamp(x.stamp()).getOr();
+                            IntegerStamp newStampX = (IntegerStamp) op.foldStamp(getSafeStamp(and.getX()), getOtherSafeStamp(y));
+                            if (foldPendingTest(thisGuard, and.getX(), newStampX, rewireGuardFunction)) {
+                                return true;
+                            }
+                        }
+                    }
+                }
+
+                if (thisGuard != null) {
+                    if (!x.isConstant()) {
+                        Stamp newStampX = binaryOpLogicNode.getSucceedingStampForX(thisGuard.isNegated(), getSafeStamp(x), getOtherSafeStamp(y));
+                        if (newStampX != null && foldPendingTest(thisGuard, x, newStampX, rewireGuardFunction)) {
+                            return true;
+                        }
+                    }
+                    if (!y.isConstant()) {
+                        Stamp newStampY = binaryOpLogicNode.getSucceedingStampForY(thisGuard.isNegated(), getOtherSafeStamp(x), getSafeStamp(y));
+                        if (newStampY != null && foldPendingTest(thisGuard, y, newStampY, rewireGuardFunction)) {
+                            return true;
+                        }
+                    }
+                }
+            } else if (node instanceof ShortCircuitOrNode) {
+                final ShortCircuitOrNode shortCircuitOrNode = (ShortCircuitOrNode) node;
+                return tryProveCondition(shortCircuitOrNode.getX(), (guard, result, guardedValueStamp, newInput) -> {
+                    if (result == !shortCircuitOrNode.isXNegated()) {
+                        return rewireGuards(guard, true, newInput, guardedValueStamp, rewireGuardFunction);
+                    } else {
+                        return tryProveCondition(shortCircuitOrNode.getY(), (innerGuard, innerResult, innerGuardedValueStamp, innerNewInput) -> {
+                            ValueNode proxifiedInput = newInput;
+                            if (proxifiedInput == null) {
+                                proxifiedInput = innerNewInput;
+                            } else if (innerNewInput != null) {
+                                if (innerNewInput != newInput) {
+                                    // Cannot canonicalize due to different proxied inputs.
+                                    return false;
+                                }
+                            }
+                            // Can only canonicalize if the guards are equal.
+                            if (innerGuard == guard) {
+                                return rewireGuards(guard, innerResult ^ shortCircuitOrNode.isYNegated(), proxifiedInput, guardedValueStamp, rewireGuardFunction);
+                            }
+                            return false;
+                        });
+                    }
+                });
+            }
+
+            return false;
+        }
+
+        protected void registerNewStamp(ValueNode maybeProxiedValue, Stamp newStamp, GuardingNode guard) {
+            assert maybeProxiedValue != null;
+            assert guard != null;
+            if (newStamp != null) {
+                ValueNode value = maybeProxiedValue;
+                Stamp stamp = newStamp;
+                ValueNode proxiedValue = null;
+                if (value instanceof PiNode) {
+                    proxiedValue = value;
+                }
+                do {
+                    counterStampsRegistered.increment();
+                    Debug.log("\t Saving stamp for node %s stamp %s guarded by %s", value, stamp, guard);
+                    assert value instanceof LogicNode || stamp.isCompatible(value.stamp()) : stamp + " vs. " + value.stamp() + " (" + value + ")";
+                    map.setAndGrow(value, new InfoElement(stamp, guard, proxiedValue, map.getAndGrow(value)));
+                    undoOperations.push(value);
+                    if (value instanceof StampInverter) {
+                        StampInverter stampInverter = (StampInverter) value;
+                        value = stampInverter.getValue();
+                        stamp = stampInverter.invertStamp(stamp);
+                    } else {
+                        value = null;
+                        stamp = null;
+                    }
+                } while (value != null && stamp != null);
+            }
+        }
+
+        protected void processAbstractBegin(AbstractBeginNode beginNode) {
+            Node predecessor = beginNode.predecessor();
+            if (predecessor instanceof IfNode) {
+                IfNode ifNode = (IfNode) predecessor;
+                boolean negated = (ifNode.falseSuccessor() == beginNode);
+                LogicNode condition = ifNode.condition();
+                registerNewCondition(condition, negated, beginNode);
+            } else if (predecessor instanceof TypeSwitchNode) {
+                TypeSwitchNode typeSwitch = (TypeSwitchNode) predecessor;
+                processTypeSwitch(beginNode, typeSwitch);
+            } else if (predecessor instanceof IntegerSwitchNode) {
+                IntegerSwitchNode integerSwitchNode = (IntegerSwitchNode) predecessor;
+                processIntegerSwitch(beginNode, integerSwitchNode);
+            }
+        }
+
+        private static boolean maybeMultipleUsages(ValueNode value) {
+            if (value.hasMoreThanOneUsage()) {
+                return true;
+            } else {
+                return value instanceof ProxyNode;
+            }
+        }
+
+        protected void processIntegerSwitch(AbstractBeginNode beginNode, IntegerSwitchNode integerSwitchNode) {
+            ValueNode value = integerSwitchNode.value();
+            if (maybeMultipleUsages(value)) {
+                Stamp stamp = integerSwitchNode.getValueStampForSuccessor(beginNode);
+                if (stamp != null) {
+                    registerNewStamp(value, stamp, beginNode);
+                }
+            }
+        }
+
+        protected void processTypeSwitch(AbstractBeginNode beginNode, TypeSwitchNode typeSwitch) {
+            ValueNode hub = typeSwitch.value();
+            if (hub instanceof LoadHubNode) {
+                LoadHubNode loadHub = (LoadHubNode) hub;
+                ValueNode value = loadHub.getValue();
+                if (maybeMultipleUsages(value)) {
+                    Stamp stamp = typeSwitch.getValueStampForSuccessor(beginNode);
+                    if (stamp != null) {
+                        registerNewStamp(value, stamp, beginNode);
+                    }
+                }
+            }
+        }
+
+        @Override
+        public void exit(Block b, Integer state) {
+            int mark = state;
+            while (undoOperations.size() > mark) {
+                Node node = undoOperations.pop();
+                if (node.isAlive()) {
+                    map.set(node, map.get(node).getParent());
+                }
+            }
+        }
+    }
+
+    @FunctionalInterface
+    protected interface InfoElementProvider {
+        Iterable<InfoElement> getInfoElements(ValueNode value);
+    }
+
+    /**
+     * Checks for safe nodes when moving pending tests up.
+     */
+    static class InputFilter extends Node.EdgeVisitor {
+        boolean ok;
+        private ValueNode value;
+
+        InputFilter(ValueNode value) {
+            this.value = value;
+            this.ok = true;
+        }
+
+        @Override
+        public Node apply(Node node, Node curNode) {
+            if (!ok) {
+                // Abort the recursion
+                return curNode;
+            }
+            if (!(curNode instanceof ValueNode)) {
+                ok = false;
+                return curNode;
+            }
+            ValueNode curValue = (ValueNode) curNode;
+            if (curValue.isConstant() || curValue == value || curValue instanceof ParameterNode) {
+                return curNode;
+            }
+            if (curValue instanceof BinaryNode || curValue instanceof UnaryNode) {
+                curValue.applyInputs(this);
+            } else {
+                ok = false;
+            }
+            return curNode;
+        }
+    }
+
+    @FunctionalInterface
+    protected interface GuardRewirer {
+        /**
+         * Called if the condition could be proven to have a constant value ({@code result}) under
+         * {@code guard}.
+         *
+         * @param guard the guard whose result is proven
+         * @param result the known result of the guard
+         * @param newInput new input to pi nodes depending on the new guard
+         * @return whether the transformation could be applied
+         */
+        boolean rewire(GuardingNode guard, boolean result, Stamp guardedValueStamp, ValueNode newInput);
+    }
+
+    protected static class PendingTest {
+        private final LogicNode condition;
+        private final DeoptimizingGuard guard;
+
+        public PendingTest(LogicNode condition, DeoptimizingGuard guard) {
+            this.condition = condition;
+            this.guard = guard;
+        }
+    }
+
+    protected static final class InfoElement {
+        private final Stamp stamp;
+        private final GuardingNode guard;
+        private final ValueNode proxifiedInput;
+        private final InfoElement parent;
+
+        public InfoElement(Stamp stamp, GuardingNode guard, ValueNode proxifiedInput, InfoElement parent) {
+            this.stamp = stamp;
+            this.guard = guard;
+            this.proxifiedInput = proxifiedInput;
+            this.parent = parent;
+        }
+
+        public InfoElement getParent() {
+            return parent;
+        }
+
+        public Stamp getStamp() {
+            return stamp;
+        }
+
+        public GuardingNode getGuard() {
+            return guard;
+        }
+
+        public ValueNode getProxifiedInput() {
+            return proxifiedInput;
+        }
+
+        @Override
+        public String toString() {
+            return stamp + " -> " + guard;
+        }
+    }
+
+    @Override
+    public float codeSizeIncrease() {
+        return 1.5f;
+    }
+}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/DominatorConditionalEliminationPhase.java	Fri May 12 13:14:25 2017 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1020 +0,0 @@
-/*
- * Copyright (c) 2015, 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.phases.common;
-
-import java.util.ArrayDeque;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Deque;
-import java.util.Iterator;
-import java.util.List;
-import java.util.function.Function;
-
-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;
-import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.And;
-import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Or;
-import org.graalvm.compiler.core.common.type.IntegerStamp;
-import org.graalvm.compiler.core.common.type.ObjectStamp;
-import org.graalvm.compiler.core.common.type.Stamp;
-import org.graalvm.compiler.core.common.type.StampFactory;
-import org.graalvm.compiler.core.common.type.TypeReference;
-import org.graalvm.compiler.debug.Debug;
-import org.graalvm.compiler.debug.DebugCounter;
-import org.graalvm.compiler.graph.Node;
-import org.graalvm.compiler.graph.NodeMap;
-import org.graalvm.compiler.graph.spi.CanonicalizerTool;
-import org.graalvm.compiler.nodeinfo.InputType;
-import org.graalvm.compiler.nodes.AbstractBeginNode;
-import org.graalvm.compiler.nodes.BeginNode;
-import org.graalvm.compiler.nodes.BinaryOpLogicNode;
-import org.graalvm.compiler.nodes.ConditionAnchorNode;
-import org.graalvm.compiler.nodes.ConstantNode;
-import org.graalvm.compiler.nodes.DeoptimizeNode;
-import org.graalvm.compiler.nodes.DeoptimizingGuard;
-import org.graalvm.compiler.nodes.FixedGuardNode;
-import org.graalvm.compiler.nodes.FixedNode;
-import org.graalvm.compiler.nodes.GuardNode;
-import org.graalvm.compiler.nodes.GuardPhiNode;
-import org.graalvm.compiler.nodes.GuardProxyNode;
-import org.graalvm.compiler.nodes.IfNode;
-import org.graalvm.compiler.nodes.LogicNode;
-import org.graalvm.compiler.nodes.LoopExitNode;
-import org.graalvm.compiler.nodes.ParameterNode;
-import org.graalvm.compiler.nodes.PiNode;
-import org.graalvm.compiler.nodes.ShortCircuitOrNode;
-import org.graalvm.compiler.nodes.StructuredGraph;
-import org.graalvm.compiler.nodes.UnaryOpLogicNode;
-import org.graalvm.compiler.nodes.ValueNode;
-import org.graalvm.compiler.nodes.ValueProxyNode;
-import org.graalvm.compiler.nodes.calc.AndNode;
-import org.graalvm.compiler.nodes.calc.BinaryArithmeticNode;
-import org.graalvm.compiler.nodes.calc.BinaryNode;
-import org.graalvm.compiler.nodes.calc.IntegerEqualsNode;
-import org.graalvm.compiler.nodes.calc.ObjectEqualsNode;
-import org.graalvm.compiler.nodes.calc.PointerEqualsNode;
-import org.graalvm.compiler.nodes.calc.UnaryNode;
-import org.graalvm.compiler.nodes.cfg.Block;
-import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
-import org.graalvm.compiler.nodes.extended.GuardingNode;
-import org.graalvm.compiler.nodes.extended.IntegerSwitchNode;
-import org.graalvm.compiler.nodes.extended.LoadHubNode;
-import org.graalvm.compiler.nodes.extended.ValueAnchorNode;
-import org.graalvm.compiler.nodes.java.LoadFieldNode;
-import org.graalvm.compiler.nodes.java.TypeSwitchNode;
-import org.graalvm.compiler.nodes.spi.NodeWithState;
-import org.graalvm.compiler.nodes.spi.ValueProxy;
-import org.graalvm.compiler.nodes.util.GraphUtil;
-import org.graalvm.compiler.phases.BasePhase;
-import org.graalvm.compiler.phases.common.LoweringPhase.Frame;
-import org.graalvm.compiler.phases.schedule.SchedulePhase;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
-import org.graalvm.util.Pair;
-
-import jdk.vm.ci.meta.JavaConstant;
-import jdk.vm.ci.meta.TriState;
-
-public class DominatorConditionalEliminationPhase extends BasePhase<PhaseContext> {
-
-    private static final DebugCounter counterStampsRegistered = Debug.counter("StampsRegistered");
-    private static final DebugCounter counterStampsFound = Debug.counter("StampsFound");
-    private static final DebugCounter counterIfsKilled = Debug.counter("CE_KilledIfs");
-    private static final DebugCounter counterLFFolded = Debug.counter("ConstantLFFolded");
-    private final boolean fullSchedule;
-
-    public static BasePhase<PhaseContext> create(boolean fullSchedule) {
-        return new NewConditionalEliminationPhase(fullSchedule);
-    }
-
-    public DominatorConditionalEliminationPhase(boolean fullSchedule) {
-        this.fullSchedule = fullSchedule;
-    }
-
-    @Override
-    @SuppressWarnings("try")
-    protected void run(StructuredGraph graph, PhaseContext context) {
-        try (Debug.Scope s = Debug.scope("DominatorConditionalElimination")) {
-            Function<Block, Iterable<? extends Node>> blockToNodes;
-            Function<Node, Block> nodeToBlock;
-            Block startBlock;
-
-            if (fullSchedule) {
-                SchedulePhase schedule = new SchedulePhase(SchedulePhase.SchedulingStrategy.EARLIEST);
-                schedule.apply(graph);
-                ControlFlowGraph cfg = graph.getLastSchedule().getCFG();
-                cfg.computePostdominators();
-                blockToNodes = b -> graph.getLastSchedule().getBlockToNodesMap().get(b);
-                nodeToBlock = n -> graph.getLastSchedule().getNodeToBlockMap().get(n);
-                startBlock = cfg.getStartBlock();
-            } else {
-                ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, true, true);
-                BlockMap<List<FixedNode>> nodes = new BlockMap<>(cfg);
-                for (Block b : cfg.getBlocks()) {
-                    ArrayList<FixedNode> curNodes = new ArrayList<>();
-                    for (FixedNode node : b.getNodes()) {
-                        if (node instanceof AbstractBeginNode || node instanceof FixedGuardNode || node instanceof ConditionAnchorNode || node instanceof IfNode) {
-                            curNodes.add(node);
-                        }
-                    }
-                    nodes.put(b, curNodes);
-                }
-                blockToNodes = b -> nodes.get(b);
-                nodeToBlock = n -> cfg.blockFor(n);
-                startBlock = cfg.getStartBlock();
-            }
-            new Instance(graph, blockToNodes, nodeToBlock, context).processBlock(startBlock);
-        }
-    }
-
-    public static class Instance {
-        protected NodeMap<Info> map;
-        protected Deque<LoopExitNode> loopExits;
-        protected final Function<Block, Iterable<? extends Node>> blockToNodes;
-        protected final Function<Node, Block> nodeToBlock;
-        protected final CanonicalizerTool tool;
-        /**
-         * Tests which may be eliminated because post dominating tests to prove a broader condition.
-         */
-        private Deque<PendingTest> pendingTests;
-
-        public Instance(StructuredGraph graph, Function<Block, Iterable<? extends Node>> blockToNodes,
-                        Function<Node, Block> nodeToBlock, PhaseContext context) {
-            map = graph.createNodeMap();
-            loopExits = new ArrayDeque<>();
-            this.blockToNodes = blockToNodes;
-            this.nodeToBlock = nodeToBlock;
-            pendingTests = new ArrayDeque<>();
-            tool = GraphUtil.getDefaultSimplifier(context.getMetaAccess(), context.getConstantReflection(), context.getConstantFieldProvider(), false, graph.getAssumptions(), graph.getOptions(),
-                            context.getLowerer());
-        }
-
-        public void processBlock(Block startBlock) {
-            LoweringPhase.processBlock(new InstanceFrame(startBlock, null));
-        }
-
-        public class InstanceFrame extends LoweringPhase.Frame<InstanceFrame> {
-            protected List<Runnable> undoOperations = new ArrayList<>();
-
-            public InstanceFrame(Block block, InstanceFrame parent) {
-                super(block, parent);
-            }
-
-            @Override
-            public Frame<?> enter(Block b) {
-                return new InstanceFrame(b, this);
-            }
-
-            @Override
-            public void postprocess() {
-                Debug.log("[Post Processing block %s]", block);
-                undoOperations.forEach(x -> x.run());
-            }
-
-            protected void processConditionAnchor(ConditionAnchorNode node) {
-                tryProveCondition(node.condition(), (guard, result, newInput) -> {
-                    if (result != node.isNegated()) {
-                        rewirePiNodes(node, newInput);
-                        node.replaceAtUsages(guard.asNode());
-                        GraphUtil.unlinkFixedNode(node);
-                        GraphUtil.killWithUnusedFloatingInputs(node);
-                    } else {
-                        ValueAnchorNode valueAnchor = node.graph().add(new ValueAnchorNode(null));
-                        node.replaceAtUsages(valueAnchor);
-                        node.graph().replaceFixedWithFixed(node, valueAnchor);
-                    }
-                    return true;
-                });
-            }
-
-            private void rewirePiNodes(GuardingNode node, ValueProxy newInput) {
-                ValueNode unproxified = GraphUtil.unproxify(newInput);
-                for (Node usage : node.asNode().usages()) {
-                    if (usage instanceof PiNode) {
-                        PiNode piNode = (PiNode) usage;
-                        if (piNode.getOriginalNode() != newInput && GraphUtil.unproxify(piNode.getOriginalNode()) == unproxified) {
-                            piNode.setOriginalNode((ValueNode) newInput.asNode());
-                        }
-                    }
-                }
-            }
-
-            protected void processGuard(GuardNode node) {
-                if (!tryProveGuardCondition(node, node.getCondition(), (guard, result, newInput) -> {
-                    if (result != node.isNegated()) {
-                        rewirePiNodes(node, newInput);
-                        node.replaceAndDelete(guard.asNode());
-                    } else {
-                        DeoptimizeNode deopt = node.graph().add(new DeoptimizeNode(node.getAction(), node.getReason(), node.getSpeculation()));
-                        AbstractBeginNode beginNode = (AbstractBeginNode) node.getAnchor();
-                        FixedNode next = beginNode.next();
-                        beginNode.setNext(deopt);
-                        GraphUtil.killCFG(next);
-                    }
-                    return true;
-                })) {
-                    registerNewCondition(node.getCondition(), node.isNegated(), node);
-                }
-            }
-
-            protected void processFixedGuard(FixedGuardNode node) {
-                if (!tryProveGuardCondition(node, node.condition(), (guard, result, newInput) -> {
-                    if (result != node.isNegated()) {
-                        rewirePiNodes(node, newInput);
-                        node.replaceAtUsages(guard.asNode());
-                        GraphUtil.unlinkFixedNode(node);
-                        GraphUtil.killWithUnusedFloatingInputs(node);
-                    } else {
-                        DeoptimizeNode deopt = node.graph().add(new DeoptimizeNode(node.getAction(), node.getReason(), node.getSpeculation()));
-                        deopt.setStateBefore(node.stateBefore());
-                        node.replaceAtPredecessor(deopt);
-                        GraphUtil.killCFG(node);
-                    }
-                    Debug.log("Kill fixed guard guard");
-                    return true;
-                })) {
-                    registerNewCondition(node.condition(), node.isNegated(), node);
-                }
-            }
-
-            protected void processIf(IfNode node) {
-                tryProveCondition(node.condition(), (guard, result, newInput) -> {
-                    AbstractBeginNode survivingSuccessor = node.getSuccessor(result);
-                    rewirePiNodes(survivingSuccessor, newInput);
-                    survivingSuccessor.replaceAtUsages(InputType.Guard, guard.asNode());
-                    survivingSuccessor.replaceAtPredecessor(null);
-                    node.replaceAtPredecessor(survivingSuccessor);
-                    GraphUtil.killCFG(node);
-                    if (survivingSuccessor instanceof BeginNode) {
-                        undoOperations.add(() -> {
-                            if (survivingSuccessor.isAlive()) {
-                                ((BeginNode) survivingSuccessor).trySimplify();
-                            }
-                        });
-                    }
-                    Debug.log("Kill if");
-                    counterIfsKilled.increment();
-                    return true;
-                });
-            }
-
-            @Override
-            public void preprocess() {
-                Debug.log("[Pre Processing block %s]", block);
-                AbstractBeginNode beginNode = block.getBeginNode();
-                if (beginNode instanceof LoopExitNode && beginNode.isAlive()) {
-                    LoopExitNode loopExitNode = (LoopExitNode) beginNode;
-                    Instance.this.loopExits.push(loopExitNode);
-                    undoOperations.add(() -> loopExits.pop());
-                } else if (block.getDominator() != null && (block.getDominator().getLoopDepth() > block.getLoopDepth() ||
-                                (block.getDominator().getLoopDepth() == block.getLoopDepth() && block.getDominator().getLoop() != block.getLoop()))) {
-                    // We are exiting the loop, but there is not a single loop exit block along our
-                    // dominator tree (e.g., we are a merge of two loop exits).
-                    final NodeMap<Info> oldMap = map;
-                    final Deque<LoopExitNode> oldLoopExits = loopExits;
-                    map = map.graph().createNodeMap();
-                    loopExits = new ArrayDeque<>();
-                    undoOperations.add(() -> {
-                        map = oldMap;
-                        loopExits = oldLoopExits;
-                    });
-                }
-
-                // For now conservatively collect guards only within the same block.
-                pendingTests.clear();
-                for (Node n : blockToNodes.apply(block)) {
-                    if (n.isAlive()) {
-                        processNode(n);
-                    }
-                }
-            }
-
-            protected void processNode(Node node) {
-                if (node instanceof NodeWithState && !(node instanceof GuardingNode)) {
-                    pendingTests.clear();
-                }
-                if (node instanceof AbstractBeginNode) {
-                    processAbstractBegin((AbstractBeginNode) node);
-                } else if (node instanceof FixedGuardNode) {
-                    processFixedGuard((FixedGuardNode) node);
-                } else if (node instanceof GuardNode) {
-                    processGuard((GuardNode) node);
-                } else if (node instanceof ConditionAnchorNode) {
-                    processConditionAnchor((ConditionAnchorNode) node);
-                } else if (node instanceof IfNode) {
-                    processIf((IfNode) node);
-                } else {
-                    return;
-                }
-            }
-
-            protected void registerNewCondition(LogicNode condition, boolean negated, GuardingNode guard) {
-                if (!negated && condition instanceof PointerEqualsNode) {
-                    PointerEqualsNode pe = (PointerEqualsNode) condition;
-                    ValueNode x = pe.getX();
-                    ValueNode y = pe.getY();
-                    if (y.isConstant()) {
-                        JavaConstant constant = y.asJavaConstant();
-                        Stamp succeeding = pe.getSucceedingStampForX(negated, x.stamp(), getSafeStamp(y));
-                        if (succeeding == null && pe instanceof ObjectEqualsNode && guard instanceof FixedGuardNode) {
-                            succeeding = y.stamp();
-                        }
-                        if (succeeding != null) {
-                            if (y.stamp() instanceof ObjectStamp) {
-                                GuardedConstantStamp cos = new GuardedConstantStamp(constant, (ObjectStamp) succeeding);
-                                registerNewStamp(x, cos, guard);
-                                return;
-                            }
-                        }
-                    }
-                }
-                if (condition instanceof UnaryOpLogicNode) {
-                    UnaryOpLogicNode unaryLogicNode = (UnaryOpLogicNode) condition;
-                    Stamp newStamp = unaryLogicNode.getSucceedingStampForValue(negated);
-                    registerNewStamp(unaryLogicNode.getValue(), newStamp, guard);
-                } else if (condition instanceof BinaryOpLogicNode) {
-                    BinaryOpLogicNode binaryOpLogicNode = (BinaryOpLogicNode) condition;
-                    ValueNode x = binaryOpLogicNode.getX();
-                    ValueNode y = binaryOpLogicNode.getY();
-                    if (!x.isConstant()) {
-                        Stamp newStampX = binaryOpLogicNode.getSucceedingStampForX(negated, x.stamp(), getSafeStamp(y));
-                        registerNewStamp(x, newStampX, guard);
-                    }
-
-                    if (!y.isConstant()) {
-                        Stamp newStampY = binaryOpLogicNode.getSucceedingStampForY(negated, getSafeStamp(x), y.stamp());
-                        registerNewStamp(y, newStampY, guard);
-                    }
-                    if (condition instanceof IntegerEqualsNode && guard instanceof DeoptimizingGuard && !negated) {
-                        if (y.isConstant() && x instanceof AndNode) {
-                            AndNode and = (AndNode) x;
-                            if (and.getY() == y) {
-                                /*
-                                 * This 'and' proves something about some of the bits in and.getX().
-                                 * It's equivalent to or'ing in the mask value since those values
-                                 * are known to be set.
-                                 */
-                                BinaryOp<Or> op = ArithmeticOpTable.forStamp(x.stamp()).getOr();
-                                IntegerStamp newStampX = (IntegerStamp) op.foldStamp(and.getX().stamp(), y.stamp());
-                                registerNewStamp(and.getX(), newStampX, guard);
-                            }
-                        }
-                    }
-                }
-                if (guard instanceof DeoptimizingGuard) {
-                    pendingTests.push(new PendingTest(condition, (DeoptimizingGuard) guard));
-                }
-                registerCondition(condition, negated, guard);
-            }
-
-            private Stamp getSafeStamp(ValueNode x) {
-                if (x.isConstant()) {
-                    return x.stamp();
-                }
-                return x.stamp().unrestricted();
-            }
-
-            @SuppressWarnings("try")
-            protected Pair<InfoElement, Stamp> foldFromConstLoadField(LoadFieldNode loadFieldNode, InfoElementProvider info) {
-                ValueNode object = loadFieldNode.object();
-                if (!loadFieldNode.field().isStatic()) {
-                    // look if we got stamp info for the object and return the constant stamp
-                    Pair<InfoElement, Stamp> pair = getConstantObjectStamp(info, object);
-                    if (pair == null) {
-                        pair = recursiveFoldStamp(object, info);
-                    }
-                    if (pair != null) {
-                        Stamp s = pair.getRight();
-                        if (s instanceof GuardedConstantStamp) {
-                            ConstantNode c = tryFoldFromLoadField(loadFieldNode, pair.getRight());
-                            if (c != null) {
-                                counterLFFolded.increment();
-                                if (c.stamp() instanceof ObjectStamp) {
-                                    GuardedConstantStamp cos = new GuardedConstantStamp(c.asJavaConstant(), (ObjectStamp) c.stamp());
-                                    return Pair.create(pair.getLeft(), cos);
-                                }
-                                return Pair.create(pair.getLeft(), c.stamp());
-                            }
-                        }
-                    }
-                }
-                return null;
-            }
-
-            private ConstantNode tryFoldFromLoadField(LoadFieldNode lf, Stamp x) {
-                GuardedConstantStamp cos = (GuardedConstantStamp) x;
-                return lf.asConstant(tool, cos.objectConstant);
-            }
-
-            private Pair<InfoElement, Stamp> getConstantObjectStamp(InfoElementProvider infos, ValueNode n) {
-                for (InfoElement infoElement : infos.getInfoElements(n)) {
-                    Stamp s = infoElement.getStamp();
-                    if (s instanceof GuardedConstantStamp) {
-                        return Pair.create(infoElement, s);
-                    }
-                }
-                return null;
-            }
-
-            Pair<InfoElement, Stamp> recursiveFoldStamp(Node node, InfoElementProvider info) {
-                if (node instanceof LoadFieldNode) {
-                    Pair<InfoElement, Stamp> pair = foldFromConstLoadField((LoadFieldNode) node, info);
-                    if (pair != null) {
-                        return pair;
-                    }
-                }
-                if (node instanceof UnaryNode) {
-                    UnaryNode unary = (UnaryNode) node;
-                    ValueNode value = unary.getValue();
-                    for (InfoElement infoElement : info.getInfoElements(value)) {
-                        Stamp result = unary.foldStamp(infoElement.getStamp());
-                        if (result != null) {
-                            return Pair.create(infoElement, result);
-                        }
-                    }
-                    Pair<InfoElement, Stamp> foldResult = recursiveFoldStamp(value, info);
-                    if (foldResult != null) {
-                        Stamp result = unary.foldStamp(foldResult.getRight());
-                        if (result != null) {
-                            return Pair.create(foldResult.getLeft(), result);
-                        }
-                    }
-                } else if (node instanceof BinaryNode) {
-                    BinaryNode binary = (BinaryNode) node;
-                    ValueNode y = binary.getY();
-                    ValueNode x = binary.getX();
-                    if (y.isConstant()) {
-                        for (InfoElement infoElement : info.getInfoElements(x)) {
-                            Stamp result = binary.foldStamp(infoElement.stamp, y.stamp());
-                            if (result != null) {
-                                return Pair.create(infoElement, result);
-                            }
-                        }
-                        Pair<InfoElement, Stamp> foldResult = recursiveFoldStamp(x, info);
-                        if (foldResult != null) {
-                            Stamp result = binary.foldStamp(foldResult.getRight(), y.stamp());
-                            if (result != null) {
-                                return Pair.create(foldResult.getLeft(), result);
-                            }
-                        }
-                    } else if (x instanceof LoadFieldNode || y instanceof LoadFieldNode) {
-                        boolean useX = x instanceof LoadFieldNode;
-                        Pair<InfoElement, Stamp> foldResult = recursiveFoldStamp(useX ? x : y, info);
-                        if (foldResult != null) {
-                            Stamp result = binary.foldStamp(useX ? foldResult.getRight() : x.stamp(), useX ? y.stamp() : foldResult.getRight());
-                            if (result != null) {
-                                return Pair.create(foldResult.getLeft(), result);
-                            }
-                        }
-                    }
-                }
-                return null;
-            }
-
-            /**
-             * Recursively try to fold stamps within this expression using information from
-             * {@link #getInfoElements(ValueNode)}. It's only safe to use constants and one
-             * {@link InfoElement} otherwise more than one guard would be required.
-             *
-             * @param node
-             * @return the pair of the @{link InfoElement} used and the stamp produced for the whole
-             *         expression
-             */
-            Pair<InfoElement, Stamp> recursiveFoldStampFromInfo(Node node) {
-                return recursiveFoldStamp(node, (value) -> getInfoElements(value));
-            }
-
-            /**
-             * Recursively try to fold stamps within this expression using {@code newStamp} if the
-             * node {@code original} is encountered in the expression. It's only safe to use
-             * constants and the passed in stamp otherwise more than one guard would be required.
-             *
-             * @param node
-             * @param original
-             * @param newStamp
-             * @return the improved stamp or null is nothing could be done
-             */
-            @SuppressWarnings("unchecked")
-            Stamp recursiveFoldStamp(Node node, ValueNode original, Stamp newStamp) {
-                Debug.log("Recursively fold stamp for node %s original %s stamp %s", node, original, newStamp);
-                InfoElement element = new InfoElement(newStamp, null, null);
-                Pair<InfoElement, Stamp> result = recursiveFoldStamp(node, (value) -> value == original ? Collections.singleton(element) : Collections.EMPTY_LIST);
-                if (result != null) {
-                    return result.getRight();
-                }
-                return null;
-            }
-
-            protected boolean foldPendingTest(DeoptimizingGuard thisGuard, ValueNode original, Stamp newStamp, GuardRewirer rewireGuardFunction) {
-                for (PendingTest pending : pendingTests) {
-                    TriState result = TriState.UNKNOWN;
-                    if (pending.condition instanceof UnaryOpLogicNode) {
-                        UnaryOpLogicNode unaryLogicNode = (UnaryOpLogicNode) pending.condition;
-                        if (unaryLogicNode.getValue() == original) {
-                            result = unaryLogicNode.tryFold(newStamp);
-                        }
-                        if (!result.isKnown()) {
-                            Stamp foldResult = recursiveFoldStamp(unaryLogicNode.getValue(), original, newStamp);
-                            if (foldResult != null) {
-                                result = unaryLogicNode.tryFold(foldResult);
-                            }
-                        }
-                    } else if (pending.condition instanceof BinaryOpLogicNode) {
-                        BinaryOpLogicNode binaryOpLogicNode = (BinaryOpLogicNode) pending.condition;
-                        ValueNode x = binaryOpLogicNode.getX();
-                        ValueNode y = binaryOpLogicNode.getY();
-                        if (binaryOpLogicNode.getX() == original) {
-                            result = binaryOpLogicNode.tryFold(newStamp, binaryOpLogicNode.getY().stamp());
-                        } else if (binaryOpLogicNode instanceof IntegerEqualsNode && y.isConstant() && x instanceof AndNode) {
-                            AndNode and = (AndNode) x;
-                            if (and.getY() == y && and.getX() == original) {
-                                BinaryOp<And> andOp = ArithmeticOpTable.forStamp(newStamp).getAnd();
-                                result = binaryOpLogicNode.tryFold(andOp.foldStamp(newStamp, y.stamp()), y.stamp());
-                            }
-                        }
-                        if (!result.isKnown() && y.isConstant()) {
-                            Stamp foldResult = recursiveFoldStamp(x, original, newStamp);
-                            if (foldResult != null) {
-                                result = binaryOpLogicNode.tryFold(foldResult, y.stamp());
-                            }
-                        }
-                    }
-                    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.
-                         */
-                        InputFilter v = new InputFilter(original);
-                        thisGuard.getCondition().applyInputs(v);
-                        if (v.ok && foldGuard(thisGuard, pending.guard, rewireGuardFunction)) {
-                            return true;
-                        }
-                    }
-                }
-                return false;
-            }
-
-            protected boolean foldGuard(DeoptimizingGuard thisGuard, DeoptimizingGuard otherGuard, GuardRewirer rewireGuardFunction) {
-                if (otherGuard.getAction() == thisGuard.getAction() && otherGuard.getReason() == thisGuard.getReason() && otherGuard.getSpeculation() == thisGuard.getSpeculation()) {
-                    LogicNode condition = (LogicNode) thisGuard.getCondition().copyWithInputs();
-                    GuardRewirer rewirer = (guard, result, newInput) -> {
-                        if (rewireGuardFunction.rewire(guard, result, newInput)) {
-                            otherGuard.setCondition(condition, thisGuard.isNegated());
-                            return true;
-                        }
-                        condition.safeDelete();
-                        return false;
-                    };
-                    // Move the later test up
-                    return rewireGuards(otherGuard, !thisGuard.isNegated(), null, rewirer);
-                }
-                return false;
-            }
-
-            protected void registerCondition(LogicNode condition, boolean negated, GuardingNode guard) {
-                registerNewStamp(condition, negated ? StampFactory.contradiction() : StampFactory.tautology(), guard);
-            }
-
-            protected Iterable<InfoElement> getInfoElements(ValueNode proxiedValue) {
-                ValueNode value = GraphUtil.unproxify(proxiedValue);
-                if (value == null) {
-                    return Collections.emptyList();
-                }
-                Info info = map.get(value);
-                if (info == null) {
-                    return Collections.emptyList();
-                } else {
-                    return info.getElements();
-                }
-            }
-
-            protected boolean rewireGuards(GuardingNode guard, boolean result, ValueProxy proxifiedInput, GuardRewirer rewireGuardFunction) {
-                counterStampsFound.increment();
-                return rewireGuardFunction.rewire(proxyGuard(guard), result, proxyValue(guard, proxifiedInput));
-            }
-
-            private Block findBlockForGuard(GuardingNode guard) {
-                Block guardBlock;
-                if (guard instanceof GuardProxyNode) {
-                    GuardProxyNode guardProxyNode = (GuardProxyNode) guard;
-                    guardBlock = nodeToBlock.apply(guardProxyNode.proxyPoint());
-                } else if (guard instanceof GuardPhiNode) {
-                    GuardPhiNode guardPhiNode = (GuardPhiNode) guard;
-                    guardBlock = nodeToBlock.apply(guardPhiNode.merge());
-                } else {
-                    guardBlock = nodeToBlock.apply(guard.asNode());
-                }
-                assert guardBlock != null;
-                return guardBlock;
-            }
-
-            protected ValueProxy proxyValue(GuardingNode guard, ValueProxy value) {
-                ValueProxy proxiedValue = value;
-                if (proxiedValue != null && !Instance.this.loopExits.isEmpty()) {
-                    Block guardBlock = findBlockForGuard(guard);
-                    for (Iterator<LoopExitNode> iter = loopExits.descendingIterator(); iter.hasNext();) {
-                        LoopExitNode loopExitNode = iter.next();
-                        Block loopExitBlock = nodeToBlock.apply(loopExitNode);
-                        if (AbstractControlFlowGraph.dominates(guardBlock, loopExitBlock)) {
-                            Block loopBeginBlock = nodeToBlock.apply(loopExitNode.loopBegin());
-                            if ((guardBlock != loopExitBlock || guard == loopExitBlock.getBeginNode()) && !AbstractControlFlowGraph.dominates(guardBlock, loopBeginBlock) ||
-                                            guardBlock == loopBeginBlock) {
-                                proxiedValue = proxiedValue.asNode().graph().unique(new ValueProxyNode((ValueNode) proxiedValue.asNode(), loopExitNode));
-                            }
-                        }
-                    }
-                }
-                return proxiedValue;
-            }
-
-            protected GuardingNode proxyGuard(GuardingNode guard) {
-                GuardingNode proxiedGuard = guard;
-                if (!Instance.this.loopExits.isEmpty()) {
-                    Block guardBlock = findBlockForGuard(guard);
-                    for (Iterator<LoopExitNode> iter = loopExits.descendingIterator(); iter.hasNext();) {
-                        LoopExitNode loopExitNode = iter.next();
-                        Block loopExitBlock = nodeToBlock.apply(loopExitNode);
-                        if (guardBlock != loopExitBlock && AbstractControlFlowGraph.dominates(guardBlock, loopExitBlock)) {
-                            Block loopBeginBlock = nodeToBlock.apply(loopExitNode.loopBegin());
-                            if (!AbstractControlFlowGraph.dominates(guardBlock, loopBeginBlock) || guardBlock == loopBeginBlock) {
-                                proxiedGuard = proxiedGuard.asNode().graph().unique(new GuardProxyNode(proxiedGuard, loopExitNode));
-                            }
-                        }
-                    }
-                }
-                return proxiedGuard;
-            }
-
-            protected boolean tryProveCondition(LogicNode node, GuardRewirer rewireGuardFunction) {
-                return tryProveGuardCondition(null, node, rewireGuardFunction);
-            }
-
-            protected boolean tryProveGuardCondition(DeoptimizingGuard thisGuard, LogicNode node, GuardRewirer rewireGuardFunction) {
-                for (InfoElement infoElement : getInfoElements(node)) {
-                    Stamp stamp = infoElement.getStamp();
-                    JavaConstant constant = (JavaConstant) stamp.asConstant();
-                    if (constant != null) {
-                        return rewireGuards(infoElement.getGuard(), constant.asBoolean(), infoElement.getProxifiedInput(), rewireGuardFunction);
-                    }
-                }
-                if (node instanceof UnaryOpLogicNode) {
-                    UnaryOpLogicNode unaryLogicNode = (UnaryOpLogicNode) node;
-                    ValueNode value = unaryLogicNode.getValue();
-                    for (InfoElement infoElement : getInfoElements(value)) {
-                        Stamp stamp = infoElement.getStamp();
-                        TriState result = unaryLogicNode.tryFold(stamp);
-                        if (result.isKnown()) {
-                            return rewireGuards(infoElement.getGuard(), result.toBoolean(), infoElement.getProxifiedInput(), rewireGuardFunction);
-                        }
-                    }
-                    Pair<InfoElement, Stamp> foldResult = recursiveFoldStampFromInfo(value);
-                    if (foldResult != null) {
-                        TriState result = unaryLogicNode.tryFold(foldResult.getRight());
-                        if (result.isKnown()) {
-                            return rewireGuards(foldResult.getLeft().getGuard(), result.toBoolean(), foldResult.getLeft().getProxifiedInput(), rewireGuardFunction);
-                        }
-                    }
-                    if (thisGuard != null) {
-                        Stamp newStamp = unaryLogicNode.getSucceedingStampForValue(thisGuard.isNegated());
-                        if (newStamp != null && foldPendingTest(thisGuard, value, newStamp, rewireGuardFunction)) {
-                            return true;
-                        }
-
-                    }
-                } else if (node instanceof BinaryOpLogicNode) {
-                    BinaryOpLogicNode binaryOpLogicNode = (BinaryOpLogicNode) node;
-                    for (InfoElement infoElement : getInfoElements(binaryOpLogicNode)) {
-                        if (infoElement.getStamp().equals(StampFactory.contradiction())) {
-                            return rewireGuards(infoElement.getGuard(), false, infoElement.getProxifiedInput(), rewireGuardFunction);
-                        } else if (infoElement.getStamp().equals(StampFactory.tautology())) {
-                            return rewireGuards(infoElement.getGuard(), true, infoElement.getProxifiedInput(), rewireGuardFunction);
-                        }
-                    }
-
-                    ValueNode x = binaryOpLogicNode.getX();
-                    ValueNode y = binaryOpLogicNode.getY();
-                    for (InfoElement infoElement : getInfoElements(x)) {
-                        TriState result = binaryOpLogicNode.tryFold(infoElement.getStamp(), y.stamp());
-                        if (result.isKnown()) {
-                            return rewireGuards(infoElement.getGuard(), result.toBoolean(), infoElement.getProxifiedInput(), rewireGuardFunction);
-                        }
-                    }
-
-                    if (y.isConstant()) {
-                        Pair<InfoElement, Stamp> foldResult = recursiveFoldStampFromInfo(x);
-                        if (foldResult != null) {
-                            TriState result = binaryOpLogicNode.tryFold(foldResult.getRight(), y.stamp());
-                            if (result.isKnown()) {
-                                return rewireGuards(foldResult.getLeft().getGuard(), result.toBoolean(), foldResult.getLeft().getProxifiedInput(), rewireGuardFunction);
-                            }
-                        }
-                    } else {
-                        for (InfoElement infoElement : getInfoElements(y)) {
-                            TriState result = binaryOpLogicNode.tryFold(x.stamp(), infoElement.getStamp());
-                            if (result.isKnown()) {
-                                return rewireGuards(infoElement.getGuard(), result.toBoolean(), infoElement.getProxifiedInput(), rewireGuardFunction);
-                            }
-                        }
-                    }
-
-                    /*
-                     * For complex expressions involving constants, see if it's possible to fold the
-                     * tests by using stamps one level up in the expression. For instance, (x + n <
-                     * y) might fold if something is known about x and all other values are
-                     * constants. The reason for the constant restriction is that if more than 1
-                     * real value is involved the code might need to adopt multiple guards to have
-                     * proper dependences.
-                     */
-                    if (x instanceof BinaryArithmeticNode<?> && y.isConstant()) {
-                        BinaryArithmeticNode<?> binary = (BinaryArithmeticNode<?>) x;
-                        if (binary.getY().isConstant()) {
-                            for (InfoElement infoElement : getInfoElements(binary.getX())) {
-                                Stamp newStampX = binary.foldStamp(infoElement.getStamp(), binary.getY().stamp());
-                                TriState result = binaryOpLogicNode.tryFold(newStampX, y.stamp());
-                                if (result.isKnown()) {
-                                    return rewireGuards(infoElement.getGuard(), result.toBoolean(), infoElement.getProxifiedInput(), rewireGuardFunction);
-                                }
-                            }
-                        }
-                    }
-                    if (thisGuard != null && binaryOpLogicNode instanceof IntegerEqualsNode && !thisGuard.isNegated()) {
-                        if (y.isConstant() && x instanceof AndNode) {
-                            AndNode and = (AndNode) x;
-                            if (and.getY() == y) {
-                                /*
-                                 * This 'and' proves something about some of the bits in and.getX().
-                                 * It's equivalent to or'ing in the mask value since those values
-                                 * are known to be set.
-                                 */
-                                BinaryOp<Or> op = ArithmeticOpTable.forStamp(x.stamp()).getOr();
-                                IntegerStamp newStampX = (IntegerStamp) op.foldStamp(and.getX().stamp(), y.stamp());
-                                if (foldPendingTest(thisGuard, and.getX(), newStampX, rewireGuardFunction)) {
-                                    return true;
-                                }
-                            }
-                        }
-                    }
-                    if (thisGuard != null) {
-                        if (!x.isConstant()) {
-                            Stamp newStampX = binaryOpLogicNode.getSucceedingStampForX(thisGuard.isNegated(), x.stamp(), getSafeStamp(y));
-                            if (newStampX != null && foldPendingTest(thisGuard, x, newStampX, rewireGuardFunction)) {
-                                return true;
-                            }
-                        }
-                        if (!y.isConstant()) {
-                            Stamp newStampY = binaryOpLogicNode.getSucceedingStampForY(thisGuard.isNegated(), getSafeStamp(x), y.stamp());
-                            if (newStampY != null && foldPendingTest(thisGuard, y, newStampY, rewireGuardFunction)) {
-                                return true;
-                            }
-                        }
-                    }
-                } else if (node instanceof ShortCircuitOrNode) {
-                    final ShortCircuitOrNode shortCircuitOrNode = (ShortCircuitOrNode) node;
-                    if (Instance.this.loopExits.isEmpty()) {
-                        return tryProveCondition(shortCircuitOrNode.getX(), (guard, result, newInput) -> {
-                            if (result == !shortCircuitOrNode.isXNegated()) {
-                                return rewireGuards(guard, true, newInput, rewireGuardFunction);
-                            } else {
-                                return tryProveCondition(shortCircuitOrNode.getY(), (innerGuard, innerResult, innerNewInput) -> {
-                                    if (innerGuard == guard && newInput == innerNewInput) {
-                                        return rewireGuards(guard, innerResult ^ shortCircuitOrNode.isYNegated(), newInput, rewireGuardFunction);
-                                    }
-                                    return false;
-                                });
-                            }
-                        });
-                    }
-                }
-
-                return false;
-            }
-
-            protected void registerNewStamp(ValueNode maybeProxiedValue, Stamp newStamp, GuardingNode guard) {
-                assert maybeProxiedValue != null;
-                assert guard != null;
-                if (newStamp != null) {
-                    ValueNode value = maybeProxiedValue;
-                    ValueProxy proxiedValue = null;
-                    if (value instanceof ValueProxy) {
-                        proxiedValue = (ValueProxy) value;
-                        value = GraphUtil.unproxify(value);
-                    }
-                    Info info = map.get(value);
-                    if (info == null) {
-                        info = new Info();
-                        map.set(value, info);
-                    }
-                    counterStampsRegistered.increment();
-                    final Info finalInfo = info;
-                    Debug.log("\t Saving stamp for node %s stamp %s guarded by %s", value, newStamp, guard == null ? "null" : guard);
-                    finalInfo.pushElement(new InfoElement(newStamp, guard, proxiedValue));
-                    undoOperations.add(() -> finalInfo.popElement());
-                }
-            }
-
-            protected void processAbstractBegin(AbstractBeginNode beginNode) {
-                Node predecessor = beginNode.predecessor();
-                if (predecessor instanceof IfNode) {
-                    IfNode ifNode = (IfNode) predecessor;
-                    boolean negated = (ifNode.falseSuccessor() == beginNode);
-                    LogicNode condition = ifNode.condition();
-                    registerNewCondition(condition, negated, beginNode);
-                } else if (predecessor instanceof TypeSwitchNode) {
-                    TypeSwitchNode typeSwitch = (TypeSwitchNode) predecessor;
-                    processTypeSwitch(beginNode, predecessor, typeSwitch);
-                } else if (predecessor instanceof IntegerSwitchNode) {
-                    IntegerSwitchNode integerSwitchNode = (IntegerSwitchNode) predecessor;
-                    processIntegerSwitch(beginNode, predecessor, integerSwitchNode);
-                }
-            }
-
-            protected void processIntegerSwitch(AbstractBeginNode beginNode, Node predecessor, IntegerSwitchNode integerSwitchNode) {
-                Stamp stamp = null;
-                for (int i = 0; i < integerSwitchNode.keyCount(); i++) {
-                    if (integerSwitchNode.keySuccessor(i) == predecessor) {
-                        if (stamp == null) {
-                            stamp = StampFactory.forConstant(integerSwitchNode.keyAt(i));
-                        } else {
-                            stamp = stamp.meet(StampFactory.forConstant(integerSwitchNode.keyAt(i)));
-                        }
-                    }
-                }
-
-                if (stamp != null) {
-                    registerNewStamp(integerSwitchNode.value(), stamp, beginNode);
-                }
-            }
-
-            protected void processTypeSwitch(AbstractBeginNode beginNode, Node predecessor, TypeSwitchNode typeSwitch) {
-                ValueNode hub = typeSwitch.value();
-                if (hub instanceof LoadHubNode) {
-                    LoadHubNode loadHub = (LoadHubNode) hub;
-                    Stamp stamp = null;
-                    for (int i = 0; i < typeSwitch.keyCount(); i++) {
-                        if (typeSwitch.keySuccessor(i) == predecessor) {
-                            if (stamp == null) {
-                                stamp = StampFactory.objectNonNull(TypeReference.createExactTrusted(typeSwitch.typeAt(i)));
-                            } else {
-                                stamp = stamp.meet(StampFactory.objectNonNull(TypeReference.createExactTrusted(typeSwitch.typeAt(i))));
-                            }
-                        }
-                    }
-                    if (stamp != null) {
-                        registerNewStamp(loadHub.getValue(), stamp, beginNode);
-                    }
-                }
-            }
-        }
-    }
-
-    @FunctionalInterface
-    protected interface InfoElementProvider {
-        Iterable<InfoElement> getInfoElements(ValueNode value);
-    }
-
-    /**
-     * Checks for safe nodes when moving pending tests up.
-     */
-    static class InputFilter extends Node.EdgeVisitor {
-        boolean ok;
-        private ValueNode value;
-
-        InputFilter(ValueNode value) {
-            this.value = value;
-            this.ok = true;
-        }
-
-        @Override
-        public Node apply(Node node, Node curNode) {
-            if (!ok) {
-                // Abort the recursion
-                return curNode;
-            }
-            if (!(curNode instanceof ValueNode)) {
-                ok = false;
-                return curNode;
-            }
-            ValueNode curValue = (ValueNode) curNode;
-            if (curValue.isConstant() || curValue == value || curValue instanceof ParameterNode) {
-                return curNode;
-            }
-            if (curValue instanceof BinaryNode || curValue instanceof UnaryNode) {
-                curValue.applyInputs(this);
-            } else {
-                ok = false;
-            }
-            return curNode;
-        }
-    }
-
-    @FunctionalInterface
-    protected interface GuardRewirer {
-        /**
-         * Called if the condition could be proven to have a constant value ({@code result}) under
-         * {@code guard}.
-         *
-         * @param guard the guard whose result is proven
-         * @param result the known result of the guard
-         * @param newInput new input to pi nodes depending on the new guard
-         * @return whether the transformation could be applied
-         */
-        boolean rewire(GuardingNode guard, boolean result, ValueProxy newInput);
-    }
-
-    protected static class PendingTest {
-        private final LogicNode condition;
-        private final DeoptimizingGuard guard;
-
-        public PendingTest(LogicNode condition, DeoptimizingGuard guard) {
-            this.condition = condition;
-            this.guard = guard;
-        }
-    }
-
-    protected static final class InfoElement {
-        private final Stamp stamp;
-        private final GuardingNode guard;
-        private final ValueProxy proxifiedInput;
-
-        public InfoElement(Stamp stamp, GuardingNode guard, ValueProxy proxifiedInput) {
-            this.stamp = stamp;
-            this.guard = guard;
-            this.proxifiedInput = proxifiedInput;
-        }
-
-        public Stamp getStamp() {
-            return stamp;
-        }
-
-        public GuardingNode getGuard() {
-            return guard;
-        }
-
-        public ValueProxy getProxifiedInput() {
-            return proxifiedInput;
-        }
-
-        @Override
-        public String toString() {
-            return stamp + " -> " + guard;
-        }
-    }
-
-    protected static final class Info {
-        private final ArrayList<InfoElement> infos;
-
-        public Info() {
-            infos = new ArrayList<>();
-        }
-
-        public Iterable<InfoElement> getElements() {
-            return infos;
-        }
-
-        public void pushElement(InfoElement element) {
-            Debug.log(Debug.VERBOSE_LEVEL, "Pushing an info element:%s", element);
-            infos.add(element);
-        }
-
-        public void popElement() {
-            infos.remove(infos.size() - 1);
-        }
-    }
-
-    private static class GuardedConstantStamp extends ObjectStamp {
-        private final JavaConstant objectConstant;
-
-        GuardedConstantStamp(JavaConstant objectConstant, ObjectStamp succeedingStamp) {
-            super(succeedingStamp.type(), succeedingStamp.isExactType(), succeedingStamp.nonNull(), succeedingStamp.alwaysNull());
-            this.objectConstant = objectConstant;
-        }
-
-    }
-
-    @Override
-    public float codeSizeIncrease() {
-        return 1.5f;
-    }
-}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ExpandLogicPhase.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ExpandLogicPhase.java	Fri May 12 13:56:13 2017 -0700
@@ -22,12 +22,15 @@
  */
 package org.graalvm.compiler.phases.common;
 
+import org.graalvm.compiler.core.common.type.FloatStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.graph.Graph;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.nodes.AbstractBeginNode;
 import org.graalvm.compiler.nodes.AbstractMergeNode;
 import org.graalvm.compiler.nodes.BeginNode;
+import org.graalvm.compiler.nodes.ConstantNode;
 import org.graalvm.compiler.nodes.EndNode;
 import org.graalvm.compiler.nodes.IfNode;
 import org.graalvm.compiler.nodes.LogicNode;
@@ -36,6 +39,11 @@
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.calc.ConditionalNode;
+import org.graalvm.compiler.nodes.calc.FloatEqualsNode;
+import org.graalvm.compiler.nodes.calc.FloatLessThanNode;
+import org.graalvm.compiler.nodes.calc.IntegerEqualsNode;
+import org.graalvm.compiler.nodes.calc.IntegerLessThanNode;
+import org.graalvm.compiler.nodes.calc.NormalizeCompareNode;
 import org.graalvm.compiler.phases.Phase;
 
 public class ExpandLogicPhase extends Phase {
@@ -46,7 +54,32 @@
             processBinary(logic);
         }
         assert graph.getNodes(ShortCircuitOrNode.TYPE).isEmpty();
-        graph.setAllowShortCircuitOr(false);
+
+        for (NormalizeCompareNode logic : graph.getNodes(NormalizeCompareNode.TYPE)) {
+            processNormalizeCompareNode(logic);
+        }
+        graph.setAfterExpandLogic();
+    }
+
+    private static void processNormalizeCompareNode(NormalizeCompareNode normalize) {
+        LogicNode equalComp;
+        LogicNode lessComp;
+        StructuredGraph graph = normalize.graph();
+        ValueNode x = normalize.getX();
+        ValueNode y = normalize.getY();
+        if (x.stamp() instanceof FloatStamp) {
+            equalComp = graph.addOrUniqueWithInputs(FloatEqualsNode.create(x, y));
+            lessComp = graph.addOrUniqueWithInputs(FloatLessThanNode.create(x, y, normalize.isUnorderedLess()));
+        } else {
+            equalComp = graph.addOrUniqueWithInputs(IntegerEqualsNode.create(x, y));
+            lessComp = graph.addOrUniqueWithInputs(IntegerLessThanNode.create(x, y));
+        }
+
+        Stamp stamp = normalize.stamp();
+        ConditionalNode equalValue = graph.unique(
+                        new ConditionalNode(equalComp, ConstantNode.forIntegerStamp(stamp, 0, graph), ConstantNode.forIntegerStamp(stamp, 1, graph)));
+        ConditionalNode value = graph.unique(new ConditionalNode(lessComp, ConstantNode.forIntegerStamp(stamp, -1, graph), equalValue));
+        normalize.replaceAtUsagesAndDelete(value);
     }
 
     private static void processBinary(ShortCircuitOrNode binary) {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/FloatingReadPhase.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/FloatingReadPhase.java	Fri May 12 13:56:13 2017 -0700
@@ -22,7 +22,7 @@
  */
 package org.graalvm.compiler.phases.common;
 
-import static org.graalvm.compiler.core.common.LocationIdentity.any;
+import static org.graalvm.api.word.LocationIdentity.any;
 import static org.graalvm.compiler.graph.Graph.NodeEvent.NODE_ADDED;
 import static org.graalvm.compiler.graph.Graph.NodeEvent.ZERO_USAGES;
 
@@ -30,7 +30,7 @@
 import java.util.Iterator;
 import java.util.List;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.core.common.cfg.Loop;
 import org.graalvm.compiler.debug.DebugCloseable;
 import org.graalvm.compiler.graph.Graph.NodeEventScope;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/IterativeConditionalEliminationPhase.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/IterativeConditionalEliminationPhase.java	Fri May 12 13:56:13 2017 -0700
@@ -52,7 +52,7 @@
         int count = 0;
         while (true) {
             try (NodeEventScope nes = graph.trackNodeEvents(listener)) {
-                DominatorConditionalEliminationPhase.create(fullSchedule).apply(graph, context);
+                new ConditionalEliminationPhase(fullSchedule).apply(graph, context);
             }
             if (listener.getNodes().isEmpty()) {
                 break;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/LoweringPhase.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/LoweringPhase.java	Fri May 12 13:56:13 2017 -0700
@@ -35,6 +35,7 @@
 import java.util.Collection;
 import java.util.List;
 
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.debug.DebugCloseable;
@@ -48,6 +49,7 @@
 import org.graalvm.compiler.nodeinfo.NodeInfo;
 import org.graalvm.compiler.nodes.AbstractBeginNode;
 import org.graalvm.compiler.nodes.BeginNode;
+import org.graalvm.compiler.nodes.ControlSinkNode;
 import org.graalvm.compiler.nodes.FixedGuardNode;
 import org.graalvm.compiler.nodes.FixedNode;
 import org.graalvm.compiler.nodes.FixedWithNextNode;
@@ -63,6 +65,7 @@
 import org.graalvm.compiler.nodes.extended.AnchoringNode;
 import org.graalvm.compiler.nodes.extended.GuardedNode;
 import org.graalvm.compiler.nodes.extended.GuardingNode;
+import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
 import org.graalvm.compiler.nodes.spi.Lowerable;
 import org.graalvm.compiler.nodes.spi.LoweringProvider;
 import org.graalvm.compiler.nodes.spi.LoweringTool;
@@ -279,6 +282,43 @@
                 assert postLoweringMark.equals(mark) : graph + ": lowering of " + node + " produced lowerable " + n + " that should have been recursively lowered as it introduces these new nodes: " +
                                 graph.getNewNodes(postLoweringMark).snapshot();
             }
+            if (graph.isAfterFloatingReadPhase() && n instanceof MemoryCheckpoint && !(node instanceof MemoryCheckpoint) && !(node instanceof ControlSinkNode)) {
+                /*
+                 * The lowering introduced a MemoryCheckpoint but the current node isn't a
+                 * checkpoint. This is only OK if the locations involved don't affect the memory
+                 * graph or if the new kill location doesn't connect into the existing graph.
+                 */
+                boolean isAny = false;
+                if (n instanceof MemoryCheckpoint.Single) {
+                    isAny = ((MemoryCheckpoint.Single) n).getLocationIdentity().isAny();
+                } else {
+                    for (LocationIdentity ident : ((MemoryCheckpoint.Multi) n).getLocationIdentities()) {
+                        if (ident.isAny()) {
+                            isAny = true;
+                        }
+                    }
+                }
+                if (isAny && n instanceof FixedWithNextNode) {
+                    /*
+                     * Check if the next kill location leads directly to a ControlSinkNode in the
+                     * new part of the graph. This is a fairly conservative test that could be made
+                     * more general if required.
+                     */
+                    FixedWithNextNode cur = (FixedWithNextNode) n;
+                    while (cur != null && graph.isNew(preLoweringMark, cur)) {
+                        if (cur.next() instanceof ControlSinkNode) {
+                            isAny = false;
+                            break;
+                        }
+                        if (cur.next() instanceof FixedWithNextNode) {
+                            cur = (FixedWithNextNode) cur.next();
+                        } else {
+                            break;
+                        }
+                    }
+                }
+                assert !isAny : node + " " + n;
+            }
         }
         return true;
     }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/NewConditionalEliminationPhase.java	Fri May 12 13:14:25 2017 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1035 +0,0 @@
-/*
- * Copyright (c) 2015, 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.phases.common;
-
-import java.util.ArrayDeque;
-import java.util.Deque;
-import java.util.List;
-
-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;
-import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.And;
-import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Or;
-import org.graalvm.compiler.core.common.type.IntegerStamp;
-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.Debug;
-import org.graalvm.compiler.debug.DebugCloseable;
-import org.graalvm.compiler.debug.DebugCounter;
-import org.graalvm.compiler.graph.Node;
-import org.graalvm.compiler.graph.NodeMap;
-import org.graalvm.compiler.graph.NodeStack;
-import org.graalvm.compiler.graph.spi.CanonicalizerTool;
-import org.graalvm.compiler.nodeinfo.InputType;
-import org.graalvm.compiler.nodes.AbstractBeginNode;
-import org.graalvm.compiler.nodes.AbstractMergeNode;
-import org.graalvm.compiler.nodes.BinaryOpLogicNode;
-import org.graalvm.compiler.nodes.ConditionAnchorNode;
-import org.graalvm.compiler.nodes.DeoptimizeNode;
-import org.graalvm.compiler.nodes.DeoptimizingGuard;
-import org.graalvm.compiler.nodes.EndNode;
-import org.graalvm.compiler.nodes.FixedGuardNode;
-import org.graalvm.compiler.nodes.FixedNode;
-import org.graalvm.compiler.nodes.FixedWithNextNode;
-import org.graalvm.compiler.nodes.GuardNode;
-import org.graalvm.compiler.nodes.IfNode;
-import org.graalvm.compiler.nodes.LogicNode;
-import org.graalvm.compiler.nodes.LoopExitNode;
-import org.graalvm.compiler.nodes.MergeNode;
-import org.graalvm.compiler.nodes.ParameterNode;
-import org.graalvm.compiler.nodes.PiNode;
-import org.graalvm.compiler.nodes.ProxyNode;
-import org.graalvm.compiler.nodes.ShortCircuitOrNode;
-import org.graalvm.compiler.nodes.StructuredGraph;
-import org.graalvm.compiler.nodes.UnaryOpLogicNode;
-import org.graalvm.compiler.nodes.ValueNode;
-import org.graalvm.compiler.nodes.ValuePhiNode;
-import org.graalvm.compiler.nodes.calc.AndNode;
-import org.graalvm.compiler.nodes.calc.BinaryArithmeticNode;
-import org.graalvm.compiler.nodes.calc.BinaryNode;
-import org.graalvm.compiler.nodes.calc.IntegerEqualsNode;
-import org.graalvm.compiler.nodes.calc.UnaryNode;
-import org.graalvm.compiler.nodes.cfg.Block;
-import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
-import org.graalvm.compiler.nodes.extended.GuardingNode;
-import org.graalvm.compiler.nodes.extended.IntegerSwitchNode;
-import org.graalvm.compiler.nodes.extended.LoadHubNode;
-import org.graalvm.compiler.nodes.extended.ValueAnchorNode;
-import org.graalvm.compiler.nodes.java.TypeSwitchNode;
-import org.graalvm.compiler.nodes.spi.NodeWithState;
-import org.graalvm.compiler.nodes.spi.StampInverter;
-import org.graalvm.compiler.nodes.util.GraphUtil;
-import org.graalvm.compiler.phases.BasePhase;
-import org.graalvm.compiler.phases.schedule.SchedulePhase;
-import org.graalvm.compiler.phases.tiers.PhaseContext;
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.Equivalence;
-import org.graalvm.util.MapCursor;
-import org.graalvm.util.Pair;
-
-import jdk.vm.ci.meta.JavaConstant;
-import jdk.vm.ci.meta.TriState;
-
-public class NewConditionalEliminationPhase extends BasePhase<PhaseContext> {
-
-    private static final DebugCounter counterStampsRegistered = Debug.counter("StampsRegistered");
-    private static final DebugCounter counterStampsFound = Debug.counter("StampsFound");
-    private static final DebugCounter counterIfsKilled = Debug.counter("CE_KilledIfs");
-    private static final DebugCounter counterPhiStampsImproved = Debug.counter("CE_ImprovedPhis");
-    private final boolean fullSchedule;
-
-    public NewConditionalEliminationPhase(boolean fullSchedule) {
-        this.fullSchedule = fullSchedule;
-    }
-
-    @Override
-    @SuppressWarnings("try")
-    protected void run(StructuredGraph graph, PhaseContext context) {
-        try (Debug.Scope s = Debug.scope("DominatorConditionalElimination")) {
-            BlockMap<List<Node>> blockToNodes = null;
-            ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, true, true);
-            if (fullSchedule) {
-                cfg.visitDominatorTree(new MoveGuardsUpwards(), graph.hasValueProxies());
-                SchedulePhase.run(graph, SchedulePhase.SchedulingStrategy.EARLIEST, cfg);
-                blockToNodes = graph.getLastSchedule().getBlockToNodesMap();
-            }
-
-            Instance visitor = new Instance(graph, blockToNodes, context);
-            cfg.visitDominatorTree(visitor, graph.hasValueProxies());
-        }
-    }
-
-    public static class MoveGuardsUpwards implements ControlFlowGraph.RecursiveVisitor<Block> {
-
-        Block anchorBlock;
-
-        @Override
-        @SuppressWarnings("try")
-        public Block enter(Block b) {
-            Block oldAnchorBlock = anchorBlock;
-            if (b.getDominator() == null || b.getDominator().getPostdominator() != b) {
-                // New anchor.
-                anchorBlock = b;
-            }
-
-            AbstractBeginNode beginNode = b.getBeginNode();
-            if (beginNode instanceof AbstractMergeNode && anchorBlock != b) {
-                AbstractMergeNode mergeNode = (AbstractMergeNode) beginNode;
-                for (GuardNode guard : mergeNode.guards().snapshot()) {
-                    try (DebugCloseable closeable = guard.withNodeSourcePosition()) {
-                        GuardNode newlyCreatedGuard = new GuardNode(guard.getCondition(), anchorBlock.getBeginNode(), guard.getReason(), guard.getAction(), guard.isNegated(), guard.getSpeculation());
-                        GuardNode newGuard = mergeNode.graph().unique(newlyCreatedGuard);
-                        guard.replaceAndDelete(newGuard);
-                    }
-                }
-            }
-
-            FixedNode endNode = b.getEndNode();
-            if (endNode instanceof IfNode) {
-                IfNode node = (IfNode) endNode;
-
-                // Check if we can move guards upwards.
-                AbstractBeginNode trueSuccessor = node.trueSuccessor();
-                EconomicMap<LogicNode, GuardNode> trueGuards = EconomicMap.create(Equivalence.IDENTITY);
-                for (GuardNode guard : trueSuccessor.guards()) {
-                    LogicNode condition = guard.getCondition();
-                    if (condition.hasMoreThanOneUsage()) {
-                        trueGuards.put(condition, guard);
-                    }
-                }
-
-                if (!trueGuards.isEmpty()) {
-                    for (GuardNode guard : node.falseSuccessor().guards().snapshot()) {
-                        GuardNode otherGuard = trueGuards.get(guard.getCondition());
-                        if (otherGuard != null && guard.isNegated() == otherGuard.isNegated()) {
-                            JavaConstant speculation = otherGuard.getSpeculation();
-                            if (speculation == null) {
-                                speculation = guard.getSpeculation();
-                            } else if (guard.getSpeculation() != null && guard.getSpeculation() != speculation) {
-                                // Cannot optimize due to different speculations.
-                                continue;
-                            }
-                            try (DebugCloseable closeable = guard.withNodeSourcePosition()) {
-                                GuardNode newlyCreatedGuard = new GuardNode(guard.getCondition(), anchorBlock.getBeginNode(), guard.getReason(), guard.getAction(), guard.isNegated(), speculation);
-                                GuardNode newGuard = node.graph().unique(newlyCreatedGuard);
-                                if (otherGuard.isAlive()) {
-                                    otherGuard.replaceAndDelete(newGuard);
-                                }
-                                guard.replaceAndDelete(newGuard);
-                            }
-                        }
-                    }
-                }
-            }
-            return oldAnchorBlock;
-        }
-
-        @Override
-        public void exit(Block b, Block value) {
-            anchorBlock = value;
-        }
-
-    }
-
-    private static final class PhiInfoElement {
-
-        private EconomicMap<EndNode, InfoElement> infoElements;
-
-        public void set(EndNode end, InfoElement infoElement) {
-            if (infoElements == null) {
-                infoElements = EconomicMap.create(Equivalence.IDENTITY);
-            }
-            infoElements.put(end, infoElement);
-        }
-
-        public InfoElement get(EndNode end) {
-            if (infoElements == null) {
-                return null;
-            }
-            return infoElements.get(end);
-        }
-    }
-
-    public static class Instance implements ControlFlowGraph.RecursiveVisitor<Integer> {
-        protected final NodeMap<InfoElement> map;
-        protected final BlockMap<List<Node>> blockToNodes;
-        protected final CanonicalizerTool tool;
-        protected final NodeStack undoOperations;
-        protected final StructuredGraph graph;
-        protected final EconomicMap<MergeNode, EconomicMap<ValuePhiNode, PhiInfoElement>> mergeMaps;
-
-        /**
-         * Tests which may be eliminated because post dominating tests to prove a broader condition.
-         */
-        private Deque<PendingTest> pendingTests;
-
-        public Instance(StructuredGraph graph, BlockMap<List<Node>> blockToNodes, PhaseContext context) {
-            this.graph = graph;
-            this.blockToNodes = blockToNodes;
-            this.undoOperations = new NodeStack();
-            this.map = graph.createNodeMap();
-            pendingTests = new ArrayDeque<>();
-            tool = GraphUtil.getDefaultSimplifier(context.getMetaAccess(), context.getConstantReflection(), context.getConstantFieldProvider(), false, graph.getAssumptions(), graph.getOptions(),
-                            context.getLowerer());
-            mergeMaps = EconomicMap.create();
-        }
-
-        protected void processConditionAnchor(ConditionAnchorNode node) {
-            tryProveCondition(node.condition(), (guard, result, guardedValueStamp, newInput) -> {
-                if (result != node.isNegated()) {
-                    node.replaceAtUsages(guard.asNode());
-                    GraphUtil.unlinkFixedNode(node);
-                    GraphUtil.killWithUnusedFloatingInputs(node);
-                } else {
-                    ValueAnchorNode valueAnchor = node.graph().add(new ValueAnchorNode(null));
-                    node.replaceAtUsages(valueAnchor);
-                    node.graph().replaceFixedWithFixed(node, valueAnchor);
-                }
-                return true;
-            });
-        }
-
-        protected void processGuard(GuardNode node) {
-            if (!tryProveGuardCondition(node, node.getCondition(), (guard, result, guardedValueStamp, newInput) -> {
-                if (result != node.isNegated()) {
-                    node.replaceAndDelete(guard.asNode());
-                } else {
-                    DeoptimizeNode deopt = node.graph().add(new DeoptimizeNode(node.getAction(), node.getReason(), node.getSpeculation()));
-                    AbstractBeginNode beginNode = (AbstractBeginNode) node.getAnchor();
-                    FixedNode next = beginNode.next();
-                    beginNode.setNext(deopt);
-                    GraphUtil.killCFG(next);
-                }
-                return true;
-            })) {
-                registerNewCondition(node.getCondition(), node.isNegated(), node);
-            }
-        }
-
-        protected void processFixedGuard(FixedGuardNode node) {
-            if (!tryProveGuardCondition(node, node.condition(), (guard, result, guardedValueStamp, newInput) -> {
-                if (result != node.isNegated()) {
-                    node.replaceAtUsages(guard.asNode());
-                    GraphUtil.unlinkFixedNode(node);
-                    GraphUtil.killWithUnusedFloatingInputs(node);
-                } else {
-                    DeoptimizeNode deopt = node.graph().add(new DeoptimizeNode(node.getAction(), node.getReason(), node.getSpeculation()));
-                    deopt.setStateBefore(node.stateBefore());
-                    node.replaceAtPredecessor(deopt);
-                    GraphUtil.killCFG(node);
-                }
-                Debug.log("Kill fixed guard guard");
-                return true;
-            })) {
-                registerNewCondition(node.condition(), node.isNegated(), node);
-            }
-        }
-
-        protected void processIf(IfNode node) {
-            tryProveCondition(node.condition(), (guard, result, guardedValueStamp, newInput) -> {
-                AbstractBeginNode survivingSuccessor = node.getSuccessor(result);
-                survivingSuccessor.replaceAtUsages(InputType.Guard, guard.asNode());
-                survivingSuccessor.replaceAtPredecessor(null);
-                node.replaceAtPredecessor(survivingSuccessor);
-                GraphUtil.killCFG(node);
-                counterIfsKilled.increment();
-                return true;
-            });
-        }
-
-        @Override
-        public Integer enter(Block block) {
-            int mark = undoOperations.size();
-            Debug.log("[Pre Processing block %s]", block);
-            // For now conservatively collect guards only within the same block.
-            pendingTests.clear();
-            if (blockToNodes != null) {
-                for (Node n : blockToNodes.get(block)) {
-                    if (n.isAlive()) {
-                        processNode(n);
-                    }
-                }
-            } else {
-                processBlock(block);
-            }
-            return mark;
-        }
-
-        private void processBlock(Block block) {
-            FixedNode n = block.getBeginNode();
-            FixedNode endNode = block.getEndNode();
-            Debug.log("[Processing block %s]", block);
-            while (n != endNode) {
-                if (n.isDeleted() || endNode.isDeleted()) {
-                    // This branch was deleted!
-                    return;
-                }
-                FixedNode next = ((FixedWithNextNode) n).next();
-                processNode(n);
-                n = next;
-            }
-            if (endNode.isAlive()) {
-                processNode(endNode);
-            }
-        }
-
-        @SuppressWarnings("try")
-        protected void processNode(Node node) {
-            try (DebugCloseable closeable = node.withNodeSourcePosition()) {
-                if (node instanceof NodeWithState && !(node instanceof GuardingNode)) {
-                    pendingTests.clear();
-                }
-
-                if (node instanceof MergeNode) {
-                    introducePisForPhis((MergeNode) node);
-                }
-
-                if (node instanceof AbstractBeginNode) {
-                    if (node instanceof LoopExitNode && graph.hasValueProxies()) {
-                        // Condition must not be used down this path.
-                        return;
-                    }
-                    processAbstractBegin((AbstractBeginNode) node);
-                } else if (node instanceof FixedGuardNode) {
-                    processFixedGuard((FixedGuardNode) node);
-                } else if (node instanceof GuardNode) {
-                    processGuard((GuardNode) node);
-                } else if (node instanceof ConditionAnchorNode) {
-                    processConditionAnchor((ConditionAnchorNode) node);
-                } else if (node instanceof IfNode) {
-                    processIf((IfNode) node);
-                } else if (node instanceof EndNode) {
-                    processEnd((EndNode) node);
-                }
-            }
-        }
-
-        private void introducePisForPhis(MergeNode merge) {
-            EconomicMap<ValuePhiNode, PhiInfoElement> mergeMap = this.mergeMaps.get(merge);
-            if (mergeMap != null) {
-                MapCursor<ValuePhiNode, PhiInfoElement> entries = mergeMap.getEntries();
-                while (entries.advance()) {
-                    ValuePhiNode phi = entries.getKey();
-                    PhiInfoElement phiInfoElements = entries.getValue();
-                    Stamp bestPossibleStamp = null;
-                    for (int i = 0; i < phi.valueCount(); ++i) {
-                        ValueNode valueAt = phi.valueAt(i);
-                        Stamp curBestStamp = valueAt.stamp();
-                        InfoElement infoElement = phiInfoElements.get(merge.forwardEndAt(i));
-                        if (infoElement != null) {
-                            curBestStamp = curBestStamp.join(infoElement.getStamp());
-                        }
-
-                        if (bestPossibleStamp == null) {
-                            bestPossibleStamp = curBestStamp;
-                        } else {
-                            bestPossibleStamp = bestPossibleStamp.meet(curBestStamp);
-                        }
-                    }
-
-                    Stamp oldStamp = phi.stamp();
-                    if (oldStamp.tryImproveWith(bestPossibleStamp) != null) {
-
-                        // Need to be careful to not run into stamp update cycles with the iterative
-                        // canonicalization.
-                        boolean allow = false;
-                        if (bestPossibleStamp instanceof ObjectStamp) {
-                            // Always allow object stamps.
-                            allow = true;
-                        } else if (bestPossibleStamp instanceof IntegerStamp) {
-                            IntegerStamp integerStamp = (IntegerStamp) bestPossibleStamp;
-                            IntegerStamp oldIntegerStamp = (IntegerStamp) oldStamp;
-                            if (integerStamp.isPositive() != oldIntegerStamp.isPositive()) {
-                                allow = true;
-                            } else if (integerStamp.isNegative() != oldIntegerStamp.isNegative()) {
-                                allow = true;
-                            } else if (integerStamp.isStrictlyPositive() != oldIntegerStamp.isStrictlyPositive()) {
-                                allow = true;
-                            } else if (integerStamp.isStrictlyNegative() != oldIntegerStamp.isStrictlyNegative()) {
-                                allow = true;
-                            } else if (integerStamp.asConstant() != null) {
-                                allow = true;
-                            } else if (oldStamp.isUnrestricted()) {
-                                allow = true;
-                            }
-                        } else {
-                            allow = (bestPossibleStamp.asConstant() != null);
-                        }
-
-                        if (allow) {
-                            ValuePhiNode newPhi = graph.addWithoutUnique(new ValuePhiNode(bestPossibleStamp, merge));
-                            for (int i = 0; i < phi.valueCount(); ++i) {
-                                ValueNode valueAt = phi.valueAt(i);
-                                if (bestPossibleStamp.meet(valueAt.stamp()).equals(bestPossibleStamp)) {
-                                    // Pi not required here.
-                                } else {
-                                    InfoElement infoElement = phiInfoElements.get(merge.forwardEndAt(i));
-                                    assert infoElement != null;
-                                    Stamp curBestStamp = infoElement.getStamp();
-                                    ValueNode input = infoElement.getProxifiedInput();
-                                    if (input == null) {
-                                        input = valueAt;
-                                    }
-                                    ValueNode valueNode = graph.maybeAddOrUnique(PiNode.create(input, curBestStamp, (ValueNode) infoElement.guard));
-                                    valueAt = valueNode;
-                                }
-                                newPhi.addInput(valueAt);
-                            }
-                            counterPhiStampsImproved.increment();
-                            phi.replaceAtUsagesAndDelete(newPhi);
-                        }
-                    }
-                }
-            }
-        }
-
-        private void processEnd(EndNode end) {
-            AbstractMergeNode abstractMerge = end.merge();
-            if (abstractMerge instanceof MergeNode) {
-                MergeNode merge = (MergeNode) abstractMerge;
-
-                EconomicMap<ValuePhiNode, PhiInfoElement> mergeMap = this.mergeMaps.get(merge);
-                for (ValuePhiNode phi : merge.valuePhis()) {
-                    ValueNode valueAt = phi.valueAt(end);
-                    InfoElement infoElement = this.getInfoElements(valueAt);
-                    while (infoElement != null) {
-                        Stamp newStamp = infoElement.getStamp();
-                        if (phi.stamp().tryImproveWith(newStamp) != null) {
-                            if (mergeMap == null) {
-                                mergeMap = EconomicMap.create();
-                                mergeMaps.put(merge, mergeMap);
-                            }
-
-                            PhiInfoElement phiInfoElement = mergeMap.get(phi);
-                            if (phiInfoElement == null) {
-                                phiInfoElement = new PhiInfoElement();
-                                mergeMap.put(phi, phiInfoElement);
-                            }
-
-                            phiInfoElement.set(end, infoElement);
-                            break;
-                        }
-                        infoElement = nextElement(infoElement);
-                    }
-                }
-            }
-        }
-
-        protected void registerNewCondition(LogicNode condition, boolean negated, GuardingNode guard) {
-            if (condition instanceof UnaryOpLogicNode) {
-                UnaryOpLogicNode unaryLogicNode = (UnaryOpLogicNode) condition;
-                ValueNode value = unaryLogicNode.getValue();
-                if (maybeMultipleUsages(value)) {
-                    Stamp newStamp = unaryLogicNode.getSucceedingStampForValue(negated);
-                    registerNewStamp(value, newStamp, guard);
-                }
-            } else if (condition instanceof BinaryOpLogicNode) {
-                BinaryOpLogicNode binaryOpLogicNode = (BinaryOpLogicNode) condition;
-                ValueNode x = binaryOpLogicNode.getX();
-                ValueNode y = binaryOpLogicNode.getY();
-                if (!x.isConstant() && maybeMultipleUsages(x)) {
-                    Stamp newStampX = binaryOpLogicNode.getSucceedingStampForX(negated, getSafeStamp(x), getOtherSafeStamp(y));
-                    registerNewStamp(x, newStampX, guard);
-                }
-
-                if (!y.isConstant() && maybeMultipleUsages(y)) {
-                    Stamp newStampY = binaryOpLogicNode.getSucceedingStampForY(negated, getOtherSafeStamp(x), getSafeStamp(y));
-                    registerNewStamp(y, newStampY, guard);
-                }
-
-                if (condition instanceof IntegerEqualsNode && guard instanceof DeoptimizingGuard && !negated) {
-                    if (y.isConstant() && x instanceof AndNode) {
-                        AndNode and = (AndNode) x;
-                        ValueNode andX = and.getX();
-                        if (and.getY() == y && maybeMultipleUsages(andX)) {
-                            /*
-                             * This 'and' proves something about some of the bits in and.getX().
-                             * It's equivalent to or'ing in the mask value since those values are
-                             * known to be set.
-                             */
-                            BinaryOp<Or> op = ArithmeticOpTable.forStamp(x.stamp()).getOr();
-                            IntegerStamp newStampX = (IntegerStamp) op.foldStamp(getSafeStamp(andX), getOtherSafeStamp(y));
-                            registerNewStamp(andX, newStampX, guard);
-                        }
-                    }
-                }
-            }
-            if (guard instanceof DeoptimizingGuard) {
-                pendingTests.push(new PendingTest(condition, (DeoptimizingGuard) guard));
-            }
-            registerCondition(condition, negated, guard);
-        }
-
-        Pair<InfoElement, Stamp> recursiveFoldStamp(Node node) {
-            if (node instanceof UnaryNode) {
-                UnaryNode unary = (UnaryNode) node;
-                ValueNode value = unary.getValue();
-                InfoElement infoElement = getInfoElements(value);
-                while (infoElement != null) {
-                    Stamp result = unary.foldStamp(infoElement.getStamp());
-                    if (result != null) {
-                        return Pair.create(infoElement, result);
-                    }
-                    infoElement = nextElement(infoElement);
-                }
-            } else if (node instanceof BinaryNode) {
-                BinaryNode binary = (BinaryNode) node;
-                ValueNode y = binary.getY();
-                ValueNode x = binary.getX();
-                if (y.isConstant()) {
-                    InfoElement infoElement = getInfoElements(x);
-                    while (infoElement != null) {
-                        Stamp result = binary.foldStamp(infoElement.stamp, y.stamp());
-                        if (result != null) {
-                            return Pair.create(infoElement, result);
-                        }
-                        infoElement = nextElement(infoElement);
-                    }
-                }
-            }
-            return null;
-        }
-
-        /**
-         * Get the stamp that may be used for the value for which we are registering the condition.
-         * We may directly use the stamp here without restriction, because any later lookup of the
-         * registered info elements is in the same chain of pi nodes.
-         */
-        private static Stamp getSafeStamp(ValueNode x) {
-            return x.stamp();
-        }
-
-        /**
-         * We can only use the stamp of a second value involved in the condition if we are sure that
-         * we are not implicitly creating a dependency on a pi node that is responsible for that
-         * stamp. For now, we are conservatively only using the stamps of constants. Under certain
-         * circumstances, we may also be able to use the stamp of the value after skipping pi nodes
-         * (e.g., the stamp of a parameter after inlining, or the stamp of a fixed node that can
-         * never be replaced with a pi node via canonicalization).
-         */
-        private static Stamp getOtherSafeStamp(ValueNode x) {
-            if (x.isConstant()) {
-                return x.stamp();
-            }
-            return x.stamp().unrestricted();
-        }
-
-        /**
-         * Recursively try to fold stamps within this expression using information from
-         * {@link #getInfoElements(ValueNode)}. It's only safe to use constants and one
-         * {@link InfoElement} otherwise more than one guard would be required.
-         *
-         * @param node
-         * @return the pair of the @{link InfoElement} used and the stamp produced for the whole
-         *         expression
-         */
-        Pair<InfoElement, Stamp> recursiveFoldStampFromInfo(Node node) {
-            return recursiveFoldStamp(node);
-        }
-
-        protected boolean foldPendingTest(DeoptimizingGuard thisGuard, ValueNode original, Stamp newStamp, GuardRewirer rewireGuardFunction) {
-            for (PendingTest pending : pendingTests) {
-                TriState result = TriState.UNKNOWN;
-                if (pending.condition instanceof UnaryOpLogicNode) {
-                    UnaryOpLogicNode unaryLogicNode = (UnaryOpLogicNode) pending.condition;
-                    if (unaryLogicNode.getValue() == original) {
-                        result = unaryLogicNode.tryFold(newStamp);
-                    }
-                } else if (pending.condition instanceof BinaryOpLogicNode) {
-                    BinaryOpLogicNode binaryOpLogicNode = (BinaryOpLogicNode) pending.condition;
-                    ValueNode x = binaryOpLogicNode.getX();
-                    ValueNode y = binaryOpLogicNode.getY();
-                    if (x == original) {
-                        result = binaryOpLogicNode.tryFold(newStamp, getOtherSafeStamp(y));
-                    } else if (y == original) {
-                        result = binaryOpLogicNode.tryFold(getOtherSafeStamp(x), newStamp);
-                    } else if (binaryOpLogicNode instanceof IntegerEqualsNode && y.isConstant() && x instanceof AndNode) {
-                        AndNode and = (AndNode) x;
-                        if (and.getY() == y && and.getX() == original) {
-                            BinaryOp<And> andOp = ArithmeticOpTable.forStamp(newStamp).getAnd();
-                            result = binaryOpLogicNode.tryFold(andOp.foldStamp(newStamp, getOtherSafeStamp(y)), getOtherSafeStamp(y));
-                        }
-                    }
-                }
-                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.
-                     */
-                    InputFilter v = new InputFilter(original);
-                    thisGuard.getCondition().applyInputs(v);
-                    if (v.ok && foldGuard(thisGuard, pending.guard, newStamp, rewireGuardFunction)) {
-                        return true;
-                    }
-                }
-            }
-            return false;
-        }
-
-        protected boolean foldGuard(DeoptimizingGuard thisGuard, DeoptimizingGuard otherGuard, Stamp guardedValueStamp, GuardRewirer rewireGuardFunction) {
-            if (otherGuard.getAction() == thisGuard.getAction() && otherGuard.getSpeculation() == thisGuard.getSpeculation()) {
-                LogicNode condition = (LogicNode) thisGuard.getCondition().copyWithInputs();
-                GuardRewirer rewirer = (guard, result, innerGuardedValueStamp, newInput) -> {
-                    if (rewireGuardFunction.rewire(guard, result, innerGuardedValueStamp, newInput)) {
-                        otherGuard.setCondition(condition, thisGuard.isNegated());
-                        return true;
-                    }
-                    condition.safeDelete();
-                    return false;
-                };
-                // Move the later test up
-                return rewireGuards(otherGuard, !thisGuard.isNegated(), null, guardedValueStamp, rewirer);
-            }
-            return false;
-        }
-
-        protected void registerCondition(LogicNode condition, boolean negated, GuardingNode guard) {
-            if (condition.getUsageCount() > 1) {
-                registerNewStamp(condition, negated ? StampFactory.contradiction() : StampFactory.tautology(), guard);
-            }
-        }
-
-        protected InfoElement getInfoElements(ValueNode proxiedValue) {
-            ValueNode value = GraphUtil.skipPi(proxiedValue);
-            if (value == null) {
-                return null;
-            }
-            return map.getAndGrow(value);
-        }
-
-        protected boolean rewireGuards(GuardingNode guard, boolean result, ValueNode proxifiedInput, Stamp guardedValueStamp, GuardRewirer rewireGuardFunction) {
-            counterStampsFound.increment();
-            return rewireGuardFunction.rewire(guard, result, guardedValueStamp, proxifiedInput);
-        }
-
-        protected boolean tryProveCondition(LogicNode node, GuardRewirer rewireGuardFunction) {
-            return tryProveGuardCondition(null, node, rewireGuardFunction);
-        }
-
-        private InfoElement nextElement(InfoElement current) {
-            InfoElement parent = current.getParent();
-            if (parent != null) {
-                return parent;
-            } else {
-                ValueNode proxifiedInput = current.getProxifiedInput();
-                if (proxifiedInput instanceof PiNode) {
-                    PiNode piNode = (PiNode) proxifiedInput;
-                    return getInfoElements(piNode.getOriginalNode());
-                }
-            }
-            return null;
-        }
-
-        protected boolean tryProveGuardCondition(DeoptimizingGuard thisGuard, LogicNode node, GuardRewirer rewireGuardFunction) {
-            InfoElement infoElement = getInfoElements(node);
-            if (infoElement != null) {
-                assert infoElement.getStamp() == StampFactory.tautology() || infoElement.getStamp() == StampFactory.contradiction();
-                // No proxified input and stamp required.
-                return rewireGuards(infoElement.getGuard(), infoElement.getStamp() == StampFactory.tautology(), null, null, rewireGuardFunction);
-            }
-            if (node instanceof UnaryOpLogicNode) {
-                UnaryOpLogicNode unaryLogicNode = (UnaryOpLogicNode) node;
-                ValueNode value = unaryLogicNode.getValue();
-                infoElement = getInfoElements(value);
-                while (infoElement != null) {
-                    Stamp stamp = infoElement.getStamp();
-                    TriState result = unaryLogicNode.tryFold(stamp);
-                    if (result.isKnown()) {
-                        return rewireGuards(infoElement.getGuard(), result.toBoolean(), infoElement.getProxifiedInput(), infoElement.getStamp(), rewireGuardFunction);
-                    }
-                    infoElement = nextElement(infoElement);
-                }
-                Pair<InfoElement, Stamp> foldResult = recursiveFoldStampFromInfo(value);
-                if (foldResult != null) {
-                    TriState result = unaryLogicNode.tryFold(foldResult.getRight());
-                    if (result.isKnown()) {
-                        return rewireGuards(foldResult.getLeft().getGuard(), result.toBoolean(), foldResult.getLeft().getProxifiedInput(), foldResult.getRight(), rewireGuardFunction);
-                    }
-                }
-                if (thisGuard != null) {
-                    Stamp newStamp = unaryLogicNode.getSucceedingStampForValue(thisGuard.isNegated());
-                    if (newStamp != null && foldPendingTest(thisGuard, value, newStamp, rewireGuardFunction)) {
-                        return true;
-                    }
-
-                }
-            } 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);
-                while (infoElement != null) {
-                    TriState result = binaryOpLogicNode.tryFold(infoElement.getStamp(), y.stamp());
-                    if (result.isKnown()) {
-                        return rewireGuards(infoElement.getGuard(), result.toBoolean(), infoElement.getProxifiedInput(), infoElement.getStamp(), rewireGuardFunction);
-                    }
-                    infoElement = nextElement(infoElement);
-                }
-
-                if (y.isConstant()) {
-                    Pair<InfoElement, Stamp> foldResult = recursiveFoldStampFromInfo(x);
-                    if (foldResult != null) {
-                        TriState result = binaryOpLogicNode.tryFold(foldResult.getRight(), y.stamp());
-                        if (result.isKnown()) {
-                            return rewireGuards(foldResult.getLeft().getGuard(), result.toBoolean(), foldResult.getLeft().getProxifiedInput(), foldResult.getRight(), rewireGuardFunction);
-                        }
-                    }
-                } else {
-                    infoElement = getInfoElements(y);
-                    while (infoElement != null) {
-                        TriState result = binaryOpLogicNode.tryFold(x.stamp(), infoElement.getStamp());
-                        if (result.isKnown()) {
-                            return rewireGuards(infoElement.getGuard(), result.toBoolean(), infoElement.getProxifiedInput(), infoElement.getStamp(), rewireGuardFunction);
-                        }
-                        infoElement = nextElement(infoElement);
-                    }
-                }
-
-                /*
-                 * For complex expressions involving constants, see if it's possible to fold the
-                 * tests by using stamps one level up in the expression. For instance, (x + n < y)
-                 * might fold if something is known about x and all other values are constants. The
-                 * reason for the constant restriction is that if more than 1 real value is involved
-                 * the code might need to adopt multiple guards to have proper dependences.
-                 */
-                if (x instanceof BinaryArithmeticNode<?> && y.isConstant()) {
-                    BinaryArithmeticNode<?> binary = (BinaryArithmeticNode<?>) x;
-                    if (binary.getY().isConstant()) {
-                        infoElement = getInfoElements(binary.getX());
-                        while (infoElement != null) {
-                            Stamp newStampX = binary.foldStamp(infoElement.getStamp(), binary.getY().stamp());
-                            TriState result = binaryOpLogicNode.tryFold(newStampX, y.stamp());
-                            if (result.isKnown()) {
-                                return rewireGuards(infoElement.getGuard(), result.toBoolean(), infoElement.getProxifiedInput(), newStampX, rewireGuardFunction);
-                            }
-                            infoElement = nextElement(infoElement);
-                        }
-                    }
-                }
-
-                if (thisGuard != null && binaryOpLogicNode instanceof IntegerEqualsNode && !thisGuard.isNegated()) {
-                    if (y.isConstant() && x instanceof AndNode) {
-                        AndNode and = (AndNode) x;
-                        if (and.getY() == y) {
-                            /*
-                             * This 'and' proves something about some of the bits in and.getX().
-                             * It's equivalent to or'ing in the mask value since those values are
-                             * known to be set.
-                             */
-                            BinaryOp<Or> op = ArithmeticOpTable.forStamp(x.stamp()).getOr();
-                            IntegerStamp newStampX = (IntegerStamp) op.foldStamp(getSafeStamp(and.getX()), getOtherSafeStamp(y));
-                            if (foldPendingTest(thisGuard, and.getX(), newStampX, rewireGuardFunction)) {
-                                return true;
-                            }
-                        }
-                    }
-                }
-
-                if (thisGuard != null) {
-                    if (!x.isConstant()) {
-                        Stamp newStampX = binaryOpLogicNode.getSucceedingStampForX(thisGuard.isNegated(), getSafeStamp(x), getOtherSafeStamp(y));
-                        if (newStampX != null && foldPendingTest(thisGuard, x, newStampX, rewireGuardFunction)) {
-                            return true;
-                        }
-                    }
-                    if (!y.isConstant()) {
-                        Stamp newStampY = binaryOpLogicNode.getSucceedingStampForY(thisGuard.isNegated(), getOtherSafeStamp(x), getSafeStamp(y));
-                        if (newStampY != null && foldPendingTest(thisGuard, y, newStampY, rewireGuardFunction)) {
-                            return true;
-                        }
-                    }
-                }
-            } else if (node instanceof ShortCircuitOrNode) {
-                final ShortCircuitOrNode shortCircuitOrNode = (ShortCircuitOrNode) node;
-                return tryProveCondition(shortCircuitOrNode.getX(), (guard, result, guardedValueStamp, newInput) -> {
-                    if (result == !shortCircuitOrNode.isXNegated()) {
-                        return rewireGuards(guard, true, newInput, guardedValueStamp, rewireGuardFunction);
-                    } else {
-                        return tryProveCondition(shortCircuitOrNode.getY(), (innerGuard, innerResult, innerGuardedValueStamp, innerNewInput) -> {
-                            ValueNode proxifiedInput = newInput;
-                            if (proxifiedInput == null) {
-                                proxifiedInput = innerNewInput;
-                            } else if (innerNewInput != null) {
-                                if (innerNewInput != newInput) {
-                                    // Cannot canonicalize due to different proxied inputs.
-                                    return false;
-                                }
-                            }
-                            // Can only canonicalize if the guards are equal.
-                            if (innerGuard == guard) {
-                                return rewireGuards(guard, innerResult ^ shortCircuitOrNode.isYNegated(), proxifiedInput, guardedValueStamp, rewireGuardFunction);
-                            }
-                            return false;
-                        });
-                    }
-                });
-            }
-
-            return false;
-        }
-
-        protected void registerNewStamp(ValueNode maybeProxiedValue, Stamp newStamp, GuardingNode guard) {
-            assert maybeProxiedValue != null;
-            assert guard != null;
-            if (newStamp != null) {
-                ValueNode value = maybeProxiedValue;
-                Stamp stamp = newStamp;
-                ValueNode proxiedValue = null;
-                if (value instanceof PiNode) {
-                    proxiedValue = value;
-                }
-                do {
-                    counterStampsRegistered.increment();
-                    Debug.log("\t Saving stamp for node %s stamp %s guarded by %s", value, stamp, guard);
-                    assert value instanceof LogicNode || stamp.isCompatible(value.stamp()) : stamp + " vs. " + value.stamp() + " (" + value + ")";
-                    map.setAndGrow(value, new InfoElement(stamp, guard, proxiedValue, map.getAndGrow(value)));
-                    undoOperations.push(value);
-                    if (value instanceof StampInverter) {
-                        StampInverter stampInverter = (StampInverter) value;
-                        value = stampInverter.getValue();
-                        stamp = stampInverter.invertStamp(stamp);
-                    } else {
-                        value = null;
-                        stamp = null;
-                    }
-                } while (value != null && stamp != null);
-            }
-        }
-
-        protected void processAbstractBegin(AbstractBeginNode beginNode) {
-            Node predecessor = beginNode.predecessor();
-            if (predecessor instanceof IfNode) {
-                IfNode ifNode = (IfNode) predecessor;
-                boolean negated = (ifNode.falseSuccessor() == beginNode);
-                LogicNode condition = ifNode.condition();
-                registerNewCondition(condition, negated, beginNode);
-            } else if (predecessor instanceof TypeSwitchNode) {
-                TypeSwitchNode typeSwitch = (TypeSwitchNode) predecessor;
-                processTypeSwitch(beginNode, typeSwitch);
-            } else if (predecessor instanceof IntegerSwitchNode) {
-                IntegerSwitchNode integerSwitchNode = (IntegerSwitchNode) predecessor;
-                processIntegerSwitch(beginNode, integerSwitchNode);
-            }
-        }
-
-        private static boolean maybeMultipleUsages(ValueNode value) {
-            if (value.hasMoreThanOneUsage()) {
-                return true;
-            } else {
-                return value instanceof ProxyNode;
-            }
-        }
-
-        protected void processIntegerSwitch(AbstractBeginNode beginNode, IntegerSwitchNode integerSwitchNode) {
-            ValueNode value = integerSwitchNode.value();
-            if (maybeMultipleUsages(value)) {
-                Stamp stamp = integerSwitchNode.getValueStampForSuccessor(beginNode);
-                if (stamp != null) {
-                    registerNewStamp(value, stamp, beginNode);
-                }
-            }
-        }
-
-        protected void processTypeSwitch(AbstractBeginNode beginNode, TypeSwitchNode typeSwitch) {
-            ValueNode hub = typeSwitch.value();
-            if (hub instanceof LoadHubNode) {
-                LoadHubNode loadHub = (LoadHubNode) hub;
-                ValueNode value = loadHub.getValue();
-                if (maybeMultipleUsages(value)) {
-                    Stamp stamp = typeSwitch.getValueStampForSuccessor(beginNode);
-                    if (stamp != null) {
-                        registerNewStamp(value, stamp, beginNode);
-                    }
-                }
-            }
-        }
-
-        @Override
-        public void exit(Block b, Integer state) {
-            int mark = state;
-            while (undoOperations.size() > mark) {
-                Node node = undoOperations.pop();
-                if (node.isAlive()) {
-                    map.set(node, map.get(node).getParent());
-                }
-            }
-        }
-    }
-
-    @FunctionalInterface
-    protected interface InfoElementProvider {
-        Iterable<InfoElement> getInfoElements(ValueNode value);
-    }
-
-    /**
-     * Checks for safe nodes when moving pending tests up.
-     */
-    static class InputFilter extends Node.EdgeVisitor {
-        boolean ok;
-        private ValueNode value;
-
-        InputFilter(ValueNode value) {
-            this.value = value;
-            this.ok = true;
-        }
-
-        @Override
-        public Node apply(Node node, Node curNode) {
-            if (!ok) {
-                // Abort the recursion
-                return curNode;
-            }
-            if (!(curNode instanceof ValueNode)) {
-                ok = false;
-                return curNode;
-            }
-            ValueNode curValue = (ValueNode) curNode;
-            if (curValue.isConstant() || curValue == value || curValue instanceof ParameterNode) {
-                return curNode;
-            }
-            if (curValue instanceof BinaryNode || curValue instanceof UnaryNode) {
-                curValue.applyInputs(this);
-            } else {
-                ok = false;
-            }
-            return curNode;
-        }
-    }
-
-    @FunctionalInterface
-    protected interface GuardRewirer {
-        /**
-         * Called if the condition could be proven to have a constant value ({@code result}) under
-         * {@code guard}.
-         *
-         * @param guard the guard whose result is proven
-         * @param result the known result of the guard
-         * @param newInput new input to pi nodes depending on the new guard
-         * @return whether the transformation could be applied
-         */
-        boolean rewire(GuardingNode guard, boolean result, Stamp guardedValueStamp, ValueNode newInput);
-    }
-
-    protected static class PendingTest {
-        private final LogicNode condition;
-        private final DeoptimizingGuard guard;
-
-        public PendingTest(LogicNode condition, DeoptimizingGuard guard) {
-            this.condition = condition;
-            this.guard = guard;
-        }
-    }
-
-    protected static final class InfoElement {
-        private final Stamp stamp;
-        private final GuardingNode guard;
-        private final ValueNode proxifiedInput;
-        private final InfoElement parent;
-
-        public InfoElement(Stamp stamp, GuardingNode guard, ValueNode proxifiedInput, InfoElement parent) {
-            this.stamp = stamp;
-            this.guard = guard;
-            this.proxifiedInput = proxifiedInput;
-            this.parent = parent;
-        }
-
-        public InfoElement getParent() {
-            return parent;
-        }
-
-        public Stamp getStamp() {
-            return stamp;
-        }
-
-        public GuardingNode getGuard() {
-            return guard;
-        }
-
-        public ValueNode getProxifiedInput() {
-            return proxifiedInput;
-        }
-
-        @Override
-        public String toString() {
-            return stamp + " -> " + guard;
-        }
-    }
-
-    @Override
-    public float codeSizeIncrease() {
-        return 1.5f;
-    }
-}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/InliningUtil.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/InliningUtil.java	Fri May 12 13:56:13 2017 -0700
@@ -214,7 +214,8 @@
             sb.append(methodName(frameState.outerFrameState(), frameState.outerFrameState().bci));
             sb.append("->");
         }
-        sb.append(frameState.getMethod().format("%h.%n"));
+        ResolvedJavaMethod method = frameState.getMethod();
+        sb.append(method != null ? method.format("%h.%n") : "?");
         sb.append("@").append(bci);
         return sb.toString();
     }
@@ -290,6 +291,7 @@
 
             ArrayList<Node> nodes = new ArrayList<>(inlineGraph.getNodes().count());
             ArrayList<ReturnNode> returnNodes = new ArrayList<>(4);
+            ArrayList<InvokeNode> partialIntrinsicExits = new ArrayList<>();
             UnwindNode unwindNode = null;
             final StartNode entryPointNode = inlineGraph.start();
             FixedNode firstCFGNode = entryPointNode.next();
@@ -303,6 +305,15 @@
                     nodes.add(node);
                     if (node instanceof ReturnNode) {
                         returnNodes.add((ReturnNode) node);
+                    } else if (node instanceof InvokeNode) {
+                        InvokeNode invokeInInlineGraph = (InvokeNode) node;
+                        if (invokeInInlineGraph.bci() == BytecodeFrame.UNKNOWN_BCI) {
+                            ResolvedJavaMethod target1 = invoke.callTarget().targetMethod();
+                            ResolvedJavaMethod target2 = invokeInInlineGraph.callTarget().targetMethod();
+                            assert target1.equals(target2) : String.format("invoke in inlined method expected to be partial intrinsic exit (i.e., call to %s), not a call to %s",
+                                            target1.format("%H.%n(%p)"), target2.format("%H.%n(%p)"));
+                            partialIntrinsicExits.add(invokeInInlineGraph);
+                        }
                     } else if (node instanceof UnwindNode) {
                         assert unwindNode == null;
                         unwindNode = (UnwindNode) node;
@@ -359,6 +370,13 @@
             for (int i = 0; i < returnNodes.size(); i++) {
                 returnNodes.set(i, (ReturnNode) duplicates.get(returnNodes.get(i)));
             }
+            for (InvokeNode exit : partialIntrinsicExits) {
+                // A partial intrinsic exit must be replaced with a call to
+                // the intrinsified method.
+                InvokeNode dup = (InvokeNode) duplicates.get(exit);
+                InvokeNode repl = graph.add(new InvokeNode(invoke.callTarget(), invoke.bci()));
+                dup.intrinsify(repl);
+            }
             if (unwindNode != null) {
                 unwindNode = (UnwindNode) duplicates.get(unwindNode);
             }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/BasePhase.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/BasePhase.java	Fri May 12 13:56:13 2017 -0700
@@ -31,8 +31,13 @@
 import org.graalvm.compiler.debug.DebugMemUseTracker;
 import org.graalvm.compiler.debug.DebugTimer;
 import org.graalvm.compiler.debug.Fingerprint;
+import org.graalvm.compiler.debug.GraalDebugConfig;
 import org.graalvm.compiler.graph.Graph;
 import org.graalvm.compiler.graph.Graph.Mark;
+import org.graalvm.compiler.graph.Graph.NodeEvent;
+import org.graalvm.compiler.graph.Graph.NodeEventListener;
+import org.graalvm.compiler.graph.Graph.NodeEventScope;
+import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.options.Option;
 import org.graalvm.compiler.options.OptionKey;
@@ -145,44 +150,22 @@
         return null;
     }
 
-    private BasePhase<?> dumpBefore(StructuredGraph graph) {
-        BasePhase<?> enclosingPhase = getEnclosingPhase();
-        boolean isTopLevel = enclosingPhase == null;
-        if (isTopLevel) {
-            if (Debug.isDumpEnabled(Debug.VERBOSE_LEVEL)) {
-                Debug.dump(Debug.VERBOSE_LEVEL, graph, "Before phase %s", getName());
-            }
-        } else {
-            if (Debug.isDumpEnabled(Debug.VERBOSE_LEVEL + 1)) {
-                Debug.dump(Debug.VERBOSE_LEVEL + 1, graph, "Before phase %s", getName());
-            }
+    private boolean dumpBefore(final StructuredGraph graph, final C context, boolean isTopLevel) {
+        if (isTopLevel && Debug.isDumpEnabled(Debug.VERBOSE_LEVEL)) {
+            Debug.dump(Debug.VERBOSE_LEVEL, graph, "Before phase %s", getName());
+        } else if (!isTopLevel && Debug.isDumpEnabled(Debug.VERBOSE_LEVEL + 1)) {
+            Debug.dump(Debug.VERBOSE_LEVEL + 1, graph, "Before subphase %s", getName());
+        } else if (Debug.isDumpEnabled(Debug.ENABLED_LEVEL) && shouldDump(graph, context)) {
+            Debug.dump(Debug.ENABLED_LEVEL, graph, "Before %s %s", isTopLevel ? "phase" : "subphase", getName());
+            return true;
         }
-        return enclosingPhase;
+        return false;
     }
 
     protected boolean isInliningPhase() {
         return false;
     }
 
-    private void dumpAfter(BasePhase<?> enclosingPhase, StructuredGraph graph) {
-        boolean isTopLevel = enclosingPhase == null;
-        if (isTopLevel) {
-            if (isInliningPhase()) {
-                if (Debug.isDumpEnabled(Debug.BASIC_LEVEL)) {
-                    Debug.dump(Debug.BASIC_LEVEL, graph, "After phase %s", getName());
-                }
-            } else {
-                if (Debug.isDumpEnabled(Debug.INFO_LEVEL)) {
-                    Debug.dump(Debug.INFO_LEVEL, graph, "After phase %s", getName());
-                }
-            }
-        } else {
-            if (Debug.isDumpEnabled(Debug.INFO_LEVEL + 1)) {
-                Debug.dump(Debug.INFO_LEVEL + 1, graph, "After phase %s", getName());
-            }
-        }
-    }
-
     @SuppressWarnings("try")
     protected final void apply(final StructuredGraph graph, final C context, final boolean dumpGraph) {
         graph.checkCancellation();
@@ -195,9 +178,10 @@
                 sizeBefore = NodeCostUtil.computeGraphSize(graph);
                 before = graph.getMark();
             }
-            BasePhase<?> enclosingPhase = null;
+            boolean isTopLevel = getEnclosingPhase() == null;
+            boolean dumpedBefore = false;
             if (dumpGraph && Debug.isEnabled()) {
-                enclosingPhase = dumpBefore(graph);
+                dumpedBefore = dumpBefore(graph, context, isTopLevel);
             }
             inputNodesCount.add(graph.getNodeCount());
             this.run(graph, context);
@@ -210,7 +194,7 @@
             }
 
             if (dumpGraph && Debug.isEnabled()) {
-                dumpAfter(enclosingPhase, graph);
+                dumpAfter(graph, isTopLevel, dumpedBefore);
             }
             if (Fingerprint.ENABLED) {
                 String graphDesc = graph.method() == null ? graph.name : graph.method().format("%H.%n(%p)");
@@ -225,6 +209,69 @@
         }
     }
 
+    private void dumpAfter(final StructuredGraph graph, boolean isTopLevel, boolean dumpedBefore) {
+        boolean dumped = false;
+        if (isTopLevel) {
+            if (isInliningPhase()) {
+                if (Debug.isDumpEnabled(Debug.BASIC_LEVEL)) {
+                    Debug.dump(Debug.BASIC_LEVEL, graph, "After phase %s", getName());
+                    dumped = true;
+                }
+            } else {
+                if (Debug.isDumpEnabled(Debug.INFO_LEVEL)) {
+                    Debug.dump(Debug.INFO_LEVEL, graph, "After phase %s", getName());
+                    dumped = true;
+                }
+            }
+        } else {
+            if (Debug.isDumpEnabled(Debug.INFO_LEVEL + 1)) {
+                Debug.dump(Debug.INFO_LEVEL + 1, graph, "After subphase %s", getName());
+                dumped = true;
+            }
+        }
+        if (!dumped && Debug.isDumpEnabled(Debug.ENABLED_LEVEL) && dumpedBefore) {
+            Debug.dump(Debug.ENABLED_LEVEL, graph, "After %s %s", isTopLevel ? "phase" : "subphase", getName());
+        }
+    }
+
+    @SuppressWarnings("try")
+    private boolean shouldDump(StructuredGraph graph, C context) {
+        String phaseChange = GraalDebugConfig.Options.DumpOnPhaseChange.getValue(graph.getOptions());
+        if (phaseChange != null && getClass().getSimpleName().contains(phaseChange)) {
+            StructuredGraph graphCopy = (StructuredGraph) graph.copy();
+            GraphChangeListener listener = new GraphChangeListener(graphCopy);
+            try (NodeEventScope s = graphCopy.trackNodeEvents(listener)) {
+                try (Scope s2 = Debug.sandbox("GraphChangeListener", null)) {
+                    run(graphCopy, context);
+                } catch (Throwable t) {
+                    Debug.handle(t);
+                }
+            }
+            return listener.changed;
+        }
+        return false;
+    }
+
+    private final class GraphChangeListener implements NodeEventListener {
+        boolean changed;
+        private StructuredGraph graph;
+        private Mark mark;
+
+        GraphChangeListener(StructuredGraph graphCopy) {
+            this.graph = graphCopy;
+            this.mark = graph.getMark();
+        }
+
+        @Override
+        public void event(NodeEvent e, Node node) {
+            if (!graph.isNew(mark, node) && node.isAlive()) {
+                if (e == NodeEvent.INPUT_CHANGED || e == NodeEvent.ZERO_USAGES) {
+                    changed = true;
+                }
+            }
+        }
+    }
+
     protected CharSequence getName() {
         String className = BasePhase.this.getClass().getName();
         String s = className.substring(className.lastIndexOf(".") + 1); // strip the package name
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/MemoryScheduleVerification.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/MemoryScheduleVerification.java	Fri May 12 13:56:13 2017 -0700
@@ -24,9 +24,10 @@
 
 import java.util.List;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.core.common.cfg.BlockMap;
 import org.graalvm.compiler.core.common.cfg.Loop;
+import org.graalvm.compiler.debug.Debug;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.nodes.AbstractBeginNode;
 import org.graalvm.compiler.nodes.AbstractMergeNode;
@@ -122,6 +123,7 @@
         for (FloatingReadNode r : cloneState(currentState)) {
             if (r.getLocationIdentity().overlaps(location)) {
                 // This read is killed by this location.
+                Debug.log(Debug.VERBOSE_LEVEL, "%s removing %s from state", n, r);
                 currentState.remove(r);
             }
         }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/SchedulePhase.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/SchedulePhase.java	Fri May 12 13:56:13 2017 -0700
@@ -30,8 +30,8 @@
 import java.util.Formatter;
 import java.util.List;
 
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.core.common.GraalOptions;
-import org.graalvm.compiler.core.common.LocationIdentity;
 import org.graalvm.compiler.core.common.SuppressFBWarnings;
 import org.graalvm.compiler.core.common.cfg.AbstractControlFlowGraph;
 import org.graalvm.compiler.core.common.cfg.BlockMap;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/verify/VerifyCallerSensitiveMethods.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/verify/VerifyCallerSensitiveMethods.java	Fri May 12 13:56:13 2017 -0700
@@ -22,7 +22,7 @@
  */
 package org.graalvm.compiler.phases.verify;
 
-import static org.graalvm.compiler.core.common.util.Util.Java8OrEarlier;
+import static org.graalvm.compiler.serviceprovider.JDK9Method.Java8OrEarlier;
 
 import java.lang.annotation.Annotation;
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/verify/VerifyDebugUsage.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/verify/VerifyDebugUsage.java	Fri May 12 13:56:13 2017 -0700
@@ -24,6 +24,7 @@
 
 import static org.graalvm.compiler.debug.Debug.BASIC_LEVEL;
 import static org.graalvm.compiler.debug.Debug.DETAILED_LEVEL;
+import static org.graalvm.compiler.debug.Debug.ENABLED_LEVEL;
 import static org.graalvm.compiler.debug.Debug.INFO_LEVEL;
 import static org.graalvm.compiler.debug.Debug.VERBOSE_LEVEL;
 import static org.graalvm.compiler.debug.Debug.VERY_DETAILED_LEVEL;
@@ -135,7 +136,7 @@
         }
     }
 
-    private static final Set<Integer> DebugLevels = new HashSet<>(Arrays.asList(BASIC_LEVEL, INFO_LEVEL, VERBOSE_LEVEL, DETAILED_LEVEL, VERY_DETAILED_LEVEL));
+    private static final Set<Integer> DebugLevels = new HashSet<>(Arrays.asList(ENABLED_LEVEL, BASIC_LEVEL, INFO_LEVEL, VERBOSE_LEVEL, DETAILED_LEVEL, VERY_DETAILED_LEVEL));
 
     /**
      * The set of methods allowed to call a {@code Debug.dump(...)} method with the {@code level}
@@ -150,7 +151,7 @@
                     "org.graalvm.compiler.phases.BasePhase.dumpAfter",
                     "org.graalvm.compiler.core.GraalCompiler.emitFrontEnd",
                     "org.graalvm.compiler.truffle.PartialEvaluator.fastPartialEvaluation",
-                    "org.graalvm.compiler.truffle.PartialEvaluator.reportPerformanceWarnings",
+                    "org.graalvm.compiler.truffle.PartialEvaluator$PerformanceInformationHandler.reportPerformanceWarnings",
                     "org.graalvm.compiler.truffle.TruffleCompiler.compileMethodHelper",
                     "org.graalvm.compiler.core.test.VerifyDebugUsageTest$ValidDumpUsagePhase.run",
                     "org.graalvm.compiler.core.test.VerifyDebugUsageTest$InvalidConcatDumpUsagePhase.run",
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/verify/VerifyInstanceOfUsage.java	Fri May 12 13:56:13 2017 -0700
@@ -0,0 +1,91 @@
+/*
+ * 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.phases.verify;
+
+import org.graalvm.compiler.lir.StandardOp.LoadConstantOp;
+import org.graalvm.compiler.lir.StandardOp.MoveOp;
+import org.graalvm.compiler.lir.StandardOp.ValueMoveOp;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.java.InstanceOfNode;
+import org.graalvm.compiler.phases.VerifyPhase;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+/**
+ * Checks that we do not use {@code instanceof} for types where faster alternatives are available.
+ */
+public class VerifyInstanceOfUsage extends VerifyPhase<PhaseContext> {
+
+    private static final Class<?>[] FORBIDDEN_INSTANCE_OF_CHECKS = {
+                    MoveOp.class,
+                    ValueMoveOp.class,
+                    LoadConstantOp.class
+    };
+
+    @Override
+    public boolean checkContract() {
+        return false;
+    }
+
+    @Override
+    protected boolean verify(StructuredGraph graph, PhaseContext context) {
+        final ResolvedJavaType[] bailoutType = new ResolvedJavaType[FORBIDDEN_INSTANCE_OF_CHECKS.length];
+        for (int i = 0; i < FORBIDDEN_INSTANCE_OF_CHECKS.length; i++) {
+            bailoutType[i] = context.getMetaAccess().lookupJavaType(FORBIDDEN_INSTANCE_OF_CHECKS[i]);
+        }
+        ResolvedJavaMethod method = graph.method();
+        ResolvedJavaType declaringClass = method.getDeclaringClass();
+        if (!isTrustedInterface(declaringClass, context.getMetaAccess())) {
+
+            for (InstanceOfNode io : graph.getNodes().filter(InstanceOfNode.class)) {
+                ResolvedJavaType type = io.type().getType();
+                for (ResolvedJavaType forbiddenType : bailoutType) {
+                    if (forbiddenType.equals(type)) {
+                        String name = forbiddenType.getUnqualifiedName();
+                        // strip outer class
+                        ResolvedJavaType enclosingType = forbiddenType.getEnclosingType();
+                        if (enclosingType != null) {
+                            name = name.substring(enclosingType.getUnqualifiedName().length() + "$".length());
+                        }
+                        throw new VerificationError("Using `op instanceof %s` is not allowed. Use `%s.is%s(op)` instead. (in %s)", name, name, name, method.format("%H.%n(%p)"));
+                    }
+                }
+            }
+        }
+        return true;
+    }
+
+    private static boolean isTrustedInterface(ResolvedJavaType declaringClass, MetaAccessProvider metaAccess) {
+        for (Class<?> trustedCls : FORBIDDEN_INSTANCE_OF_CHECKS) {
+            ResolvedJavaType trusted = metaAccess.lookupJavaType(trustedCls);
+            if (trusted.equals(declaringClass)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraphPrinter.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraphPrinter.java	Fri May 12 13:56:13 2017 -0700
@@ -22,18 +22,18 @@
  */
 package org.graalvm.compiler.printer;
 
-import static org.graalvm.compiler.core.common.util.Util.JAVA_SPECIFICATION_VERSION;
-
 import java.io.Closeable;
 import java.io.IOException;
 import java.lang.reflect.Array;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
+
 import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
-import org.graalvm.compiler.core.common.util.ModuleAPI;
 import org.graalvm.compiler.graph.Graph;
 import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.serviceprovider.JDK9Method;
+
 import jdk.vm.ci.meta.JavaConstant;
 import jdk.vm.ci.meta.JavaKind;
 import jdk.vm.ci.meta.MetaUtil;
@@ -68,15 +68,14 @@
     void close();
 
     /**
-     * A JVMCI package {@linkplain Services#exportJVMCITo(Class) dynamically exported} to trusted
-     * modules.
+     * A JVMCI package dynamically exported to trusted modules.
      */
     String JVMCI_RUNTIME_PACKAGE = JVMCI.class.getPackage().getName();
 
     /**
      * {@code jdk.vm.ci} module.
      */
-    Object JVMCI_MODULE = JAVA_SPECIFICATION_VERSION < 9 ? null : ModuleAPI.getModule.invoke(Services.class);
+    Object JVMCI_MODULE = JDK9Method.JAVA_SPECIFICATION_VERSION < 9 ? null : JDK9Method.getModule.invoke(Services.class);
 
     /**
      * Classes whose {@link #toString()} method does not run any untrusted code.
@@ -102,14 +101,14 @@
         if (TRUSTED_CLASSES.contains(c)) {
             return true;
         }
-        if (JAVA_SPECIFICATION_VERSION < 9) {
+        if (JDK9Method.JAVA_SPECIFICATION_VERSION < 9) {
             if (c.getClassLoader() == Services.class.getClassLoader()) {
                 // Loaded by the JVMCI class loader
                 return true;
             }
         } else {
-            Object module = ModuleAPI.getModule.invoke(c);
-            if (JVMCI_MODULE == module || (Boolean) ModuleAPI.isExportedTo.invoke(JVMCI_MODULE, JVMCI_RUNTIME_PACKAGE, module)) {
+            Object module = JDK9Method.getModule.invoke(c);
+            if (JVMCI_MODULE == module || (Boolean) JDK9Method.isOpenTo.invoke(JVMCI_MODULE, JVMCI_RUNTIME_PACKAGE, module)) {
                 // Can access non-statically-exported package in JVMCI
                 return true;
             }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraphPrinterDumpHandler.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraphPrinterDumpHandler.java	Fri May 12 13:56:13 2017 -0700
@@ -295,7 +295,7 @@
              */
             if (lastMethodOrGraph == null || asJavaMethod(lastMethodOrGraph) == null || !asJavaMethod(lastMethodOrGraph).equals(method) ||
                             (lastMethodOrGraph != o && lastMethodOrGraph instanceof Graph && o instanceof Graph)) {
-                result.add(method.format("%H::%n(%p)"));
+                result.add(method.format("%H.%n(%p)"));
             } else {
                 /*
                  * This prevents multiple adjacent method context objects for the same method from
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64GraphBuilderPlugins.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64GraphBuilderPlugins.java	Fri May 12 13:56:13 2017 -0700
@@ -22,7 +22,6 @@
  */
 package org.graalvm.compiler.replacements.amd64;
 
-import static org.graalvm.compiler.core.common.util.Util.Java8OrEarlier;
 import static org.graalvm.compiler.replacements.nodes.BinaryMathIntrinsicNode.BinaryOperation.POW;
 import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.COS;
 import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.EXP;
@@ -30,9 +29,10 @@
 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.Java8OrEarlier;
 
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.bytecode.BytecodeProvider;
-import org.graalvm.compiler.core.common.LocationIdentity;
 import org.graalvm.compiler.lir.amd64.AMD64ArithmeticLIRGeneratorTool.RoundingMode;
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringIndexOfNode.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringIndexOfNode.java	Fri May 12 13:56:13 2017 -0700
@@ -25,7 +25,8 @@
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_256;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_64;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
+import org.graalvm.api.word.Pointer;
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.graph.NodeInputList;
@@ -39,7 +40,6 @@
 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.word.Pointer;
 
 import jdk.vm.ci.meta.JavaKind;
 import jdk.vm.ci.meta.Value;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringSubstitutions.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringSubstitutions.java	Fri May 12 13:56:13 2017 -0700
@@ -22,10 +22,10 @@
  */
 package org.graalvm.compiler.replacements.amd64;
 
+import org.graalvm.api.word.Pointer;
 import org.graalvm.compiler.api.replacements.ClassSubstitution;
 import org.graalvm.compiler.api.replacements.MethodSubstitution;
 import org.graalvm.compiler.graph.Node.ConstantNodeParameter;
-import org.graalvm.compiler.word.Pointer;
 import org.graalvm.compiler.word.Word;
 
 import sun.misc.Unsafe;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ArrayStoreBytecodeExceptionTest.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ArrayStoreBytecodeExceptionTest.java	Fri May 12 13:56:13 2017 -0700
@@ -51,13 +51,14 @@
     }
 
     @Override
-    protected void registerPlugin(InvocationPlugins plugins) {
-        plugins.register(new InvocationPlugin() {
+    protected void registerInvocationPlugins(InvocationPlugins invocationPlugins) {
+        invocationPlugins.register(new InvocationPlugin() {
             @Override
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode obj) {
                 return throwBytecodeException(b, ArrayStoreException.class, obj);
             }
         }, Exceptions.class, "throwArrayStore", Object.class);
+        super.registerInvocationPlugins(invocationPlugins);
     }
 
     public static void arrayStoreSnippet(Object obj) {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/BytecodeExceptionTest.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/BytecodeExceptionTest.java	Fri May 12 13:56:13 2017 -0700
@@ -26,9 +26,7 @@
 import org.graalvm.compiler.nodes.UnwindNode;
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.extended.BytecodeExceptionNode;
-import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
-import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
 
 public abstract class BytecodeExceptionTest extends GraalCompilerTest {
 
@@ -37,13 +35,4 @@
         b.add(new UnwindNode(exceptionNode));
         return true;
     }
-
-    protected abstract void registerPlugin(InvocationPlugins plugins);
-
-    @Override
-    protected GraphBuilderConfiguration editGraphBuilderConfiguration(GraphBuilderConfiguration conf) {
-        GraphBuilderConfiguration ret = super.editGraphBuilderConfiguration(conf);
-        registerPlugin(ret.getPlugins().getInvocationPlugins());
-        return ret;
-    }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ClassCastBytecodeExceptionTest.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ClassCastBytecodeExceptionTest.java	Fri May 12 13:56:13 2017 -0700
@@ -75,8 +75,8 @@
     }
 
     @Override
-    protected void registerPlugin(InvocationPlugins plugins) {
-        plugins.register(new InvocationPlugin() {
+    protected void registerInvocationPlugins(InvocationPlugins invocationPlugins) {
+        invocationPlugins.register(new InvocationPlugin() {
             @Override
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode obj, ValueNode classNode) {
                 ResolvedJavaType type = b.getConstantReflection().asJavaType(classNode.asConstant());
@@ -86,6 +86,7 @@
                 return throwBytecodeException(b, ClassCastException.class, obj, hubConst);
             }
         }, Exceptions.class, "throwClassCast", Object.class, Class.class);
+        super.registerInvocationPlugins(invocationPlugins);
     }
 
     @Parameter(0) public Object object;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/DerivedOopTest.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/DerivedOopTest.java	Fri May 12 13:56:13 2017 -0700
@@ -24,20 +24,24 @@
 
 import java.util.Objects;
 
-import org.junit.Assert;
-import org.junit.Test;
-
 import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.debug.Debug;
+import org.graalvm.compiler.debug.DebugConfigScope;
+import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.ValueNode;
-import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration;
 import org.graalvm.compiler.replacements.Snippets;
 import org.graalvm.compiler.replacements.classfile.ClassfileBytecodeProvider;
 import org.graalvm.compiler.word.Word;
-import org.graalvm.compiler.word.nodes.WordCastNode;
+import org.graalvm.compiler.word.WordCastNode;
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
 
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 
@@ -135,10 +139,113 @@
         return obj;
     }
 
+    @Rule public final ExpectedException thrown = ExpectedException.none();
+    private static final String UNKNOWN_REFERENCE_AT_SAFEPOINT_MSG = "should not reach here: unknown reference alive across safepoint";
+
+    @Test
+    @SuppressWarnings("try")
+    public void testFieldOffsetMergeNonLiveBasePointer() {
+        thrown.expect(GraalError.class);
+        thrown.expectMessage(UNKNOWN_REFERENCE_AT_SAFEPOINT_MSG);
+        try (DebugConfigScope s = Debug.setConfig(Debug.silentConfig())) {
+            // Run a couple times to encourage objects to move
+            for (int i = 0; i < 4; i++) {
+                Result r = new Result();
+                test("fieldOffsetMergeSnippet01", r, 8L, 16L);
+                Assert.assertEquals(r.beforeGC.delta(), r.afterGC.delta());
+            }
+        }
+    }
+
+    @Test
+    public void testFieldOffsetMergeNonLiveBasePointerNotAccrossSafepoint() {
+        // Run a couple times to encourage objects to move
+        for (int i = 0; i < 4; i++) {
+            Result r = new Result();
+            test("fieldOffsetMergeSnippet02", r, 8L, 16L);
+        }
+    }
+
+    @Test
+    @SuppressWarnings("try")
+    public void testFieldOffsetMergeLiveBasePointer() {
+        thrown.expect(GraalError.class);
+        thrown.expectMessage(UNKNOWN_REFERENCE_AT_SAFEPOINT_MSG);
+        try (DebugConfigScope s = Debug.setConfig(Debug.silentConfig())) {
+            // Run a couple times to encourage objects to move
+            for (int i = 0; i < 4; i++) {
+                Result r = new Result();
+                test("fieldOffsetMergeSnippet03", r, new Result(), new Result(), 8L, 16L);
+                Assert.assertEquals(r.beforeGC.delta(), r.afterGC.delta());
+            }
+        }
+    }
+
+    public static boolean SideEffectB;
+    public static long SideEffect1 = 16;
+    public static long SideEffect2 = 16;
+    public static Object o1 = new Result();
+    public static Object o2 = o1;
+
+    public static Result fieldOffsetMergeSnippet01(Result objResult, long offsetA, long offsetB) {
+        long internalPointer;
+        if (SideEffectB) {
+            internalPointer = getRawPointer(o1) + offsetA;
+            SideEffect1 = internalPointer;
+        } else {
+            internalPointer = getRawPointer(o2) + offsetB;
+            SideEffect2 = internalPointer;
+        }
+        // make sure the internal pointer is computed before the safepoint
+        GraalDirectives.blackhole(internalPointer);
+        objResult.beforeGC.basePointer = getRawPointer(objResult);
+        objResult.beforeGC.internalPointer = internalPointer;
+        System.gc();
+        objResult.afterGC.basePointer = getRawPointer(objResult);
+        objResult.afterGC.internalPointer = internalPointer;
+        return objResult;
+    }
+
+    public static Result fieldOffsetMergeSnippet02(Result objResult, long offsetA, long offsetB) {
+        long internalPointer;
+        if (SideEffectB) {
+            internalPointer = getRawPointer(o1) + offsetA;
+            SideEffect1 = internalPointer;
+        } else {
+            internalPointer = getRawPointer(o2) + offsetB;
+            SideEffect2 = internalPointer;
+        }
+        // make sure the internal pointer is computed before the safepoint
+        GraalDirectives.blackhole(internalPointer);
+        objResult.beforeGC.basePointer = getRawPointer(objResult);
+        objResult.beforeGC.internalPointer = internalPointer;
+        objResult.afterGC.basePointer = getRawPointer(objResult);
+        objResult.afterGC.internalPointer = internalPointer;
+        return objResult;
+    }
+
+    public static Result fieldOffsetMergeSnippet03(Result objResult, Result a, Result b, long offsetA, long offsetB) {
+        long internalPointer;
+        if (SideEffectB) {
+            internalPointer = getRawPointer(a) + offsetA;
+            SideEffect1 = internalPointer;
+        } else {
+            internalPointer = getRawPointer(b) + offsetB;
+            SideEffect2 = internalPointer;
+        }
+        // make sure the internal pointer is computed before the safepoint
+        GraalDirectives.blackhole(internalPointer);
+        objResult.beforeGC.basePointer = getRawPointer(objResult);
+        objResult.beforeGC.internalPointer = internalPointer;
+        System.gc();
+        objResult.afterGC.basePointer = getRawPointer(objResult);
+        objResult.afterGC.internalPointer = internalPointer;
+        return objResult;
+    }
+
     @Override
-    protected Plugins getDefaultGraphBuilderPlugins() {
-        Plugins plugins = super.getDefaultGraphBuilderPlugins();
-        Registration r = new Registration(plugins.getInvocationPlugins(), DerivedOopTest.class);
+    protected void registerInvocationPlugins(InvocationPlugins invocationPlugins) {
+        Registration r = new Registration(invocationPlugins, DerivedOopTest.class);
         ClassfileBytecodeProvider bytecodeProvider = getSystemClassLoaderBytecodeProvider();
 
         ResolvedJavaMethod intrinsic = getResolvedJavaMethod("getRawPointerIntrinsic");
@@ -148,8 +255,7 @@
                 return b.intrinsify(bytecodeProvider, targetMethod, intrinsic, receiver, new ValueNode[]{arg});
             }
         });
-
-        return plugins;
+        super.registerInvocationPlugins(invocationPlugins);
     }
 
     @Override
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/FoldTest.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/FoldTest.java	Fri May 12 13:56:13 2017 -0700
@@ -22,8 +22,6 @@
  */
 package org.graalvm.compiler.replacements.test;
 
-import org.junit.Test;
-
 import org.graalvm.compiler.api.directives.GraalDirectives;
 import org.graalvm.compiler.api.replacements.ClassSubstitution;
 import org.graalvm.compiler.api.replacements.Fold;
@@ -32,12 +30,11 @@
 import org.graalvm.compiler.nodes.ReturnNode;
 import org.graalvm.compiler.nodes.StartNode;
 import org.graalvm.compiler.nodes.StructuredGraph;
-import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
-import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration;
 import org.graalvm.compiler.nodes.graphbuilderconf.NodeIntrinsicPluginFactory.InjectionProvider;
 import org.graalvm.compiler.replacements.NodeIntrinsificationProvider;
+import org.junit.Test;
 
 public class FoldTest extends ReplacementsTest {
 
@@ -81,12 +78,13 @@
     }
 
     @Override
-    protected GraphBuilderConfiguration editGraphBuilderConfiguration(GraphBuilderConfiguration conf) {
-        InvocationPlugins invocationPlugins = conf.getPlugins().getInvocationPlugins();
+    protected void registerInvocationPlugins(InvocationPlugins invocationPlugins) {
+        InjectionProvider injection = new NodeIntrinsificationProvider(getMetaAccess(), getSnippetReflection(), getProviders().getForeignCalls(), null);
+        new PluginFactory_FoldTest().registerPlugins(invocationPlugins, injection);
         BytecodeProvider replacementBytecodeProvider = getSystemClassLoaderBytecodeProvider();
         Registration r = new Registration(invocationPlugins, TestMethod.class, replacementBytecodeProvider);
         r.registerMethodSubstitution(TestMethodSubstitution.class, "test");
-        return super.editGraphBuilderConfiguration(conf);
+        super.registerInvocationPlugins(invocationPlugins);
     }
 
     public static int callTest() {
@@ -94,15 +92,6 @@
     }
 
     @Override
-    protected Plugins getDefaultGraphBuilderPlugins() {
-        Plugins ret = super.getDefaultGraphBuilderPlugins();
-        // manually register generated factories, jvmci service providers don't work from unit tests
-        InjectionProvider injection = new NodeIntrinsificationProvider(getMetaAccess(), getSnippetReflection(), getProviders().getForeignCalls(), null);
-        new PluginFactory_FoldTest().registerPlugins(ret.getInvocationPlugins(), injection);
-        return ret;
-    }
-
-    @Override
     protected boolean checkHighTierGraph(StructuredGraph graph) {
         // check that folding happened correctly
         StartNode start = graph.start();
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/IndexOobBytecodeExceptionTest.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/IndexOobBytecodeExceptionTest.java	Fri May 12 13:56:13 2017 -0700
@@ -52,13 +52,14 @@
     }
 
     @Override
-    protected void registerPlugin(InvocationPlugins plugins) {
-        plugins.register(new InvocationPlugin() {
+    protected void registerInvocationPlugins(InvocationPlugins invocationPlugins) {
+        invocationPlugins.register(new InvocationPlugin() {
             @Override
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode idx) {
                 return throwBytecodeException(b, ArrayIndexOutOfBoundsException.class, idx);
             }
         }, Exceptions.class, "throwOutOfBounds", int.class);
+        super.registerInvocationPlugins(invocationPlugins);
     }
 
     public static void oobSnippet(int idx) {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/NullBytecodeExceptionTest.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/NullBytecodeExceptionTest.java	Fri May 12 13:56:13 2017 -0700
@@ -42,13 +42,14 @@
     }
 
     @Override
-    protected void registerPlugin(InvocationPlugins plugins) {
-        plugins.register(new InvocationPlugin() {
+    protected void registerInvocationPlugins(InvocationPlugins invocationPlugins) {
+        invocationPlugins.register(new InvocationPlugin() {
             @Override
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
                 return throwBytecodeException(b, NullPointerException.class);
             }
         }, Exceptions.class, "throwNull");
+        super.registerInvocationPlugins(invocationPlugins);
     }
 
     public static void nullSnippet() {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ObjectAccessTest.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ObjectAccessTest.java	Fri May 12 13:56:13 2017 -0700
@@ -22,8 +22,10 @@
  */
 package org.graalvm.compiler.replacements.test;
 
+import org.graalvm.api.word.LocationIdentity;
+import org.graalvm.api.word.Pointer;
+import org.graalvm.api.word.WordFactory;
 import org.graalvm.compiler.api.replacements.Snippet;
-import org.graalvm.compiler.core.common.LocationIdentity;
 import org.graalvm.compiler.nodes.NamedLocationIdentity;
 import org.graalvm.compiler.nodes.ReturnNode;
 import org.graalvm.compiler.nodes.StructuredGraph;
@@ -33,8 +35,6 @@
 import org.graalvm.compiler.nodes.extended.JavaWriteNode;
 import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
 import org.graalvm.compiler.word.ObjectAccess;
-import org.graalvm.compiler.word.Pointer;
-import org.graalvm.compiler.word.Word;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -142,7 +142,7 @@
 
     @Snippet
     public static byte readByte2(Object o, int offset) {
-        return ObjectAccess.readByte(o, Word.signed(offset), ID);
+        return ObjectAccess.readByte(o, WordFactory.signed(offset), ID);
     }
 
     @Snippet
@@ -157,7 +157,7 @@
 
     @Snippet
     public static void writeByte2(Object o, int offset, byte value) {
-        ObjectAccess.writeByte(o, Word.signed(offset), value, ID);
+        ObjectAccess.writeByte(o, WordFactory.signed(offset), value, ID);
     }
 
     @Snippet
@@ -172,7 +172,7 @@
 
     @Snippet
     public static char readChar2(Object o, int offset) {
-        return ObjectAccess.readChar(o, Word.signed(offset), ID);
+        return ObjectAccess.readChar(o, WordFactory.signed(offset), ID);
     }
 
     @Snippet
@@ -187,7 +187,7 @@
 
     @Snippet
     public static void writeChar2(Object o, int offset, char value) {
-        ObjectAccess.writeChar(o, Word.signed(offset), value, ID);
+        ObjectAccess.writeChar(o, WordFactory.signed(offset), value, ID);
     }
 
     @Snippet
@@ -202,7 +202,7 @@
 
     @Snippet
     public static short readShort2(Object o, int offset) {
-        return ObjectAccess.readShort(o, Word.signed(offset), ID);
+        return ObjectAccess.readShort(o, WordFactory.signed(offset), ID);
     }
 
     @Snippet
@@ -217,7 +217,7 @@
 
     @Snippet
     public static void writeShort2(Object o, int offset, short value) {
-        ObjectAccess.writeShort(o, Word.signed(offset), value, ID);
+        ObjectAccess.writeShort(o, WordFactory.signed(offset), value, ID);
     }
 
     @Snippet
@@ -232,7 +232,7 @@
 
     @Snippet
     public static int readInt2(Object o, int offset) {
-        return ObjectAccess.readInt(o, Word.signed(offset), ID);
+        return ObjectAccess.readInt(o, WordFactory.signed(offset), ID);
     }
 
     @Snippet
@@ -247,7 +247,7 @@
 
     @Snippet
     public static void writeInt2(Object o, int offset, int value) {
-        ObjectAccess.writeInt(o, Word.signed(offset), value, ID);
+        ObjectAccess.writeInt(o, WordFactory.signed(offset), value, ID);
     }
 
     @Snippet
@@ -262,7 +262,7 @@
 
     @Snippet
     public static long readLong2(Object o, int offset) {
-        return ObjectAccess.readLong(o, Word.signed(offset), ID);
+        return ObjectAccess.readLong(o, WordFactory.signed(offset), ID);
     }
 
     @Snippet
@@ -277,7 +277,7 @@
 
     @Snippet
     public static void writeLong2(Object o, int offset, long value) {
-        ObjectAccess.writeLong(o, Word.signed(offset), value, ID);
+        ObjectAccess.writeLong(o, WordFactory.signed(offset), value, ID);
     }
 
     @Snippet
@@ -292,7 +292,7 @@
 
     @Snippet
     public static float readFloat2(Object o, int offset) {
-        return ObjectAccess.readFloat(o, Word.signed(offset), ID);
+        return ObjectAccess.readFloat(o, WordFactory.signed(offset), ID);
     }
 
     @Snippet
@@ -307,7 +307,7 @@
 
     @Snippet
     public static void writeFloat2(Object o, int offset, float value) {
-        ObjectAccess.writeFloat(o, Word.signed(offset), value, ID);
+        ObjectAccess.writeFloat(o, WordFactory.signed(offset), value, ID);
     }
 
     @Snippet
@@ -322,7 +322,7 @@
 
     @Snippet
     public static double readDouble2(Object o, int offset) {
-        return ObjectAccess.readDouble(o, Word.signed(offset), ID);
+        return ObjectAccess.readDouble(o, WordFactory.signed(offset), ID);
     }
 
     @Snippet
@@ -337,7 +337,7 @@
 
     @Snippet
     public static void writeDouble2(Object o, int offset, double value) {
-        ObjectAccess.writeDouble(o, Word.signed(offset), value, ID);
+        ObjectAccess.writeDouble(o, WordFactory.signed(offset), value, ID);
     }
 
     @Snippet
@@ -352,7 +352,7 @@
 
     @Snippet
     public static Object readObject2(Object o, int offset) {
-        return ObjectAccess.readObject(o, Word.signed(offset), ID);
+        return ObjectAccess.readObject(o, WordFactory.signed(offset), ID);
     }
 
     @Snippet
@@ -367,7 +367,7 @@
 
     @Snippet
     public static void writeObject2(Object o, int offset, Object value) {
-        ObjectAccess.writeObject(o, Word.signed(offset), value, ID);
+        ObjectAccess.writeObject(o, WordFactory.signed(offset), value, ID);
     }
 
     @Snippet
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PEGraphDecoderTest.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PEGraphDecoderTest.java	Fri May 12 13:56:13 2017 -0700
@@ -23,9 +23,9 @@
 package org.graalvm.compiler.replacements.test;
 
 import static org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin.InlineInfo.createStandardInlineInfo;
+
+import org.graalvm.api.word.LocationIdentity;
 import org.junit.Test;
-
-import org.graalvm.compiler.core.common.LocationIdentity;
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.core.test.GraalCompilerTest;
 import org.graalvm.compiler.debug.Debug;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PointerTest.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PointerTest.java	Fri May 12 13:56:13 2017 -0700
@@ -22,8 +22,10 @@
  */
 package org.graalvm.compiler.replacements.test;
 
+import org.graalvm.api.word.LocationIdentity;
+import org.graalvm.api.word.Pointer;
+import org.graalvm.api.word.WordFactory;
 import org.graalvm.compiler.api.replacements.Snippet;
-import org.graalvm.compiler.core.common.LocationIdentity;
 import org.graalvm.compiler.nodes.NamedLocationIdentity;
 import org.graalvm.compiler.nodes.ReturnNode;
 import org.graalvm.compiler.nodes.StructuredGraph;
@@ -35,9 +37,8 @@
 import org.graalvm.compiler.phases.OptimisticOptimizations;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.tiers.HighTierContext;
-import org.graalvm.compiler.word.Pointer;
 import org.graalvm.compiler.word.Word;
-import org.graalvm.compiler.word.nodes.WordCastNode;
+import org.graalvm.compiler.word.WordCastNode;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -160,7 +161,7 @@
 
     @Snippet
     public static byte readByte2(Object o, int offset) {
-        return Word.objectToTrackedPointer(o).readByte(Word.signed(offset), ID);
+        return Word.objectToTrackedPointer(o).readByte(WordFactory.signed(offset), ID);
     }
 
     @Snippet
@@ -175,7 +176,7 @@
 
     @Snippet
     public static void writeByte2(Object o, int offset, byte value) {
-        Word.objectToTrackedPointer(o).writeByte(Word.signed(offset), value, ID);
+        Word.objectToTrackedPointer(o).writeByte(WordFactory.signed(offset), value, ID);
     }
 
     @Snippet
@@ -190,7 +191,7 @@
 
     @Snippet
     public static char readChar2(Object o, int offset) {
-        return Word.objectToTrackedPointer(o).readChar(Word.signed(offset), ID);
+        return Word.objectToTrackedPointer(o).readChar(WordFactory.signed(offset), ID);
     }
 
     @Snippet
@@ -205,7 +206,7 @@
 
     @Snippet
     public static void writeChar2(Object o, int offset, char value) {
-        Word.objectToTrackedPointer(o).writeChar(Word.signed(offset), value, ID);
+        Word.objectToTrackedPointer(o).writeChar(WordFactory.signed(offset), value, ID);
     }
 
     @Snippet
@@ -220,7 +221,7 @@
 
     @Snippet
     public static short readShort2(Object o, int offset) {
-        return Word.objectToTrackedPointer(o).readShort(Word.signed(offset), ID);
+        return Word.objectToTrackedPointer(o).readShort(WordFactory.signed(offset), ID);
     }
 
     @Snippet
@@ -235,7 +236,7 @@
 
     @Snippet
     public static void writeShort2(Object o, int offset, short value) {
-        Word.objectToTrackedPointer(o).writeShort(Word.signed(offset), value, ID);
+        Word.objectToTrackedPointer(o).writeShort(WordFactory.signed(offset), value, ID);
     }
 
     @Snippet
@@ -250,7 +251,7 @@
 
     @Snippet
     public static int readInt2(Object o, int offset) {
-        return Word.objectToTrackedPointer(o).readInt(Word.signed(offset), ID);
+        return Word.objectToTrackedPointer(o).readInt(WordFactory.signed(offset), ID);
     }
 
     @Snippet
@@ -265,7 +266,7 @@
 
     @Snippet
     public static void writeInt2(Object o, int offset, int value) {
-        Word.objectToTrackedPointer(o).writeInt(Word.signed(offset), value, ID);
+        Word.objectToTrackedPointer(o).writeInt(WordFactory.signed(offset), value, ID);
     }
 
     @Snippet
@@ -280,7 +281,7 @@
 
     @Snippet
     public static long readLong2(Object o, int offset) {
-        return Word.objectToTrackedPointer(o).readLong(Word.signed(offset), ID);
+        return Word.objectToTrackedPointer(o).readLong(WordFactory.signed(offset), ID);
     }
 
     @Snippet
@@ -295,7 +296,7 @@
 
     @Snippet
     public static void writeLong2(Object o, int offset, long value) {
-        Word.objectToTrackedPointer(o).writeLong(Word.signed(offset), value, ID);
+        Word.objectToTrackedPointer(o).writeLong(WordFactory.signed(offset), value, ID);
     }
 
     @Snippet
@@ -310,7 +311,7 @@
 
     @Snippet
     public static float readFloat2(Object o, int offset) {
-        return Word.objectToTrackedPointer(o).readFloat(Word.signed(offset), ID);
+        return Word.objectToTrackedPointer(o).readFloat(WordFactory.signed(offset), ID);
     }
 
     @Snippet
@@ -325,7 +326,7 @@
 
     @Snippet
     public static void writeFloat2(Object o, int offset, float value) {
-        Word.objectToTrackedPointer(o).writeFloat(Word.signed(offset), value, ID);
+        Word.objectToTrackedPointer(o).writeFloat(WordFactory.signed(offset), value, ID);
     }
 
     @Snippet
@@ -340,7 +341,7 @@
 
     @Snippet
     public static double readDouble2(Object o, int offset) {
-        return Word.objectToTrackedPointer(o).readDouble(Word.signed(offset), ID);
+        return Word.objectToTrackedPointer(o).readDouble(WordFactory.signed(offset), ID);
     }
 
     @Snippet
@@ -355,7 +356,7 @@
 
     @Snippet
     public static void writeDouble2(Object o, int offset, double value) {
-        Word.objectToTrackedPointer(o).writeDouble(Word.signed(offset), value, ID);
+        Word.objectToTrackedPointer(o).writeDouble(WordFactory.signed(offset), value, ID);
     }
 
     @Snippet
@@ -370,7 +371,7 @@
 
     @Snippet
     public static Object readObject2(Object o, int offset) {
-        return Word.objectToTrackedPointer(o).readObject(Word.signed(offset), ID);
+        return Word.objectToTrackedPointer(o).readObject(WordFactory.signed(offset), ID);
     }
 
     @Snippet
@@ -385,7 +386,7 @@
 
     @Snippet
     public static void writeObject2(Object o, int offset, Object value) {
-        Word.objectToTrackedPointer(o).writeObject(Word.signed(offset), value, ID);
+        Word.objectToTrackedPointer(o).writeObject(WordFactory.signed(offset), value, ID);
     }
 
     @Snippet
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PointerTrackingTest.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PointerTrackingTest.java	Fri May 12 13:56:13 2017 -0700
@@ -22,20 +22,19 @@
  */
 package org.graalvm.compiler.replacements.test;
 
-import org.junit.Test;
-
 import org.graalvm.compiler.api.directives.GraalDirectives;
 import org.graalvm.compiler.bytecode.BytecodeProvider;
 import org.graalvm.compiler.debug.Debug;
 import org.graalvm.compiler.debug.DebugConfigScope;
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.nodes.ValueNode;
-import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration;
 import org.graalvm.compiler.replacements.Snippets;
 import org.graalvm.compiler.word.Word;
+import org.junit.Test;
 
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 
@@ -129,13 +128,10 @@
     }
 
     @Override
-    protected Plugins getDefaultGraphBuilderPlugins() {
-        Plugins plugins = super.getDefaultGraphBuilderPlugins();
-        Registration r = new Registration(plugins.getInvocationPlugins(), PointerTrackingTest.class);
+    protected void registerInvocationPlugins(InvocationPlugins invocationPlugins) {
+        Registration r = new Registration(invocationPlugins, PointerTrackingTest.class);
 
         register(r, "getTrackedPointer");
         register(r, "getUntrackedPointer");
-
-        return plugins;
     }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ReplacementsParseTest.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ReplacementsParseTest.java	Fri May 12 13:56:13 2017 -0700
@@ -24,18 +24,16 @@
 
 import java.util.function.Function;
 
-import org.junit.Test;
-
 import org.graalvm.compiler.api.replacements.ClassSubstitution;
 import org.graalvm.compiler.api.replacements.MethodSubstitution;
 import org.graalvm.compiler.bytecode.BytecodeProvider;
 import org.graalvm.compiler.graph.Node.ConstantNodeParameter;
 import org.graalvm.compiler.graph.Node.NodeIntrinsic;
 import org.graalvm.compiler.nodes.PiNode;
-import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
-import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin.Receiver;
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration;
+import org.junit.Test;
 
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 
@@ -44,22 +42,14 @@
  */
 public class ReplacementsParseTest extends ReplacementsTest {
 
-    @Override
-    protected Plugins getDefaultGraphBuilderPlugins() {
-        Plugins ret = super.getDefaultGraphBuilderPlugins();
-        // Manually register generated factory as Graal service providers don't work for unit tests
-        new PluginFactory_ReplacementsParseTest().registerPlugins(ret.getInvocationPlugins(), null);
-        return ret;
-    }
-
-    private static final Object THROW_EXCEPTION_MARKER = new Object() {
+    static final Object THROW_EXCEPTION_MARKER = new Object() {
         @Override
         public String toString() {
             return "THROW_EXCEPTION_MARKER";
         }
     };
 
-    static class TestMethods {
+    static class TestObject {
         static double next(double v) {
             return Math.nextAfter(v, 1.0);
         }
@@ -72,6 +62,25 @@
             return Math.nextAfter(x, d);
         }
 
+        TestObject() {
+            this(null);
+        }
+
+        TestObject(Object id) {
+            this.id = id;
+        }
+
+        final Object id;
+
+        String stringizeId() {
+            String res = String.valueOf(id);
+            if (res.equals(THROW_EXCEPTION_MARKER.toString())) {
+                // Tests exception throwing from partial intrinsification
+                throw new RuntimeException("ex: " + id);
+            }
+            return res;
+        }
+
         static String stringize(Object obj) {
             String res = String.valueOf(obj);
             if (res.equals(THROW_EXCEPTION_MARKER.toString())) {
@@ -86,8 +95,8 @@
         }
     }
 
-    @ClassSubstitution(TestMethods.class)
-    static class TestMethodsSubstitutions {
+    @ClassSubstitution(TestObject.class)
+    static class TestObjectSubstitutions {
 
         @MethodSubstitution(isStatic = true)
         static double nextAfter(double x, double d) {
@@ -96,7 +105,7 @@
         }
 
         /**
-         * Tests partial intrinsification.
+         * Tests conditional intrinsification of a static method.
          */
         @MethodSubstitution
         static String stringize(Object obj) {
@@ -110,6 +119,25 @@
             }
         }
 
+        /**
+         * Tests conditional intrinsification of a non-static method.
+         */
+        @MethodSubstitution(isStatic = false)
+        static String stringizeId(TestObject thisObj) {
+            if (thisObj.id != null && thisObj.id.getClass() == String.class) {
+                return asNonNullString(thisObj.id);
+            } else {
+                // A recursive call denotes exiting/deoptimizing
+                // out of the partial intrinsification to the
+                // slow/uncommon case.
+                return outOfLinePartialIntrinsification(thisObj);
+            }
+        }
+
+        static String outOfLinePartialIntrinsification(TestObject thisObj) {
+            return stringizeId(thisObj);
+        }
+
         public static String asNonNullString(Object object) {
             return asNonNullStringIntrinsic(object, String.class, true, true);
         }
@@ -131,16 +159,18 @@
     }
 
     @Override
-    protected GraphBuilderConfiguration editGraphBuilderConfiguration(GraphBuilderConfiguration conf) {
-        InvocationPlugins invocationPlugins = conf.getPlugins().getInvocationPlugins();
+    protected void registerInvocationPlugins(InvocationPlugins invocationPlugins) {
         BytecodeProvider replacementBytecodeProvider = getSystemClassLoaderBytecodeProvider();
-        Registration r = new Registration(invocationPlugins, TestMethods.class, replacementBytecodeProvider);
-        r.registerMethodSubstitution(TestMethodsSubstitutions.class, "nextAfter", double.class, double.class);
-        r.registerMethodSubstitution(TestMethodsSubstitutions.class, "stringize", Object.class);
+        Registration r = new Registration(invocationPlugins, TestObject.class, replacementBytecodeProvider);
+        new PluginFactory_ReplacementsParseTest().registerPlugins(invocationPlugins, null);
+        r.registerMethodSubstitution(TestObjectSubstitutions.class, "nextAfter", double.class, double.class);
+        r.registerMethodSubstitution(TestObjectSubstitutions.class, "stringize", Object.class);
+        r.registerMethodSubstitution(TestObjectSubstitutions.class, "stringizeId", Receiver.class);
+
         if (replacementBytecodeProvider.supportsInvokedynamic()) {
-            r.registerMethodSubstitution(TestMethodsSubstitutions.class, "identity", String.class);
+            r.registerMethodSubstitution(TestObjectSubstitutions.class, "identity", String.class);
         }
-        return super.editGraphBuilderConfiguration(conf);
+        super.registerInvocationPlugins(invocationPlugins);
     }
 
     /**
@@ -152,7 +182,7 @@
     }
 
     public double test1Snippet(double d) {
-        return TestMethods.next(d);
+        return TestObject.next(d);
     }
 
     /**
@@ -164,7 +194,7 @@
     }
 
     public double test2Snippet(double d) {
-        return TestMethods.next2(d);
+        return TestObject.next2(d);
     }
 
     /**
@@ -185,7 +215,7 @@
     public void doNextAfter(double[] outArray, double[] inArray) {
         for (int i = 0; i < inArray.length; i++) {
             double direction = (i & 1) == 0 ? Double.POSITIVE_INFINITY : -Double.NEGATIVE_INFINITY;
-            outArray[i] = TestMethods.nextAfter(inArray[i], direction);
+            outArray[i] = TestObject.nextAfter(inArray[i], direction);
         }
     }
 
@@ -196,13 +226,29 @@
         test("callStringize", Boolean.TRUE);
     }
 
+    @Test
+    public void testCallStringizeId() {
+        test("callStringizeId", new TestObject("a string"));
+        test("callStringizeId", new TestObject(THROW_EXCEPTION_MARKER));
+        test("callStringizeId", new TestObject(Boolean.TRUE));
+    }
+
     public static Object callStringize(Object obj) {
-        return TestMethods.stringize(obj);
+        return TestObject.stringize(obj);
+    }
+
+    public static Object callStringizeId(TestObject testObj) {
+        return indirect(testObj);
+    }
+
+    @BytecodeParserNeverInline
+    private static String indirect(TestObject testObj) {
+        return testObj.stringizeId();
     }
 
     @Test
     public void testRootCompileStringize() {
-        ResolvedJavaMethod method = getResolvedJavaMethod(TestMethods.class, "stringize");
+        ResolvedJavaMethod method = getResolvedJavaMethod(TestObject.class, "stringize");
         test(method, null, "a string");
         test(method, null, Boolean.TRUE);
         test(method, null, THROW_EXCEPTION_MARKER);
@@ -215,6 +261,6 @@
     }
 
     public static String callLambda(String value) {
-        return TestMethods.identity(value);
+        return TestObject.identity(value);
     }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/SnippetsTest.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/SnippetsTest.java	Fri May 12 13:56:13 2017 -0700
@@ -27,24 +27,24 @@
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
 import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.replacements.ReplacementsImpl;
-import org.graalvm.compiler.replacements.Snippets;
 import org.graalvm.compiler.replacements.classfile.ClassfileBytecodeProvider;
 
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 
-public abstract class SnippetsTest extends ReplacementsTest implements Snippets {
+public abstract class SnippetsTest extends ReplacementsTest {
 
     protected final ReplacementsImpl installer;
+    protected final ClassfileBytecodeProvider bytecodeProvider;
 
     protected SnippetsTest() {
         ReplacementsImpl d = (ReplacementsImpl) getReplacements();
-        ClassfileBytecodeProvider bytecodeProvider = getSystemClassLoaderBytecodeProvider();
+        bytecodeProvider = getSystemClassLoaderBytecodeProvider();
         installer = new ReplacementsImpl(getInitialOptions(), d.providers, d.snippetReflection, bytecodeProvider, d.target);
         installer.setGraphBuilderPlugins(d.getGraphBuilderPlugins());
     }
 
     @Override
     protected StructuredGraph parseEager(ResolvedJavaMethod m, AllowAssumptions allowAssumptions, CompilationIdentifier compilationId, OptionValues options) {
-        return installer.makeGraph(m, null, null);
+        return installer.makeGraph(bytecodeProvider, m, null, null);
     }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/SubstitutionsTest.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/SubstitutionsTest.java	Fri May 12 13:56:13 2017 -0700
@@ -28,9 +28,6 @@
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED;
 import static org.hamcrest.CoreMatchers.instanceOf;
 
-import org.junit.Assert;
-import org.junit.Test;
-
 import org.graalvm.compiler.api.replacements.ClassSubstitution;
 import org.graalvm.compiler.api.replacements.MethodSubstitution;
 import org.graalvm.compiler.core.common.type.StampFactory;
@@ -46,12 +43,12 @@
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.calc.FloatingNode;
 import org.graalvm.compiler.nodes.extended.GuardingNode;
-import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
-import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration;
 import org.graalvm.compiler.nodes.memory.MemoryNode;
 import org.graalvm.compiler.replacements.classfile.ClassfileBytecodeProvider;
+import org.junit.Assert;
+import org.junit.Test;
 
 import jdk.vm.ci.meta.JavaKind;
 
@@ -118,12 +115,12 @@
     }
 
     @Override
-    protected GraphBuilderConfiguration editGraphBuilderConfiguration(GraphBuilderConfiguration conf) {
-        InvocationPlugins invocationPlugins = conf.getPlugins().getInvocationPlugins();
+    protected void registerInvocationPlugins(InvocationPlugins invocationPlugins) {
+        new PluginFactory_SubstitutionsTest().registerPlugins(invocationPlugins, null);
         ClassfileBytecodeProvider bytecodeProvider = getSystemClassLoaderBytecodeProvider();
         Registration r = new Registration(invocationPlugins, TestMethod.class, bytecodeProvider);
         r.registerMethodSubstitution(TestMethodSubstitution.class, "test");
-        return super.editGraphBuilderConfiguration(conf);
+        super.registerInvocationPlugins(invocationPlugins);
     }
 
     public static int callTest() {
@@ -131,14 +128,6 @@
     }
 
     @Override
-    protected Plugins getDefaultGraphBuilderPlugins() {
-        Plugins ret = super.getDefaultGraphBuilderPlugins();
-        // manually register generated factories, Graal service providers don't work from unit tests
-        new PluginFactory_SubstitutionsTest().registerPlugins(ret.getInvocationPlugins(), null);
-        return ret;
-    }
-
-    @Override
     protected boolean checkHighTierGraph(StructuredGraph graph) {
         // Check that the graph contains the expected test nodes.
         NodeIterable<ReturnNode> retNodes = graph.getNodes().filter(ReturnNode.class);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/WordTest.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/WordTest.java	Fri May 12 13:56:13 2017 -0700
@@ -22,15 +22,16 @@
  */
 package org.graalvm.compiler.replacements.test;
 
+import org.graalvm.api.word.Pointer;
+import org.graalvm.api.word.Unsigned;
+import org.graalvm.api.word.WordBase;
+import org.graalvm.api.word.WordFactory;
 import org.graalvm.compiler.api.replacements.Snippet;
 import org.graalvm.compiler.core.common.CompilationIdentifier;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
 import org.graalvm.compiler.options.OptionValues;
-import org.graalvm.compiler.word.Pointer;
-import org.graalvm.compiler.word.Unsigned;
 import org.graalvm.compiler.word.Word;
-import org.graalvm.compiler.word.WordBase;
 import org.junit.Test;
 
 import jdk.vm.ci.meta.ResolvedJavaMethod;
@@ -43,7 +44,7 @@
     @Override
     protected StructuredGraph parseEager(ResolvedJavaMethod m, AllowAssumptions allowAssumptions, CompilationIdentifier compilationId, OptionValues options) {
         // create a copy to assign a valid compilation id
-        return installer.makeGraph(m, null, null).copyWithIdentifier(compilationId);
+        return installer.makeGraph(bytecodeProvider, m, null, null).copyWithIdentifier(compilationId);
     }
 
     @Test
@@ -115,7 +116,7 @@
 
     @Snippet
     public static long cast(long input) {
-        WordBase base = Word.signed(input);
+        WordBase base = WordFactory.signed(input);
         Unsigned unsigned = (Unsigned) base;
         Pointer pointer = (Pointer) unsigned;
         Word word = (Word) pointer;
@@ -124,111 +125,111 @@
 
     @Snippet
     public static long unsignedLong(long word) {
-        return Word.unsigned(word).rawValue();
+        return WordFactory.unsigned(word).rawValue();
     }
 
     @Snippet
     public static long unsignedInt(int word) {
-        return Word.unsigned(word).rawValue();
+        return WordFactory.unsigned(word).rawValue();
     }
 
     @Snippet
     public static long signedLong(long word) {
-        return Word.signed(word).rawValue();
+        return WordFactory.signed(word).rawValue();
     }
 
     @Snippet
     public static long signedInt(int word) {
-        return Word.signed(word).rawValue();
+        return WordFactory.signed(word).rawValue();
     }
 
     @Snippet
     public static long unsignedPlusInt(long word, int addend) {
-        return Word.unsigned(word).add(addend).rawValue();
+        return WordFactory.unsigned(word).add(addend).rawValue();
     }
 
     @Snippet
     public static long unsignedMinusInt(long word, int addend) {
-        return Word.unsigned(word).subtract(addend).rawValue();
+        return WordFactory.unsigned(word).subtract(addend).rawValue();
     }
 
     @Snippet
     public static long unsignedPlusLong(long word, long addend) {
-        return Word.unsigned(word).add(Word.unsigned(addend)).rawValue();
+        return WordFactory.unsigned(word).add(WordFactory.unsigned(addend)).rawValue();
     }
 
     @Snippet
     public static long unsignedMinusLong(long word, long addend) {
-        return Word.unsigned(word).subtract(Word.unsigned(addend)).rawValue();
+        return WordFactory.unsigned(word).subtract(WordFactory.unsigned(addend)).rawValue();
     }
 
     @Snippet
     public static long signedPlusInt(long word, int addend) {
-        return Word.signed(word).add(addend).rawValue();
+        return WordFactory.signed(word).add(addend).rawValue();
     }
 
     @Snippet
     public static long signedMinusInt(long word, int addend) {
-        return Word.signed(word).subtract(addend).rawValue();
+        return WordFactory.signed(word).subtract(addend).rawValue();
     }
 
     @Snippet
     public static long signedPlusLong(long word, long addend) {
-        return Word.signed(word).add(Word.signed(addend)).rawValue();
+        return WordFactory.signed(word).add(WordFactory.signed(addend)).rawValue();
     }
 
     @Snippet
     public static long signedMinusLong(long word, long addend) {
-        return Word.signed(word).subtract(Word.signed(addend)).rawValue();
+        return WordFactory.signed(word).subtract(WordFactory.signed(addend)).rawValue();
     }
 
     @Snippet
     public static long signedNot(long word) {
-        return Word.signed(word).not().rawValue();
+        return WordFactory.signed(word).not().rawValue();
     }
 
     @Snippet
     public static long unsignedNot(long word) {
-        return Word.unsigned(word).not().rawValue();
+        return WordFactory.unsigned(word).not().rawValue();
     }
 
     @Snippet
     public static boolean aboveOrEqual(long word1, long word2) {
-        return Word.unsigned(word1).aboveOrEqual(Word.unsigned(word2));
+        return WordFactory.unsigned(word1).aboveOrEqual(WordFactory.unsigned(word2));
     }
 
     @Snippet
     public static boolean above(long word1, long word2) {
-        return Word.unsigned(word1).aboveThan(Word.unsigned(word2));
+        return WordFactory.unsigned(word1).aboveThan(WordFactory.unsigned(word2));
     }
 
     @Snippet
     public static boolean belowOrEqual(long word1, long word2) {
-        return Word.unsigned(word1).belowOrEqual(Word.unsigned(word2));
+        return WordFactory.unsigned(word1).belowOrEqual(WordFactory.unsigned(word2));
     }
 
     @Snippet
     public static boolean below(long word1, long word2) {
-        return Word.unsigned(word1).belowThan(Word.unsigned(word2));
+        return WordFactory.unsigned(word1).belowThan(WordFactory.unsigned(word2));
     }
 
     @Snippet
     public static long andInt(long word, int addend) {
-        return Word.unsigned(word).and(addend).rawValue();
+        return WordFactory.unsigned(word).and(addend).rawValue();
     }
 
     @Snippet
     public static long orInt(long word, int addend) {
-        return Word.unsigned(word).or(addend).rawValue();
+        return WordFactory.unsigned(word).or(addend).rawValue();
     }
 
     @Snippet
     public static long andLong(long word, long addend) {
-        return Word.unsigned(word).and(Word.unsigned(addend)).rawValue();
+        return WordFactory.unsigned(word).and(WordFactory.unsigned(addend)).rawValue();
     }
 
     @Snippet
     public static long orLong(long word, long addend) {
-        return Word.unsigned(word).or(Word.unsigned(addend)).rawValue();
+        return WordFactory.unsigned(word).or(WordFactory.unsigned(addend)).rawValue();
     }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/classfile/RedefineIntrinsicTest.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/classfile/RedefineIntrinsicTest.java	Fri May 12 13:56:13 2017 -0700
@@ -22,6 +22,9 @@
  */
 package org.graalvm.compiler.replacements.test.classfile;
 
+import static org.graalvm.compiler.test.SubprocessUtil.getVMCommandLine;
+import static org.graalvm.compiler.test.SubprocessUtil.java;
+import static org.graalvm.compiler.test.SubprocessUtil.withoutDebuggerArguments;
 import static org.junit.Assume.assumeTrue;
 
 import java.io.FileOutputStream;
@@ -35,6 +38,7 @@
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.security.ProtectionDomain;
+import java.util.List;
 import java.util.jar.Attributes;
 import java.util.jar.JarEntry;
 import java.util.jar.JarOutputStream;
@@ -42,16 +46,15 @@
 
 import javax.tools.ToolProvider;
 
-import org.junit.Assert;
-import org.junit.Test;
-
 import org.graalvm.compiler.api.replacements.ClassSubstitution;
 import org.graalvm.compiler.api.replacements.MethodSubstitution;
 import org.graalvm.compiler.bytecode.BytecodeProvider;
-import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration;
 import org.graalvm.compiler.replacements.test.ReplacementsTest;
+import org.graalvm.compiler.test.SubprocessUtil.Subprocess;
+import org.junit.Assert;
+import org.junit.Test;
 
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 
@@ -78,12 +81,11 @@
     }
 
     @Override
-    protected GraphBuilderConfiguration editGraphBuilderConfiguration(GraphBuilderConfiguration conf) {
-        InvocationPlugins invocationPlugins = conf.getPlugins().getInvocationPlugins();
+    protected void registerInvocationPlugins(InvocationPlugins invocationPlugins) {
         BytecodeProvider replacementBytecodeProvider = getSystemClassLoaderBytecodeProvider();
         Registration r = new Registration(invocationPlugins, Original.class, replacementBytecodeProvider);
         r.registerMethodSubstitution(Intrinsic.class, "getValue");
-        return super.editGraphBuilderConfiguration(conf);
+        super.registerInvocationPlugins(invocationPlugins);
     }
 
     public static String callOriginalGetValue() {
@@ -98,6 +100,22 @@
 
     @Test
     public void test() throws Throwable {
+        String recursionPropName = getClass().getName() + ".recursion";
+        if (Java8OrEarlier || Boolean.getBoolean(recursionPropName)) {
+            testHelper();
+        } else {
+            List<String> vmArgs = withoutDebuggerArguments(getVMCommandLine());
+            vmArgs.add("-D" + recursionPropName + "=true");
+            vmArgs.add("-Djdk.attach.allowAttachSelf=true");
+            Subprocess proc = java(vmArgs, "com.oracle.mxtool.junit.MxJUnitWrapper", getClass().getName());
+            if (proc.exitCode != 0) {
+                Assert.fail(String.format("non-zero exit code %d for command:%n%s", proc.exitCode, proc));
+            }
+        }
+    }
+
+    public void testHelper() throws Throwable {
+
         Object receiver = null;
         Object[] args = {};
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/DefaultJavaLoweringProvider.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/DefaultJavaLoweringProvider.java	Fri May 12 13:56:13 2017 -0700
@@ -37,10 +37,10 @@
 import java.util.BitSet;
 import java.util.List;
 
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.api.directives.GraalDirectives;
 import org.graalvm.compiler.api.replacements.Snippet;
 import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
-import org.graalvm.compiler.core.common.LocationIdentity;
 import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
 import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
 import org.graalvm.compiler.core.common.type.IntegerStamp;
@@ -49,6 +49,7 @@
 import org.graalvm.compiler.core.common.type.TypeReference;
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodeinfo.InputType;
 import org.graalvm.compiler.nodes.ConstantNode;
 import org.graalvm.compiler.nodes.FieldLocationIdentity;
 import org.graalvm.compiler.nodes.FixedNode;
@@ -761,18 +762,53 @@
             allocations[objIndex] = anchor;
             graph.addBeforeFixed(commit, anchor);
         }
+        /*
+         * Note that the FrameState that is assigned to these MonitorEnterNodes isn't the correct
+         * state. It will be the state from before the allocation occurred instead of a valid state
+         * after the locking is performed. In practice this should be fine since these are newly
+         * allocated objects. The bytecodes themselves permit allocating an object, doing a
+         * monitorenter and then dropping all references to the object which would produce the same
+         * state, though that would normally produce an IllegalMonitorStateException. In HotSpot
+         * some form of fast path locking should always occur so the FrameState should never
+         * actually be used.
+         */
+        ArrayList<MonitorEnterNode> enters = null;
         for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
-            for (MonitorIdNode monitorId : commit.getLocks(objIndex)) {
+            List<MonitorIdNode> locks = commit.getLocks(objIndex);
+            if (locks.size() > 1) {
+                // Ensure that the lock operations are performed in lock depth order
+                ArrayList<MonitorIdNode> newList = new ArrayList<>(locks);
+                newList.sort((a, b) -> Integer.compare(a.getLockDepth(), b.getLockDepth()));
+                locks = newList;
+            }
+            int lastDepth = -1;
+            for (MonitorIdNode monitorId : locks) {
+                assert lastDepth < monitorId.getLockDepth();
+                lastDepth = monitorId.getLockDepth();
                 MonitorEnterNode enter = graph.add(new MonitorEnterNode(allocations[objIndex], monitorId));
                 graph.addBeforeFixed(commit, enter);
+                if (enters == null) {
+                    enters = new ArrayList<>();
+                }
+                enters.add(enter);
+            }
+        }
+        for (Node usage : commit.usages().snapshot()) {
+            if (usage instanceof AllocatedObjectNode) {
+                AllocatedObjectNode addObject = (AllocatedObjectNode) usage;
+                int index = commit.getVirtualObjects().indexOf(addObject.getVirtualObject());
+                addObject.replaceAtUsagesAndDelete(allocations[index]);
+            } else {
+                assert enters != null;
+                commit.replaceAtUsages(InputType.Memory, enters.get(enters.size() - 1));
+            }
+        }
+        if (enters != null) {
+            for (MonitorEnterNode enter : enters) {
                 enter.lower(tool);
             }
         }
-        for (Node usage : commit.usages().snapshot()) {
-            AllocatedObjectNode addObject = (AllocatedObjectNode) usage;
-            int index = commit.getVirtualObjects().indexOf(addObject.getVirtualObject());
-            addObject.replaceAtUsagesAndDelete(allocations[index]);
-        }
+        assert commit.hasNoUsages();
         insertAllocationBarrier(commit, graph);
     }
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/GraphKit.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/GraphKit.java	Fri May 12 13:56:13 2017 -0700
@@ -88,7 +88,7 @@
 
     private final List<Structure> structures;
 
-    abstract static class Structure {
+    protected abstract static class Structure {
     }
 
     public GraphKit(StructuredGraph graph, Providers providers, WordTypes wordTypes, GraphBuilderConfiguration.Plugins graphBuilderPlugins) {
@@ -304,7 +304,7 @@
         GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault(plugins);
 
         StructuredGraph calleeGraph = new StructuredGraph.Builder(invoke.getOptions()).method(method).build();
-        IntrinsicContext initialReplacementContext = new IntrinsicContext(method, method, providers.getReplacements().getReplacementBytecodeProvider(), INLINE_AFTER_PARSING);
+        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,
                         initialReplacementContext);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.java	Fri May 12 13:56:13 2017 -0700
@@ -626,7 +626,7 @@
     }
 
     protected boolean tryInvocationPlugin(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData, MethodCallTargetNode callTarget) {
-        if (invocationPlugins == null || invocationPlugins.size() == 0) {
+        if (invocationPlugins == null || invocationPlugins.isEmpty()) {
             return false;
         }
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ReplacementsImpl.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ReplacementsImpl.java	Fri May 12 13:56:13 2017 -0700
@@ -37,6 +37,7 @@
 import org.graalvm.compiler.api.replacements.Snippet;
 import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
 import org.graalvm.compiler.api.replacements.SnippetTemplateCache;
+import org.graalvm.compiler.bytecode.Bytecode;
 import org.graalvm.compiler.bytecode.BytecodeProvider;
 import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecode;
 import org.graalvm.compiler.core.common.GraalOptions;
@@ -74,6 +75,7 @@
 import org.graalvm.compiler.phases.tiers.PhaseContext;
 import org.graalvm.compiler.phases.util.Providers;
 import org.graalvm.compiler.word.Word;
+import org.graalvm.compiler.word.WordOperationPlugin;
 import org.graalvm.util.EconomicMap;
 import org.graalvm.util.Equivalence;
 
@@ -101,13 +103,18 @@
      */
     protected final ConcurrentMap<ResolvedJavaMethod, StructuredGraph> graphs;
 
-    protected final BytecodeProvider bytecodeProvider;
+    /**
+     * The default {@link BytecodeProvider} to use for accessing the bytecode of a replacement if
+     * the replacement doesn't provide another {@link BytecodeProvider}.
+     */
+    protected final BytecodeProvider defaultBytecodeProvider;
 
     public void setGraphBuilderPlugins(GraphBuilderConfiguration.Plugins plugins) {
         assert this.graphBuilderPlugins == null;
         this.graphBuilderPlugins = plugins;
     }
 
+    @Override
     public GraphBuilderConfiguration.Plugins getGraphBuilderPlugins() {
         return graphBuilderPlugins;
     }
@@ -131,11 +138,11 @@
      */
     @Override
     public InlineInfo shouldInlineInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) {
-        ResolvedJavaMethod subst = getSubstitutionMethod(method);
+        Bytecode subst = getSubstitutionBytecode(method);
         if (subst != null) {
             if (b.parsingIntrinsic() || InlineDuringParsing.getValue(b.getOptions()) || InlineIntrinsicsDuringParsing.getValue(b.getOptions())) {
                 // Forced inlining of intrinsics
-                return createIntrinsicInlineInfo(subst, bytecodeProvider);
+                return createIntrinsicInlineInfo(subst.getMethod(), subst.getOrigin());
             }
             return null;
         }
@@ -143,7 +150,7 @@
             assert b.getDepth() < MAX_GRAPH_INLINING_DEPTH : "inlining limit exceeded";
 
             // Force inlining when parsing replacements
-            return createIntrinsicInlineInfo(method, bytecodeProvider);
+            return createIntrinsicInlineInfo(method, 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);
@@ -180,7 +187,7 @@
         this.target = target;
         this.graphs = new ConcurrentHashMap<>();
         this.snippetTemplateCache = EconomicMap.create(Equivalence.DEFAULT);
-        this.bytecodeProvider = bytecodeProvider;
+        this.defaultBytecodeProvider = bytecodeProvider;
     }
 
     private static final DebugTimer SnippetPreparationTime = Debug.timer("SnippetPreparationTime");
@@ -199,7 +206,7 @@
         StructuredGraph graph = UseSnippetGraphCache.getValue(options) ? graphs.get(method) : null;
         if (graph == null) {
             try (DebugCloseable a = SnippetPreparationTime.start()) {
-                StructuredGraph newGraph = makeGraph(method, args, recursiveEntry);
+                StructuredGraph newGraph = makeGraph(defaultBytecodeProvider, method, args, recursiveEntry);
                 Debug.counter("SnippetNodeCount[%#s]", method).add(newGraph.getNodeCount());
                 if (!UseSnippetGraphCache.getValue(options) || args != null) {
                     return newGraph;
@@ -223,16 +230,17 @@
     }
 
     @Override
-    public BytecodeProvider getReplacementBytecodeProvider() {
-        return bytecodeProvider;
+    public BytecodeProvider getDefaultReplacementBytecodeProvider() {
+        return defaultBytecodeProvider;
     }
 
     @Override
-    public ResolvedJavaMethod getSubstitutionMethod(ResolvedJavaMethod method) {
+    public Bytecode getSubstitutionBytecode(ResolvedJavaMethod method) {
         InvocationPlugin plugin = graphBuilderPlugins.getInvocationPlugins().lookupInvocation(method);
         if (plugin instanceof MethodSubstitutionPlugin) {
             MethodSubstitutionPlugin msPlugin = (MethodSubstitutionPlugin) plugin;
-            return msPlugin.getSubstitute(providers.getMetaAccess());
+            ResolvedJavaMethod substitute = msPlugin.getSubstitute(providers.getMetaAccess());
+            return msPlugin.getBytecodeProvider().getBytecode(substitute);
         }
         return null;
     }
@@ -248,7 +256,7 @@
                 ResolvedJavaMethod substitute = msPlugin.getSubstitute(metaAccess);
                 StructuredGraph graph = graphs.get(substitute);
                 if (graph == null) {
-                    graph = makeGraph(substitute, null, method);
+                    graph = makeGraph(msPlugin.getBytecodeProvider(), substitute, null, method);
                     graph.freeze();
                     graphs.putIfAbsent(substitute, graph);
                     graph = graphs.get(substitute);
@@ -256,7 +264,7 @@
                 assert graph.isFrozen();
                 result = graph;
             } else {
-                ResolvedJavaMethodBytecode code = new ResolvedJavaMethodBytecode(method);
+                Bytecode code = new ResolvedJavaMethodBytecode(method);
                 ConstantReflectionProvider constantReflection = providers.getConstantReflection();
                 ConstantFieldProvider constantFieldProvider = providers.getConstantFieldProvider();
                 StampProvider stampProvider = providers.getStampProvider();
@@ -271,14 +279,14 @@
     /**
      * Creates a preprocessed graph for a snippet or method substitution.
      *
+     * @param bytecodeProvider how to access the bytecode of {@code method}
      * @param method the snippet or method substitution for which a graph will be created
      * @param args
      * @param original the original method if {@code method} is a {@linkplain MethodSubstitution
      *            substitution} otherwise null
      */
-    @SuppressWarnings("try")
-    public StructuredGraph makeGraph(ResolvedJavaMethod method, Object[] args, ResolvedJavaMethod original) {
-        return createGraphMaker(method, original).makeGraph(args);
+    public StructuredGraph makeGraph(BytecodeProvider bytecodeProvider, ResolvedJavaMethod method, Object[] args, ResolvedJavaMethod original) {
+        return createGraphMaker(method, original).makeGraph(bytecodeProvider, args);
     }
 
     /**
@@ -315,10 +323,10 @@
         }
 
         @SuppressWarnings("try")
-        public StructuredGraph makeGraph(Object[] args) {
+        public StructuredGraph makeGraph(BytecodeProvider bytecodeProvider, Object[] args) {
             try (Scope s = Debug.scope("BuildSnippetGraph", method)) {
                 assert method.hasBytecodes() : method;
-                StructuredGraph graph = buildInitialGraph(method, args);
+                StructuredGraph graph = buildInitialGraph(bytecodeProvider, method, args);
 
                 finalizeGraph(graph);
 
@@ -379,10 +387,10 @@
         }
 
         /**
-         * Builds the initial graph for a snippet.
+         * Builds the initial graph for a replacement.
          */
         @SuppressWarnings("try")
-        protected StructuredGraph buildInitialGraph(final ResolvedJavaMethod methodToParse, Object[] args) {
+        protected StructuredGraph buildInitialGraph(BytecodeProvider bytecodeProvider, final ResolvedJavaMethod methodToParse, Object[] args) {
             // Replacements cannot have optimistic assumptions since they have
             // to be valid for the entire run of the VM.
 
@@ -403,11 +411,11 @@
                 IntrinsicContext initialIntrinsicContext = null;
                 if (method.getAnnotation(Snippet.class) == null) {
                     // Post-parse inlined intrinsic
-                    initialIntrinsicContext = new IntrinsicContext(substitutedMethod, method, replacements.bytecodeProvider, INLINE_AFTER_PARSING);
+                    initialIntrinsicContext = new IntrinsicContext(substitutedMethod, method, bytecodeProvider, INLINE_AFTER_PARSING);
                 } else {
                     // Snippet
                     ResolvedJavaMethod original = substitutedMethod != null ? substitutedMethod : method;
-                    initialIntrinsicContext = new IntrinsicContext(original, method, replacements.bytecodeProvider, INLINE_AFTER_PARSING);
+                    initialIntrinsicContext = new IntrinsicContext(original, method, bytecodeProvider, INLINE_AFTER_PARSING);
                 }
 
                 createGraphBuilder(metaAccess, replacements.providers.getStampProvider(), replacements.providers.getConstantReflection(), replacements.providers.getConstantFieldProvider(), config,
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetCounterNode.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetCounterNode.java	Fri May 12 13:56:13 2017 -0700
@@ -29,11 +29,11 @@
 import java.lang.reflect.Field;
 import java.util.Arrays;
 
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.api.replacements.Fold;
 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.core.common.LocationIdentity;
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.graph.NodeClass;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetLowerableMemoryNode.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetLowerableMemoryNode.java	Fri May 12 13:56:13 2017 -0700
@@ -25,7 +25,7 @@
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.graph.NodeInputList;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetTemplate.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetTemplate.java	Fri May 12 13:56:13 2017 -0700
@@ -23,7 +23,7 @@
 package org.graalvm.compiler.replacements;
 
 import static java.util.FormattableFlags.ALTERNATE;
-import static org.graalvm.compiler.core.common.LocationIdentity.any;
+import static org.graalvm.api.word.LocationIdentity.any;
 import static org.graalvm.compiler.debug.Debug.applyFormattingFlagsAndWidth;
 import static org.graalvm.compiler.debug.GraalDebugConfig.Options.DebugStubsAndSnippets;
 import static org.graalvm.compiler.graph.iterators.NodePredicates.isNotA;
@@ -45,13 +45,14 @@
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.function.Predicate;
 
+import org.graalvm.api.word.LocationIdentity;
+import org.graalvm.api.word.WordBase;
 import org.graalvm.compiler.api.replacements.Snippet;
 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.LocationIdentity;
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.core.common.type.StampPair;
@@ -123,7 +124,6 @@
 import org.graalvm.compiler.phases.util.Providers;
 import org.graalvm.compiler.replacements.nodes.ExplodeLoopNode;
 import org.graalvm.compiler.replacements.nodes.LoadSnippetVarargParameterNode;
-import org.graalvm.compiler.word.WordBase;
 import org.graalvm.util.CollectionsUtil;
 import org.graalvm.util.EconomicMap;
 import org.graalvm.util.EconomicSet;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java	Fri May 12 13:56:13 2017 -0700
@@ -30,16 +30,16 @@
 import static jdk.vm.ci.code.MemoryBarriers.LOAD_STORE;
 import static jdk.vm.ci.code.MemoryBarriers.STORE_LOAD;
 import static jdk.vm.ci.code.MemoryBarriers.STORE_STORE;
-import static org.graalvm.compiler.core.common.util.Util.Java8OrEarlier;
+import static org.graalvm.compiler.serviceprovider.JDK9Method.Java8OrEarlier;
 
 import java.lang.reflect.Array;
 import java.lang.reflect.Field;
 import java.util.Arrays;
 
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.api.directives.GraalDirectives;
 import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
 import org.graalvm.compiler.bytecode.BytecodeProvider;
-import org.graalvm.compiler.core.common.LocationIdentity;
 import org.graalvm.compiler.core.common.calc.Condition;
 import org.graalvm.compiler.core.common.calc.UnsignedMath;
 import org.graalvm.compiler.core.common.type.ObjectStamp;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/WordOperationPlugin.java	Fri May 12 13:14:25 2017 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,502 +0,0 @@
-/*
- * Copyright (c) 2015, 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.replacements;
-
-import static org.graalvm.compiler.core.common.LocationIdentity.any;
-import static org.graalvm.compiler.nodes.ConstantNode.forInt;
-import static org.graalvm.compiler.nodes.ConstantNode.forIntegerKind;
-
-import java.lang.reflect.Constructor;
-import java.util.Arrays;
-
-import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
-import org.graalvm.compiler.bytecode.BridgeMethodUtils;
-import org.graalvm.compiler.core.common.LocationIdentity;
-import org.graalvm.compiler.core.common.calc.Condition;
-import org.graalvm.compiler.core.common.type.Stamp;
-import org.graalvm.compiler.core.common.type.StampFactory;
-import org.graalvm.compiler.core.common.type.StampPair;
-import org.graalvm.compiler.core.common.type.TypeReference;
-import org.graalvm.compiler.debug.GraalError;
-import org.graalvm.compiler.nodes.ConstantNode;
-import org.graalvm.compiler.nodes.Invoke;
-import org.graalvm.compiler.nodes.ValueNode;
-import org.graalvm.compiler.nodes.calc.CompareNode;
-import org.graalvm.compiler.nodes.calc.ConditionalNode;
-import org.graalvm.compiler.nodes.calc.IntegerBelowNode;
-import org.graalvm.compiler.nodes.calc.IntegerEqualsNode;
-import org.graalvm.compiler.nodes.calc.IntegerLessThanNode;
-import org.graalvm.compiler.nodes.calc.NarrowNode;
-import org.graalvm.compiler.nodes.calc.SignExtendNode;
-import org.graalvm.compiler.nodes.calc.XorNode;
-import org.graalvm.compiler.nodes.calc.ZeroExtendNode;
-import org.graalvm.compiler.nodes.extended.JavaReadNode;
-import org.graalvm.compiler.nodes.extended.JavaWriteNode;
-import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
-import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderTool;
-import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin;
-import org.graalvm.compiler.nodes.graphbuilderconf.NodePlugin;
-import org.graalvm.compiler.nodes.graphbuilderconf.TypePlugin;
-import org.graalvm.compiler.nodes.java.AbstractCompareAndSwapNode;
-import org.graalvm.compiler.nodes.java.LoadFieldNode;
-import org.graalvm.compiler.nodes.java.LoadIndexedNode;
-import org.graalvm.compiler.nodes.java.LogicCompareAndSwapNode;
-import org.graalvm.compiler.nodes.java.StoreIndexedNode;
-import org.graalvm.compiler.nodes.java.ValueCompareAndSwapNode;
-import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType;
-import org.graalvm.compiler.nodes.memory.address.AddressNode;
-import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
-import org.graalvm.compiler.nodes.type.StampTool;
-import org.graalvm.compiler.word.Word;
-import org.graalvm.compiler.word.Word.Opcode;
-import org.graalvm.compiler.word.Word.Operation;
-import org.graalvm.compiler.word.WordTypes;
-import org.graalvm.compiler.word.nodes.WordCastNode;
-
-import jdk.vm.ci.code.BailoutException;
-import jdk.vm.ci.meta.JavaKind;
-import jdk.vm.ci.meta.JavaType;
-import jdk.vm.ci.meta.JavaTypeProfile;
-import jdk.vm.ci.meta.ResolvedJavaField;
-import jdk.vm.ci.meta.ResolvedJavaMethod;
-import jdk.vm.ci.meta.ResolvedJavaType;
-
-/**
- * A plugin for calls to {@linkplain Operation word operations}, as well as all other nodes that
- * need special handling for {@link Word} types.
- */
-public class WordOperationPlugin implements NodePlugin, TypePlugin, InlineInvokePlugin {
-    protected final WordTypes wordTypes;
-    protected final JavaKind wordKind;
-    protected final SnippetReflectionProvider snippetReflection;
-
-    public WordOperationPlugin(SnippetReflectionProvider snippetReflection, WordTypes wordTypes) {
-        this.snippetReflection = snippetReflection;
-        this.wordTypes = wordTypes;
-        this.wordKind = wordTypes.getWordKind();
-    }
-
-    @Override
-    public boolean canChangeStackKind(GraphBuilderContext b) {
-        return true;
-    }
-
-    /**
-     * Processes a call to a method if it is annotated with {@link Operation} by adding nodes to the
-     * graph being built that implement the denoted operation.
-     *
-     * @return {@code true} iff {@code method} is annotated with {@link Operation} (and was thus
-     *         processed by this method)
-     */
-    @Override
-    public boolean handleInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) {
-        if (!wordTypes.isWordOperation(method)) {
-            return false;
-        }
-        processWordOperation(b, args, wordTypes.getWordOperation(method, b.getMethod().getDeclaringClass()));
-        return true;
-    }
-
-    @Override
-    public StampPair interceptType(GraphBuilderTool b, JavaType declaredType, boolean nonNull) {
-        Stamp wordStamp = null;
-        if (declaredType instanceof ResolvedJavaType) {
-            ResolvedJavaType resolved = (ResolvedJavaType) declaredType;
-            if (wordTypes.isWord(resolved)) {
-                wordStamp = wordTypes.getWordStamp(resolved);
-            } else if (resolved.isArray() && wordTypes.isWord(resolved.getElementalType())) {
-                TypeReference trusted = TypeReference.createTrustedWithoutAssumptions(resolved);
-                wordStamp = StampFactory.object(trusted, nonNull);
-            }
-        }
-        if (wordStamp != null) {
-            return StampPair.createSingle(wordStamp);
-        } else {
-            return null;
-        }
-    }
-
-    @Override
-    public void notifyNotInlined(GraphBuilderContext b, ResolvedJavaMethod method, Invoke invoke) {
-        if (wordTypes.isWord(invoke.asNode())) {
-            invoke.asNode().setStamp(wordTypes.getWordStamp(StampTool.typeOrNull(invoke.asNode())));
-        }
-    }
-
-    @Override
-    public boolean handleLoadField(GraphBuilderContext b, ValueNode receiver, ResolvedJavaField field) {
-        StampPair wordStamp = interceptType(b, field.getType(), false);
-        if (wordStamp != null) {
-            LoadFieldNode loadFieldNode = LoadFieldNode.createOverrideStamp(wordStamp, receiver, field);
-            b.addPush(field.getJavaKind(), loadFieldNode);
-            return true;
-        }
-        return false;
-    }
-
-    @Override
-    public boolean handleLoadStaticField(GraphBuilderContext b, ResolvedJavaField staticField) {
-        return handleLoadField(b, null, staticField);
-    }
-
-    @Override
-    public boolean handleLoadIndexed(GraphBuilderContext b, ValueNode array, ValueNode index, JavaKind elementKind) {
-        ResolvedJavaType arrayType = StampTool.typeOrNull(array);
-        /*
-         * There are cases where the array does not have a known type yet, i.e., the type is null.
-         * In that case we assume it is not a word type.
-         */
-        if (arrayType != null && wordTypes.isWord(arrayType.getComponentType())) {
-            assert elementKind == JavaKind.Object;
-            b.addPush(elementKind, createLoadIndexedNode(array, index));
-            return true;
-        }
-        return false;
-    }
-
-    protected LoadIndexedNode createLoadIndexedNode(ValueNode array, ValueNode index) {
-        return new LoadIndexedNode(null, array, index, wordTypes.getWordKind());
-    }
-
-    @Override
-    public boolean handleStoreField(GraphBuilderContext b, ValueNode object, ResolvedJavaField field, ValueNode value) {
-        if (field.getJavaKind() == JavaKind.Object) {
-            boolean isWordField = wordTypes.isWord(field.getType());
-            boolean isWordValue = value.getStackKind() == wordTypes.getWordKind();
-
-            if (isWordField && !isWordValue) {
-                throw bailout(b, "Cannot store a non-word value into a word field: " + field.format("%H.%n"));
-            } else if (!isWordField && isWordValue) {
-                throw bailout(b, "Cannot store a word value into a non-word field: " + field.format("%H.%n"));
-            }
-        }
-
-        /* We never need to intercept the field store. */
-        return false;
-    }
-
-    @Override
-    public boolean handleStoreStaticField(GraphBuilderContext b, ResolvedJavaField field, ValueNode value) {
-        return handleStoreField(b, null, field, value);
-    }
-
-    @Override
-    public boolean handleStoreIndexed(GraphBuilderContext b, ValueNode array, ValueNode index, JavaKind elementKind, ValueNode value) {
-        ResolvedJavaType arrayType = StampTool.typeOrNull(array);
-        if (arrayType != null && wordTypes.isWord(arrayType.getComponentType())) {
-            assert elementKind == JavaKind.Object;
-            if (value.getStackKind() != wordTypes.getWordKind()) {
-                throw bailout(b, "Cannot store a non-word value into a word array: " + arrayType.toJavaName(true));
-            }
-            b.add(createStoreIndexedNode(array, index, value));
-            return true;
-        }
-        if (elementKind == JavaKind.Object && value.getStackKind() == wordTypes.getWordKind()) {
-            throw bailout(b, "Cannot store a word value into a non-word array: " + arrayType.toJavaName(true));
-        }
-        return false;
-    }
-
-    protected StoreIndexedNode createStoreIndexedNode(ValueNode array, ValueNode index, ValueNode value) {
-        return new StoreIndexedNode(array, index, wordTypes.getWordKind(), value);
-    }
-
-    @Override
-    public boolean handleCheckCast(GraphBuilderContext b, ValueNode object, ResolvedJavaType type, JavaTypeProfile profile) {
-        if (!wordTypes.isWord(type)) {
-            if (object.getStackKind() != JavaKind.Object) {
-                throw bailout(b, "Cannot cast a word value to a non-word type: " + type.toJavaName(true));
-            }
-            return false;
-        }
-
-        if (object.getStackKind() != wordTypes.getWordKind()) {
-            throw bailout(b, "Cannot cast a non-word value to a word type: " + type.toJavaName(true));
-        }
-        b.push(JavaKind.Object, object);
-        return true;
-    }
-
-    @Override
-    public boolean handleInstanceOf(GraphBuilderContext b, ValueNode object, ResolvedJavaType type, JavaTypeProfile profile) {
-        if (wordTypes.isWord(type)) {
-            throw bailout(b, "Cannot use instanceof for word a type: " + type.toJavaName(true));
-        } else if (object.getStackKind() != JavaKind.Object) {
-            throw bailout(b, "Cannot use instanceof on a word value: " + type.toJavaName(true));
-        }
-        return false;
-    }
-
-    protected void processWordOperation(GraphBuilderContext b, ValueNode[] args, ResolvedJavaMethod wordMethod) throws GraalError {
-        Operation operation = BridgeMethodUtils.getAnnotation(Word.Operation.class, wordMethod);
-        JavaKind returnKind = wordMethod.getSignature().getReturnKind();
-        switch (operation.opcode()) {
-            case NODE_CLASS:
-                assert args.length == 2;
-                ValueNode left = args[0];
-                ValueNode right = operation.rightOperandIsInt() ? toUnsigned(b, args[1], JavaKind.Int) : fromSigned(b, args[1]);
-
-                b.addPush(returnKind, createBinaryNodeInstance(operation.node(), left, right));
-                break;
-
-            case COMPARISON:
-                assert args.length == 2;
-                b.push(returnKind, comparisonOp(b, operation.condition(), args[0], fromSigned(b, args[1])));
-                break;
-
-            case NOT:
-                assert args.length == 1;
-                b.addPush(returnKind, new XorNode(args[0], b.add(forIntegerKind(wordKind, -1))));
-                break;
-
-            case READ_POINTER:
-            case READ_OBJECT:
-            case READ_BARRIERED: {
-                assert args.length == 2 || args.length == 3;
-                JavaKind readKind = wordTypes.asKind(wordMethod.getSignature().getReturnType(wordMethod.getDeclaringClass()));
-                AddressNode address = makeAddress(b, args[0], args[1]);
-                LocationIdentity location;
-                if (args.length == 2) {
-                    location = any();
-                } else {
-                    assert args[2].isConstant();
-                    location = snippetReflection.asObject(LocationIdentity.class, args[2].asJavaConstant());
-                }
-                b.push(returnKind, readOp(b, readKind, address, location, operation.opcode()));
-                break;
-            }
-            case READ_HEAP: {
-                assert args.length == 3;
-                JavaKind readKind = wordTypes.asKind(wordMethod.getSignature().getReturnType(wordMethod.getDeclaringClass()));
-                AddressNode address = makeAddress(b, args[0], args[1]);
-                BarrierType barrierType = snippetReflection.asObject(BarrierType.class, args[2].asJavaConstant());
-                b.push(returnKind, readOp(b, readKind, address, any(), barrierType, true));
-                break;
-            }
-            case WRITE_POINTER:
-            case WRITE_OBJECT:
-            case WRITE_BARRIERED:
-            case INITIALIZE: {
-                assert args.length == 3 || args.length == 4;
-                JavaKind writeKind = wordTypes.asKind(wordMethod.getSignature().getParameterType(wordMethod.isStatic() ? 2 : 1, wordMethod.getDeclaringClass()));
-                AddressNode address = makeAddress(b, args[0], args[1]);
-                LocationIdentity location;
-                if (args.length == 3) {
-                    location = any();
-                } else {
-                    assert args[3].isConstant();
-                    location = snippetReflection.asObject(LocationIdentity.class, args[3].asJavaConstant());
-                }
-                writeOp(b, writeKind, address, location, args[2], operation.opcode());
-                break;
-            }
-            case ZERO:
-                assert args.length == 0;
-                b.addPush(returnKind, forIntegerKind(wordKind, 0L));
-                break;
-
-            case FROM_UNSIGNED:
-                assert args.length == 1;
-                b.push(returnKind, fromUnsigned(b, args[0]));
-                break;
-
-            case FROM_SIGNED:
-                assert args.length == 1;
-                b.push(returnKind, fromSigned(b, args[0]));
-                break;
-
-            case TO_RAW_VALUE:
-                assert args.length == 1;
-                b.push(returnKind, toUnsigned(b, args[0], JavaKind.Long));
-                break;
-
-            case OBJECT_TO_TRACKED:
-                assert args.length == 1;
-                WordCastNode objectToTracked = b.add(WordCastNode.objectToTrackedPointer(args[0], wordKind));
-                b.push(returnKind, objectToTracked);
-                break;
-
-            case OBJECT_TO_UNTRACKED:
-                assert args.length == 1;
-                WordCastNode objectToUntracked = b.add(WordCastNode.objectToUntrackedPointer(args[0], wordKind));
-                b.push(returnKind, objectToUntracked);
-                break;
-
-            case FROM_ADDRESS:
-                assert args.length == 1;
-                WordCastNode addressToWord = b.add(WordCastNode.addressToWord(args[0], wordKind));
-                b.push(returnKind, addressToWord);
-                break;
-
-            case TO_OBJECT:
-                assert args.length == 1;
-                WordCastNode wordToObject = b.add(WordCastNode.wordToObject(args[0], wordKind));
-                b.push(returnKind, wordToObject);
-                break;
-
-            case TO_OBJECT_NON_NULL:
-                assert args.length == 1;
-                WordCastNode wordToObjectNonNull = b.add(WordCastNode.wordToObjectNonNull(args[0], wordKind));
-                b.push(returnKind, wordToObjectNonNull);
-                break;
-
-            case CAS_POINTER:
-                assert args.length == 5;
-                AddressNode address = makeAddress(b, args[0], args[1]);
-                JavaKind valueKind = wordTypes.asKind(wordMethod.getSignature().getParameterType(1, wordMethod.getDeclaringClass()));
-                assert valueKind.equals(wordTypes.asKind(wordMethod.getSignature().getParameterType(2, wordMethod.getDeclaringClass()))) : wordMethod.getSignature();
-                assert args[4].isConstant() : Arrays.toString(args);
-                LocationIdentity location = snippetReflection.asObject(LocationIdentity.class, args[4].asJavaConstant());
-                JavaType returnType = wordMethod.getSignature().getReturnType(wordMethod.getDeclaringClass());
-                b.addPush(returnKind, casOp(valueKind, wordTypes.asKind(returnType), address, location, args[2], args[3]));
-                break;
-            default:
-                throw new GraalError("Unknown opcode: %s", operation.opcode());
-        }
-    }
-
-    /**
-     * Create an instance of a binary node which is used to lower {@link Word} operations. This
-     * method is called for all {@link Word} operations which are annotated with @Operation(node =
-     * ...) and encapsulates the reflective allocation of the node.
-     */
-    private static ValueNode createBinaryNodeInstance(Class<? extends ValueNode> nodeClass, ValueNode left, ValueNode right) {
-        try {
-            Constructor<?> cons = nodeClass.getDeclaredConstructor(ValueNode.class, ValueNode.class);
-            return (ValueNode) cons.newInstance(left, right);
-        } catch (Throwable ex) {
-            throw new GraalError(ex).addContext(nodeClass.getName());
-        }
-    }
-
-    private ValueNode comparisonOp(GraphBuilderContext graph, Condition condition, ValueNode left, ValueNode right) {
-        assert left.getStackKind() == wordKind && right.getStackKind() == wordKind;
-
-        // mirroring gets the condition into canonical form
-        boolean mirror = condition.canonicalMirror();
-
-        ValueNode a = mirror ? right : left;
-        ValueNode b = mirror ? left : right;
-
-        CompareNode comparison;
-        if (condition == Condition.EQ || condition == Condition.NE) {
-            comparison = new IntegerEqualsNode(a, b);
-        } else if (condition.isUnsigned()) {
-            comparison = new IntegerBelowNode(a, b);
-        } else {
-            comparison = new IntegerLessThanNode(a, b);
-        }
-
-        ConstantNode trueValue = graph.add(forInt(1));
-        ConstantNode falseValue = graph.add(forInt(0));
-
-        if (condition.canonicalNegate()) {
-            ConstantNode temp = trueValue;
-            trueValue = falseValue;
-            falseValue = temp;
-        }
-        ConditionalNode materialize = graph.add(new ConditionalNode(graph.add(comparison), trueValue, falseValue));
-        return materialize;
-    }
-
-    protected ValueNode readOp(GraphBuilderContext b, JavaKind readKind, AddressNode address, LocationIdentity location, Opcode op) {
-        assert op == Opcode.READ_POINTER || op == Opcode.READ_OBJECT || op == Opcode.READ_BARRIERED;
-        final BarrierType barrier = (op == Opcode.READ_BARRIERED ? BarrierType.PRECISE : BarrierType.NONE);
-        final boolean compressible = (op == Opcode.READ_OBJECT || op == Opcode.READ_BARRIERED);
-
-        return readOp(b, readKind, address, location, barrier, compressible);
-    }
-
-    public static ValueNode readOp(GraphBuilderContext b, JavaKind readKind, AddressNode address, LocationIdentity location, BarrierType barrierType, boolean compressible) {
-        /*
-         * A JavaReadNode lowered to a ReadNode that will not float. This means it cannot float
-         * above an explicit zero check on its base address or any other test that ensures the read
-         * is safe.
-         */
-        JavaReadNode read = b.add(new JavaReadNode(readKind, address, location, barrierType, compressible));
-        return read;
-    }
-
-    protected void writeOp(GraphBuilderContext b, JavaKind writeKind, AddressNode address, LocationIdentity location, ValueNode value, Opcode op) {
-        assert op == Opcode.WRITE_POINTER || op == Opcode.WRITE_OBJECT || op == Opcode.WRITE_BARRIERED || op == Opcode.INITIALIZE;
-        final BarrierType barrier = (op == Opcode.WRITE_BARRIERED ? BarrierType.PRECISE : BarrierType.NONE);
-        final boolean compressible = (op == Opcode.WRITE_OBJECT || op == Opcode.WRITE_BARRIERED);
-        assert op != Opcode.INITIALIZE || location.isInit() : "must use init location for initializing";
-        b.add(new JavaWriteNode(writeKind, address, location, value, barrier, compressible));
-    }
-
-    protected AbstractCompareAndSwapNode casOp(JavaKind writeKind, JavaKind returnKind, AddressNode address, LocationIdentity location, ValueNode expectedValue, ValueNode newValue) {
-        boolean isLogic = returnKind == JavaKind.Boolean;
-        assert isLogic || writeKind == returnKind : writeKind + " != " + returnKind;
-        AbstractCompareAndSwapNode cas;
-        if (isLogic) {
-            cas = new LogicCompareAndSwapNode(address, expectedValue, newValue, location);
-        } else {
-            cas = new ValueCompareAndSwapNode(address, expectedValue, newValue, location);
-        }
-        return cas;
-    }
-
-    public AddressNode makeAddress(GraphBuilderContext b, ValueNode base, ValueNode offset) {
-        return b.add(new OffsetAddressNode(base, fromSigned(b, offset)));
-    }
-
-    public ValueNode fromUnsigned(GraphBuilderContext b, ValueNode value) {
-        return convert(b, value, wordKind, true);
-    }
-
-    public ValueNode fromSigned(GraphBuilderContext b, ValueNode value) {
-        return convert(b, value, wordKind, false);
-    }
-
-    public ValueNode toUnsigned(GraphBuilderContext b, ValueNode value, JavaKind toKind) {
-        return convert(b, value, toKind, true);
-    }
-
-    public ValueNode convert(GraphBuilderContext b, ValueNode value, JavaKind toKind, boolean unsigned) {
-        if (value.getStackKind() == toKind) {
-            return value;
-        }
-
-        if (toKind == JavaKind.Int) {
-            assert value.getStackKind() == JavaKind.Long;
-            return b.add(new NarrowNode(value, 32));
-        } else {
-            assert toKind == JavaKind.Long;
-            assert value.getStackKind() == JavaKind.Int;
-            if (unsigned) {
-                return b.add(new ZeroExtendNode(value, 64));
-            } else {
-                return b.add(new SignExtendNode(value, 64));
-            }
-        }
-    }
-
-    public WordTypes getWordTypes() {
-        return wordTypes;
-    }
-
-    private static BailoutException bailout(GraphBuilderContext b, String msg) {
-        throw b.bailout(msg + "\nat " + b.getCode().asStackTraceElement(b.bci()));
-    }
-}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileBytecode.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileBytecode.java	Fri May 12 13:56:13 2017 -0700
@@ -28,6 +28,7 @@
 import java.lang.instrument.Instrumentation;
 
 import org.graalvm.compiler.bytecode.Bytecode;
+import org.graalvm.compiler.bytecode.BytecodeProvider;
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.replacements.classfile.ClassfileConstant.Utf8;
 
@@ -78,6 +79,11 @@
         readCodeAttributes(stream);
     }
 
+    @Override
+    public BytecodeProvider getOrigin() {
+        return constantPool.context;
+    }
+
     private void readCodeAttributes(DataInputStream stream) throws IOException {
         int count = stream.readUnsignedShort();
         for (int i = 0; i < count; i++) {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileBytecodeProvider.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileBytecodeProvider.java	Fri May 12 13:56:13 2017 -0700
@@ -22,9 +22,8 @@
  */
 package org.graalvm.compiler.replacements.classfile;
 
-import static org.graalvm.compiler.core.common.util.ModuleAPI.getModule;
-import static org.graalvm.compiler.core.common.util.ModuleAPI.getResourceAsStream;
-import static org.graalvm.compiler.core.common.util.Util.JAVA_SPECIFICATION_VERSION;
+import static org.graalvm.compiler.serviceprovider.JDK9Method.getModule;
+import static org.graalvm.compiler.serviceprovider.JDK9Method.getResourceAsStream;
 
 import java.io.DataInputStream;
 import java.io.IOException;
@@ -34,6 +33,7 @@
 import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
 import org.graalvm.compiler.bytecode.Bytecode;
 import org.graalvm.compiler.bytecode.BytecodeProvider;
+import org.graalvm.compiler.serviceprovider.JDK9Method;
 import org.graalvm.util.EconomicMap;
 import org.graalvm.util.Equivalence;
 
@@ -101,7 +101,7 @@
 
     private static InputStream getClassfileAsStream(Class<?> c) {
         String classfilePath = c.getName().replace('.', '/') + ".class";
-        if (JAVA_SPECIFICATION_VERSION >= 9) {
+        if (JDK9Method.JAVA_SPECIFICATION_VERSION >= 9) {
             Object module = getModule.invoke(c);
             return getResourceAsStream.invoke(module, classfilePath);
         } else {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ArrayEqualsNode.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ArrayEqualsNode.java	Fri May 12 13:56:13 2017 -0700
@@ -26,7 +26,7 @@
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_1024;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1024;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.graph.NodeClass;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BasicArrayCopyNode.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BasicArrayCopyNode.java	Fri May 12 13:56:13 2017 -0700
@@ -22,13 +22,13 @@
  */
 package org.graalvm.compiler.replacements.nodes;
 
-import static org.graalvm.compiler.core.common.LocationIdentity.any;
+import static org.graalvm.api.word.LocationIdentity.any;
 import static org.graalvm.compiler.nodeinfo.InputType.Memory;
 import static org.graalvm.compiler.nodeinfo.InputType.State;
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_256;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_64;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.debug.Debug;
 import org.graalvm.compiler.graph.NodeClass;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroStateSplitNode.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroStateSplitNode.java	Fri May 12 13:56:13 2017 -0700
@@ -22,7 +22,7 @@
  */
 package org.graalvm.compiler.replacements.nodes;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.core.common.type.StampPair;
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.graph.NodeClass;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/GraalServices.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/GraalServices.java	Fri May 12 13:56:13 2017 -0700
@@ -22,9 +22,17 @@
  */
 package org.graalvm.compiler.serviceprovider;
 
+import static org.graalvm.compiler.serviceprovider.JDK9Method.Java8OrEarlier;
+import static org.graalvm.compiler.serviceprovider.JDK9Method.addOpens;
+import static org.graalvm.compiler.serviceprovider.JDK9Method.getModule;
+import static org.graalvm.compiler.serviceprovider.JDK9Method.getPackages;
+import static org.graalvm.compiler.serviceprovider.JDK9Method.isOpenTo;
+
+import java.lang.reflect.Method;
 import java.util.Iterator;
 import java.util.ServiceConfigurationError;
 import java.util.ServiceLoader;
+import java.util.Set;
 
 import jdk.vm.ci.services.JVMCIPermission;
 import jdk.vm.ci.services.Services;
@@ -32,14 +40,32 @@
 /**
  * A mechanism for accessing service providers that abstracts over whether Graal is running on
  * JVMCI-8 or JVMCI-9. In JVMCI-8, a JVMCI specific mechanism is used to lookup services via the
- * hidden JVMCI class loader. in JVMCI-9, the standard {@link ServiceLoader} mechanism is used.
+ * hidden JVMCI class loader. In JVMCI-9, the standard {@link ServiceLoader} mechanism is used.
  */
 public final class GraalServices {
 
     private GraalServices() {
     }
 
-    public static final boolean Java8OrEarlier = System.getProperty("java.specification.version").compareTo("1.9") < 0;
+    /**
+     * Opens all JVMCI packages to the module of a given class. This relies on JVMCI already having
+     * opened all its packages to the module defining {@link GraalServices}.
+     *
+     * @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);
+        if (jvmci != otherModule) {
+            Set<String> packages = getPackages.invoke(jvmci);
+            for (String pkg : packages) {
+                boolean opened = isOpenTo.invoke(jvmci, pkg, otherModule);
+                if (!opened) {
+                    addOpens.invoke(jvmci, pkg, otherModule);
+                }
+            }
+        }
+    }
 
     /**
      * Gets an {@link Iterable} of the providers available for a given service.
@@ -50,9 +76,9 @@
     public static <S> Iterable<S> load(Class<S> service) {
         assert !service.getName().startsWith("jdk.vm.ci") : "JVMCI services must be loaded via " + Services.class.getName();
         if (Java8OrEarlier) {
-            return Services.load(service);
+            return load8(service);
         }
-        ServiceLoader<S> iterable = ServiceLoader.load(service);
+        Iterable<S> iterable = ServiceLoader.load(service);
         return new Iterable<S>() {
             @Override
             public Iterator<S> iterator() {
@@ -66,8 +92,8 @@
                     @Override
                     public S next() {
                         S provider = iterator.next();
-                        // Allow Graal extensions to access JVMCI assuming they have JVMCIPermission
-                        Services.exportJVMCITo(provider.getClass());
+                        // Allow Graal extensions to access JVMCI
+                        openJVMCITo(provider.getClass());
                         return provider;
                     }
 
@@ -81,6 +107,23 @@
     }
 
     /**
+     * {@code Services.load(Class)} is only defined in JVMCI-8.
+     */
+    private static volatile Method loadMethod;
+
+    @SuppressWarnings("unchecked")
+    private static <S> Iterable<S> load8(Class<S> service) throws InternalError {
+        try {
+            if (loadMethod == null) {
+                loadMethod = Services.class.getMethod("load", Class.class);
+            }
+            return (Iterable<S>) loadMethod.invoke(null, service);
+        } catch (Exception e) {
+            throw new InternalError(e);
+        }
+    }
+
+    /**
      * Gets the provider for a given service for which at most one provider must be available.
      *
      * @param service the service whose provider is being requested
@@ -92,16 +135,14 @@
      */
     public static <S> S loadSingle(Class<S> service, boolean required) {
         assert !service.getName().startsWith("jdk.vm.ci") : "JVMCI services must be loaded via " + Services.class.getName();
-        if (Java8OrEarlier) {
-            return Services.loadSingle(service, required);
-        }
-        Iterable<S> providers = ServiceLoader.load(service);
+        Iterable<S> providers = load(service);
         S singleProvider = null;
         try {
             for (Iterator<S> it = providers.iterator(); it.hasNext();) {
                 singleProvider = it.next();
                 if (it.hasNext()) {
-                    throw new InternalError(String.format("Multiple %s providers found", service.getName()));
+                    S other = it.next();
+                    throw new InternalError(String.format("Multiple %s providers found: %s, %s", service.getName(), singleProvider.getClass().getName(), other.getClass().getName()));
                 }
             }
         } catch (ServiceConfigurationError e) {
@@ -111,9 +152,6 @@
             if (required) {
                 throw new InternalError(String.format("No provider for %s found", service.getName()));
             }
-        } else {
-            // Allow Graal extensions to access JVMCI assuming they have JVMCIPermission
-            Services.exportJVMCITo(singleProvider.getClass());
         }
         return singleProvider;
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/JDK9Method.java	Fri May 12 13:56:13 2017 -0700
@@ -0,0 +1,148 @@
+/*
+ * 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.serviceprovider;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+/**
+ * Reflection based access to API introduced by JDK 9. This allows the API to be used in code that
+ * must be compiled on a JDK prior to 9.
+ */
+public final class JDK9Method {
+
+    private static int getJavaSpecificationVersion() {
+        String value = System.getProperty("java.specification.version");
+        if (value.startsWith("1.")) {
+            value = value.substring(2);
+        }
+        return Integer.parseInt(value);
+    }
+
+    /**
+     * The integer value corresponding to the value of the {@code java.specification.version} system
+     * property after any leading {@code "1."} has been stripped.
+     */
+    public static final int JAVA_SPECIFICATION_VERSION = getJavaSpecificationVersion();
+
+    public JDK9Method(Class<?> declaringClass, String name, Class<?>... parameterTypes) {
+        try {
+            this.method = declaringClass.getMethod(name, parameterTypes);
+        } catch (Exception e) {
+            throw new InternalError(e);
+        }
+    }
+
+    /**
+     * Determines if the Java runtime is version 8 or earlier.
+     */
+    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;
+
+    /**
+     * {@code java.lang.Module.getPackages()}.
+     */
+    public static final JDK9Method getPackages;
+
+    /**
+     * {@code java.lang.Module.getResourceAsStream(String)}.
+     */
+    public static final JDK9Method getResourceAsStream;
+
+    /**
+     * {@code java.lang.Module.addOpens(String, Module)}.
+     */
+    public static final JDK9Method addOpens;
+
+    /**
+     * {@code java.lang.Module.isOpen(String, Module)}.
+     */
+    public static final JDK9Method 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());
+        try {
+            return (T) method.invoke(null, args);
+        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+            throw new InternalError(e);
+        }
+    }
+
+    /**
+     * 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);
+        }
+    }
+
+    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);
+        } else {
+            JDK9Method unavailable = new JDK9Method();
+            getModule = unavailable;
+            getPackages = unavailable;
+            addOpens = unavailable;
+            getResourceAsStream = unavailable;
+            isOpenTo = unavailable;
+        }
+    }
+
+    private JDK9Method() {
+        method = null;
+    }
+}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/GraalTest.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/GraalTest.java	Fri May 12 13:56:13 2017 -0700
@@ -37,7 +37,6 @@
 /**
  * Base class that contains common utility methods and classes useful in unit tests.
  */
-@AddExports("jdk.internal.vm.ci/jdk.vm.ci.services")
 public class GraalTest {
 
     public static final Unsafe UNSAFE;
@@ -81,7 +80,7 @@
         }
     }
 
-    protected Method getMethod(Class<?> clazz, String methodName, Class<?>[] parameterTypes) {
+    protected Method getMethod(Class<?> clazz, String methodName, Class<?>... parameterTypes) {
         try {
             return clazz.getMethod(methodName, parameterTypes);
         } catch (NoSuchMethodException | SecurityException e) {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/JLModule.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/JLModule.java	Fri May 12 13:56:13 2017 -0700
@@ -22,6 +22,7 @@
  */
 package org.graalvm.compiler.test;
 
+import java.lang.reflect.AccessibleObject;
 import java.lang.reflect.Method;
 import java.util.Set;
 
@@ -50,15 +51,28 @@
     private static final Method isExportedMethod;
     private static final Method isExported2Method;
     private static final Method addExportsMethod;
+    /**
+     * {@code jdk.internal.module.Modules.addExports(Module, String, Module)}.
+     */
+    private static final Method modulesAddExportsMethod;
+
+    /**
+     * {@code jdk.internal.module.Modules.addOpens(Module, String, Module)}.
+     */
+    private static final Method modulesAddOpensMethod;
+
     static {
         try {
             moduleClass = Class.forName("java.lang.Module");
+            Class<?> modulesClass = Class.forName("jdk.internal.module.Modules");
             getModuleMethod = Class.class.getMethod("getModule");
             getUnnamedModuleMethod = ClassLoader.class.getMethod("getUnnamedModule");
             getPackagesMethod = moduleClass.getMethod("getPackages");
             isExportedMethod = moduleClass.getMethod("isExported", String.class);
             isExported2Method = moduleClass.getMethod("isExported", String.class, moduleClass);
             addExportsMethod = moduleClass.getMethod("addExports", String.class, moduleClass);
+            modulesAddExportsMethod = modulesClass.getDeclaredMethod("addExports", moduleClass, String.class, moduleClass);
+            modulesAddOpensMethod = modulesClass.getDeclaredMethod("addOpens", moduleClass, String.class, moduleClass);
         } catch (Exception e) {
             throw new AssertionError(e);
         }
@@ -96,6 +110,7 @@
         }
     }
 
+    @SuppressWarnings("unchecked")
     public Set<String> getPackages() {
         try {
             return (Set<String>) getPackagesMethod.invoke(realModule);
@@ -127,4 +142,76 @@
             throw new AssertionError(e);
         }
     }
+
+    private static Object unbox(Object obj) {
+        if (obj instanceof JLModule) {
+            return ((JLModule) obj).realModule;
+        }
+        return obj;
+    }
+
+    /**
+     * Updates module m1 to export a package to module m2. Same as m1.addExports(pn, m2) but without
+     * a caller check
+     */
+    public static void uncheckedAddExports(Object m1, String pn, Object m2) {
+        try {
+            modulesAddExportsMethod.invoke(null, unbox(m1), pn, unbox(m2));
+        } catch (Exception e) {
+            throw new AssertionError(e);
+        }
+    }
+
+    /**
+     * Opens all packages in {@code moduleMember}'s module for deep reflection (i.e., allow
+     * {@link AccessibleObject#setAccessible(boolean)} to be called for any class/method/field) by
+     * {@code requestor}'s module.
+     */
+    public static void openAllPackagesForReflectionTo(Class<?> moduleMember, Class<?> requestor) {
+        try {
+            Object moduleToOpen = getModuleMethod.invoke(moduleMember);
+            Object requestorModule = getModuleMethod.invoke(requestor);
+            if (moduleToOpen != requestorModule) {
+                String[] packages = (String[]) getPackagesMethod.invoke(moduleToOpen);
+                for (String pkg : packages) {
+                    modulesAddOpensMethod.invoke(moduleToOpen, pkg, requestorModule);
+                }
+            }
+        } catch (Exception e) {
+            throw new AssertionError(e);
+        }
+    }
+
+    /**
+     * Opens {@code declaringClass}'s package to allow a method declared in {@code accessor} to call
+     * {@link AccessibleObject#setAccessible(boolean)} on an {@link AccessibleObject} representing a
+     * field or method declared by {@code declaringClass}.
+     */
+    public static void openForReflectionTo(Class<?> declaringClass, Class<?> accessor) {
+        try {
+            Object moduleToOpen = getModuleMethod.invoke(declaringClass);
+            Object accessorModule = getModuleMethod.invoke(accessor);
+            if (moduleToOpen != accessorModule) {
+                modulesAddOpensMethod.invoke(null, moduleToOpen, declaringClass.getPackage().getName(), accessorModule);
+            }
+        } catch (Exception e) {
+            throw new AssertionError(e);
+        }
+    }
+
+    /**
+     * Exports the package named {@code packageName} declared in {@code moduleMember}'s module to
+     * {@code requestor}'s module.
+     */
+    public static void exportPackageTo(Class<?> moduleMember, String packageName, Class<?> requestor) {
+        try {
+            Object moduleToExport = getModuleMethod.invoke(moduleMember);
+            Object requestorModule = getModuleMethod.invoke(requestor);
+            if (moduleToExport != requestorModule) {
+                modulesAddExportsMethod.invoke(null, moduleToExport, packageName, requestorModule);
+            }
+        } catch (Exception e) {
+            throw new AssertionError(e);
+        }
+    }
 }
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/SubprocessUtil.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/SubprocessUtil.java	Fri May 12 13:56:13 2017 -0700
@@ -22,10 +22,13 @@
  */
 package org.graalvm.compiler.test;
 
+import java.io.BufferedReader;
 import java.io.File;
 import java.io.IOException;
+import java.io.InputStreamReader;
 import java.nio.file.Files;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Formatter;
 import java.util.List;
 import java.util.regex.Matcher;
@@ -79,30 +82,6 @@
     }
 
     /**
-     * Formats an executed shell command followed by its output. The command is formatted such that
-     * it can be copy and pasted into a console for re-execution.
-     *
-     * @param command the list containing the program and its arguments
-     * @param outputLines the output of the command broken into lines
-     * @param header if non null, the returned string has a prefix of this value plus a newline
-     * @param trailer if non null, the returned string has a suffix of this value plus a newline
-     */
-    public static String formatExecutedCommand(List<String> command, List<String> outputLines, String header, String trailer) {
-        Formatter msg = new Formatter();
-        if (header != null) {
-            msg.format("%s%n", header);
-        }
-        msg.format("%s%n", CollectionsUtil.mapAndJoin(command, e -> quoteShellArg(String.valueOf(e)), " "));
-        for (String line : outputLines) {
-            msg.format("%s%n", line);
-        }
-        if (trailer != null) {
-            msg.format("%s%n", trailer);
-        }
-        return msg.toString();
-    }
-
-    /**
      * Returns a new copy {@code args} with debugger arguments removed.
      */
     public static List<String> withoutDebuggerArguments(List<String> args) {
@@ -130,6 +109,95 @@
         }
     }
 
+    /**
+     * The details of a subprocess execution.
+     */
+    public static class Subprocess {
+
+        /**
+         * The command line of the subprocess.
+         */
+        public final List<String> command;
+
+        /**
+         * Exit code of the subprocess.
+         */
+        public final int exitCode;
+
+        /**
+         * Output from the subprocess broken into lines.
+         */
+        public final List<String> output;
+
+        public Subprocess(List<String> command, int exitCode, List<String> output) {
+            this.command = command;
+            this.exitCode = exitCode;
+            this.output = output;
+        }
+
+        public static final String DASHES_DELIMITER = "-------------------------------------------------------";
+
+        /**
+         * Returns the command followed by the output as a string.
+         *
+         * @param delimiter if non-null, the returned string has this value as a prefix and suffix
+         */
+        public String toString(String delimiter) {
+            Formatter msg = new Formatter();
+            if (delimiter != null) {
+                msg.format("%s%n", delimiter);
+            }
+            msg.format("%s%n", CollectionsUtil.mapAndJoin(command, e -> quoteShellArg(String.valueOf(e)), " "));
+            for (String line : output) {
+                msg.format("%s%n", line);
+            }
+            if (delimiter != null) {
+                msg.format("%s%n", delimiter);
+            }
+            return msg.toString();
+        }
+
+        /**
+         * Returns the command followed by the output as a string delimited by
+         * {@value #DASHES_DELIMITER}.
+         */
+        @Override
+        public String toString() {
+            return toString(DASHES_DELIMITER);
+        }
+    }
+
+    /**
+     * Executes a Java subprocess.
+     *
+     * @param vmArgs the VM arguments
+     * @param mainClassAndArgs the main class and its arguments
+     */
+    public static Subprocess java(List<String> vmArgs, String... mainClassAndArgs) throws IOException, InterruptedException {
+        return java(vmArgs, Arrays.asList(mainClassAndArgs));
+    }
+
+    /**
+     * Executes a Java subprocess.
+     *
+     * @param vmArgs the VM arguments
+     * @param mainClassAndArgs the main class and its arguments
+     */
+    public static Subprocess java(List<String> vmArgs, List<String> mainClassAndArgs) throws IOException, InterruptedException {
+        List<String> command = new ArrayList<>(vmArgs);
+        command.addAll(mainClassAndArgs);
+        ProcessBuilder processBuilder = new ProcessBuilder(command);
+        processBuilder.redirectErrorStream(true);
+        Process process = processBuilder.start();
+        BufferedReader stdout = new BufferedReader(new InputStreamReader(process.getInputStream()));
+        String line;
+        List<String> output = new ArrayList<>();
+        while ((line = stdout.readLine()) != null) {
+            output.add(line);
+        }
+        return new Subprocess(command, process.waitFor(), output);
+    }
+
     private static final boolean isJava8OrEarlier = System.getProperty("java.specification.version").compareTo("1.9") < 0;
 
     private static boolean hasArg(String optionName) {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsClosure.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsClosure.java	Fri May 12 13:56:13 2017 -0700
@@ -25,7 +25,7 @@
 import java.util.ArrayList;
 import java.util.List;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.core.common.cfg.BlockMap;
 import org.graalvm.compiler.core.common.cfg.Loop;
 import org.graalvm.compiler.core.common.type.Stamp;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationBlockState.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationBlockState.java	Fri May 12 13:56:13 2017 -0700
@@ -25,7 +25,7 @@
 import java.util.Iterator;
 import java.util.List;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.nodes.FieldLocationIdentity;
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.virtual.AllocatedObjectNode;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationClosure.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationClosure.java	Fri May 12 13:56:13 2017 -0700
@@ -29,7 +29,7 @@
 import java.util.Iterator;
 import java.util.List;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.core.common.cfg.Loop;
 import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
 import org.graalvm.compiler.debug.Debug;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/ReadEliminationBlockState.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/ReadEliminationBlockState.java	Fri May 12 13:56:13 2017 -0700
@@ -24,7 +24,7 @@
 
 import java.util.Iterator;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.util.Equivalence;
 import org.graalvm.util.EconomicMap;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/ReadEliminationClosure.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/ReadEliminationClosure.java	Fri May 12 13:56:13 2017 -0700
@@ -22,13 +22,13 @@
  */
 package org.graalvm.compiler.virtual.phases.ea;
 
+import static org.graalvm.api.word.LocationIdentity.any;
 import static org.graalvm.compiler.core.common.GraalOptions.ReadEliminationMaxLoopVisits;
-import static org.graalvm.compiler.core.common.LocationIdentity.any;
 
 import java.util.Iterator;
 import java.util.List;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.core.common.cfg.Loop;
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.debug.Debug;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/AtomicUnsigned.java	Fri May 12 13:14:25 2017 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,71 +0,0 @@
-/*
- * Copyright (c) 2015, 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
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package org.graalvm.compiler.word;
-
-/**
- * A {@link Unsigned} value that may be updated atomically. See the
- * {@link java.util.concurrent.atomic} package specification for description of the properties of
- * atomic variables.
- */
-public class AtomicUnsigned extends AtomicWord<Unsigned> {
-
-    /**
-     * Atomically adds the given value to the current value.
-     *
-     * @param delta the value to add
-     * @return the previous value
-     */
-    public final Unsigned getAndAdd(Unsigned delta) {
-        return Word.unsigned(value.getAndAdd(delta.rawValue()));
-    }
-
-    /**
-     * Atomically adds the given value to the current value.
-     *
-     * @param delta the value to add
-     * @return the updated value
-     */
-    public final Unsigned addAndGet(Unsigned delta) {
-        return Word.unsigned(value.addAndGet(delta.rawValue()));
-    }
-
-    /**
-     * Atomically subtracts the given value from the current value.
-     *
-     * @param delta the value to add
-     * @return the previous value
-     */
-    public final Unsigned getAndSubtract(Unsigned delta) {
-        return Word.unsigned(value.getAndAdd(-delta.rawValue()));
-    }
-
-    /**
-     * Atomically subtracts the given value from the current value.
-     *
-     * @param delta the value to add
-     * @return the updated value
-     */
-    public final Unsigned subtractAndGet(Unsigned delta) {
-        return Word.unsigned(value.addAndGet(-delta.rawValue()));
-    }
-}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/AtomicWord.java	Fri May 12 13:14:25 2017 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,93 +0,0 @@
-/*
- * Copyright (c) 2015, 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
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package org.graalvm.compiler.word;
-
-import java.util.concurrent.atomic.AtomicLong;
-import java.util.concurrent.atomic.AtomicReference;
-
-/**
- * A {@link WordBase word} value that may be updated atomically. See the
- * {@link java.util.concurrent.atomic} package specification for description of the properties of
- * atomic variables.
- *
- * Similar to {@link AtomicReference}, but for {@link WordBase word} types. A dedicated
- * implementation is necessary because Object and word types cannot be mixed.
- */
-public class AtomicWord<T extends WordBase> {
-
-    /**
-     * For simplicity, we convert the word value to a long and delegate to existing atomic
-     * operations.
-     */
-    protected final AtomicLong value;
-
-    /**
-     * Creates a new AtomicLong with initial value {@link Word#zero}.
-     */
-    public AtomicWord() {
-        value = new AtomicLong();
-    }
-
-    /**
-     * Gets the current value.
-     *
-     * @return the current value
-     */
-    @SuppressWarnings("unchecked")
-    public final T get() {
-        return (T) Word.unsigned(value.get());
-    }
-
-    /**
-     * Sets to the given value.
-     *
-     * @param newValue the new value
-     */
-    public final void set(T newValue) {
-        value.set(newValue.rawValue());
-    }
-
-    /**
-     * Atomically sets to the given value and returns the old value.
-     *
-     * @param newValue the new value
-     * @return the previous value
-     */
-    @SuppressWarnings("unchecked")
-    public final T getAndSet(T newValue) {
-        return (T) Word.unsigned(value.getAndSet(newValue.rawValue()));
-    }
-
-    /**
-     * Atomically sets the value to the given updated value if the current value {@code ==} the
-     * expected value.
-     *
-     * @param expect the expected value
-     * @param update the new value
-     * @return {@code true} if successful. False return indicates that the actual value was not
-     *         equal to the expected value.
-     */
-    public final boolean compareAndSet(T expect, T update) {
-        return value.compareAndSet(expect.rawValue(), update.rawValue());
-    }
-}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/BarrieredAccess.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/BarrieredAccess.java	Fri May 12 13:56:13 2017 -0700
@@ -22,7 +22,11 @@
  */
 package org.graalvm.compiler.word;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
+import org.graalvm.api.word.Pointer;
+import org.graalvm.api.word.Signed;
+import org.graalvm.api.word.Unsigned;
+import org.graalvm.api.word.WordBase;
 import org.graalvm.compiler.word.Word.Opcode;
 import org.graalvm.compiler.word.Word.Operation;
 
@@ -152,7 +156,7 @@
      * @return the result of the memory access
      */
     @Operation(opcode = Opcode.READ_BARRIERED)
-    public static native Word readWord(Object object, WordBase offset, LocationIdentity locationIdentity);
+    public static native <T extends WordBase> T readWord(Object object, WordBase offset, LocationIdentity locationIdentity);
 
     /**
      * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
@@ -255,7 +259,7 @@
      * @return the result of the memory access
      */
     @Operation(opcode = Opcode.READ_BARRIERED)
-    public static native Word readWord(Object object, int offset, LocationIdentity locationIdentity);
+    public static native <T extends WordBase> T readWord(Object object, int offset, LocationIdentity locationIdentity);
 
     /**
      * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
@@ -612,7 +616,7 @@
      * @return the result of the memory access
      */
     @Operation(opcode = Opcode.READ_BARRIERED)
-    public static native Word readWord(Object object, WordBase offset);
+    public static native <T extends WordBase> T readWord(Object object, WordBase offset);
 
     /**
      * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
@@ -706,7 +710,7 @@
      * @return the result of the memory access
      */
     @Operation(opcode = Opcode.READ_BARRIERED)
-    public static native Word readWord(Object object, int offset);
+    public static native <T extends WordBase> T readWord(Object object, int offset);
 
     /**
      * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/ComparableWord.java	Fri May 12 13:14:25 2017 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2012, 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.word;
-
-public interface ComparableWord extends WordBase {
-
-    /**
-     * Compares this word with the specified value.
-     *
-     * @param val value to which this word is to be compared.
-     * @return {@code this == val}
-     */
-    boolean equal(ComparableWord val);
-
-    /**
-     * Compares this word with the specified value.
-     *
-     * @param val value to which this word is to be compared.
-     * @return {@code this != val}
-     */
-    boolean notEqual(ComparableWord val);
-}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/ObjectAccess.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/ObjectAccess.java	Fri May 12 13:56:13 2017 -0700
@@ -22,7 +22,11 @@
  */
 package org.graalvm.compiler.word;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.LocationIdentity;
+import org.graalvm.api.word.Pointer;
+import org.graalvm.api.word.Signed;
+import org.graalvm.api.word.Unsigned;
+import org.graalvm.api.word.WordBase;
 import org.graalvm.compiler.word.Word.Opcode;
 import org.graalvm.compiler.word.Word.Operation;
 
@@ -152,7 +156,7 @@
      * @return the result of the memory access
      */
     @Operation(opcode = Opcode.READ_OBJECT)
-    public static native Word readWord(Object object, WordBase offset, LocationIdentity locationIdentity);
+    public static native <T extends WordBase> T readWord(Object object, WordBase offset, LocationIdentity locationIdentity);
 
     /**
      * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
@@ -255,7 +259,7 @@
      * @return the result of the memory access
      */
     @Operation(opcode = Opcode.READ_OBJECT)
-    public static native Word readWord(Object object, int offset, LocationIdentity locationIdentity);
+    public static native <T extends WordBase> T readWord(Object object, int offset, LocationIdentity locationIdentity);
 
     /**
      * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
@@ -612,7 +616,7 @@
      * @return the result of the memory access
      */
     @Operation(opcode = Opcode.READ_OBJECT)
-    public static native Word readWord(Object object, WordBase offset);
+    public static native <T extends WordBase> T readWord(Object object, WordBase offset);
 
     /**
      * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
@@ -706,7 +710,7 @@
      * @return the result of the memory access
      */
     @Operation(opcode = Opcode.READ_OBJECT)
-    public static native Word readWord(Object object, int offset);
+    public static native <T extends WordBase> T readWord(Object object, int offset);
 
     /**
      * Reads the memory at address {@code (object + offset)}. The offset is in bytes.
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/Pointer.java	Fri May 12 13:14:25 2017 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,994 +0,0 @@
-/*
- * Copyright (c) 2012, 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.word;
-
-import org.graalvm.compiler.core.common.LocationIdentity;
-import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType;
-
-/**
- * Lowest-level memory access of native C memory. These methods access the raw memory without any
- * null checks, read- or write barriers. Even when the VM uses compressed pointers, then readObject
- * and writeObject methods access uncompressed pointers.
- * <p>
- * Do not use these methods to access Java objects, i.e., do not use
- * {@code Word.fromObject(obj).readXxx()}. Instead, use {@link ObjectAccess} or
- * {@link BarrieredAccess} to access Java objects.
- */
-public interface Pointer extends Unsigned, PointerBase {
-
-    /**
-     * Unsafe conversion of this Pointer to a Java language object. No correctness checks or type
-     * checks are performed. The caller must ensure that the Pointer contains a valid Java object
-     * that can i.e., processed by the garbage collector.
-     *
-     * @return this Pointer cast to Object.
-     */
-    Object toObject();
-
-    /**
-     * Unsafe conversion of this Pointer to a Java language object. No correctness checks or type
-     * checks are performed. The caller must ensure that the Pointer contains a valid Java object
-     * that can i.e., processed by the garbage collector and the Pointer does not contain 0.
-     *
-     * @return this Pointer cast to non-null Object.
-     */
-    Object toObjectNonNull();
-
-    /**
-     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     * <p>
-     * The offset is always treated as a {@link Signed} value. However, the static type is
-     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
-     * knows that the highest-order bit of the unsigned value is never used).
-     *
-     * @param offset the signed offset for the memory access
-     * @param locationIdentity the identity of the read
-     * @return the result of the memory access
-     */
-    byte readByte(WordBase offset, LocationIdentity locationIdentity);
-
-    /**
-     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     * <p>
-     * The offset is always treated as a {@link Signed} value. However, the static type is
-     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
-     * knows that the highest-order bit of the unsigned value is never used).
-     *
-     * @param offset the signed offset for the memory access
-     * @param locationIdentity the identity of the read
-     * @return the result of the memory access
-     */
-    char readChar(WordBase offset, LocationIdentity locationIdentity);
-
-    /**
-     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     * <p>
-     * The offset is always treated as a {@link Signed} value. However, the static type is
-     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
-     * knows that the highest-order bit of the unsigned value is never used).
-     *
-     * @param offset the signed offset for the memory access
-     * @param locationIdentity the identity of the read
-     * @return the result of the memory access
-     */
-    short readShort(WordBase offset, LocationIdentity locationIdentity);
-
-    /**
-     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     * <p>
-     * The offset is always treated as a {@link Signed} value. However, the static type is
-     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
-     * knows that the highest-order bit of the unsigned value is never used).
-     *
-     * @param offset the signed offset for the memory access
-     * @param locationIdentity the identity of the read
-     * @return the result of the memory access
-     */
-    int readInt(WordBase offset, LocationIdentity locationIdentity);
-
-    /**
-     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     * <p>
-     * The offset is always treated as a {@link Signed} value. However, the static type is
-     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
-     * knows that the highest-order bit of the unsigned value is never used).
-     *
-     * @param offset the signed offset for the memory access
-     * @param locationIdentity the identity of the read
-     * @return the result of the memory access
-     */
-    long readLong(WordBase offset, LocationIdentity locationIdentity);
-
-    /**
-     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     * <p>
-     * The offset is always treated as a {@link Signed} value. However, the static type is
-     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
-     * knows that the highest-order bit of the unsigned value is never used).
-     *
-     * @param offset the signed offset for the memory access
-     * @param locationIdentity the identity of the read
-     * @return the result of the memory access
-     */
-    float readFloat(WordBase offset, LocationIdentity locationIdentity);
-
-    /**
-     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     * <p>
-     * The offset is always treated as a {@link Signed} value. However, the static type is
-     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
-     * knows that the highest-order bit of the unsigned value is never used).
-     *
-     * @param offset the signed offset for the memory access
-     * @param locationIdentity the identity of the read
-     * @return the result of the memory access
-     */
-    double readDouble(WordBase offset, LocationIdentity locationIdentity);
-
-    /**
-     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     * <p>
-     * The offset is always treated as a {@link Signed} value. However, the static type is
-     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
-     * knows that the highest-order bit of the unsigned value is never used).
-     *
-     * @param offset the signed offset for the memory access
-     * @param locationIdentity the identity of the read
-     * @return the result of the memory access
-     */
-    Word readWord(WordBase offset, LocationIdentity locationIdentity);
-
-    /**
-     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     * <p>
-     * The offset is always treated as a {@link Signed} value. However, the static type is
-     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
-     * knows that the highest-order bit of the unsigned value is never used).
-     *
-     * @param offset the signed offset for the memory access
-     * @param locationIdentity the identity of the read
-     * @return the result of the memory access
-     */
-    Object readObject(WordBase offset, LocationIdentity locationIdentity);
-
-    /**
-     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     *
-     * @param offset the signed offset for the memory access
-     * @param locationIdentity the identity of the read
-     * @return the result of the memory access
-     */
-    byte readByte(int offset, LocationIdentity locationIdentity);
-
-    /**
-     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     *
-     * @param offset the signed offset for the memory access
-     * @param locationIdentity the identity of the read
-     * @return the result of the memory access
-     */
-    char readChar(int offset, LocationIdentity locationIdentity);
-
-    /**
-     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     *
-     * @param offset the signed offset for the memory access
-     * @param locationIdentity the identity of the read
-     * @return the result of the memory access
-     */
-    short readShort(int offset, LocationIdentity locationIdentity);
-
-    /**
-     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     *
-     * @param offset the signed offset for the memory access
-     * @param locationIdentity the identity of the read
-     * @return the result of the memory access
-     */
-    int readInt(int offset, LocationIdentity locationIdentity);
-
-    /**
-     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     *
-     * @param offset the signed offset for the memory access
-     * @param locationIdentity the identity of the read
-     * @return the result of the memory access
-     */
-    long readLong(int offset, LocationIdentity locationIdentity);
-
-    /**
-     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     *
-     * @param offset the signed offset for the memory access
-     * @param locationIdentity the identity of the read
-     * @return the result of the memory access
-     */
-    float readFloat(int offset, LocationIdentity locationIdentity);
-
-    /**
-     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     *
-     * @param offset the signed offset for the memory access
-     * @param locationIdentity the identity of the read
-     * @return the result of the memory access
-     */
-    double readDouble(int offset, LocationIdentity locationIdentity);
-
-    /**
-     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     *
-     * @param offset the signed offset for the memory access
-     * @param locationIdentity the identity of the read
-     * @return the result of the memory access
-     */
-    Word readWord(int offset, LocationIdentity locationIdentity);
-
-    /**
-     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     *
-     * @param offset the signed offset for the memory access
-     * @param locationIdentity the identity of the read
-     * @return the result of the memory access
-     */
-    Object readObject(int offset, LocationIdentity locationIdentity);
-
-    /**
-     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     * <p>
-     * The offset is always treated as a {@link Signed} value. However, the static type is
-     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
-     * knows that the highest-order bit of the unsigned value is never used).
-     *
-     * @param offset the signed offset for the memory access
-     * @param locationIdentity the identity of the write
-     * @param val the value to be written to memory
-     */
-    void writeByte(WordBase offset, byte val, LocationIdentity locationIdentity);
-
-    /**
-     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     * <p>
-     * The offset is always treated as a {@link Signed} value. However, the static type is
-     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
-     * knows that the highest-order bit of the unsigned value is never used).
-     *
-     * @param offset the signed offset for the memory access
-     * @param locationIdentity the identity of the write
-     * @param val the value to be written to memory
-     */
-    void writeChar(WordBase offset, char val, LocationIdentity locationIdentity);
-
-    /**
-     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     * <p>
-     * The offset is always treated as a {@link Signed} value. However, the static type is
-     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
-     * knows that the highest-order bit of the unsigned value is never used).
-     *
-     * @param offset the signed offset for the memory access
-     * @param locationIdentity the identity of the write
-     * @param val the value to be written to memory
-     */
-    void writeShort(WordBase offset, short val, LocationIdentity locationIdentity);
-
-    /**
-     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     * <p>
-     * The offset is always treated as a {@link Signed} value. However, the static type is
-     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
-     * knows that the highest-order bit of the unsigned value is never used).
-     *
-     * @param offset the signed offset for the memory access
-     * @param locationIdentity the identity of the write
-     * @param val the value to be written to memory
-     */
-    void writeInt(WordBase offset, int val, LocationIdentity locationIdentity);
-
-    /**
-     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     * <p>
-     * The offset is always treated as a {@link Signed} value. However, the static type is
-     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
-     * knows that the highest-order bit of the unsigned value is never used).
-     *
-     * @param offset the signed offset for the memory access
-     * @param locationIdentity the identity of the write
-     * @param val the value to be written to memory
-     */
-    void writeLong(WordBase offset, long val, LocationIdentity locationIdentity);
-
-    /**
-     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     * <p>
-     * The offset is always treated as a {@link Signed} value. However, the static type is
-     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
-     * knows that the highest-order bit of the unsigned value is never used).
-     *
-     * @param offset the signed offset for the memory access
-     * @param locationIdentity the identity of the write
-     * @param val the value to be written to memory
-     */
-    void writeFloat(WordBase offset, float val, LocationIdentity locationIdentity);
-
-    /**
-     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     * <p>
-     * The offset is always treated as a {@link Signed} value. However, the static type is
-     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
-     * knows that the highest-order bit of the unsigned value is never used).
-     *
-     * @param offset the signed offset for the memory access
-     * @param locationIdentity the identity of the write
-     * @param val the value to be written to memory
-     */
-    void writeDouble(WordBase offset, double val, LocationIdentity locationIdentity);
-
-    /**
-     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     * <p>
-     * The offset is always treated as a {@link Signed} value. However, the static type is
-     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
-     * knows that the highest-order bit of the unsigned value is never used).
-     *
-     * @param offset the signed offset for the memory access
-     * @param locationIdentity the identity of the write
-     * @param val the value to be written to memory
-     */
-    void writeWord(WordBase offset, WordBase val, LocationIdentity locationIdentity);
-
-    /**
-     * Initializes the memory at address {@code (this + offset)}. Both the base address and offset
-     * are in bytes. The memory must be uninitialized or zero prior to this operation.
-     * <p>
-     * The offset is always treated as a {@link Signed} value. However, the static type is
-     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
-     * knows that the highest-order bit of the unsigned value is never used).
-     *
-     * @param offset the signed offset for the memory access
-     * @param locationIdentity the identity of the write
-     * @param val the value to be written to memory
-     */
-    void initializeLong(WordBase offset, long val, LocationIdentity locationIdentity);
-
-    /**
-     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     * <p>
-     * The offset is always treated as a {@link Signed} value. However, the static type is
-     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
-     * knows that the highest-order bit of the unsigned value is never used).
-     *
-     * @param offset the signed offset for the memory access
-     * @param locationIdentity the identity of the write
-     * @param val the value to be written to memory
-     */
-    void writeObject(WordBase offset, Object val, LocationIdentity locationIdentity);
-
-    /**
-     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     *
-     * @param offset the signed offset for the memory access
-     * @param locationIdentity the identity of the write
-     * @param val the value to be written to memory
-     */
-    void writeByte(int offset, byte val, LocationIdentity locationIdentity);
-
-    /**
-     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     *
-     * @param offset the signed offset for the memory access
-     * @param locationIdentity the identity of the write
-     * @param val the value to be written to memory
-     */
-    void writeChar(int offset, char val, LocationIdentity locationIdentity);
-
-    /**
-     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     *
-     * @param offset the signed offset for the memory access
-     * @param locationIdentity the identity of the write
-     * @param val the value to be written to memory
-     */
-    void writeShort(int offset, short val, LocationIdentity locationIdentity);
-
-    /**
-     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     *
-     * @param offset the signed offset for the memory access
-     * @param locationIdentity the identity of the write
-     * @param val the value to be written to memory
-     */
-    void writeInt(int offset, int val, LocationIdentity locationIdentity);
-
-    /**
-     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     *
-     * @param offset the signed offset for the memory access
-     * @param locationIdentity the identity of the write
-     * @param val the value to be written to memory
-     */
-    void writeLong(int offset, long val, LocationIdentity locationIdentity);
-
-    /**
-     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     *
-     * @param offset the signed offset for the memory access
-     * @param locationIdentity the identity of the write
-     * @param val the value to be written to memory
-     */
-    void writeFloat(int offset, float val, LocationIdentity locationIdentity);
-
-    /**
-     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     *
-     * @param offset the signed offset for the memory access
-     * @param locationIdentity the identity of the write
-     * @param val the value to be written to memory
-     */
-    void writeDouble(int offset, double val, LocationIdentity locationIdentity);
-
-    /**
-     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     *
-     * @param offset the signed offset for the memory access
-     * @param locationIdentity the identity of the write
-     * @param val the value to be written to memory
-     */
-    void writeWord(int offset, WordBase val, LocationIdentity locationIdentity);
-
-    /**
-     * Initializes the memory at address {@code (this + offset)}. Both the base address and offset
-     * are in bytes. The memory must be uninitialized or zero prior to this operation.
-     *
-     * @param offset the signed offset for the memory access
-     * @param locationIdentity the identity of the write
-     * @param val the value to be written to memory
-     */
-    void initializeLong(int offset, long val, LocationIdentity locationIdentity);
-
-    /**
-     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     *
-     * @param offset the signed offset for the memory access
-     * @param locationIdentity the identity of the write
-     * @param val the value to be written to memory
-     */
-    void writeObject(int offset, Object val, LocationIdentity locationIdentity);
-
-    /**
-     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     * <p>
-     * The offset is always treated as a {@link Signed} value. However, the static type is
-     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
-     * knows that the highest-order bit of the unsigned value is never used).
-     *
-     * @param offset the signed offset for the memory access
-     * @return the result of the memory access
-     */
-    byte readByte(WordBase offset);
-
-    /**
-     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     * <p>
-     * The offset is always treated as a {@link Signed} value. However, the static type is
-     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
-     * knows that the highest-order bit of the unsigned value is never used).
-     *
-     * @param offset the signed offset for the memory access
-     * @return the result of the memory access
-     */
-    char readChar(WordBase offset);
-
-    /**
-     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     * <p>
-     * The offset is always treated as a {@link Signed} value. However, the static type is
-     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
-     * knows that the highest-order bit of the unsigned value is never used).
-     *
-     * @param offset the signed offset for the memory access
-     * @return the result of the memory access
-     */
-    short readShort(WordBase offset);
-
-    /**
-     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     * <p>
-     * The offset is always treated as a {@link Signed} value. However, the static type is
-     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
-     * knows that the highest-order bit of the unsigned value is never used).
-     *
-     * @param offset the signed offset for the memory access
-     * @return the result of the memory access
-     */
-    int readInt(WordBase offset);
-
-    /**
-     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     * <p>
-     * The offset is always treated as a {@link Signed} value. However, the static type is
-     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
-     * knows that the highest-order bit of the unsigned value is never used).
-     *
-     * @param offset the signed offset for the memory access
-     * @return the result of the memory access
-     */
-    long readLong(WordBase offset);
-
-    /**
-     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     * <p>
-     * The offset is always treated as a {@link Signed} value. However, the static type is
-     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
-     * knows that the highest-order bit of the unsigned value is never used).
-     *
-     * @param offset the signed offset for the memory access
-     * @return the result of the memory access
-     */
-    float readFloat(WordBase offset);
-
-    /**
-     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     * <p>
-     * The offset is always treated as a {@link Signed} value. However, the static type is
-     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
-     * knows that the highest-order bit of the unsigned value is never used).
-     *
-     * @param offset the signed offset for the memory access
-     * @return the result of the memory access
-     */
-    double readDouble(WordBase offset);
-
-    /**
-     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     * <p>
-     * The offset is always treated as a {@link Signed} value. However, the static type is
-     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
-     * knows that the highest-order bit of the unsigned value is never used).
-     *
-     * @param offset the signed offset for the memory access
-     * @return the result of the memory access
-     */
-    Word readWord(WordBase offset);
-
-    /**
-     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     * <p>
-     * The offset is always treated as a {@link Signed} value. However, the static type is
-     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
-     * knows that the highest-order bit of the unsigned value is never used).
-     *
-     * @param offset the signed offset for the memory access
-     * @return the result of the memory access
-     */
-    Object readObject(WordBase offset);
-
-    /**
-     * Reads the memory at address {@code (this + offset)}. This access will decompress the oop if
-     * the VM uses compressed oops, and it can be parameterized to allow read barriers (G1 referent
-     * field).
-     * <p>
-     * The offset is always treated as a {@link Signed} value. However, the static type is
-     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
-     * knows that the highest-order bit of the unsigned value is never used).
-     *
-     * @param offset the signed offset for the memory access
-     * @param barrierType the type of the read barrier to be added
-     * @return the result of the memory access
-     */
-    Object readObject(WordBase offset, BarrierType barrierType);
-
-    /**
-     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     *
-     * @param offset the signed offset for the memory access
-     * @return the result of the memory access
-     */
-    byte readByte(int offset);
-
-    /**
-     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     *
-     * @param offset the signed offset for the memory access
-     * @return the result of the memory access
-     */
-    char readChar(int offset);
-
-    /**
-     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     *
-     * @param offset the signed offset for the memory access
-     * @return the result of the memory access
-     */
-    short readShort(int offset);
-
-    /**
-     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     *
-     * @param offset the signed offset for the memory access
-     * @return the result of the memory access
-     */
-    int readInt(int offset);
-
-    /**
-     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     *
-     * @param offset the signed offset for the memory access
-     * @return the result of the memory access
-     */
-    long readLong(int offset);
-
-    /**
-     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     *
-     * @param offset the signed offset for the memory access
-     * @return the result of the memory access
-     */
-    float readFloat(int offset);
-
-    /**
-     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     *
-     * @param offset the signed offset for the memory access
-     * @return the result of the memory access
-     */
-    double readDouble(int offset);
-
-    /**
-     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     *
-     * @param offset the signed offset for the memory access
-     * @return the result of the memory access
-     */
-    Word readWord(int offset);
-
-    /**
-     * Reads the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     *
-     * @param offset the signed offset for the memory access
-     * @return the result of the memory access
-     */
-    Object readObject(int offset);
-
-    /**
-     * Reads the memory at address {@code (this + offset)}. This access will decompress the oop if
-     * the VM uses compressed oops, and it can be parameterized to allow read barriers (G1 referent
-     * field).
-     *
-     * @param offset the signed offset for the memory access
-     * @param barrierType the type of the read barrier to be added
-     * @return the result of the memory access
-     */
-    Object readObject(int offset, BarrierType barrierType);
-
-    /**
-     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     * <p>
-     * The offset is always treated as a {@link Signed} value. However, the static type is
-     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
-     * knows that the highest-order bit of the unsigned value is never used).
-     *
-     * @param offset the signed offset for the memory access
-     * @param val the value to be written to memory
-     */
-    void writeByte(WordBase offset, byte val);
-
-    /**
-     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     * <p>
-     * The offset is always treated as a {@link Signed} value. However, the static type is
-     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
-     * knows that the highest-order bit of the unsigned value is never used).
-     *
-     * @param offset the signed offset for the memory access
-     * @param val the value to be written to memory
-     */
-    void writeChar(WordBase offset, char val);
-
-    /**
-     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     * <p>
-     * The offset is always treated as a {@link Signed} value. However, the static type is
-     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
-     * knows that the highest-order bit of the unsigned value is never used).
-     *
-     * @param offset the signed offset for the memory access
-     * @param val the value to be written to memory
-     */
-    void writeShort(WordBase offset, short val);
-
-    /**
-     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     * <p>
-     * The offset is always treated as a {@link Signed} value. However, the static type is
-     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
-     * knows that the highest-order bit of the unsigned value is never used).
-     *
-     * @param offset the signed offset for the memory access
-     * @param val the value to be written to memory
-     */
-    void writeInt(WordBase offset, int val);
-
-    /**
-     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     * <p>
-     * The offset is always treated as a {@link Signed} value. However, the static type is
-     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
-     * knows that the highest-order bit of the unsigned value is never used).
-     *
-     * @param offset the signed offset for the memory access
-     * @param val the value to be written to memory
-     */
-    void writeLong(WordBase offset, long val);
-
-    /**
-     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     * <p>
-     * The offset is always treated as a {@link Signed} value. However, the static type is
-     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
-     * knows that the highest-order bit of the unsigned value is never used).
-     *
-     * @param offset the signed offset for the memory access
-     * @param val the value to be written to memory
-     */
-    void writeFloat(WordBase offset, float val);
-
-    /**
-     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     * <p>
-     * The offset is always treated as a {@link Signed} value. However, the static type is
-     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
-     * knows that the highest-order bit of the unsigned value is never used).
-     *
-     * @param offset the signed offset for the memory access
-     * @param val the value to be written to memory
-     */
-    void writeDouble(WordBase offset, double val);
-
-    /**
-     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     * <p>
-     * The offset is always treated as a {@link Signed} value. However, the static type is
-     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
-     * knows that the highest-order bit of the unsigned value is never used).
-     *
-     * @param offset the signed offset for the memory access
-     * @param val the value to be written to memory
-     */
-    void writeWord(WordBase offset, WordBase val);
-
-    /**
-     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     * <p>
-     * The offset is always treated as a {@link Signed} value. However, the static type is
-     * {@link WordBase} to avoid the frequent casts to of {@link Unsigned} values (where the caller
-     * knows that the highest-order bit of the unsigned value is never used).
-     *
-     * @param offset the signed offset for the memory access
-     * @param val the value to be written to memory
-     */
-    void writeObject(WordBase offset, Object val);
-
-    int compareAndSwapInt(WordBase offset, int expectedValue, int newValue, LocationIdentity locationIdentity);
-
-    long compareAndSwapLong(WordBase offset, long expectedValue, long newValue, LocationIdentity locationIdentity);
-
-    Word compareAndSwapWord(WordBase offset, WordBase expectedValue, WordBase newValue, LocationIdentity locationIdentity);
-
-    Object compareAndSwapObject(WordBase offset, Object expectedValue, Object newValue, LocationIdentity locationIdentity);
-
-    boolean logicCompareAndSwapInt(WordBase offset, int expectedValue, int newValue, LocationIdentity locationIdentity);
-
-    boolean logicCompareAndSwapLong(WordBase offset, long expectedValue, long newValue, LocationIdentity locationIdentity);
-
-    boolean logicCompareAndSwapWord(WordBase offset, WordBase expectedValue, WordBase newValue, LocationIdentity locationIdentity);
-
-    boolean logicCompareAndSwapObject(WordBase offset, Object expectedValue, Object newValue, LocationIdentity locationIdentity);
-
-    /**
-     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     *
-     * @param offset the signed offset for the memory access
-     * @param val the value to be written to memory
-     */
-    void writeByte(int offset, byte val);
-
-    /**
-     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     *
-     * @param offset the signed offset for the memory access
-     * @param val the value to be written to memory
-     */
-    void writeChar(int offset, char val);
-
-    /**
-     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     *
-     * @param offset the signed offset for the memory access
-     * @param val the value to be written to memory
-     */
-    void writeShort(int offset, short val);
-
-    /**
-     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     *
-     * @param offset the signed offset for the memory access
-     * @param val the value to be written to memory
-     */
-    void writeInt(int offset, int val);
-
-    /**
-     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     *
-     * @param offset the signed offset for the memory access
-     * @param val the value to be written to memory
-     */
-    void writeLong(int offset, long val);
-
-    /**
-     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     *
-     * @param offset the signed offset for the memory access
-     * @param val the value to be written to memory
-     */
-    void writeFloat(int offset, float val);
-
-    /**
-     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     *
-     * @param offset the signed offset for the memory access
-     * @param val the value to be written to memory
-     */
-    void writeDouble(int offset, double val);
-
-    /**
-     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     *
-     * @param offset the signed offset for the memory access
-     * @param val the value to be written to memory
-     */
-    void writeWord(int offset, WordBase val);
-
-    /**
-     * Writes the memory at address {@code (this + offset)}. Both the base address and offset are in
-     * bytes.
-     *
-     * @param offset the signed offset for the memory access
-     * @param val the value to be written to memory
-     */
-    void writeObject(int offset, Object val);
-
-    int compareAndSwapInt(int offset, int expectedValue, int newValue, LocationIdentity locationIdentity);
-
-    long compareAndSwapLong(int offset, long expectedValue, long newValue, LocationIdentity locationIdentity);
-
-    Word compareAndSwapWord(int offset, WordBase expectedValue, WordBase newValue, LocationIdentity locationIdentity);
-
-    Object compareAndSwapObject(int offset, Object expectedValue, Object newValue, LocationIdentity locationIdentity);
-
-    boolean logicCompareAndSwapInt(int offset, int expectedValue, int newValue, LocationIdentity locationIdentity);
-
-    boolean logicCompareAndSwapLong(int offset, long expectedValue, long newValue, LocationIdentity locationIdentity);
-
-    boolean logicCompareAndSwapWord(int offset, WordBase expectedValue, WordBase newValue, LocationIdentity locationIdentity);
-
-    boolean logicCompareAndSwapObject(int offset, Object expectedValue, Object newValue, LocationIdentity locationIdentity);
-
-    // Math functions that are defined in Unsigned, but known to preserve the
-    // pointer-characteristics.
-    // It is therefore safe that they return a static type of Pointer instead of Unsigned.
-
-    @Override
-    Pointer add(Unsigned val);
-
-    @Override
-    Pointer add(int val);
-
-    @Override
-    Pointer subtract(Unsigned val);
-
-    @Override
-    Pointer subtract(int val);
-
-    @Override
-    Pointer and(Unsigned val);
-
-    @Override
-    Pointer and(int val);
-
-    @Override
-    Pointer or(Unsigned val);
-
-    @Override
-    Pointer or(int val);
-}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/PointerBase.java	Fri May 12 13:14:25 2017 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,30 +0,0 @@
-/*
- * Copyright (c) 2013, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package org.graalvm.compiler.word;
-
-/**
- * Marker interface for all {@link WordBase word types} that have the semantic of a pointer (but not
- * necessarily all the memory access methods defined in {@link Pointer}).
- */
-public interface PointerBase extends ComparableWord {
-}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/PointerUtils.java	Fri May 12 13:14:25 2017 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,135 +0,0 @@
-/*
- * Copyright (c) 2015, 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
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package org.graalvm.compiler.word;
-
-/**
- * Utility methods on Pointers.
- */
-public final class PointerUtils {
-
-    private PointerUtils() {
-        // This is a class of static methods, so no need for any instances.
-    }
-
-    /**
-     * The value of a null Pointer.
-     *
-     * @return A null Pointer value.
-     */
-    @SuppressWarnings("unchecked")
-    public static <T extends PointerBase> T nullPointer() {
-        return (T) Word.zero();
-    }
-
-    /**
-     * Predicate to check for the null Pointer value.
-     *
-     * @return Whether that Pointer is the null Pointer.
-     */
-    public static boolean isNull(ComparableWord that) {
-        return that.equal(nullPointer());
-    }
-
-    /**
-     * Predicate to check for a non-null Pointer value.
-     *
-     * @return Whether that Pointer is not the null Pointer.
-     */
-    public static boolean isNonNull(ComparableWord that) {
-        return that.notEqual(nullPointer());
-    }
-
-    /**
-     * Round a Pointer down to the nearest smaller multiple.
-     *
-     * @param that The Pointer to be rounded up.
-     * @param multiple The multiple to which that Pointer should be decreased.
-     * @return That Pointer, but rounded down.
-     */
-    public static Pointer roundDown(PointerBase that, Unsigned multiple) {
-        return (Pointer) UnsignedUtils.roundDown((Unsigned) that, multiple);
-    }
-
-    /**
-     * Round a Pointer up to the nearest larger multiple.
-     *
-     * @param that The Pointer to be rounded up.
-     * @param multiple The multiple to which that Pointer should be increased.
-     * @return That Pointer, but rounded up.
-     */
-    public static Pointer roundUp(PointerBase that, Unsigned multiple) {
-        return (Pointer) UnsignedUtils.roundUp((Unsigned) that, multiple);
-    }
-
-    /**
-     * Check that a Pointer is an even multiple.
-     *
-     * @param that The Pointer to be verified as a multiple.
-     * @param multiple The multiple against which the Pointer should be verified.
-     * @return true if that Pointer is a multiple, false otherwise.
-     */
-    public static boolean isAMultiple(PointerBase that, Unsigned multiple) {
-        return that.equal(PointerUtils.roundDown(that, multiple));
-    }
-
-    /**
-     * Return the distance between two Pointers.
-     *
-     * @param pointer1 A first Pointer.
-     * @param pointer2 A second Pointer.
-     * @return The distance in bytes between the two Pointers.
-     */
-    public static Unsigned absoluteDifference(PointerBase pointer1, PointerBase pointer2) {
-        Pointer p1 = (Pointer) pointer1;
-        Pointer p2 = (Pointer) pointer2;
-        final Unsigned result;
-        if (p1.aboveOrEqual(p2)) {
-            result = p1.subtract(p2);
-        } else {
-            result = p2.subtract(p1);
-        }
-        return result;
-    }
-
-    /**
-     * The minimum of two Pointers.
-     *
-     * @param x A Pointer.
-     * @param y Another Pointer.
-     * @return The whichever Pointer is smaller.
-     */
-    public static <T extends PointerBase> T min(T x, T y) {
-        return (((Pointer) x).belowOrEqual((Pointer) y)) ? x : y;
-    }
-
-    /**
-     * The maximum of two Pointers.
-     *
-     * @param x A Pointer.
-     * @param y Another Pointer.
-     * @return The whichever Pointer is larger.
-     */
-    public static <T extends PointerBase> T max(T x, T y) {
-        return (((Pointer) x).aboveOrEqual((Pointer) y)) ? x : y;
-    }
-}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/Signed.java	Fri May 12 13:14:25 2017 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,296 +0,0 @@
-/*
- * Copyright (c) 2012, 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.word;
-
-public interface Signed extends ComparableWord {
-
-    /**
-     * Returns a Signed whose value is {@code (this + val)}.
-     *
-     * @param val value to be added to this Signed.
-     * @return {@code this + val}
-     */
-    Signed add(Signed val);
-
-    /**
-     * Returns a Signed whose value is {@code (this - val)}.
-     *
-     * @param val value to be subtracted from this Signed.
-     * @return {@code this - val}
-     */
-    Signed subtract(Signed val);
-
-    /**
-     * Returns a Signed whose value is {@code (this * val)}.
-     *
-     * @param val value to be multiplied by this Signed.
-     * @return {@code this * val}
-     */
-    Signed multiply(Signed val);
-
-    /**
-     * Returns a Signed whose value is {@code (this / val)}.
-     *
-     * @param val value by which this Signed is to be divided.
-     * @return {@code this / val}
-     */
-    Signed signedDivide(Signed val);
-
-    /**
-     * Returns a Signed whose value is {@code (this % val)}.
-     *
-     * @param val value by which this Signed is to be divided, and the remainder computed.
-     * @return {@code this % val}
-     */
-    Signed signedRemainder(Signed val);
-
-    /**
-     * Returns a Signed whose value is {@code (this << n)}.
-     *
-     * @param n shift distance, in bits.
-     * @return {@code this << n}
-     */
-    Signed shiftLeft(Unsigned n);
-
-    /**
-     * Returns a Signed whose value is {@code (this >> n)}. Sign extension is performed.
-     *
-     * @param n shift distance, in bits.
-     * @return {@code this >> n}
-     */
-    Signed signedShiftRight(Unsigned n);
-
-    /**
-     * Returns a Signed whose value is {@code (this & val)}. (This method returns a negative Signed
-     * if and only if this and val are both negative.)
-     *
-     * @param val value to be AND'ed with this Signed.
-     * @return {@code this & val}
-     */
-    Signed and(Signed val);
-
-    /**
-     * Returns a Signed whose value is {@code (this | val)}. (This method returns a negative Signed
-     * if and only if either this or val is negative.)
-     *
-     * @param val value to be OR'ed with this Signed.
-     * @return {@code this | val}
-     */
-    Signed or(Signed val);
-
-    /**
-     * Returns a Signed whose value is {@code (this ^ val)}. (This method returns a negative Signed
-     * if and only if exactly one of this and val are negative.)
-     *
-     * @param val value to be XOR'ed with this Signed.
-     * @return {@code this ^ val}
-     */
-    Signed xor(Signed val);
-
-    /**
-     * Returns a Signed whose value is {@code (~this)}. (This method returns a negative value if and
-     * only if this Signed is non-negative.)
-     *
-     * @return {@code ~this}
-     */
-    Signed not();
-
-    /**
-     * Compares this Signed with the specified value.
-     *
-     * @param val value to which this Signed is to be compared.
-     * @return {@code this == val}
-     */
-    boolean equal(Signed val);
-
-    /**
-     * Compares this Signed with the specified value.
-     *
-     * @param val value to which this Signed is to be compared.
-     * @return {@code this != val}
-     */
-    boolean notEqual(Signed val);
-
-    /**
-     * Compares this Signed with the specified value.
-     *
-     * @param val value to which this Signed is to be compared.
-     * @return {@code this < val}
-     */
-    boolean lessThan(Signed val);
-
-    /**
-     * Compares this Signed with the specified value.
-     *
-     * @param val value to which this Signed is to be compared.
-     * @return {@code this <= val}
-     */
-    boolean lessOrEqual(Signed val);
-
-    /**
-     * Compares this Signed with the specified value.
-     *
-     * @param val value to which this Signed is to be compared.
-     * @return {@code this > val}
-     */
-    boolean greaterThan(Signed val);
-
-    /**
-     * Compares this Signed with the specified value.
-     *
-     * @param val value to which this Signed is to be compared.
-     * @return {@code this >= val}
-     */
-    boolean greaterOrEqual(Signed val);
-
-    /**
-     * Returns a Signed whose value is {@code (this + val)}.
-     *
-     * @param val value to be added to this Signed.
-     * @return {@code this + val}
-     */
-    Signed add(int val);
-
-    /**
-     * Returns a Signed whose value is {@code (this - val)}.
-     *
-     * @param val value to be subtracted from this Signed.
-     * @return {@code this - val}
-     */
-    Signed subtract(int val);
-
-    /**
-     * Returns a Signed whose value is {@code (this * val)}.
-     *
-     * @param val value to be multiplied by this Signed.
-     * @return {@code this * val}
-     */
-    Signed multiply(int val);
-
-    /**
-     * Returns a Signed whose value is {@code (this / val)}.
-     *
-     * @param val value by which this Signed is to be divided.
-     * @return {@code this / val}
-     */
-    Signed signedDivide(int val);
-
-    /**
-     * Returns a Signed whose value is {@code (this % val)}.
-     *
-     * @param val value by which this Signed is to be divided, and the remainder computed.
-     * @return {@code this % val}
-     */
-    Signed signedRemainder(int val);
-
-    /**
-     * Returns a Signed whose value is {@code (this << n)}.
-     *
-     * @param n shift distance, in bits.
-     * @return {@code this << n}
-     */
-    Signed shiftLeft(int n);
-
-    /**
-     * Returns a Signed whose value is {@code (this >> n)}. Sign extension is performed.
-     *
-     * @param n shift distance, in bits.
-     * @return {@code this >> n}
-     */
-    Signed signedShiftRight(int n);
-
-    /**
-     * Returns a Signed whose value is {@code (this & val)}. (This method returns a negative Signed
-     * if and only if this and val are both negative.)
-     *
-     * @param val value to be AND'ed with this Signed.
-     * @return {@code this & val}
-     */
-    Signed and(int val);
-
-    /**
-     * Returns a Signed whose value is {@code (this | val)}. (This method returns a negative Signed
-     * if and only if either this or val is negative.)
-     *
-     * @param val value to be OR'ed with this Signed.
-     * @return {@code this | val}
-     */
-    Signed or(int val);
-
-    /**
-     * Returns a Signed whose value is {@code (this ^ val)}. (This method returns a negative Signed
-     * if and only if exactly one of this and val are negative.)
-     *
-     * @param val value to be XOR'ed with this Signed.
-     * @return {@code this ^ val}
-     */
-    Signed xor(int val);
-
-    /**
-     * Compares this Signed with the specified value.
-     *
-     * @param val value to which this Signed is to be compared.
-     * @return {@code this == val}
-     */
-    boolean equal(int val);
-
-    /**
-     * Compares this Signed with the specified value.
-     *
-     * @param val value to which this Signed is to be compared.
-     * @return {@code this != val}
-     */
-    boolean notEqual(int val);
-
-    /**
-     * Compares this Signed with the specified value.
-     *
-     * @param val value to which this Signed is to be compared.
-     * @return {@code this < val}
-     */
-    boolean lessThan(int val);
-
-    /**
-     * Compares this Signed with the specified value.
-     *
-     * @param val value to which this Signed is to be compared.
-     * @return {@code this <= val}
-     */
-    boolean lessOrEqual(int val);
-
-    /**
-     * Compares this Signed with the specified value.
-     *
-     * @param val value to which this Signed is to be compared.
-     * @return {@code this > val}
-     */
-    boolean greaterThan(int val);
-
-    /**
-     * Compares this Signed with the specified value.
-     *
-     * @param val value to which this Signed is to be compared.
-     * @return {@code this >= val}
-     */
-    boolean greaterOrEqual(int val);
-}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/Unsigned.java	Fri May 12 13:14:25 2017 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,337 +0,0 @@
-/*
- * Copyright (c) 2012, 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.word;
-
-public interface Unsigned extends ComparableWord {
-
-    /**
-     * Returns a Unsigned whose value is {@code (this + val)}.
-     *
-     * @param val value to be added to this Unsigned.
-     * @return {@code this + val}
-     */
-    Unsigned add(Unsigned val);
-
-    /**
-     * Returns a Unsigned whose value is {@code (this - val)}.
-     *
-     * @param val value to be subtracted from this Unsigned.
-     * @return {@code this - val}
-     */
-    Unsigned subtract(Unsigned val);
-
-    /**
-     * Returns a Unsigned whose value is {@code (this * val)}.
-     *
-     * @param val value to be multiplied by this Unsigned.
-     * @return {@code this * val}
-     */
-    Unsigned multiply(Unsigned val);
-
-    /**
-     * Returns a Unsigned whose value is {@code (this / val)}.
-     *
-     * @param val value by which this Unsigned is to be divided.
-     * @return {@code this / val}
-     */
-    Unsigned unsignedDivide(Unsigned val);
-
-    /**
-     * Returns a Unsigned whose value is {@code (this % val)}.
-     *
-     * @param val value by which this Unsigned is to be divided, and the remainder computed.
-     * @return {@code this % val}
-     */
-    Unsigned unsignedRemainder(Unsigned val);
-
-    /**
-     * Returns a Unsigned whose value is {@code (this << n)}.
-     *
-     * @param n shift distance, in bits.
-     * @return {@code this << n}
-     */
-    Unsigned shiftLeft(Unsigned n);
-
-    /**
-     * Returns a Unsigned whose value is {@code (this >>> n)}. No sign extension is performed.
-     *
-     * @param n shift distance, in bits.
-     * @return {@code this >> n}
-     */
-    Unsigned unsignedShiftRight(Unsigned n);
-
-    /**
-     * Returns a Unsigned whose value is {@code (this & val)}.
-     *
-     * @param val value to be AND'ed with this Unsigned.
-     * @return {@code this & val}
-     */
-    Unsigned and(Unsigned val);
-
-    /**
-     * Returns a Unsigned whose value is {@code (this | val)}.
-     *
-     * @param val value to be OR'ed with this Unsigned.
-     * @return {@code this | val}
-     */
-    Unsigned or(Unsigned val);
-
-    /**
-     * Returns a Unsigned whose value is {@code (this ^ val)}.
-     *
-     * @param val value to be XOR'ed with this Unsigned.
-     * @return {@code this ^ val}
-     */
-    Unsigned xor(Unsigned val);
-
-    /**
-     * Returns a Unsigned whose value is {@code (~this)}.
-     *
-     * @return {@code ~this}
-     */
-    Unsigned not();
-
-    /**
-     * Compares this Unsigned with the specified value.
-     *
-     * @param val value to which this Unsigned is to be compared.
-     * @return {@code this == val}
-     */
-    boolean equal(Unsigned val);
-
-    /**
-     * Compares this Unsigned with the specified value.
-     *
-     * @param val value to which this Unsigned is to be compared.
-     * @return {@code this != val}
-     */
-    boolean notEqual(Unsigned val);
-
-    /**
-     * Compares this Unsigned with the specified value.
-     *
-     * @param val value to which this Unsigned is to be compared.
-     * @return {@code this < val}
-     */
-    boolean belowThan(Unsigned val);
-
-    /**
-     * Compares this Unsigned with the specified value.
-     *
-     * @param val value to which this Unsigned is to be compared.
-     * @return {@code this <= val}
-     */
-    boolean belowOrEqual(Unsigned val);
-
-    /**
-     * Compares this Unsigned with the specified value.
-     *
-     * @param val value to which this Unsigned is to be compared.
-     * @return {@code this > val}
-     */
-    boolean aboveThan(Unsigned val);
-
-    /**
-     * Compares this Unsigned with the specified value.
-     *
-     * @param val value to which this Unsigned is to be compared.
-     * @return {@code this >= val}
-     */
-    boolean aboveOrEqual(Unsigned val);
-
-    /**
-     * Returns a Unsigned whose value is {@code (this + val)}.
-     * <p>
-     * Note that the right operand is a signed value, while the operation is performed unsigned.
-     * Therefore, the result is only well-defined for positive right operands.
-     *
-     * @param val value to be added to this Unsigned.
-     * @return {@code this + val}
-     */
-    Unsigned add(int val);
-
-    /**
-     * Returns a Unsigned whose value is {@code (this - val)}.
-     * <p>
-     * Note that the right operand is a signed value, while the operation is performed unsigned.
-     * Therefore, the result is only well-defined for positive right operands.
-     *
-     * @param val value to be subtracted from this Unsigned.
-     * @return {@code this - val}
-     */
-    Unsigned subtract(int val);
-
-    /**
-     * Returns a Unsigned whose value is {@code (this * val)}.
-     * <p>
-     * Note that the right operand is a signed value, while the operation is performed unsigned.
-     * Therefore, the result is only well-defined for positive right operands.
-     *
-     * @param val value to be multiplied by this Unsigned.
-     * @return {@code this * val}
-     */
-    Unsigned multiply(int val);
-
-    /**
-     * Returns a Unsigned whose value is {@code (this / val)}.
-     * <p>
-     * Note that the right operand is a signed value, while the operation is performed unsigned.
-     * Therefore, the result is only well-defined for positive right operands.
-     *
-     * @param val value by which this Unsigned is to be divided.
-     * @return {@code this / val}
-     */
-    Unsigned unsignedDivide(int val);
-
-    /**
-     * Returns a Unsigned whose value is {@code (this % val)}.
-     * <p>
-     * Note that the right operand is a signed value, while the operation is performed unsigned.
-     * Therefore, the result is only well-defined for positive right operands.
-     *
-     * @param val value by which this Unsigned is to be divided, and the remainder computed.
-     * @return {@code this % val}
-     */
-    Unsigned unsignedRemainder(int val);
-
-    /**
-     * Returns a Unsigned whose value is {@code (this << n)}.
-     * <p>
-     * Note that the right operand is a signed value, while the operation is performed unsigned.
-     * Therefore, the result is only well-defined for positive right operands.
-     *
-     * @param n shift distance, in bits.
-     * @return {@code this << n}
-     */
-    Unsigned shiftLeft(int n);
-
-    /**
-     * Returns a Unsigned whose value is {@code (this >>> n)}. No sign extension is performed.
-     * <p>
-     * Note that the right operand is a signed value, while the operation is performed unsigned.
-     * Therefore, the result is only well-defined for positive right operands.
-     *
-     * @param n shift distance, in bits.
-     * @return {@code this >> n}
-     */
-    Unsigned unsignedShiftRight(int n);
-
-    /**
-     * Returns a Unsigned whose value is {@code (this & val)}.
-     * <p>
-     * Note that the right operand is a signed value, while the operation is performed unsigned.
-     * Therefore, the result is only well-defined for positive right operands.
-     *
-     * @param val value to be AND'ed with this Unsigned.
-     * @return {@code this & val}
-     */
-    Unsigned and(int val);
-
-    /**
-     * Returns a Unsigned whose value is {@code (this | val)}.
-     * <p>
-     * Note that the right operand is a signed value, while the operation is performed unsigned.
-     * Therefore, the result is only well-defined for positive right operands.
-     *
-     * @param val value to be OR'ed with this Unsigned.
-     * @return {@code this | val}
-     */
-    Unsigned or(int val);
-
-    /**
-     * Returns a Unsigned whose value is {@code (this ^ val)}.
-     * <p>
-     * Note that the right operand is a signed value, while the operation is performed unsigned.
-     * Therefore, the result is only well-defined for positive right operands.
-     *
-     * @param val value to be XOR'ed with this Unsigned.
-     * @return {@code this ^ val}
-     */
-    Unsigned xor(int val);
-
-    /**
-     * Compares this Unsigned with the specified value.
-     * <p>
-     * Note that the right operand is a signed value, while the operation is performed unsigned.
-     * Therefore, the result is only well-defined for positive right operands.
-     *
-     * @param val value to which this Unsigned is to be compared.
-     * @return {@code this == val}
-     */
-    boolean equal(int val);
-
-    /**
-     * Compares this Unsigned with the specified value.
-     * <p>
-     * Note that the right operand is a signed value, while the operation is performed unsigned.
-     * Therefore, the result is only well-defined for positive right operands.
-     *
-     * @param val value to which this Unsigned is to be compared.
-     * @return {@code this != val}
-     */
-    boolean notEqual(int val);
-
-    /**
-     * Compares this Unsigned with the specified value.
-     * <p>
-     * Note that the right operand is a signed value, while the operation is performed unsigned.
-     * Therefore, the result is only well-defined for positive right operands.
-     *
-     * @param val value to which this Unsigned is to be compared.
-     * @return {@code this < val}
-     */
-    boolean belowThan(int val);
-
-    /**
-     * Compares this Unsigned with the specified value.
-     * <p>
-     * Note that the right operand is a signed value, while the operation is performed unsigned.
-     * Therefore, the result is only well-defined for positive right operands.
-     *
-     * @param val value to which this Unsigned is to be compared.
-     * @return {@code this <= val}
-     */
-    boolean belowOrEqual(int val);
-
-    /**
-     * Compares this Unsigned with the specified value.
-     * <p>
-     * Note that the right operand is a signed value, while the operation is performed unsigned.
-     * Therefore, the result is only well-defined for positive right operands.
-     *
-     * @param val value to which this Unsigned is to be compared.
-     * @return {@code this > val}
-     */
-    boolean aboveThan(int val);
-
-    /**
-     * Compares this Unsigned with the specified value.
-     * <p>
-     * Note that the right operand is a signed value, while the operation is performed unsigned.
-     * Therefore, the result is only well-defined for positive right operands.
-     *
-     * @param val value to which this Unsigned is to be compared.
-     * @return {@code this >= val}
-     */
-    boolean aboveOrEqual(int val);
-}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/UnsignedUtils.java	Fri May 12 13:14:25 2017 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,88 +0,0 @@
-/*
- * Copyright (c) 2015, 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
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package org.graalvm.compiler.word;
-
-/**
- * Utility methods on Unsigned values.
- */
-public final class UnsignedUtils {
-
-    private UnsignedUtils() {
-        // This is a class of static methods, so no need for any instances.
-    }
-
-    /**
-     * Round an Unsigned down to the nearest smaller multiple.
-     *
-     * @param that The Unsigned to be rounded down.
-     * @param multiple The multiple to which that Unsigned should be decreased.
-     * @return That Unsigned, but rounded down.
-     */
-    public static Unsigned roundDown(Unsigned that, Unsigned multiple) {
-        return that.unsignedDivide(multiple).multiply(multiple);
-    }
-
-    /**
-     * Round an Unsigned up to the nearest larger multiple.
-     *
-     * @param that The Unsigned to be rounded up.
-     * @param multiple The multiple to which that Unsigned should be increased.
-     * @return That Unsigned, but rounded up.
-     */
-    public static Unsigned roundUp(Unsigned that, Unsigned multiple) {
-        return UnsignedUtils.roundDown(that.add(multiple.subtract(1)), multiple);
-    }
-
-    /**
-     * Check that an Unsigned is an even multiple.
-     *
-     * @param that The Unsigned to be verified as a multiple.
-     * @param multiple The multiple against which the Unsigned should be verified.
-     * @return true if that Unsigned is a multiple, false otherwise.
-     */
-    public static boolean isAMultiple(Unsigned that, Unsigned multiple) {
-        return that.equal(UnsignedUtils.roundDown(that, multiple));
-    }
-
-    /**
-     * The minimum of two Unsigneds.
-     *
-     * @param x An Unsigned.
-     * @param y Another Unsigned.
-     * @return The whichever Unsigned is smaller.
-     */
-    public static Unsigned min(Unsigned x, Unsigned y) {
-        return (x.belowOrEqual(y)) ? x : y;
-    }
-
-    /**
-     * The maximum of two Unsigneds.
-     *
-     * @param x An Unsigned.
-     * @param y Another Unsigned.
-     * @return The whichever Unsigned is larger.
-     */
-    public static Unsigned max(Unsigned x, Unsigned y) {
-        return (x.aboveOrEqual(y)) ? x : y;
-    }
-}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/Word.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/Word.java	Fri May 12 13:56:13 2017 -0700
@@ -29,7 +29,13 @@
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
-import org.graalvm.compiler.core.common.LocationIdentity;
+import org.graalvm.api.word.ComparableWord;
+import org.graalvm.api.word.LocationIdentity;
+import org.graalvm.api.word.Pointer;
+import org.graalvm.api.word.Signed;
+import org.graalvm.api.word.Unsigned;
+import org.graalvm.api.word.WordBase;
+import org.graalvm.api.word.WordFactory;
 import org.graalvm.compiler.core.common.calc.Condition;
 import org.graalvm.compiler.core.common.calc.UnsignedMath;
 import org.graalvm.compiler.debug.GraalError;
@@ -50,7 +56,7 @@
 import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType;
 import org.graalvm.compiler.nodes.memory.address.AddressNode.Address;
 
-public abstract class Word implements Signed, Unsigned, Pointer {
+public abstract class Word extends WordFactory implements Signed, Unsigned, Pointer {
 
     /**
      * Links a method to a canonical operation represented by an {@link Opcode} val.
@@ -71,38 +77,42 @@
     /**
      * The canonical {@link Operation} represented by a method in the {@link Word} class.
      */
-    // @formatter:off
-     public enum Opcode {
-         NODE_CLASS,
-         COMPARISON,
-         NOT,
-         READ_POINTER,
-         READ_OBJECT,
-         READ_BARRIERED,
-         READ_HEAP,
-         WRITE_POINTER,
-         WRITE_OBJECT,
-         WRITE_BARRIERED,
-         CAS_POINTER,
-         INITIALIZE,
-         ZERO,
-         FROM_UNSIGNED,
-         FROM_SIGNED,
-         FROM_ADDRESS,
-         OBJECT_TO_TRACKED,
-         OBJECT_TO_UNTRACKED,
-         TO_OBJECT,
-         TO_OBJECT_NON_NULL,
-         TO_RAW_VALUE,
+    public enum Opcode {
+        NODE_CLASS,
+        COMPARISON,
+        NOT,
+        READ_POINTER,
+        READ_OBJECT,
+        READ_BARRIERED,
+        READ_HEAP,
+        WRITE_POINTER,
+        WRITE_OBJECT,
+        WRITE_BARRIERED,
+        CAS_POINTER,
+        INITIALIZE,
+        FROM_ADDRESS,
+        OBJECT_TO_TRACKED,
+        OBJECT_TO_UNTRACKED,
+        TO_OBJECT,
+        TO_OBJECT_NON_NULL,
+        TO_RAW_VALUE,
     }
-     // @formatter:on
+
+    public static class BoxFactoryImpl implements BoxFactory {
+        @SuppressWarnings("unchecked")
+        @Override
+        public <T extends WordBase> T box(long val) {
+            return (T) HostedWord.boxLong(val);
+        }
+    }
 
     /*
-     * Outside users should use the different signed() and unsigned() methods to ensure proper
+     * Outside users must use the different signed() and unsigned() methods to ensure proper
      * expansion of 32-bit values on 64-bit systems.
      */
-    private static Word box(long val) {
-        return HostedWord.boxLong(val);
+    @SuppressWarnings("unchecked")
+    private static <T extends WordBase> T box(long val) {
+        return (T) HostedWord.boxLong(val);
     }
 
     protected abstract long unbox();
@@ -111,78 +121,6 @@
         return box(val);
     }
 
-    /**
-     * The constant 0, i.e., the word with no bits set. There is no difference between a signed and
-     * unsigned zero.
-     *
-     * @return the constant 0.
-     */
-    @Operation(opcode = Opcode.ZERO)
-    public static Word zero() {
-        return box(0L);
-    }
-
-    /**
-     * Unsafe conversion from a Java long value to a Word. The parameter is treated as an unsigned
-     * 64-bit value (in contrast to the semantics of a Java long).
-     *
-     * @param val a 64 bit unsigned value
-     * @return the value cast to Word
-     */
-    @Operation(opcode = Opcode.FROM_UNSIGNED)
-    public static Word unsigned(long val) {
-        return box(val);
-    }
-
-    /**
-     * Unsafe conversion from a Java long value to a {@link PointerBase pointer}. The parameter is
-     * treated as an unsigned 64-bit value (in contrast to the semantics of a Java long).
-     *
-     * @param val a 64 bit unsigned value
-     * @return the value cast to PointerBase
-     */
-    @Operation(opcode = Opcode.FROM_UNSIGNED)
-    @SuppressWarnings("unchecked")
-    public static <T extends PointerBase> T pointer(long val) {
-        return (T) box(val);
-    }
-
-    /**
-     * Unsafe conversion from a Java int value to a Word. The parameter is treated as an unsigned
-     * 32-bit value (in contrast to the semantics of a Java int).
-     *
-     * @param val a 32 bit unsigned value
-     * @return the value cast to Word
-     */
-    @Operation(opcode = Opcode.FROM_UNSIGNED)
-    public static Word unsigned(int val) {
-        return box(val & 0xffffffffL);
-    }
-
-    /**
-     * Unsafe conversion from a Java long value to a Word. The parameter is treated as a signed
-     * 64-bit value (unchanged semantics of a Java long).
-     *
-     * @param val a 64 bit signed value
-     * @return the value cast to Word
-     */
-    @Operation(opcode = Opcode.FROM_SIGNED)
-    public static Word signed(long val) {
-        return box(val);
-    }
-
-    /**
-     * Unsafe conversion from a Java int value to a Word. The parameter is treated as a signed
-     * 32-bit value (unchanged semantics of a Java int).
-     *
-     * @param val a 32 bit signed value
-     * @return the value cast to Word
-     */
-    @Operation(opcode = Opcode.FROM_SIGNED)
-    public static Word signed(int val) {
-        return box(val);
-    }
-
     @Override
     @Operation(opcode = Opcode.TO_RAW_VALUE)
     public long rawValue() {
@@ -196,7 +134,7 @@
      * deal with derived references, this may work correctly, or result in a compiler error.
      */
     @Operation(opcode = Opcode.OBJECT_TO_TRACKED)
-    public static native Pointer objectToTrackedPointer(Object val);
+    public static native Word objectToTrackedPointer(Object val);
 
     /**
      * Convert an {@link Object} to a {@link Pointer}, dropping the reference information. If the
@@ -211,10 +149,10 @@
      * {@link #objectToTrackedPointer(Object)} instead.
      */
     @Operation(opcode = Opcode.OBJECT_TO_UNTRACKED)
-    public static native Pointer objectToUntrackedPointer(Object val);
+    public static native Word objectToUntrackedPointer(Object val);
 
     @Operation(opcode = Opcode.FROM_ADDRESS)
-    public static native Pointer fromAddress(Address address);
+    public static native Word fromAddress(Address address);
 
     @Override
     @Operation(opcode = Opcode.TO_OBJECT)
@@ -725,7 +663,7 @@
 
     @Override
     @Operation(opcode = Opcode.READ_POINTER)
-    public Word readWord(WordBase offset, LocationIdentity locationIdentity) {
+    public <T extends WordBase> T readWord(WordBase offset, LocationIdentity locationIdentity) {
         return box(UNSAFE.getAddress(add((Word) offset).unbox()));
     }
 
@@ -777,7 +715,7 @@
 
     @Override
     @Operation(opcode = Opcode.READ_POINTER)
-    public Word readWord(int offset, LocationIdentity locationIdentity) {
+    public <T extends WordBase> T readWord(int offset, LocationIdentity locationIdentity) {
         return readWord(signed(offset), locationIdentity);
     }
 
@@ -949,7 +887,7 @@
 
     @Override
     @Operation(opcode = Opcode.READ_POINTER)
-    public Word readWord(WordBase offset) {
+    public <T extends WordBase> T readWord(WordBase offset) {
         return box(UNSAFE.getAddress(add((Word) offset).unbox()));
     }
 
@@ -957,7 +895,6 @@
     @Operation(opcode = Opcode.READ_POINTER)
     public native Object readObject(WordBase offset);
 
-    @Override
     @Operation(opcode = Opcode.READ_HEAP)
     public native Object readObject(WordBase offset, BarrierType barrierType);
 
@@ -1005,7 +942,7 @@
 
     @Override
     @Operation(opcode = Opcode.READ_POINTER)
-    public Word readWord(int offset) {
+    public <T extends WordBase> T readWord(int offset) {
         return readWord(signed(offset));
     }
 
@@ -1015,7 +952,6 @@
         return readObject(signed(offset));
     }
 
-    @Override
     @Operation(opcode = Opcode.READ_HEAP)
     public Object readObject(int offset, BarrierType barrierType) {
         return readObject(signed(offset), barrierType);
@@ -1073,7 +1009,7 @@
 
     @Override
     @Operation(opcode = Opcode.CAS_POINTER)
-    public native Word compareAndSwapWord(WordBase offset, WordBase expectedValue, WordBase newValue, LocationIdentity locationIdentity);
+    public native <T extends WordBase> T compareAndSwapWord(WordBase offset, T expectedValue, T newValue, LocationIdentity locationIdentity);
 
     @Override
     @Operation(opcode = Opcode.CAS_POINTER)
@@ -1179,7 +1115,7 @@
 
     @Override
     @Operation(opcode = Opcode.CAS_POINTER)
-    public Word compareAndSwapWord(int offset, WordBase expectedValue, WordBase newValue, LocationIdentity locationIdentity) {
+    public <T extends WordBase> T compareAndSwapWord(int offset, T expectedValue, T newValue, LocationIdentity locationIdentity) {
         return compareAndSwapWord(signed(offset), expectedValue, newValue, locationIdentity);
     }
 
@@ -1213,6 +1149,13 @@
         return logicCompareAndSwapObject(signed(offset), expectedValue, newValue, locationIdentity);
     }
 
+    /**
+     * This is deprecated because of the easy to mistype name collision between {@link #equals} and
+     * the other equals routines like {@link #equal(Word)}. In general you should never be
+     * statically calling this method for Word types.
+     */
+    @SuppressWarnings("deprecation")
+    @Deprecated
     @Override
     public final boolean equals(Object obj) {
         throw GraalError.shouldNotReachHere("equals must not be called on words");
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/WordBase.java	Fri May 12 13:14:25 2017 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,28 +0,0 @@
-/*
- * Copyright (c) 2012, 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.word;
-
-public interface WordBase {
-
-    long rawValue();
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/WordCastNode.java	Fri May 12 13:56:13 2017 -0700
@@ -0,0 +1,143 @@
+/*
+ * 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.word;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_1;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.type.AbstractPointerStamp;
+import org.graalvm.compiler.core.common.type.ObjectStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.lir.ConstantValue;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.Value;
+import jdk.vm.ci.meta.ValueKind;
+
+/**
+ * Casts between Word and Object exposed by the {@link Word#fromAddress},
+ * {@link Word#objectToTrackedPointer}, {@link Word#objectToUntrackedPointer} and
+ * {@link Word#toObject()} operations. It has an impact on the pointer maps for the GC, so it must
+ * not be scheduled or optimized away.
+ */
+@NodeInfo(cycles = CYCLES_1, size = SIZE_1)
+public final class WordCastNode extends FixedWithNextNode implements LIRLowerable, Canonicalizable {
+
+    public static final NodeClass<WordCastNode> TYPE = NodeClass.create(WordCastNode.class);
+
+    @Input ValueNode input;
+    public final boolean trackedPointer;
+
+    public static WordCastNode wordToObject(ValueNode input, JavaKind wordKind) {
+        assert input.getStackKind() == wordKind;
+        return new WordCastNode(StampFactory.object(), input);
+    }
+
+    public static WordCastNode wordToObjectNonNull(ValueNode input, JavaKind wordKind) {
+        assert input.getStackKind() == wordKind;
+        return new WordCastNode(StampFactory.objectNonNull(), input);
+    }
+
+    public static WordCastNode addressToWord(ValueNode input, JavaKind wordKind) {
+        assert input.stamp() instanceof AbstractPointerStamp;
+        return new WordCastNode(StampFactory.forKind(wordKind), input);
+    }
+
+    public static WordCastNode objectToTrackedPointer(ValueNode input, JavaKind wordKind) {
+        assert input.stamp() instanceof ObjectStamp;
+        return new WordCastNode(StampFactory.forKind(wordKind), input, true);
+    }
+
+    public static WordCastNode objectToUntrackedPointer(ValueNode input, JavaKind wordKind) {
+        assert input.stamp() instanceof ObjectStamp;
+        return new WordCastNode(StampFactory.forKind(wordKind), input, false);
+    }
+
+    protected WordCastNode(Stamp stamp, ValueNode input) {
+        this(stamp, input, true);
+    }
+
+    protected WordCastNode(Stamp stamp, ValueNode input, boolean trackedPointer) {
+        super(TYPE, stamp);
+        this.input = input;
+        this.trackedPointer = trackedPointer;
+    }
+
+    public ValueNode getInput() {
+        return input;
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        if (tool.allUsagesAvailable() && hasNoUsages()) {
+            /* If the cast is unused, it can be eliminated. */
+            return input;
+        }
+
+        assert !stamp().isCompatible(input.stamp());
+        if (input.isConstant()) {
+            /* Null pointers are uncritical for GC, so they can be constant folded. */
+            if (input.asJavaConstant().isNull()) {
+                return ConstantNode.forIntegerStamp(stamp(), 0);
+            } else if (input.asJavaConstant().getJavaKind().isNumericInteger() && input.asJavaConstant().asLong() == 0) {
+                return ConstantNode.forConstant(stamp(), JavaConstant.NULL_POINTER, tool.getMetaAccess());
+            }
+        }
+
+        return this;
+    }
+
+    @Override
+    public void generate(NodeLIRBuilderTool generator) {
+        Value value = generator.operand(input);
+        ValueKind<?> kind = generator.getLIRGeneratorTool().getLIRKind(stamp());
+        assert kind.getPlatformKind().getSizeInBytes() == value.getPlatformKind().getSizeInBytes();
+
+        if (trackedPointer && LIRKind.isValue(kind) && !LIRKind.isValue(value)) {
+            // just change the PlatformKind, but don't drop reference information
+            kind = value.getValueKind().changeType(kind.getPlatformKind());
+        }
+
+        if (kind.equals(value.getValueKind()) && !(value instanceof ConstantValue)) {
+            generator.setResult(this, value);
+        } else {
+            AllocatableValue result = generator.getLIRGeneratorTool().newVariable(kind);
+            generator.getLIRGeneratorTool().emitMove(result, value);
+            generator.setResult(this, result);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/WordOperationPlugin.java	Fri May 12 13:56:13 2017 -0700
@@ -0,0 +1,506 @@
+/*
+ * Copyright (c) 2015, 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.word;
+
+import static org.graalvm.api.word.LocationIdentity.any;
+import static org.graalvm.compiler.nodes.ConstantNode.forInt;
+import static org.graalvm.compiler.nodes.ConstantNode.forIntegerKind;
+
+import java.lang.reflect.Constructor;
+import java.util.Arrays;
+
+import org.graalvm.api.word.LocationIdentity;
+import org.graalvm.api.word.WordFactory;
+import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
+import org.graalvm.compiler.bytecode.BridgeMethodUtils;
+import org.graalvm.compiler.core.common.calc.Condition;
+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.core.common.type.TypeReference;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.Invoke;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.CompareNode;
+import org.graalvm.compiler.nodes.calc.ConditionalNode;
+import org.graalvm.compiler.nodes.calc.IntegerBelowNode;
+import org.graalvm.compiler.nodes.calc.IntegerEqualsNode;
+import org.graalvm.compiler.nodes.calc.IntegerLessThanNode;
+import org.graalvm.compiler.nodes.calc.NarrowNode;
+import org.graalvm.compiler.nodes.calc.SignExtendNode;
+import org.graalvm.compiler.nodes.calc.XorNode;
+import org.graalvm.compiler.nodes.calc.ZeroExtendNode;
+import org.graalvm.compiler.nodes.extended.JavaReadNode;
+import org.graalvm.compiler.nodes.extended.JavaWriteNode;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
+import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderTool;
+import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin;
+import org.graalvm.compiler.nodes.graphbuilderconf.NodePlugin;
+import org.graalvm.compiler.nodes.graphbuilderconf.TypePlugin;
+import org.graalvm.compiler.nodes.java.AbstractCompareAndSwapNode;
+import org.graalvm.compiler.nodes.java.LoadFieldNode;
+import org.graalvm.compiler.nodes.java.LoadIndexedNode;
+import org.graalvm.compiler.nodes.java.LogicCompareAndSwapNode;
+import org.graalvm.compiler.nodes.java.StoreIndexedNode;
+import org.graalvm.compiler.nodes.java.ValueCompareAndSwapNode;
+import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
+import org.graalvm.compiler.nodes.type.StampTool;
+import org.graalvm.compiler.word.Word.Opcode;
+import org.graalvm.compiler.word.Word.Operation;
+
+import jdk.vm.ci.code.BailoutException;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.JavaType;
+import jdk.vm.ci.meta.JavaTypeProfile;
+import jdk.vm.ci.meta.ResolvedJavaField;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+/**
+ * A plugin for calls to {@linkplain Operation word operations}, as well as all other nodes that
+ * need special handling for {@link Word} types.
+ */
+public class WordOperationPlugin extends WordFactory implements NodePlugin, TypePlugin, InlineInvokePlugin {
+    protected final WordTypes wordTypes;
+    protected final JavaKind wordKind;
+    protected final SnippetReflectionProvider snippetReflection;
+
+    public WordOperationPlugin(SnippetReflectionProvider snippetReflection, WordTypes wordTypes) {
+        this.snippetReflection = snippetReflection;
+        this.wordTypes = wordTypes;
+        this.wordKind = wordTypes.getWordKind();
+    }
+
+    @Override
+    public boolean canChangeStackKind(GraphBuilderContext b) {
+        return true;
+    }
+
+    /**
+     * Processes a call to a method if it is annotated as a word operation by adding nodes to the
+     * graph being built that implement the denoted operation.
+     *
+     * @return {@code true} iff {@code method} is annotated with {@link Operation} (and was thus
+     *         processed by this method)
+     */
+    @Override
+    public boolean handleInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) {
+        if (!wordTypes.isWordOperation(method)) {
+            return false;
+        }
+        processWordOperation(b, args, wordTypes.getWordOperation(method, b.getMethod().getDeclaringClass()));
+        return true;
+    }
+
+    @Override
+    public StampPair interceptType(GraphBuilderTool b, JavaType declaredType, boolean nonNull) {
+        Stamp wordStamp = null;
+        if (declaredType instanceof ResolvedJavaType) {
+            ResolvedJavaType resolved = (ResolvedJavaType) declaredType;
+            if (wordTypes.isWord(resolved)) {
+                wordStamp = wordTypes.getWordStamp(resolved);
+            } else if (resolved.isArray() && wordTypes.isWord(resolved.getElementalType())) {
+                TypeReference trusted = TypeReference.createTrustedWithoutAssumptions(resolved);
+                wordStamp = StampFactory.object(trusted, nonNull);
+            }
+        }
+        if (wordStamp != null) {
+            return StampPair.createSingle(wordStamp);
+        } else {
+            return null;
+        }
+    }
+
+    @Override
+    public void notifyNotInlined(GraphBuilderContext b, ResolvedJavaMethod method, Invoke invoke) {
+        if (wordTypes.isWord(invoke.asNode())) {
+            invoke.asNode().setStamp(wordTypes.getWordStamp(StampTool.typeOrNull(invoke.asNode())));
+        }
+    }
+
+    @Override
+    public boolean handleLoadField(GraphBuilderContext b, ValueNode receiver, ResolvedJavaField field) {
+        StampPair wordStamp = interceptType(b, field.getType(), false);
+        if (wordStamp != null) {
+            LoadFieldNode loadFieldNode = LoadFieldNode.createOverrideStamp(wordStamp, receiver, field);
+            b.addPush(field.getJavaKind(), loadFieldNode);
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public boolean handleLoadStaticField(GraphBuilderContext b, ResolvedJavaField staticField) {
+        return handleLoadField(b, null, staticField);
+    }
+
+    @Override
+    public boolean handleLoadIndexed(GraphBuilderContext b, ValueNode array, ValueNode index, JavaKind elementKind) {
+        ResolvedJavaType arrayType = StampTool.typeOrNull(array);
+        /*
+         * There are cases where the array does not have a known type yet, i.e., the type is null.
+         * In that case we assume it is not a word type.
+         */
+        if (arrayType != null && wordTypes.isWord(arrayType.getComponentType())) {
+            assert elementKind == JavaKind.Object;
+            b.addPush(elementKind, createLoadIndexedNode(array, index));
+            return true;
+        }
+        return false;
+    }
+
+    protected LoadIndexedNode createLoadIndexedNode(ValueNode array, ValueNode index) {
+        return new LoadIndexedNode(null, array, index, wordTypes.getWordKind());
+    }
+
+    @Override
+    public boolean handleStoreField(GraphBuilderContext b, ValueNode object, ResolvedJavaField field, ValueNode value) {
+        if (field.getJavaKind() == JavaKind.Object) {
+            boolean isWordField = wordTypes.isWord(field.getType());
+            boolean isWordValue = value.getStackKind() == wordTypes.getWordKind();
+
+            if (isWordField && !isWordValue) {
+                throw bailout(b, "Cannot store a non-word value into a word field: " + field.format("%H.%n"));
+            } else if (!isWordField && isWordValue) {
+                throw bailout(b, "Cannot store a word value into a non-word field: " + field.format("%H.%n"));
+            }
+        }
+
+        /* We never need to intercept the field store. */
+        return false;
+    }
+
+    @Override
+    public boolean handleStoreStaticField(GraphBuilderContext b, ResolvedJavaField field, ValueNode value) {
+        return handleStoreField(b, null, field, value);
+    }
+
+    @Override
+    public boolean handleStoreIndexed(GraphBuilderContext b, ValueNode array, ValueNode index, JavaKind elementKind, ValueNode value) {
+        ResolvedJavaType arrayType = StampTool.typeOrNull(array);
+        if (arrayType != null && wordTypes.isWord(arrayType.getComponentType())) {
+            assert elementKind == JavaKind.Object;
+            if (value.getStackKind() != wordTypes.getWordKind()) {
+                throw bailout(b, "Cannot store a non-word value into a word array: " + arrayType.toJavaName(true));
+            }
+            b.add(createStoreIndexedNode(array, index, value));
+            return true;
+        }
+        if (elementKind == JavaKind.Object && value.getStackKind() == wordTypes.getWordKind()) {
+            throw bailout(b, "Cannot store a word value into a non-word array: " + arrayType.toJavaName(true));
+        }
+        return false;
+    }
+
+    protected StoreIndexedNode createStoreIndexedNode(ValueNode array, ValueNode index, ValueNode value) {
+        return new StoreIndexedNode(array, index, wordTypes.getWordKind(), value);
+    }
+
+    @Override
+    public boolean handleCheckCast(GraphBuilderContext b, ValueNode object, ResolvedJavaType type, JavaTypeProfile profile) {
+        if (!wordTypes.isWord(type)) {
+            if (object.getStackKind() != JavaKind.Object) {
+                throw bailout(b, "Cannot cast a word value to a non-word type: " + type.toJavaName(true));
+            }
+            return false;
+        }
+
+        if (object.getStackKind() != wordTypes.getWordKind()) {
+            throw bailout(b, "Cannot cast a non-word value to a word type: " + type.toJavaName(true));
+        }
+        b.push(JavaKind.Object, object);
+        return true;
+    }
+
+    @Override
+    public boolean handleInstanceOf(GraphBuilderContext b, ValueNode object, ResolvedJavaType type, JavaTypeProfile profile) {
+        if (wordTypes.isWord(type)) {
+            throw bailout(b, "Cannot use instanceof for word a type: " + type.toJavaName(true));
+        } else if (object.getStackKind() != JavaKind.Object) {
+            throw bailout(b, "Cannot use instanceof on a word value: " + type.toJavaName(true));
+        }
+        return false;
+    }
+
+    protected void processWordOperation(GraphBuilderContext b, ValueNode[] args, ResolvedJavaMethod wordMethod) throws GraalError {
+        JavaKind returnKind = wordMethod.getSignature().getReturnKind();
+        WordFactory.FactoryOperation factoryOperation = BridgeMethodUtils.getAnnotation(WordFactory.FactoryOperation.class, wordMethod);
+        if (factoryOperation != null) {
+            switch (factoryOperation.opcode()) {
+                case ZERO:
+                    assert args.length == 0;
+                    b.addPush(returnKind, forIntegerKind(wordKind, 0L));
+                    return;
+
+                case FROM_UNSIGNED:
+                    assert args.length == 1;
+                    b.push(returnKind, fromUnsigned(b, args[0]));
+                    return;
+
+                case FROM_SIGNED:
+                    assert args.length == 1;
+                    b.push(returnKind, fromSigned(b, args[0]));
+                    return;
+            }
+        }
+
+        Word.Operation operation = BridgeMethodUtils.getAnnotation(Word.Operation.class, wordMethod);
+        switch (operation.opcode()) {
+            case NODE_CLASS:
+                assert args.length == 2;
+                ValueNode left = args[0];
+                ValueNode right = operation.rightOperandIsInt() ? toUnsigned(b, args[1], JavaKind.Int) : fromSigned(b, args[1]);
+
+                b.addPush(returnKind, createBinaryNodeInstance(operation.node(), left, right));
+                break;
+
+            case COMPARISON:
+                assert args.length == 2;
+                b.push(returnKind, comparisonOp(b, operation.condition(), args[0], fromSigned(b, args[1])));
+                break;
+
+            case NOT:
+                assert args.length == 1;
+                b.addPush(returnKind, new XorNode(args[0], b.add(forIntegerKind(wordKind, -1))));
+                break;
+
+            case READ_POINTER:
+            case READ_OBJECT:
+            case READ_BARRIERED: {
+                assert args.length == 2 || args.length == 3;
+                JavaKind readKind = wordTypes.asKind(wordMethod.getSignature().getReturnType(wordMethod.getDeclaringClass()));
+                AddressNode address = makeAddress(b, args[0], args[1]);
+                LocationIdentity location;
+                if (args.length == 2) {
+                    location = any();
+                } else {
+                    assert args[2].isConstant();
+                    location = snippetReflection.asObject(LocationIdentity.class, args[2].asJavaConstant());
+                }
+                b.push(returnKind, readOp(b, readKind, address, location, operation.opcode()));
+                break;
+            }
+            case READ_HEAP: {
+                assert args.length == 3;
+                JavaKind readKind = wordTypes.asKind(wordMethod.getSignature().getReturnType(wordMethod.getDeclaringClass()));
+                AddressNode address = makeAddress(b, args[0], args[1]);
+                BarrierType barrierType = snippetReflection.asObject(BarrierType.class, args[2].asJavaConstant());
+                b.push(returnKind, readOp(b, readKind, address, any(), barrierType, true));
+                break;
+            }
+            case WRITE_POINTER:
+            case WRITE_OBJECT:
+            case WRITE_BARRIERED:
+            case INITIALIZE: {
+                assert args.length == 3 || args.length == 4;
+                JavaKind writeKind = wordTypes.asKind(wordMethod.getSignature().getParameterType(wordMethod.isStatic() ? 2 : 1, wordMethod.getDeclaringClass()));
+                AddressNode address = makeAddress(b, args[0], args[1]);
+                LocationIdentity location;
+                if (args.length == 3) {
+                    location = any();
+                } else {
+                    assert args[3].isConstant();
+                    location = snippetReflection.asObject(LocationIdentity.class, args[3].asJavaConstant());
+                }
+                writeOp(b, writeKind, address, location, args[2], operation.opcode());
+                break;
+            }
+
+            case TO_RAW_VALUE:
+                assert args.length == 1;
+                b.push(returnKind, toUnsigned(b, args[0], JavaKind.Long));
+                break;
+
+            case OBJECT_TO_TRACKED:
+                assert args.length == 1;
+                WordCastNode objectToTracked = b.add(WordCastNode.objectToTrackedPointer(args[0], wordKind));
+                b.push(returnKind, objectToTracked);
+                break;
+
+            case OBJECT_TO_UNTRACKED:
+                assert args.length == 1;
+                WordCastNode objectToUntracked = b.add(WordCastNode.objectToUntrackedPointer(args[0], wordKind));
+                b.push(returnKind, objectToUntracked);
+                break;
+
+            case FROM_ADDRESS:
+                assert args.length == 1;
+                WordCastNode addressToWord = b.add(WordCastNode.addressToWord(args[0], wordKind));
+                b.push(returnKind, addressToWord);
+                break;
+
+            case TO_OBJECT:
+                assert args.length == 1;
+                WordCastNode wordToObject = b.add(WordCastNode.wordToObject(args[0], wordKind));
+                b.push(returnKind, wordToObject);
+                break;
+
+            case TO_OBJECT_NON_NULL:
+                assert args.length == 1;
+                WordCastNode wordToObjectNonNull = b.add(WordCastNode.wordToObjectNonNull(args[0], wordKind));
+                b.push(returnKind, wordToObjectNonNull);
+                break;
+
+            case CAS_POINTER:
+                assert args.length == 5;
+                AddressNode address = makeAddress(b, args[0], args[1]);
+                JavaKind valueKind = wordTypes.asKind(wordMethod.getSignature().getParameterType(1, wordMethod.getDeclaringClass()));
+                assert valueKind.equals(wordTypes.asKind(wordMethod.getSignature().getParameterType(2, wordMethod.getDeclaringClass()))) : wordMethod.getSignature();
+                assert args[4].isConstant() : Arrays.toString(args);
+                LocationIdentity location = snippetReflection.asObject(LocationIdentity.class, args[4].asJavaConstant());
+                JavaType returnType = wordMethod.getSignature().getReturnType(wordMethod.getDeclaringClass());
+                b.addPush(returnKind, casOp(valueKind, wordTypes.asKind(returnType), address, location, args[2], args[3]));
+                break;
+            default:
+                throw new GraalError("Unknown opcode: %s", operation.opcode());
+        }
+    }
+
+    /**
+     * Create an instance of a binary node which is used to lower {@link Word} operations. This
+     * method is called for all {@link Word} operations which are annotated with @Operation(node =
+     * ...) and encapsulates the reflective allocation of the node.
+     */
+    private static ValueNode createBinaryNodeInstance(Class<? extends ValueNode> nodeClass, ValueNode left, ValueNode right) {
+        try {
+            Constructor<?> cons = nodeClass.getDeclaredConstructor(ValueNode.class, ValueNode.class);
+            return (ValueNode) cons.newInstance(left, right);
+        } catch (Throwable ex) {
+            throw new GraalError(ex).addContext(nodeClass.getName());
+        }
+    }
+
+    private ValueNode comparisonOp(GraphBuilderContext graph, Condition condition, ValueNode left, ValueNode right) {
+        assert left.getStackKind() == wordKind && right.getStackKind() == wordKind;
+
+        // mirroring gets the condition into canonical form
+        boolean mirror = condition.canonicalMirror();
+
+        ValueNode a = mirror ? right : left;
+        ValueNode b = mirror ? left : right;
+
+        CompareNode comparison;
+        if (condition == Condition.EQ || condition == Condition.NE) {
+            comparison = new IntegerEqualsNode(a, b);
+        } else if (condition.isUnsigned()) {
+            comparison = new IntegerBelowNode(a, b);
+        } else {
+            comparison = new IntegerLessThanNode(a, b);
+        }
+
+        ConstantNode trueValue = graph.add(forInt(1));
+        ConstantNode falseValue = graph.add(forInt(0));
+
+        if (condition.canonicalNegate()) {
+            ConstantNode temp = trueValue;
+            trueValue = falseValue;
+            falseValue = temp;
+        }
+        ConditionalNode materialize = graph.add(new ConditionalNode(graph.add(comparison), trueValue, falseValue));
+        return materialize;
+    }
+
+    protected ValueNode readOp(GraphBuilderContext b, JavaKind readKind, AddressNode address, LocationIdentity location, Opcode op) {
+        assert op == Opcode.READ_POINTER || op == Opcode.READ_OBJECT || op == Opcode.READ_BARRIERED;
+        final BarrierType barrier = (op == Opcode.READ_BARRIERED ? BarrierType.PRECISE : BarrierType.NONE);
+        final boolean compressible = (op == Opcode.READ_OBJECT || op == Opcode.READ_BARRIERED);
+
+        return readOp(b, readKind, address, location, barrier, compressible);
+    }
+
+    public static ValueNode readOp(GraphBuilderContext b, JavaKind readKind, AddressNode address, LocationIdentity location, BarrierType barrierType, boolean compressible) {
+        /*
+         * A JavaReadNode lowered to a ReadNode that will not float. This means it cannot float
+         * above an explicit zero check on its base address or any other test that ensures the read
+         * is safe.
+         */
+        JavaReadNode read = b.add(new JavaReadNode(readKind, address, location, barrierType, compressible));
+        return read;
+    }
+
+    protected void writeOp(GraphBuilderContext b, JavaKind writeKind, AddressNode address, LocationIdentity location, ValueNode value, Opcode op) {
+        assert op == Opcode.WRITE_POINTER || op == Opcode.WRITE_OBJECT || op == Opcode.WRITE_BARRIERED || op == Opcode.INITIALIZE;
+        final BarrierType barrier = (op == Opcode.WRITE_BARRIERED ? BarrierType.PRECISE : BarrierType.NONE);
+        final boolean compressible = (op == Opcode.WRITE_OBJECT || op == Opcode.WRITE_BARRIERED);
+        assert op != Opcode.INITIALIZE || location.isInit() : "must use init location for initializing";
+        b.add(new JavaWriteNode(writeKind, address, location, value, barrier, compressible));
+    }
+
+    protected AbstractCompareAndSwapNode casOp(JavaKind writeKind, JavaKind returnKind, AddressNode address, LocationIdentity location, ValueNode expectedValue, ValueNode newValue) {
+        boolean isLogic = returnKind == JavaKind.Boolean;
+        assert isLogic || writeKind == returnKind : writeKind + " != " + returnKind;
+        AbstractCompareAndSwapNode cas;
+        if (isLogic) {
+            cas = new LogicCompareAndSwapNode(address, expectedValue, newValue, location);
+        } else {
+            cas = new ValueCompareAndSwapNode(address, expectedValue, newValue, location);
+        }
+        return cas;
+    }
+
+    public AddressNode makeAddress(GraphBuilderContext b, ValueNode base, ValueNode offset) {
+        return b.add(new OffsetAddressNode(base, fromSigned(b, offset)));
+    }
+
+    public ValueNode fromUnsigned(GraphBuilderContext b, ValueNode value) {
+        return convert(b, value, wordKind, true);
+    }
+
+    public ValueNode fromSigned(GraphBuilderContext b, ValueNode value) {
+        return convert(b, value, wordKind, false);
+    }
+
+    public ValueNode toUnsigned(GraphBuilderContext b, ValueNode value, JavaKind toKind) {
+        return convert(b, value, toKind, true);
+    }
+
+    public ValueNode convert(GraphBuilderContext b, ValueNode value, JavaKind toKind, boolean unsigned) {
+        if (value.getStackKind() == toKind) {
+            return value;
+        }
+
+        if (toKind == JavaKind.Int) {
+            assert value.getStackKind() == JavaKind.Long;
+            return b.add(new NarrowNode(value, 32));
+        } else {
+            assert toKind == JavaKind.Long;
+            assert value.getStackKind() == JavaKind.Int;
+            if (unsigned) {
+                return b.add(new ZeroExtendNode(value, 64));
+            } else {
+                return b.add(new SignExtendNode(value, 64));
+            }
+        }
+    }
+
+    public WordTypes getWordTypes() {
+        return wordTypes;
+    }
+
+    private static BailoutException bailout(GraphBuilderContext b, String msg) {
+        throw b.bailout(msg + "\nat " + b.getCode().asStackTraceElement(b.bci()));
+    }
+}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/WordTypes.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/WordTypes.java	Fri May 12 13:56:13 2017 -0700
@@ -22,7 +22,8 @@
  */
 package org.graalvm.compiler.word;
 
-import org.graalvm.compiler.bytecode.BridgeMethodUtils;
+import org.graalvm.api.word.WordBase;
+import org.graalvm.api.word.WordFactory;
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.nodes.ValueNode;
@@ -51,6 +52,11 @@
     private final ResolvedJavaType wordImplType;
 
     /**
+     * Resolved type for {@link WordFactory}.
+     */
+    private final ResolvedJavaType wordFactoryType;
+
+    /**
      * Resolved type for {@link ObjectAccess}.
      */
     private final ResolvedJavaType objectAccessType;
@@ -66,14 +72,21 @@
         this.wordKind = wordKind;
         this.wordBaseType = metaAccess.lookupJavaType(WordBase.class);
         this.wordImplType = metaAccess.lookupJavaType(Word.class);
+        this.wordFactoryType = metaAccess.lookupJavaType(WordFactory.class);
         this.objectAccessType = metaAccess.lookupJavaType(ObjectAccess.class);
         this.barrieredAccessType = metaAccess.lookupJavaType(BarrieredAccess.class);
+
+        this.wordImplType.initialize();
     }
 
     /**
      * Determines if a given method denotes a word operation.
      */
     public boolean isWordOperation(ResolvedJavaMethod targetMethod) {
+        final boolean isWordFactory = wordFactoryType.equals(targetMethod.getDeclaringClass());
+        if (isWordFactory) {
+            return true;
+        }
         final boolean isObjectAccess = objectAccessType.equals(targetMethod.getDeclaringClass());
         final boolean isBarrieredAccess = barrieredAccessType.equals(targetMethod.getDeclaringClass());
         if (isObjectAccess || isBarrieredAccess) {
@@ -99,7 +112,6 @@
             wordMethod = wordImplType.resolveConcreteMethod(targetMethod, callingContextType);
         }
         assert wordMethod != null : targetMethod;
-        assert BridgeMethodUtils.getAnnotation(Operation.class, wordMethod) != null;
         return wordMethod;
     }
 
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/nodes/WordCastNode.java	Fri May 12 13:14:25 2017 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,144 +0,0 @@
-/*
- * 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
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package org.graalvm.compiler.word.nodes;
-
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_1;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
-
-import org.graalvm.compiler.core.common.LIRKind;
-import org.graalvm.compiler.core.common.type.AbstractPointerStamp;
-import org.graalvm.compiler.core.common.type.ObjectStamp;
-import org.graalvm.compiler.core.common.type.Stamp;
-import org.graalvm.compiler.core.common.type.StampFactory;
-import org.graalvm.compiler.graph.Node;
-import org.graalvm.compiler.graph.NodeClass;
-import org.graalvm.compiler.graph.spi.Canonicalizable;
-import org.graalvm.compiler.graph.spi.CanonicalizerTool;
-import org.graalvm.compiler.lir.ConstantValue;
-import org.graalvm.compiler.nodeinfo.NodeInfo;
-import org.graalvm.compiler.nodes.ConstantNode;
-import org.graalvm.compiler.nodes.FixedWithNextNode;
-import org.graalvm.compiler.nodes.ValueNode;
-import org.graalvm.compiler.nodes.spi.LIRLowerable;
-import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
-import org.graalvm.compiler.word.Word.Opcode;
-
-import jdk.vm.ci.meta.AllocatableValue;
-import jdk.vm.ci.meta.JavaConstant;
-import jdk.vm.ci.meta.JavaKind;
-import jdk.vm.ci.meta.Value;
-import jdk.vm.ci.meta.ValueKind;
-
-/**
- * Casts between Word and Object exposed by the {@link Opcode#FROM_ADDRESS},
- * {@link Opcode#OBJECT_TO_TRACKED}, {@link Opcode#OBJECT_TO_UNTRACKED} and {@link Opcode#TO_OBJECT}
- * operations. It has an impact on the pointer maps for the GC, so it must not be scheduled or
- * optimized away.
- */
-@NodeInfo(cycles = CYCLES_1, size = SIZE_1)
-public final class WordCastNode extends FixedWithNextNode implements LIRLowerable, Canonicalizable {
-
-    public static final NodeClass<WordCastNode> TYPE = NodeClass.create(WordCastNode.class);
-
-    @Input ValueNode input;
-    public final boolean trackedPointer;
-
-    public static WordCastNode wordToObject(ValueNode input, JavaKind wordKind) {
-        assert input.getStackKind() == wordKind;
-        return new WordCastNode(StampFactory.object(), input);
-    }
-
-    public static WordCastNode wordToObjectNonNull(ValueNode input, JavaKind wordKind) {
-        assert input.getStackKind() == wordKind;
-        return new WordCastNode(StampFactory.objectNonNull(), input);
-    }
-
-    public static WordCastNode addressToWord(ValueNode input, JavaKind wordKind) {
-        assert input.stamp() instanceof AbstractPointerStamp;
-        return new WordCastNode(StampFactory.forKind(wordKind), input);
-    }
-
-    public static WordCastNode objectToTrackedPointer(ValueNode input, JavaKind wordKind) {
-        assert input.stamp() instanceof ObjectStamp;
-        return new WordCastNode(StampFactory.forKind(wordKind), input, true);
-    }
-
-    public static WordCastNode objectToUntrackedPointer(ValueNode input, JavaKind wordKind) {
-        assert input.stamp() instanceof ObjectStamp;
-        return new WordCastNode(StampFactory.forKind(wordKind), input, false);
-    }
-
-    protected WordCastNode(Stamp stamp, ValueNode input) {
-        this(stamp, input, true);
-    }
-
-    protected WordCastNode(Stamp stamp, ValueNode input, boolean trackedPointer) {
-        super(TYPE, stamp);
-        this.input = input;
-        this.trackedPointer = trackedPointer;
-    }
-
-    public ValueNode getInput() {
-        return input;
-    }
-
-    @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (tool.allUsagesAvailable() && hasNoUsages()) {
-            /* If the cast is unused, it can be eliminated. */
-            return input;
-        }
-
-        assert !stamp().isCompatible(input.stamp());
-        if (input.isConstant()) {
-            /* Null pointers are uncritical for GC, so they can be constant folded. */
-            if (input.asJavaConstant().isNull()) {
-                return ConstantNode.forIntegerStamp(stamp(), 0);
-            } else if (input.asJavaConstant().getJavaKind().isNumericInteger() && input.asJavaConstant().asLong() == 0) {
-                return ConstantNode.forConstant(stamp(), JavaConstant.NULL_POINTER, tool.getMetaAccess());
-            }
-        }
-
-        return this;
-    }
-
-    @Override
-    public void generate(NodeLIRBuilderTool generator) {
-        Value value = generator.operand(input);
-        ValueKind<?> kind = generator.getLIRGeneratorTool().getLIRKind(stamp());
-        assert kind.getPlatformKind().getSizeInBytes() == value.getPlatformKind().getSizeInBytes();
-
-        if (trackedPointer && LIRKind.isValue(kind) && !LIRKind.isValue(value)) {
-            // just change the PlatformKind, but don't drop reference information
-            kind = value.getValueKind().changeType(kind.getPlatformKind());
-        }
-
-        if (kind.equals(value.getValueKind()) && !(value instanceof ConstantValue)) {
-            generator.setResult(this, value);
-        } else {
-            AllocatableValue result = generator.getLIRGeneratorTool().newVariable(kind);
-            generator.getLIRGeneratorTool().emitMove(result, value);
-            generator.setResult(this, result);
-        }
-    }
-}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/impl/EconomicMapImpl.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/impl/EconomicMapImpl.java	Fri May 12 13:56:13 2017 -0700
@@ -815,7 +815,7 @@
         while (cursor.advance()) {
             builder.append("(").append(cursor.getKey()).append(",").append(cursor.getValue()).append("),");
         }
-        builder.append("}");
+        builder.append("})");
         return builder.toString();
     }
 
--- a/hotspot/test/ProblemList.txt	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/test/ProblemList.txt	Fri May 12 13:56:13 2017 -0700
@@ -44,6 +44,7 @@
 compiler/compilercontrol/jcmd/ClearDirectivesFileStackTest.java 8140405 generic-all
 compiler/jvmci/compilerToVM/GetResolvedJavaTypeTest.java 8158860 generic-all
 compiler/jvmci/compilerToVM/InvalidateInstalledCodeTest.java 8163894 generic-all
+compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/NativeCallTest.java 8180324 generic-all
 compiler/startup/SmallCodeCacheStartup.java 8134286 generic-all
 compiler/tiered/LevelTransitionTest.java 8067651 generic-all
 compiler/types/correctness/CorrectnessTest.java 8066173 generic-all